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 😅

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 ...

Then in your source code to load asset you do:

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

And compile .rc file with rc.exe and add .res file it produces to your linker.

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.


Edited by Mārtiņš Možeiko on

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

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.


Edited by Adamarla on Reason: Missed detail in previous post

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.


Edited by Mārtiņš Možeiko on
Replying to adamarla (#25704)

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?


Replying to mmozeiko (#25534)

Just in case you want to use aligned SSE ops on it. Otherwise it is not needed and you can remove all alignment, strings don't need it.

.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.


Edited by Mārtiņš Možeiko on
Replying to neo_ar (#25706)

Ahh I see, I guess there are those SSE string ops; that seems worth doing 16-byte alignment then. Not necessary in the case of noid, but I should probably preparse the metadesk file and embed the result of that rather than doin' it at runtime...


Replying to mmozeiko (#25707)