Last post we looked at Jai’s powerful standard library and probably praised it too much for making what others would probably call a bad decision: including too much specific stuff in the standard. But you know what, it brought me a lot of joy to be able to do something like that out of the box, so thats ok. In this post we’ll look at another gripe I have with C++ and see if Jai can save us from it.
Rage Against C/C++ Resource Embedding Hell Link to heading
In another universe not so far away, there exists another problem I’ve had the misfortune of meeting at least three times in my C++ career: resource embedding. i.e. embedding your images, audio, data, etc. inside of an executable so you can distribute a standalone executable without the need for an installer, and having your program keep track of where a bunch of resource files are. Java didn’t get much right, but the executable Jar is a good case study of resource embedding and one thing I think java did get right. Windows also provides some platform specific shenanigans for embedding resources but this is not viable cross platform.
#embed
directive exactly for this purpose, however as of writing 6/24/2024, it is still not supported by any compilers. Read this post for a good overview on C23’s #embed
and its implementation difficulties.In C/C++ the tried and true solution is to programmatically generate a header file containing the entire resource as an array of bytes (see here). There are utilities to do this as well, the hexdump utility xxd
on linux has a flag -i
that will cause it to dump a file foo.xyz
to a C header file foo.h
. The header file xxd -i foo.xyz
will take the form:
unsigned char foo[] = {
0x48, 0x65, 0x6c, //...
};
unsigned int foo_len = 47;
The issues begin to arise when you have resources that mutate between builds and want to do this in a cross platform way (tools like xxd
are platform dependent). I’ve discussed this at length with a friend of mine who at the time was on the the CMake development team, and I was shocked to hear
that when it comes to doing this in enterprise scale applications, almost everyone is rolling their own CMake solution or trying and borrow and adapt someone elses solution (see here for a CMake solution). Thus the nightmare begins.
Can Jai Help? Link to heading
Let us return to our Jai program for rendering a png to a window from the last post. Recall that we have a resource blow.png
that we load at runtime.
bitmap := get_bitmap("blow.png");
image : Simp.Texture;
Simp.texture_load_from_bitmap(*image, *bitmap);
For the sake of learning, lets try moving the executable out of the folder with blow.png
and see what happens.
>main1.exe
Unable to load bitmap 'blow.png'.
main.jai:15,5: Assertion failed: Failed to load bitmap from blow.png
jai/modules/Basic/module.jai:87: assert_helper
main.jai:15: get_bitmap
main.jai:27: main
As expected, the program can’t find the resource. This sucks because I would like to DM this exe to my friends on discord and have them see Johnathan’s face when they run it, but I don’t want them to have to download blow.png
as well.
If only there were a way to embed the image in the application at compile time. Well we’re in luck… there is a way to do this, and it only requires
adding a single directive to the program, #run
.
bitmap := #run get_bitmap("blow.png");
image : Simp.Texture;
Simp.texture_load_from_bitmap(*image, *bitmap);
Alright and now we can compile it:
jai main2.jai
and move it out of the folder with blow.png
and run it:
main2.exe
and voilà:
So what exactly does #run
do? It instructs the compiler to evaluate Jai code during compilation. What makes Jai’s version of this particularly powerful is that Jai can do ANYTHING in a #run
directive, from opening files to downloading data over the internet.
#run
directive I strongly suggest reading the Jai community wiki articleIn our small example we run the get_bitmap
call at compile time and the generated bitmap is embedded in the .data
section of the executable.
#run
gets copied into the data section of the executable even if assigned with :=
instead of ::
-Local Jai ExpertUpon seeing #run
in action for the first time I immediately thought of embedding as an application but honestly this does not even scratch the surface of its true power. Im looking forward to seeing and playing around with more applications. Since embedding has given me so much grief in C++ over the years and I was able to embed a resource in Jai with one word, I would say that Jai has once again brought me joy.
All code in this post is available here on my GitHub.