Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embed resources (eg, shader code; images) into executable/library with CMake

I am writing an application in C++ which relies on various resources in my project. Right now, I have the relative path from the produced executable to each resource hard-coded in my sources, and that allows my program to open the files and read in the data in each resource. This works ok, but it requires that I start the executable from a specific path relative to the resources. So if I try to start my executable from anywhere else, it fails to open the files and cannot proceed.

Is there a portable way to have CMake embed my resources into the executables (or libraries) such that I can simply access them in memory at runtime instead of opening files whose paths are brittle? I have found a related question, and it looks like embedding resources can be done well enough with some ld magic. So my question is how do I do this in a portable, cross platform manner using CMake? I actually need my application run on both x86 and ARM. I am ok with supporting only Linux (Embedded), but bonus points if anyone can suggest how to do this for Windows (Embedded) as well.

EDIT: I forgot to mention a desired property of the solution. I would like to be able to use CMake to cross-compile the application when I am building for ARM rather than have to compile it natively on my ARM target.

like image 422
Nicu Stiurca Avatar asked Aug 05 '12 01:08

Nicu Stiurca


People also ask

Why use CMake for embedded files?

Also the embedded files should take advantage of CMake’s features and automatically keep the binary data up to date if the source file changes. The first thing we are interested in is figuring out how to get the data from an arbitrary file into CMake.

How to embed a resource into an executable?

Sometimes it is necessary to embed resource such as icons, images, texts or even arbitrary binary data into executables. There several approaches for acomplishing this: Create a resource script, for instance resource.rc, and compile the resource to object code with the MSVC resource compiler. rc.exe or GCC/Mingw resource compiler, windres.exe.

How can I embed a binary file in a C++ program?

There are several ways of embedding binary data into an executable using the linker, but that would not be cross platform across the many C++ compilers like GCC, Clang, and MSVC and others. Also the embedded files should take advantage of CMake’s features and automatically keep the binary data up to date if the source file changes.


1 Answers

As an alternative to the answer of sfstewman, here's a small cmake (2.8) function to convert all files in a specific folder to C data and write them in wished output file:

# Creates C resources file from files in given directory function(create_resources dir output)     # Create empty output file     file(WRITE ${output} "")     # Collect input files     file(GLOB bins ${dir}/*)     # Iterate through input files     foreach(bin ${bins})         # Get short filename         string(REGEX MATCH "([^/]+)$" filename ${bin})         # Replace filename spaces & extension separator for C compatibility         string(REGEX REPLACE "\\.| |-" "_" filename ${filename})         # Read hex data from file         file(READ ${bin} filedata HEX)         # Convert hex data for C compatibility         string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," filedata ${filedata})         # Append data to output file         file(APPEND ${output} "const unsigned char ${filename}[] = {${filedata}};\nconst unsigned ${filename}_size = sizeof(${filename});\n")     endforeach() endfunction() 
like image 110
Youka Avatar answered Sep 24 '22 00:09

Youka