find_program(EMBED_LD ${CMAKE_LINKER}) find_program(EMBED_OBJCOPY ${CMAKE_OBJCOPY}) function(_generate_embed_source EMBED_NAME) set(options) set(oneValueArgs SOURCE HEADER) set(multiValueArgs FILES SYMBOLS) cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(VIEW_DECLARATIONS) set(VOID_DECLARATIONS) set(DEFINITIONS) foreach (FILE SYMBOL IN ZIP_LISTS PARSE_FILES PARSE_SYMBOLS) get_filename_component(FILE_NAME "${FILE}" NAME) string(MAKE_C_IDENTIFIER "${FILE_NAME}" IDENTIFIER) set(START_SYMBOL "_binary_${SYMBOL}_start") set(END_SYMBOL "_binary_${SYMBOL}_end") string(APPEND VIEW_DECLARATIONS " /// ${FILE} Text Contents\n" " extern std::string_view const ${IDENTIFIER};\n") string(APPEND VOID_DECLARATIONS " /// ${FILE} Binary Contents\n" " extern void* const ${IDENTIFIER};\n") string(APPEND DEFINITIONS "// ${IDENTIFIER} (${FILE})\n" "extern \"C\" const char ${START_SYMBOL}[], ${END_SYMBOL}[];\n" "std::string_view const ${EMBED_NAME}::${IDENTIFIER}(${START_SYMBOL}, ${END_SYMBOL});\n" "void* const ${EMBED_NAME}::bin::${IDENTIFIER} = (void *) ${START_SYMBOL};\n\n") endforeach () file(WRITE "${PARSE_HEADER}" "#pragma once\n" "#include \n\n" "namespace ${EMBED_NAME} {\n${VIEW_DECLARATIONS}}\n\n" "namespace ${EMBED_NAME}::bin {\n${VOID_DECLARATIONS}}\n") file(WRITE "${PARSE_SOURCE}" "#include <${EMBED_NAME}.hpp>\n\n" "${DEFINITIONS}") endfunction() function(_embed_file OUTPUT_OBJECT OUTPUT_SYMBOL FILE) set(OBJECT "${CMAKE_CURRENT_BINARY_DIR}/${FILE}.o") string(MAKE_C_IDENTIFIER "${FILE}" SYMBOL) set(${OUTPUT_OBJECT} ${OBJECT} PARENT_SCOPE) set(${OUTPUT_SYMBOL} ${SYMBOL} PARENT_SCOPE) add_custom_command( COMMENT "Embedding ${FILE} in ${OBJECT}" OUTPUT "${FILE}.o" DEPENDS "${FILE}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND ${EMBED_LD} -r -o "${OBJECT}" -z noexecstack --format=binary "${FILE}" COMMAND ${EMBED_OBJCOPY} --rename-section .data=.rodata,alloc,load,readonly,data,contents "${OBJECT}" VERBATIM ) endfunction() function(add_embed_library EMBED_NAME) set(FILES ${ARGN}) set(EMBED_ROOT ${CMAKE_CURRENT_BINARY_DIR}/_embed/${EMBED_NAME}) set(EMBED_SOURCE "${EMBED_ROOT}/${EMBED_NAME}.cpp") set(EMBED_INCLUDE "${EMBED_ROOT}/include") set(EMBED_HEADER "${EMBED_INCLUDE}/${EMBED_NAME}.hpp") set(OBJECTS) set(SYMBOLS) foreach (FILE ${ARGN}) _embed_file(OBJECT SYMBOL ${FILE}) list(APPEND OBJECTS ${OBJECT}) list(APPEND SYMBOLS ${SYMBOL}) endforeach () message(STATUS "Generating embedding library ${EMBED_NAME}") _generate_embed_source( ${EMBED_NAME} SOURCE ${EMBED_SOURCE} HEADER ${EMBED_HEADER} FILES ${FILES} SYMBOLS ${SYMBOLS}) add_library(${EMBED_NAME} STATIC ${OBJECTS} "${EMBED_SOURCE}") target_include_directories(${EMBED_NAME} PUBLIC "${EMBED_INCLUDE}") set_target_properties(${EMBED_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) endfunction()