mirror of
https://git.lynn.is/Gwen/pretty-automata.git
synced 2024-05-04 17:01:10 +02:00
337 lines
11 KiB
CMake
337 lines
11 KiB
CMake
# Module for embedding resources in binaries
|
|
|
|
find_program(HEXDUMP_COMMAND NAMES xxd)
|
|
|
|
#[==[
|
|
Adds an object library target containing embedded binary resources and
|
|
generates a header file, where you can access them as `span<byte const>`.
|
|
|
|
To use with older C++ standards, you can override both the `span` template
|
|
and the `byte` type to use with e.g. span-lite, Microsoft.GSL or range-v3
|
|
(don't forget to link your span library of choice to the generated target).
|
|
|
|
Usage:
|
|
add_embedded_binary_resources(
|
|
name # Name of the created target
|
|
|
|
OUT_DIR <dir> # Directory where the header and sources will be created
|
|
# (relative to the build directory)
|
|
HEADER <header> # Name of the generated header
|
|
NAMESPACE [namespace] # Namespace of created symbols (optional)
|
|
RESOURCE_NAMES <names [...]> # Names (symbols) of the resources
|
|
RESOURCES <resources [...]> # Resource files
|
|
SPAN_TEMPLATE [template name] # Name of the `span` template, default `std::span`
|
|
SPAN_HEADER [header] # Header with the `span` template, default `<span>`
|
|
BYTE_TYPE [type name] # Name of the `byte` type, default `std::byte`
|
|
BYTE_HEADER [header] # Header with the `byte` type, default `<cstddef>`
|
|
)
|
|
]==]
|
|
function(add_embedded_binary_resources NAME)
|
|
set(OPTIONS "")
|
|
set(ONE_VALUE_ARGS OUT_DIR HEADER NAMESPACE SPAN_TEMPLATE SPAN_HEADER BYTE_TYPE BYTE_HEADER)
|
|
set(MULTI_VALUE_ARGS RESOURCE_NAMES RESOURCES)
|
|
cmake_parse_arguments(ARGS "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})
|
|
|
|
if(NOT HEXDUMP_COMMAND)
|
|
message(FATAL_ERROR "Cannot embed resources - xxd not found.")
|
|
endif()
|
|
|
|
set(FULL_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_OUT_DIR}/${ARGS_HEADER}")
|
|
|
|
if(NOT DEFINED ARGS_SPAN_TEMPLATE)
|
|
set(ARGS_SPAN_TEMPLATE "std::span")
|
|
endif()
|
|
|
|
if(NOT DEFINED ARGS_SPAN_HEADER)
|
|
set(ARGS_SPAN_HEADER "<span>")
|
|
endif()
|
|
|
|
if(NOT DEFINED ARGS_BYTE_TYPE)
|
|
set(ARGS_BYTE_TYPE "std::byte")
|
|
endif()
|
|
|
|
if(NOT DEFINED ARGS_BYTE_HEADER)
|
|
set(ARGS_BYTE_HEADER "<cstddef>")
|
|
endif()
|
|
|
|
add_library("${NAME}" OBJECT)
|
|
target_include_directories("${NAME}" PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
|
|
|
if(ARGS_SPAN_HEADER STREQUAL "<span>")
|
|
target_compile_features("${NAME}" PUBLIC cxx_std_20)
|
|
elseif(ARGS_BYTE_HEADER STREQUAL "<cstddef>")
|
|
target_compile_features("${NAME}" PUBLIC cxx_std_17)
|
|
endif()
|
|
|
|
# fPIC not added automatically to object libraries due to defect in CMake
|
|
set_target_properties(
|
|
"${NAME}"
|
|
|
|
PROPERTIES
|
|
POSITION_INDEPENDENT_CODE ON
|
|
)
|
|
|
|
file(
|
|
WRITE "${FULL_HEADER_PATH}"
|
|
|
|
"#pragma once\n"
|
|
"\n"
|
|
"#include ${ARGS_BYTE_HEADER}\n"
|
|
"#include ${ARGS_SPAN_HEADER}\n"
|
|
"\n"
|
|
)
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_HEADER_PATH}"
|
|
|
|
"namespace ${ARGS_NAMESPACE}\n"
|
|
"{\n"
|
|
"\n"
|
|
)
|
|
endif()
|
|
|
|
foreach(RESOURCE_NAME RESOURCE IN ZIP_LISTS ARGS_RESOURCE_NAMES ARGS_RESOURCES)
|
|
set(FULL_RESOURCE_UNIT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_OUT_DIR}/${RESOURCE_NAME}.cpp")
|
|
set(FULL_RESOURCE_HEX_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_OUT_DIR}/${RESOURCE_NAME}.inc")
|
|
|
|
# Add symbol to header
|
|
file(
|
|
APPEND "${FULL_HEADER_PATH}"
|
|
|
|
"[[nodiscard]] ${ARGS_SPAN_TEMPLATE}<${ARGS_BYTE_TYPE} const>\n"
|
|
"${RESOURCE_NAME}() noexcept;\n"
|
|
"\n"
|
|
)
|
|
|
|
# Write .cpp
|
|
file(
|
|
WRITE "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"#include \"${ARGS_HEADER}\"\n"
|
|
"\n"
|
|
"#include <cstdint>\n"
|
|
"\n"
|
|
)
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"namespace ${ARGS_NAMESPACE}\n"
|
|
"{\n"
|
|
"\n"
|
|
)
|
|
endif()
|
|
|
|
file(
|
|
APPEND "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"namespace\n"
|
|
"{\n"
|
|
"\n"
|
|
"std::uint8_t const ${RESOURCE_NAME}_data[] = {\n"
|
|
"#include \"${RESOURCE_NAME}.inc\"\n"
|
|
"};\n"
|
|
"\n"
|
|
"} // namespace\n"
|
|
"\n"
|
|
"${ARGS_SPAN_TEMPLATE}<${ARGS_BYTE_TYPE} const>\n"
|
|
"${RESOURCE_NAME}() noexcept\n"
|
|
"{\n"
|
|
" return as_bytes(${ARGS_SPAN_TEMPLATE}<std::uint8_t const>{${RESOURCE_NAME}_data, sizeof(${RESOURCE_NAME}_data)});\n"
|
|
"}\n"
|
|
)
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"\n"
|
|
"} // namespace ${ARGS_NAMESPACE}\n"
|
|
)
|
|
endif()
|
|
|
|
target_sources("${NAME}" PRIVATE "${FULL_RESOURCE_UNIT_PATH}")
|
|
|
|
add_custom_command(
|
|
OUTPUT "${FULL_RESOURCE_HEX_PATH}"
|
|
COMMAND "${HEXDUMP_COMMAND}" -i < "${RESOURCE}" > "${FULL_RESOURCE_HEX_PATH}"
|
|
MAIN_DEPENDENCY "${RESOURCE}"
|
|
)
|
|
list(APPEND RESOURCES_HEX_FILES "${FULL_RESOURCE_HEX_PATH}")
|
|
endforeach()
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_HEADER_PATH}"
|
|
|
|
"} // namespace ${ARGS_NAMESPACE}\n"
|
|
)
|
|
endif()
|
|
|
|
target_sources("${NAME}" PUBLIC "${FULL_HEADER_PATH}")
|
|
|
|
add_custom_target("${NAME}_hexdump" DEPENDS "${RESOURCES_HEX_FILES}")
|
|
add_dependencies("${NAME}" "${NAME}_hexdump")
|
|
endfunction()
|
|
|
|
#[==[
|
|
Adds an object library target containing embedded text resources and
|
|
generates a header file, where you can access them as `string_view`.
|
|
|
|
To use with older C++ standards, you can override the `string_view` type
|
|
to use with e.g. string-view-lite (don't forget to link your string view
|
|
library of choice to the generated target).
|
|
|
|
Usage:
|
|
add_embedded_text_resources(
|
|
name # Name of the created target
|
|
|
|
OUT_DIR <dir> # Directory where the header and sources will be created
|
|
# (relative to the build directory)
|
|
HEADER <header> # Name of the generated header
|
|
NAMESPACE [namespace] # Namespace of created symbols (optional)
|
|
RESOURCE_NAMES <names [...]> # Names (symbols) of the resources
|
|
RESOURCES <resources [...]> # Resource files
|
|
STRING_VIEW_TYPE [type name] # Name of the `string_view` type, default `std::string_view`
|
|
STRING_VIEW_HEADER [header] # Header with the `string_view` type, default `<string_view>`
|
|
)
|
|
]==]
|
|
function(add_embedded_text_resources NAME)
|
|
set(OPTIONS "")
|
|
set(ONE_VALUE_ARGS OUT_DIR HEADER NAMESPACE STRING_VIEW_TYPE STRING_VIEW_HEADER)
|
|
set(MULTI_VALUE_ARGS RESOURCE_NAMES RESOURCES)
|
|
cmake_parse_arguments(ARGS "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})
|
|
|
|
if(NOT HEXDUMP_COMMAND)
|
|
message(FATAL_ERROR "Cannot embed resources - xxd not found.")
|
|
endif()
|
|
|
|
set(FULL_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_OUT_DIR}/${ARGS_HEADER}")
|
|
|
|
if(NOT DEFINED ARGS_STRING_VIEW_TYPE)
|
|
set(ARGS_STRING_VIEW_TYPE "std::string_view")
|
|
endif()
|
|
|
|
if(NOT DEFINED ARGS_STRING_VIEW_HEADER)
|
|
set(ARGS_STRING_VIEW_HEADER "<string_view>")
|
|
endif()
|
|
|
|
add_library("${NAME}" OBJECT)
|
|
target_include_directories("${NAME}" PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
|
|
|
if(ARGS_STRING_VIEW_HEADER STREQUAL "<string_view>")
|
|
target_compile_features("${NAME}" PUBLIC cxx_std_17)
|
|
endif()
|
|
|
|
# fPIC not added automatically to object libraries due to defect in CMake
|
|
set_target_properties(
|
|
"${NAME}"
|
|
|
|
PROPERTIES
|
|
POSITION_INDEPENDENT_CODE ON
|
|
)
|
|
|
|
file(
|
|
WRITE "${FULL_HEADER_PATH}"
|
|
|
|
"#pragma once\n"
|
|
"\n"
|
|
"#include ${ARGS_STRING_VIEW_HEADER}\n"
|
|
"\n"
|
|
)
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_HEADER_PATH}"
|
|
|
|
"namespace ${ARGS_NAMESPACE}\n"
|
|
"{\n"
|
|
"\n"
|
|
)
|
|
endif()
|
|
|
|
foreach(RESOURCE_NAME RESOURCE IN ZIP_LISTS ARGS_RESOURCE_NAMES ARGS_RESOURCES)
|
|
set(FULL_RESOURCE_UNIT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_OUT_DIR}/${RESOURCE_NAME}.cpp")
|
|
set(FULL_RESOURCE_HEX_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_OUT_DIR}/${RESOURCE_NAME}.inc")
|
|
|
|
# Add symbol to header
|
|
file(
|
|
APPEND "${FULL_HEADER_PATH}"
|
|
|
|
"[[nodiscard]] ${ARGS_STRING_VIEW_TYPE}\n"
|
|
"${RESOURCE_NAME}() noexcept;\n"
|
|
"\n"
|
|
)
|
|
|
|
# Write .cpp
|
|
file(
|
|
WRITE "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"#include \"${ARGS_HEADER}\"\n"
|
|
"\n"
|
|
)
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"namespace ${ARGS_NAMESPACE}\n"
|
|
"{\n"
|
|
"\n"
|
|
)
|
|
endif()
|
|
|
|
file(
|
|
APPEND "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"namespace\n"
|
|
"{\n"
|
|
"\n"
|
|
"char const ${RESOURCE_NAME}_data[] = {\n"
|
|
"#include \"${RESOURCE_NAME}.inc\"\n"
|
|
"};\n"
|
|
"\n"
|
|
"} // namespace\n"
|
|
"\n"
|
|
"${ARGS_STRING_VIEW_TYPE}\n"
|
|
"${RESOURCE_NAME}() noexcept\n"
|
|
"{\n"
|
|
" return ${ARGS_STRING_VIEW_TYPE}{${RESOURCE_NAME}_data, sizeof(${RESOURCE_NAME}_data)};\n"
|
|
"}\n"
|
|
)
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_RESOURCE_UNIT_PATH}"
|
|
|
|
"\n"
|
|
"} // namespace ${ARGS_NAMESPACE}\n"
|
|
)
|
|
endif()
|
|
|
|
target_sources("${NAME}" PRIVATE "${FULL_RESOURCE_UNIT_PATH}")
|
|
|
|
add_custom_command(
|
|
OUTPUT "${FULL_RESOURCE_HEX_PATH}"
|
|
COMMAND "${HEXDUMP_COMMAND}" -i < "${RESOURCE}" > "${FULL_RESOURCE_HEX_PATH}"
|
|
MAIN_DEPENDENCY "${RESOURCE}"
|
|
)
|
|
list(APPEND RESOURCES_HEX_FILES "${FULL_RESOURCE_HEX_PATH}")
|
|
endforeach()
|
|
|
|
if(DEFINED ARGS_NAMESPACE)
|
|
file(
|
|
APPEND "${FULL_HEADER_PATH}"
|
|
|
|
"} // namespace ${ARGS_NAMESPACE}\n"
|
|
)
|
|
endif()
|
|
|
|
target_sources("${NAME}" PUBLIC "${FULL_HEADER_PATH}")
|
|
|
|
add_custom_target("${NAME}_hexdump" DEPENDS "${RESOURCES_HEX_FILES}")
|
|
add_dependencies("${NAME}" "${NAME}_hexdump")
|
|
endfunction()
|