Oliver Marsh
193 posts / 1 project
Olster1.github.io
Attach assets to exe

In a handmade chat I remember Casey say you can attach your assets to the end of your exe to turn your program into a single file.

The only way I can work out how do this is append the assets to the end of the exe, but instead of having the meta data (like asset offsets etc.) straight after where the original exe ended, putting it at the end. So I can get the file size of my bundled exe when I run my program & move backward from the end of the file.

Is this how you would do it without knowing the size of your original exe prior to building it?

Hope I explained it satisfactory 😅

Mārtiņš Možeiko
2381 posts / 2 projects
Attach assets to exe
Edited by Mārtiņš Možeiko on

That is one way how to do that. Sometimes strict corporate anti-virus software may not like that, because technically those kind of exe files have invalid format.

"Proper" way is to put them in resources.

Create whatever.rc file and put all your assets there in following format:

1 RCDATA "image.png"
2 RCDATA "sounds.wav"
3 RCDATA ...


void LoadAsset(int id)
{
HRSRC res = FindResource(GetModuleHandle(0), MAKEINTRESOURCE(id), RT_RCDATA);
void* data = LockResource(handle);
DWORD size = SizeofResource(0, res);
// ... use data & size
}


You can even share those 1/2/3 numbers with your c code by having them as #define's in some .h file and including it in .rc and .c files.

And if you choose to use clang compiler, then there is even better way - which works on Windows and Linux the same, using .incbin inline assembly directive: https://gist.github.com/mmozeiko/ed9655cf50341553d282 This way you can have all your assets referenced from source code.

Regardless of which option you choose, don't forget that exe/dll files on Windows have 2GB size limitation.

Oliver Marsh
193 posts / 1 project
Olster1.github.io
Attach assets to exe

Thanks Martin, that helps a lot. Oh didn't realise the 2gb limit which might make it not worth it.

3 posts
Attach assets to exe
Edited by Adamarla on Reason: Missed detail in previous post

Could your INCBIN macro be used to include separate glsl files as char* literals? I guess the difference would be appending a 0 byte. A separate file would make going to errors by line number easier, improve syntax highlighting and indentation.

I suppose for msvc it would need to preprocess to another file for inclusion.

Mārtiņš Možeiko
2381 posts / 2 projects
Attach assets to exe
Edited by Mārtiņš Možeiko on

incbin can include as many files as you want. Just use different name for variable name. Currently it automatically appends 0 byte at end (that's what .byte 0 means there).

Not sure what you mean by separate files. When GLSL error happens, the shader compiler does not know filename where string is coming from, it will not show .c/.cpp file name. It will show line number in original glsl file. It's your job to map it to correct file name when you get error message.

As for msvc - yeah, it does not support this kind of inline assembly. What I've done before is to make custom build step for .c file that contains these incbins, and call clang-cl.exe on them - that produces same .obj as cl.exe that I can link together. Then simply have extern's to access them for other TU's.

Neo Ar
165 posts / 1 project
riscy.tv host
Attach assets to exe

What is the reasoning for the 16-byte alignment? I don't know as much about x86; I thought we just want 4-byte alignment for data and 16-byte alignment was just a stack abi convention? In noid I used 4-byte alignment for this (https://gitlab.com/riscy-business/noid/-/blob/v1.0.0-alpha.5.1/ototo_kun.s) but if there is a perf reason for a different alignment I'll change it. Also should .balign be preferred over .align for any reason here / any other recommendations to improve how I did it for noid?

Mārtiņš Možeiko
2381 posts / 2 projects
Attach assets to exe
Edited by Mārtiņš Možeiko on
.align number is platform specific. For some targets it is amount of bytes, in some it is log2 of amount (basically zero bit count in LSB). .balign is always in bytes for GNU compatible assemblers.