Unverified Commit 24148857 authored by Artur Wojcik's avatar Artur Wojcik Committed by GitHub
Browse files

embed.cmake: add support for Windows resource file (#2330)

This PR introduces the support of Windows resource files to Embed.cmake. It is ON by default on Windows, and when it is OFF *.cpp files will be used. The same applies to Linux - ON -> *.o (LD) or OFF -> *.cpp .

This PR fixes building resources on Linux with ld and objcopy commands.
parent 624f8ef5
...@@ -21,17 +21,25 @@ ...@@ -21,17 +21,25 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
##################################################################################### #####################################################################################
find_program(EMBED_LD ld)
find_program(EMBED_OBJCOPY objcopy)
option(EMBED_USE_LD "Use ld to embed data files" OFF) if(WIN32)
set(EMBED_USE RC CACHE STRING "Use RC or CArrays to embed data files")
set_property(CACHE EMBED_USE PROPERTY STRINGS "RC;CArrays")
else()
set(EMBED_USE CArrays CACHE STRING "Use LD or CArrays to embed data files")
set_property(CACHE EMBED_USE PROPERTY STRINGS "LD;CArrays")
endif()
if(EMBED_USE STREQUAL "LD")
find_program(EMBED_LD ld REQUIRED)
find_program(EMBED_OBJCOPY objcopy REQUIRED)
endif()
function(wrap_string) function(wrap_string)
set(options) set(options)
set(oneValueArgs VARIABLE AT_COLUMN) set(oneValueArgs VARIABLE AT_COLUMN)
set(multiValueArgs) set(multiValueArgs)
cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${PARSE_VARIABLE}} string_length) string(LENGTH ${${PARSE_VARIABLE}} string_length)
math(EXPR offset "0") math(EXPR offset "0")
...@@ -54,97 +62,108 @@ function(wrap_string) ...@@ -54,97 +62,108 @@ function(wrap_string)
set(${PARSE_VARIABLE} "${lines}" PARENT_SCOPE) set(${PARSE_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction() endfunction()
function(generate_embed_source EMBED_NAME) function(generate_embed_source EMBED_NAME EMBED_DIR BASE_DIRECTORY)
set(options) set(options)
set(oneValueArgs SRC HEADER RELATIVE) set(oneValueArgs)
set(multiValueArgs OBJECTS SYMBOLS FILES) set(multiValueArgs SYMBOLS FILES)
cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(EXTERNS) set(RESOURCE_ID 100)
set(INIT_KERNELS) foreach(SYMBOL FILE IN ZIP_LISTS PARSE_SYMBOLS PARSE_FILES)
cmake_path(RELATIVE_PATH FILE BASE_DIRECTORY ${BASE_DIRECTORY} OUTPUT_VARIABLE BASE_NAME)
list(LENGTH PARSE_SYMBOLS SYMBOLS_LEN) if(EMBED_USE STREQUAL "RC")
list(LENGTH PARSE_OBJECTS OBJECTS_LEN) string(TOUPPER "${SYMBOL}" SYMBOL)
if(NOT ${SYMBOLS_LEN} EQUAL ${OBJECTS_LEN}) string(APPEND FILE_IDS "#define IDR_${SYMBOL} ${RESOURCE_ID}\n")
message(FATAL_ERROR "Symbols and objects dont match: ${SYMBOLS_LEN} != ${OBJECTS_LEN}") cmake_path(NATIVE_PATH FILE NORMALIZE NATIVE_FILE)
endif() string(REPLACE "\\" "\\\\" NATIVE_FILE "${NATIVE_FILE}")
math(EXPR LEN "${SYMBOLS_LEN} - 1") string(APPEND RC_FILE_MAPPING "IDR_${SYMBOL} TEXTFILE \"${NATIVE_FILE}\"\n")
string(APPEND INIT_KERNELS "\n {\"${BASE_NAME}\", resource::read(IDR_${SYMBOL})},")
foreach(idx RANGE ${LEN}) math(EXPR RESOURCE_ID "${RESOURCE_ID} + 1" OUTPUT_FORMAT DECIMAL)
list(GET PARSE_SYMBOLS ${idx} SYMBOL) else()
list(GET PARSE_OBJECTS ${idx} OBJECT)
list(GET PARSE_FILES ${idx} FILE)
set(START_SYMBOL "_binary_${SYMBOL}_start") set(START_SYMBOL "_binary_${SYMBOL}_start")
set(LENGTH_SYMBOL "_binary_${SYMBOL}_length") set(LENGTH_SYMBOL "_binary_${SYMBOL}_length")
if(EMBED_USE_LD) if(EMBED_USE STREQUAL "LD")
string(APPEND EXTERNS " string(APPEND EXTERNS "
extern const char ${START_SYMBOL}[]; extern const char ${START_SYMBOL}[];
extern const size_t _binary_${SYMBOL}_size; extern const size_t _binary_${SYMBOL}_size;
const auto ${LENGTH_SYMBOL} = reinterpret_cast<size_t>(&_binary_${SYMBOL}_size); const auto ${LENGTH_SYMBOL} = reinterpret_cast<size_t>(&_binary_${SYMBOL}_size);
") ")
else() else()
string(APPEND EXTERNS " string(APPEND EXTERNS "
extern const char ${START_SYMBOL}[]; extern const char ${START_SYMBOL}[];
extern const size_t ${LENGTH_SYMBOL}; extern const size_t ${LENGTH_SYMBOL};
") ")
endif()
if(PARSE_RELATIVE)
file(RELATIVE_PATH BASE_NAME ${PARSE_RELATIVE} "${FILE}")
else()
get_filename_component(BASE_NAME "${FILE}" NAME)
endif() endif()
string(APPEND INIT_KERNELS " string(APPEND INIT_KERNELS "
{ \"${BASE_NAME}\", { ${START_SYMBOL}, ${LENGTH_SYMBOL}} },") { \"${BASE_NAME}\", { ${START_SYMBOL}, ${LENGTH_SYMBOL}} },")
endif()
endforeach() endforeach()
if(EMBED_USE STREQUAL "RC")
file(WRITE "${EMBED_DIR}/include/resource.h" "
#define TEXTFILE 256
${FILE_IDS}
")
file(WRITE "${EMBED_DIR}/resource.rc" "
#include \"resource.h\"
${RC_FILE_MAPPING}
")
set(EXTERNS "
#include <Windows.h>
#include \"resource.h\"
file(WRITE "${PARSE_HEADER}" " namespace resource {
std::string_view read(int id)
{
HMODULE handle = GetModuleHandle(nullptr);
HRSRC rc = FindResource(handle, MAKEINTRESOURCE(id), MAKEINTRESOURCE(TEXTFILE));
HGLOBAL data = LoadResource(handle, rc);
return {static_cast<const char*>(LockResource(data)), SizeofResource(handle, rc)};
}
}
")
set(EMBED_FILES ${EMBED_DIR}/include/resource.h ${EMBED_DIR}/resource.rc)
endif()
file(WRITE "${EMBED_DIR}/include/${EMBED_NAME}.hpp" "
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
std::unordered_map<std::string_view, std::string_view> ${EMBED_NAME}(); std::unordered_map<std::string_view, std::string_view> ${EMBED_NAME}();
") ")
file(WRITE "${PARSE_SRC}" " file(WRITE "${EMBED_DIR}/${EMBED_NAME}.cpp" "
#include <${EMBED_NAME}.hpp> #include <${EMBED_NAME}.hpp>
${EXTERNS} ${EXTERNS}
std::unordered_map<std::string_view, std::string_view> ${EMBED_NAME}() std::unordered_map<std::string_view, std::string_view> ${EMBED_NAME}()
{ {
static std::unordered_map<std::string_view, std::string_view> result = {${INIT_KERNELS}}; static std::unordered_map<std::string_view, std::string_view> result = {${INIT_KERNELS}
};
return result; return result;
} }
") ")
list(APPEND EMBED_FILES ${EMBED_DIR}/${EMBED_NAME}.cpp ${EMBED_DIR}/include/${EMBED_NAME}.hpp)
set(EMBED_FILES ${EMBED_FILES} PARENT_SCOPE)
endfunction() endfunction()
function(embed_file OUTPUT_FILE OUTPUT_SYMBOL FILE) function(embed_file FILE BASE_DIRECTORY)
set(WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) message(STATUS " ${FILE}")
# Glob is used to compute the relative path cmake_path(RELATIVE_PATH FILE BASE_DIRECTORY "${BASE_DIRECTORY}" OUTPUT_VARIABLE REL_FILE)
file(GLOB FILES RELATIVE ${WORKING_DIRECTORY} ${FILE}) string(MAKE_C_IDENTIFIER "${REL_FILE}" OUTPUT_SYMBOL)
foreach(REL_FILE ${FILES})
string(MAKE_C_IDENTIFIER "${REL_FILE}" SYMBOL)
get_filename_component(OUTPUT_FILE_DIR "${REL_FILE}" DIRECTORY) get_filename_component(OUTPUT_FILE_DIR "${REL_FILE}" DIRECTORY)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE_DIR}") file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE_DIR}")
if(EMBED_USE_LD) if(EMBED_USE STREQUAL "LD")
set(OUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${REL_FILE}.o") set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${REL_FILE}.o")
else()
set(OUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${REL_FILE}.cpp")
endif()
set(${OUTPUT_SYMBOL} ${SYMBOL} PARENT_SCOPE)
set(${OUTPUT_FILE} "${OUT_FILE}" PARENT_SCOPE)
if(EMBED_USE_LD)
add_custom_command( add_custom_command(
OUTPUT "${OUT_FILE}" OUTPUT "${OUTPUT_FILE}"
COMMAND ${EMBED_LD} -r -o "${OUT_FILE}" -z noexecstack --format=binary "${REL_FILE}" COMMAND ${EMBED_LD} -r -o "${OUTPUT_FILE}" -z noexecstack --format=binary "${REL_FILE}"
COMMAND ${EMBED_OBJCOPY} --rename-section .data=.rodata,alloc,load,readonly,data,contents "${OUT_FILE}" COMMAND ${EMBED_OBJCOPY} --rename-section .data=.rodata,alloc,load,readonly,data,contents "${OUTPUT_FILE}"
WORKING_DIRECTORY ${WORKING_DIRECTORY} WORKING_DIRECTORY "${BASE_DIRECTORY}"
DEPENDS ${FILE} DEPENDS "${FILE}"
VERBATIM VERBATIM)
) set(OUTPUT_FILE ${OUTPUT_FILE} PARENT_SCOPE)
else() elseif(EMBED_USE STREQUAL "CArrays")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${FILE}) set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${REL_FILE}.cpp")
# reads source file contents as hex string # reads source file contents as hex string
file(READ ${FILE} HEX_STRING HEX) file(READ ${FILE} HEX_STRING HEX)
# wraps the hex string into multiple lines # wraps the hex string into multiple lines
...@@ -153,13 +172,14 @@ function(embed_file OUTPUT_FILE OUTPUT_SYMBOL FILE) ...@@ -153,13 +172,14 @@ function(embed_file OUTPUT_FILE OUTPUT_SYMBOL FILE)
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " ARRAY_VALUES ${HEX_STRING}) string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " ARRAY_VALUES ${HEX_STRING})
# removes trailing comma # removes trailing comma
string(REGEX REPLACE ", $" "" ARRAY_VALUES ${ARRAY_VALUES}) string(REGEX REPLACE ", $" "" ARRAY_VALUES ${ARRAY_VALUES})
file(WRITE "${OUT_FILE}" " file(WRITE "${OUTPUT_FILE}" "
#include <cstddef> #include <cstddef>
extern const char _binary_${SYMBOL}_start[] = { ${ARRAY_VALUES} }; extern const char _binary_${OUTPUT_SYMBOL}_start[] = { ${ARRAY_VALUES} };
extern const size_t _binary_${SYMBOL}_length = sizeof(_binary_${SYMBOL}_start); extern const size_t _binary_${OUTPUT_SYMBOL}_length = sizeof(_binary_${OUTPUT_SYMBOL}_start);
") ")
set(OUTPUT_FILE ${OUTPUT_FILE} PARENT_SCOPE)
endif() endif()
endforeach() set(OUTPUT_SYMBOL ${OUTPUT_SYMBOL} PARENT_SCOPE)
endfunction() endfunction()
function(add_embed_library EMBED_NAME) function(add_embed_library EMBED_NAME)
...@@ -168,35 +188,32 @@ function(add_embed_library EMBED_NAME) ...@@ -168,35 +188,32 @@ function(add_embed_library EMBED_NAME)
set(multiValueArgs) set(multiValueArgs)
cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/embed)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBED_NAME})
set(EMBED_DIR ${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBED_NAME}) set(EMBED_DIR ${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBED_NAME})
set(SRC_FILE "${EMBED_DIR}/${EMBED_NAME}.cpp") file(MAKE_DIRECTORY ${EMBED_DIR})
set(HEADER_FILE "${EMBED_DIR}/include/${EMBED_NAME}.hpp") message(STATUS "Embedding kernel files:")
set(WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(OUTPUT_FILES)
set(SYMBOLS)
message(STATUS "Embedding files")
foreach(FILE ${PARSE_UNPARSED_ARGUMENTS}) foreach(FILE ${PARSE_UNPARSED_ARGUMENTS})
embed_file(OUTPUT_FILE OUTPUT_SYMBOL ${FILE}) embed_file(${FILE} ${PARSE_RELATIVE})
list(APPEND OUTPUT_FILES ${OUTPUT_FILE}) list(APPEND OUTPUT_FILES ${OUTPUT_FILE})
list(APPEND SYMBOLS ${OUTPUT_SYMBOL}) list(APPEND SYMBOLS ${OUTPUT_SYMBOL})
endforeach() endforeach()
message(STATUS "Generating embedding library ${EMBED_NAME}") message(STATUS "Generating embedding library '${EMBED_NAME}'")
generate_embed_source(${EMBED_NAME} SRC ${SRC_FILE} HEADER ${HEADER_FILE} OBJECTS ${OUTPUT_FILES} SYMBOLS ${SYMBOLS} RELATIVE ${PARSE_RELATIVE} FILES ${PARSE_UNPARSED_ARGUMENTS}) generate_embed_source(${EMBED_NAME} ${EMBED_DIR} "${PARSE_RELATIVE}" SYMBOLS ${SYMBOLS} FILES ${PARSE_UNPARSED_ARGUMENTS})
set(INTERNAL_EMBED_LIB embed_lib_${EMBED_NAME}) set(INTERNAL_EMBED_LIB embed_lib_${EMBED_NAME})
add_library(${INTERNAL_EMBED_LIB} OBJECT "${SRC_FILE}") add_library(${INTERNAL_EMBED_LIB} OBJECT ${EMBED_FILES})
if(EMBED_USE STREQUAL "CArrays")
target_sources(${INTERNAL_EMBED_LIB} PRIVATE ${OUTPUT_FILES})
endif()
target_include_directories(${INTERNAL_EMBED_LIB} PRIVATE "${EMBED_DIR}/include") target_include_directories(${INTERNAL_EMBED_LIB} PRIVATE "${EMBED_DIR}/include")
target_compile_options(${INTERNAL_EMBED_LIB} PRIVATE -Wno-reserved-identifier -Wno-extern-initializer -Wno-missing-variable-declarations) target_compile_options(${INTERNAL_EMBED_LIB} PRIVATE -Wno-reserved-identifier -Wno-extern-initializer -Wno-missing-variable-declarations)
set_target_properties(${INTERNAL_EMBED_LIB} PROPERTIES POSITION_INDEPENDENT_CODE On) set_target_properties(${INTERNAL_EMBED_LIB} PROPERTIES POSITION_INDEPENDENT_CODE On)
add_library(${EMBED_NAME} INTERFACE) add_library(${EMBED_NAME} INTERFACE)
if(EMBED_USE_LD) if(EMBED_USE STREQUAL "LD")
target_sources(${EMBED_NAME} INTERFACE ${OUTPUT_FILES}) target_sources(${EMBED_NAME} INTERFACE ${OUTPUT_FILES})
else() endif()
target_sources(${INTERNAL_EMBED_LIB} PRIVATE ${OUTPUT_FILES}) if(EMBED_USE STREQUAL "RC")
target_link_libraries(${EMBED_NAME} INTERFACE $<TARGET_OBJECTS:${INTERNAL_EMBED_LIB}>)
endif() endif()
target_sources(${EMBED_NAME} INTERFACE $<TARGET_OBJECTS:${INTERNAL_EMBED_LIB}>) target_sources(${EMBED_NAME} INTERFACE $<TARGET_OBJECTS:${INTERNAL_EMBED_LIB}>)
target_include_directories(${EMBED_NAME} INTERFACE "${EMBED_DIR}/include") target_include_directories(${EMBED_NAME} INTERFACE "${EMBED_DIR}/include")
endfunction() endfunction()
...@@ -49,7 +49,6 @@ endif() ...@@ -49,7 +49,6 @@ endif()
file(GLOB KERNEL_FILES CONFIGURE_DEPENDS file(GLOB KERNEL_FILES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/kernels/include/migraphx/kernels/*.hpp) ${CMAKE_CURRENT_SOURCE_DIR}/kernels/include/migraphx/kernels/*.hpp)
message(STATUS "KERNEL_FILES: ${KERNEL_FILES}")
if(NOT MIGRAPHX_USE_COMPOSABLEKERNEL) if(NOT MIGRAPHX_USE_COMPOSABLEKERNEL)
list(REMOVE_ITEM KERNEL_FILES list(REMOVE_ITEM KERNEL_FILES
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment