Embed.cmake 9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#####################################################################################
# The MIT License (MIT)
#
# Copyright (c) 2015-2022 Advanced Micro Devices, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#####################################################################################
Paul Fultz II's avatar
Paul Fultz II committed
24

25
26
27
28
29
30
31
32
33
34
35
36
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()
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

function(wrap_string)
    set(options)
    set(oneValueArgs VARIABLE AT_COLUMN)
    set(multiValueArgs)
    cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    string(LENGTH ${${PARSE_VARIABLE}} string_length)
    math(EXPR offset "0")

    while(string_length GREATER 0)

        if(string_length GREATER ${PARSE_AT_COLUMN})
            math(EXPR length "${PARSE_AT_COLUMN}")
        else()
            math(EXPR length "${string_length}")
        endif()

        string(SUBSTRING ${${PARSE_VARIABLE}} ${offset} ${length} line)
        set(lines "${lines}\n${line}")

        math(EXPR string_length "${string_length} - ${length}")
        math(EXPR offset "${offset} + ${length}")
    endwhile()

    set(${PARSE_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction()

65
function(generate_embed_source EMBED_NAME EMBED_DIR BASE_DIRECTORY)
Paul Fultz II's avatar
Paul Fultz II committed
66
    set(options)
67
68
    set(oneValueArgs)
    set(multiValueArgs SYMBOLS FILES)
Paul Fultz II's avatar
Paul Fultz II committed
69
70
    cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    set(RESOURCE_ID 100)
    foreach(SYMBOL FILE IN ZIP_LISTS PARSE_SYMBOLS PARSE_FILES)
        cmake_path(RELATIVE_PATH FILE BASE_DIRECTORY ${BASE_DIRECTORY} OUTPUT_VARIABLE BASE_NAME)
        if(EMBED_USE STREQUAL "RC")
            string(TOUPPER "${SYMBOL}" SYMBOL)
            string(APPEND FILE_IDS "#define IDR_${SYMBOL} ${RESOURCE_ID}\n")
            cmake_path(NATIVE_PATH FILE NORMALIZE NATIVE_FILE)
            string(REPLACE "\\" "\\\\" NATIVE_FILE "${NATIVE_FILE}")
            string(APPEND RC_FILE_MAPPING "IDR_${SYMBOL} TEXTFILE \"${NATIVE_FILE}\"\n")
            string(APPEND INIT_KERNELS "\n        {\"${BASE_NAME}\", resource::read(IDR_${SYMBOL})},")
            math(EXPR RESOURCE_ID "${RESOURCE_ID} + 1" OUTPUT_FORMAT DECIMAL)
        else()
            set(START_SYMBOL "_binary_${SYMBOL}_start")
            set(LENGTH_SYMBOL "_binary_${SYMBOL}_length")
            if(EMBED_USE STREQUAL "LD")
                string(APPEND EXTERNS "
87
88
89
extern const char ${START_SYMBOL}[];
extern const size_t _binary_${SYMBOL}_size;
const auto ${LENGTH_SYMBOL} = reinterpret_cast<size_t>(&_binary_${SYMBOL}_size);
90
91
92
")
            else()
                string(APPEND EXTERNS "
93
94
extern const char ${START_SYMBOL}[];
extern const size_t ${LENGTH_SYMBOL};
95
96
97
98
")
            endif()
            string(APPEND INIT_KERNELS "
        { \"${BASE_NAME}\", { ${START_SYMBOL}, ${LENGTH_SYMBOL}} },")
99
        endif()
100
101
102
103
    endforeach()
    if(EMBED_USE STREQUAL "RC")
       file(WRITE "${EMBED_DIR}/include/resource.h" "
#define TEXTFILE 256
Paul Fultz II's avatar
Paul Fultz II committed
104

105
106
107
108
${FILE_IDS}
")
        file(WRITE "${EMBED_DIR}/resource.rc" "
#include \"resource.h\"
Paul Fultz II's avatar
Paul Fultz II committed
109

110
111
112
113
114
${RC_FILE_MAPPING}
")
        set(EXTERNS "
#include <Windows.h>
#include \"resource.h\"
Paul Fultz II's avatar
Paul Fultz II committed
115

116
117
118
119
120
121
122
123
124
125
126
127
128
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" "
129
#include <string_view>
Paul Fultz II's avatar
Paul Fultz II committed
130
#include <unordered_map>
131
#include <utility>
132
std::unordered_map<std::string_view, std::string_view> ${EMBED_NAME}();
Paul Fultz II's avatar
Paul Fultz II committed
133
134
")

135
    file(WRITE "${EMBED_DIR}/${EMBED_NAME}.cpp" "
Paul Fultz II's avatar
Paul Fultz II committed
136
137
#include <${EMBED_NAME}.hpp>
${EXTERNS}
138
std::unordered_map<std::string_view, std::string_view> ${EMBED_NAME}()
Paul Fultz II's avatar
Paul Fultz II committed
139
{
140
141
    static std::unordered_map<std::string_view, std::string_view> result = {${INIT_KERNELS}
    };
Paul Fultz II's avatar
Paul Fultz II committed
142
143
144
    return result;
}
")
145
146
    list(APPEND EMBED_FILES ${EMBED_DIR}/${EMBED_NAME}.cpp ${EMBED_DIR}/include/${EMBED_NAME}.hpp)
    set(EMBED_FILES ${EMBED_FILES} PARENT_SCOPE)
Paul Fultz II's avatar
Paul Fultz II committed
147
148
endfunction()

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
function(embed_file FILE BASE_DIRECTORY)
    message(STATUS "    ${FILE}")
    cmake_path(RELATIVE_PATH FILE BASE_DIRECTORY "${BASE_DIRECTORY}" OUTPUT_VARIABLE REL_FILE)
    string(MAKE_C_IDENTIFIER "${REL_FILE}" OUTPUT_SYMBOL)
    get_filename_component(OUTPUT_FILE_DIR "${REL_FILE}" DIRECTORY)
    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE_DIR}")
    if(EMBED_USE STREQUAL "LD")
        set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${REL_FILE}.o")
        add_custom_command(
            OUTPUT "${OUTPUT_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 "${OUTPUT_FILE}"
            WORKING_DIRECTORY "${BASE_DIRECTORY}"
            DEPENDS "${FILE}"
            VERBATIM)
        set(OUTPUT_FILE ${OUTPUT_FILE} PARENT_SCOPE)
    elseif(EMBED_USE STREQUAL "CArrays")
        set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${REL_FILE}.cpp")
        # reads source file contents as hex string
        file(READ ${FILE} HEX_STRING HEX)
        # wraps the hex string into multiple lines
        wrap_string(VARIABLE HEX_STRING AT_COLUMN 80)
        # adds '0x' prefix and comma suffix before and after every byte respectively
        string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " ARRAY_VALUES ${HEX_STRING})
        # removes trailing comma
        string(REGEX REPLACE ", $" "" ARRAY_VALUES ${ARRAY_VALUES})
        file(WRITE "${OUTPUT_FILE}" "
176
#include <cstddef>
177
178
extern const char _binary_${OUTPUT_SYMBOL}_start[] = { ${ARRAY_VALUES} };
extern const size_t _binary_${OUTPUT_SYMBOL}_length = sizeof(_binary_${OUTPUT_SYMBOL}_start);
179
")
180
181
182
        set(OUTPUT_FILE ${OUTPUT_FILE} PARENT_SCOPE)
    endif()
    set(OUTPUT_SYMBOL ${OUTPUT_SYMBOL} PARENT_SCOPE)
Paul Fultz II's avatar
Paul Fultz II committed
183
184
185
endfunction()

function(add_embed_library EMBED_NAME)
186
187
188
189
190
    set(options)
    set(oneValueArgs RELATIVE)
    set(multiValueArgs)
    cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

Paul Fultz II's avatar
Paul Fultz II committed
191
    set(EMBED_DIR ${CMAKE_CURRENT_BINARY_DIR}/embed/${EMBED_NAME})
192
193
    file(MAKE_DIRECTORY ${EMBED_DIR})
    message(STATUS "Embedding kernel files:")
194
    foreach(FILE ${PARSE_UNPARSED_ARGUMENTS})
195
        embed_file(${FILE} ${PARSE_RELATIVE})
Paul Fultz II's avatar
Paul Fultz II committed
196
197
198
        list(APPEND OUTPUT_FILES ${OUTPUT_FILE})
        list(APPEND SYMBOLS ${OUTPUT_SYMBOL})
    endforeach()
199
200
    message(STATUS "Generating embedding library '${EMBED_NAME}'")
    generate_embed_source(${EMBED_NAME} ${EMBED_DIR} "${PARSE_RELATIVE}" SYMBOLS ${SYMBOLS} FILES ${PARSE_UNPARSED_ARGUMENTS})
201
    set(INTERNAL_EMBED_LIB embed_lib_${EMBED_NAME})
202
203
204
205
    add_library(${INTERNAL_EMBED_LIB} OBJECT ${EMBED_FILES})
    if(EMBED_USE STREQUAL "CArrays")
        target_sources(${INTERNAL_EMBED_LIB} PRIVATE ${OUTPUT_FILES})
    endif()
206
207
208
209
    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)
    set_target_properties(${INTERNAL_EMBED_LIB} PROPERTIES POSITION_INDEPENDENT_CODE On)
    add_library(${EMBED_NAME} INTERFACE)
210
    if(EMBED_USE STREQUAL "LD")
211
        target_sources(${EMBED_NAME} INTERFACE ${OUTPUT_FILES})
212
213
214
    endif()
    if(EMBED_USE STREQUAL "RC")
        target_link_libraries(${EMBED_NAME} INTERFACE $<TARGET_OBJECTS:${INTERNAL_EMBED_LIB}>)
215
216
217
    endif()
    target_sources(${EMBED_NAME} INTERFACE $<TARGET_OBJECTS:${INTERNAL_EMBED_LIB}>)
    target_include_directories(${EMBED_NAME} INTERFACE "${EMBED_DIR}/include")
Paul Fultz II's avatar
Paul Fultz II committed
218
endfunction()
219