|
| 1 | + |
| 2 | +find_program(EMBED_LD ld) |
| 3 | +find_program(EMBED_OBJCOPY objcopy) |
| 4 | + |
| 5 | +function(generate_embed_source EMBED_NAME) |
| 6 | + set(options) |
| 7 | + set(oneValueArgs SRC HEADER) |
| 8 | + set(multiValueArgs OBJECTS SYMBOLS) |
| 9 | + |
| 10 | + cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) |
| 11 | + |
| 12 | + set(EXTERNS) |
| 13 | + set(INIT_KERNELS) |
| 14 | + |
| 15 | + # TODO: check the lens are the same |
| 16 | + list(LENGTH PARSE_SYMBOLS SYMBOLS_LEN) |
| 17 | + list(LENGTH PARSE_OBJECTS OBJECTS_LEN) |
| 18 | + if(NOT ${SYMBOLS_LEN} EQUAL ${OBJECTS_LEN}) |
| 19 | + message(FATAL_ERROR "Symbols and objects dont match: ${SYMBOLS_LEN} != ${OBJECTS_LEN}") |
| 20 | + endif() |
| 21 | + math(EXPR LEN "${SYMBOLS_LEN} - 1") |
| 22 | + |
| 23 | + foreach(idx RANGE ${LEN}) |
| 24 | + list(GET PARSE_SYMBOLS ${idx} SYMBOL) |
| 25 | + list(GET PARSE_OBJECTS ${idx} OBJECT) |
| 26 | + # foreach(SYMBOL ${PARSE_SYMBOLS}) |
| 27 | + set(START_SYMBOL "_binary_${SYMBOL}_start") |
| 28 | + set(END_SYMBOL "_binary_${SYMBOL}_end") |
| 29 | + string(APPEND EXTERNS " |
| 30 | + extern const char ${START_SYMBOL}[]; |
| 31 | + extern const char ${END_SYMBOL}[]; |
| 32 | + ") |
| 33 | + |
| 34 | + get_filename_component(BASE_NAME "${OBJECT}" NAME) |
| 35 | + |
| 36 | + string(APPEND INIT_KERNELS " |
| 37 | + { \"${BASE_NAME}\", { ${START_SYMBOL}, ${END_SYMBOL}} }, |
| 38 | + ") |
| 39 | + endforeach() |
| 40 | + |
| 41 | + file(WRITE "${PARSE_HEADER}" " |
| 42 | +#include <unordered_map> |
| 43 | +const std::unordered_map<std::string, std::pair<const char*,const char*>>& ${EMBED_NAME}(); |
| 44 | +") |
| 45 | + |
| 46 | + file(WRITE "${PARSE_SRC}" " |
| 47 | +#include <${EMBED_NAME}.hpp> |
| 48 | +${EXTERNS} |
| 49 | +const std::unordered_map<std::string, std::pair<const char*,const char*>>& ${EMBED_NAME}() |
| 50 | +{ |
| 51 | + static const std::unordered_map<std::string, std::pair<const char*,const char*>> result = {${INIT_KERNELS}}; |
| 52 | + return result; |
| 53 | +} |
| 54 | +") |
| 55 | +endfunction() |
| 56 | + |
| 57 | +function(embed_file OUTPUT_FILE OUTPUT_SYMBOL FILE) |
| 58 | + set(${OUTPUT_FILE} "${FILE}.o" PARENT_SCOPE) |
| 59 | + set(WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) |
| 60 | + # Glob is used to compute the relative path |
| 61 | + file(GLOB FILES RELATIVE ${WORKING_DIRECTORY} ${FILE}) |
| 62 | + foreach(REL_FILE ${FILES}) |
| 63 | + string(MAKE_C_IDENTIFIER "${REL_FILE}" SYMBOL) |
| 64 | + set(${OUTPUT_SYMBOL} ${SYMBOL} PARENT_SCOPE) |
| 65 | + add_custom_command( |
| 66 | + OUTPUT "${FILE}.o" |
| 67 | + COMMAND ${EMBED_LD} -r -o "${REL_FILE}.o" -z noexecstack --format=binary "${REL_FILE}" |
| 68 | + COMMAND ${EMBED_OBJCOPY} --rename-section .data=.rodata,alloc,load,readonly,data,contents "${REL_FILE}.o" |
| 69 | + WORKING_DIRECTORY ${WORKING_DIRECTORY} |
| 70 | + DEPENDS ${FILE} |
| 71 | + VERBATIM |
| 72 | + ) |
| 73 | + endforeach() |
| 74 | +endfunction() |
| 75 | + |
| 76 | +function(add_embed_library EMBED_NAME) |
| 77 | + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/embed) |
| 78 | + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBED_NAME}) |
| 79 | + set(EMBED_DIR ${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBED_NAME}) |
| 80 | + set(SRC_FILE "${EMBED_DIR}/${EMBED_NAME}.cpp") |
| 81 | + set(HEADER_FILE "${EMBED_DIR}/include/${EMBED_NAME}.hpp") |
| 82 | + set(WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) |
| 83 | + set(OUTPUT_FILES) |
| 84 | + set(SYMBOLS) |
| 85 | + message(STATUS "Embedding files") |
| 86 | + foreach(FILE ${ARGN}) |
| 87 | + # message(STATUS "Embedding file ${FILE}") |
| 88 | + embed_file(OUTPUT_FILE OUTPUT_SYMBOL ${FILE}) |
| 89 | + list(APPEND OUTPUT_FILES ${OUTPUT_FILE}) |
| 90 | + list(APPEND SYMBOLS ${OUTPUT_SYMBOL}) |
| 91 | + endforeach() |
| 92 | + message(STATUS "Generating embedding library ${EMBED_NAME}") |
| 93 | + generate_embed_source(${EMBED_NAME} SRC ${SRC_FILE} HEADER ${HEADER_FILE} OBJECTS ${OUTPUT_FILES} SYMBOLS ${SYMBOLS}) |
| 94 | + add_library(${EMBED_NAME} STATIC ${OUTPUT_FILES} "${SRC_FILE}") |
| 95 | + target_include_directories(${EMBED_NAME} PUBLIC "${EMBED_DIR}/include") |
| 96 | + set_target_properties(${EMBED_NAME} PROPERTIES POSITION_INDEPENDENT_CODE On) |
| 97 | +endfunction() |
0 commit comments