Embed.cmake 8.86 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

Artur Wojcik's avatar
Artur Wojcik committed
25
26
27
28
29
30
31
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()
32

Artur Wojcik's avatar
Artur Wojcik committed
33
if(EMBED_USE STREQUAL "LD")
34
35
36
    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
    set(oneValueArgs)
68
    set(multiValueArgs SYMBOLS FILES)
Paul Fultz II's avatar
Paul Fultz II committed
69
70
    cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

71
    set(RESOURCE_ID 100)
72
    foreach(SYMBOL FILE IN ZIP_LISTS PARSE_SYMBOLS PARSE_FILES)
73
        cmake_path(RELATIVE_PATH FILE BASE_DIRECTORY ${BASE_DIRECTORY} OUTPUT_VARIABLE BASE_NAME)
Artur Wojcik's avatar
Artur Wojcik committed
74
        if(EMBED_USE STREQUAL "RC")
75
76
            string(TOUPPER "${SYMBOL}" SYMBOL)
            string(APPEND FILE_IDS "#define IDR_${SYMBOL} ${RESOURCE_ID}\n")
Artur Wojcik's avatar
Artur Wojcik committed
77
            cmake_path(NATIVE_PATH FILE NORMALIZE NATIVE_FILE)
78
            string(REPLACE "\\" "\\\\" NATIVE_FILE "${NATIVE_FILE}")
Artur Wojcik's avatar
Artur Wojcik committed
79
80
            string(APPEND RC_FILE_MAPPING "IDR_${SYMBOL} TEXTFILE \"${NATIVE_FILE}\"\n")
            string(APPEND INIT_KERNELS "\n        {\"${BASE_NAME}\", resource::read(IDR_${SYMBOL})},")
81
82
83
84
            math(EXPR RESOURCE_ID "${RESOURCE_ID} + 1" OUTPUT_FORMAT DECIMAL)
        else()
            set(START_SYMBOL "_binary_${SYMBOL}_start")
            set(LENGTH_SYMBOL "_binary_${SYMBOL}_length")
Artur Wojcik's avatar
Artur Wojcik committed
85
            if(EMBED_USE STREQUAL "LD")
86
                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()
Paul Fultz II's avatar
Paul Fultz II committed
100
    endforeach()
Artur Wojcik's avatar
Artur Wojcik committed
101
    if(EMBED_USE STREQUAL "RC")
102
103
       file(WRITE "${EMBED_DIR}/include/resource.h" "
#define TEXTFILE 256
Paul Fultz II's avatar
Paul Fultz II committed
104

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
${FILE_IDS}
")
        file(WRITE "${EMBED_DIR}/resource.rc" "
#include \"resource.h\"

${RC_FILE_MAPPING}
")
        set(EXTERNS "
#include <Windows.h>
#include \"resource.h\"

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>
130
131
132
#include <unordered_map>
#include <utility>
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
{
Artur Wojcik's avatar
Artur Wojcik committed
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
function(embed_file FILE BASE_DIRECTORY)
150
    message(STATUS "    ${FILE}")
151
    cmake_path(RELATIVE_PATH FILE BASE_DIRECTORY "${BASE_DIRECTORY}" OUTPUT_VARIABLE REL_FILE)
152
153
154
    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}")
Artur Wojcik's avatar
Artur Wojcik committed
155
156
157
158
159
160
161
162
163
164
165
    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")
166
167
168
169
170
171
172
173
174
175
176
177
        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}" "
#include <cstddef>
extern const char _binary_${OUTPUT_SYMBOL}_start[] = { ${ARRAY_VALUES} };
178
extern const size_t _binary_${OUTPUT_SYMBOL}_length = sizeof(_binary_${OUTPUT_SYMBOL}_start);
179
")
180
        set(OUTPUT_FILE ${OUTPUT_FILE} PARENT_SCOPE)
181
182
183
    endif()
    set(OUTPUT_SYMBOL ${OUTPUT_SYMBOL} PARENT_SCOPE)
endfunction()
Paul Fultz II's avatar
Paul Fultz II committed
184
185

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

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
    message(STATUS "Generating embedding library '${EMBED_NAME}'")
200
201
202
    generate_embed_source(${EMBED_NAME} ${EMBED_DIR} "${PARSE_RELATIVE}" SYMBOLS ${SYMBOLS} FILES ${PARSE_UNPARSED_ARGUMENTS})
    set(INTERNAL_EMBED_LIB embed_lib_${EMBED_NAME})
    add_library(${INTERNAL_EMBED_LIB} OBJECT ${EMBED_FILES})
Artur Wojcik's avatar
Artur Wojcik committed
203
    if(EMBED_USE STREQUAL "CArrays")
204
        target_sources(${INTERNAL_EMBED_LIB} PRIVATE ${OUTPUT_FILES})
205
    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 $<TARGET_OBJECTS:${INTERNAL_EMBED_LIB}> ${OUTPUT_FILES})
Artur Wojcik's avatar
Artur Wojcik committed
210
    if(EMBED_USE STREQUAL "RC")
211
        target_link_libraries(${EMBED_NAME} INTERFACE $<TARGET_OBJECTS:${INTERNAL_EMBED_LIB}>)
212
    endif()
213
    target_include_directories(${EMBED_NAME} INTERFACE "${EMBED_DIR}/include")
Paul Fultz II's avatar
Paul Fultz II committed
214
endfunction()
Artur Wojcik's avatar
Artur Wojcik committed
215