DEV Community

Addy
Addy

Posted on

Simple CMake to Compile Resources

Recently I have been working on a project that has a Simple Web Server, so I needed a way to serve HTML files. I didn't want to distribute the files as part of a "package" and instead wanted them compiled into the distributed binary.

I went to Google and searched c++ cmake compile resources. The first project I found was this. However this project was much more involved than I needed, going so far as to implement a mini-filesystem, much like Qt's resource system.

I wanted something more simple. I wanted to take a resource, compile it into a header as a char array.

This was my solution:

function(generate_header INPUTFILE OUTPUTFILE VARNAME)
    set(DONE FALSE)
    set(CURRENTPOS 0)

    file(READ ${INPUTFILE} FILEDATA HEX)
    string(LENGTH "${FILEDATA}" DATALEN)
    set(OUTPUT_DATA "")

    file(WRITE ${OUTPUTFILE} "#pragma once\n\nstatic const char ${VARNAME}[] = { ")

    foreach(BYTE_OFFSET RANGE 0 "${DATALEN}" 2)
        string(SUBSTRING "${FILEDATA}" "${BYTE_OFFSET}" 2 HEX_STRING)
        string(LENGTH "${HEX_STRING}" TEMPLEN)
        if ("${TEMPLEN}" GREATER 0)
            set(OUTPUT_DATA "${OUTPUT_DATA}0x${HEX_STRING}, ")
        endif()
    endforeach()

    file(APPEND ${OUTPUTFILE} "${OUTPUT_DATA}0")
    file(APPEND ${OUTPUTFILE} " };\n")
endfunction()

function(z_compile_resources RESOURCE_LIST)
    foreach(RESOURCE_NAME ${ARGN})
        set(RESOURCE_FILENAME "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_NAME}")

        get_filename_component(FILENAME ${RESOURCE_NAME} NAME_WE)
        get_filename_component(EXT ${RESOURCE_NAME} EXT)
        string(SUBSTRING ${EXT} 1 -1 EXT)
        set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}_${EXT}.h")
        set(VARIABLE_NAME "${FILENAME}_${EXT}")

        generate_header(${RESOURCE_FILENAME} ${OUTPUT_FILE} ${VARIABLE_NAME})
    endforeach()
endfunction()
Enter fullscreen mode Exit fullscreen mode

Now I can compile resources in my CMake file like so:

z_compile_resources(RESOURCE_FILES
    html/index.html
)
Enter fullscreen mode Exit fullscreen mode

And now CMake will generate a header file that looks like this:

#pragma once

static const char index_html[] = { 0x3c, 0x68, ... , 0 };
Enter fullscreen mode Exit fullscreen mode

This is awesome! And now in my source file I can use it like so:

#include "index_html.h"

/* lots of code here */
std::cout << index_html << '\n';
Enter fullscreen mode Exit fullscreen mode

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more