You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
7.1 KiB
CMake

#[==[
@file vtkEncodeString.cmake
This module contains the @ref vtk_encode_string function which may be used to
turn a file into a C string. This is primarily used within a program so that
the content does not need to be retrieved from the filesystem at runtime, but
can still be developed as a standalone file.
#]==]
set(_vtkEncodeString_script_file "${CMAKE_CURRENT_LIST_FILE}")
include(CMakeParseArguments)
#[==[
@brief Encode a file as a C string at build time
Adds a rule to turn a file into a C string. Note that any Unicode characters
will not be replaced with escaping, so it is recommended to avoid their usage
in the input.
~~~
vtk_encode_string
INPUT <input>
[NAME <name>]
[EXPORT_SYMBOL <symbol>]
[EXPORT_HEADER <header>]
[HEADER_OUTPUT <variable>]
[SOURCE_OUTPUT <variable>]
[BINARY] [NUL_TERMINATE])
~~~
The only required variable is `INPUT`, however, it is likely that at least one
of `HEADER_OUTPUT` or `SOURCE_OUTPUT` will be required to add them to a
library.
* `INPUT`: (Required) The path to the file to be embedded. If a relative path
is given, it will be interpreted as being relative to
`CMAKE_CURRENT_SOURCE_DIR`.
* `NAME`: This is the base name of the files that will be generated as well
as the variable name for the C string. It defaults to the basename of the
input without extensions.
* `EXPORT_SYMBOL`: The symbol to use for exporting the variable. By default,
it will not be exported. If set, `EXPORT_HEADER` must also be set.
* `EXPORT_HEADER`: The header to include for providing the given export
symbol. If set, `EXPORT_SYMBOL` should also be set.
* `HEADER_OUTPUT`: The variable to store the generated header path.
* `SOURCE_OUTPUT`: The variable to store the generated source path.
* `BINARY`: If given, the data will be written as an array of `unsigned char`
bytes.
* `NUL_TERMINATE`: If given, the binary data will be `NUL`-terminated. Only
makes sense with the `BINARY` flag. This is intended to be used if
embedding a file as a C string exceeds compiler limits on string literals
in various compilers.
#]==]
function (vtk_encode_string)
cmake_parse_arguments(_vtk_encode_string
"BINARY;NUL_TERMINATE"
"INPUT;NAME;EXPORT_SYMBOL;EXPORT_HEADER;HEADER_OUTPUT;SOURCE_OUTPUT"
""
${ARGN})
if (_vtk_encode_string_UNPARSED_ARGUMENTS)
message(FATAL_ERROR
"Unrecognized arguments to vtk_encode_string: "
"${_vtk_encode_string_UNPARSED_ARGUMENTS}")
endif ()
if (NOT DEFINED _vtk_encode_string_INPUT)
message(FATAL_ERROR
"Missing `INPUT` for vtk_encode_string.")
endif ()
if (NOT DEFINED _vtk_encode_string_NAME)
get_filename_component(_vtk_encode_string_NAME
"${_vtk_encode_string_INPUT}" NAME_WE)
endif ()
if (DEFINED _vtk_encode_string_EXPORT_SYMBOL AND
NOT DEFINED _vtk_encode_string_EXPORT_HEADER)
message(FATAL_ERROR
"Missing `EXPORT_HEADER` when using `EXPORT_SYMBOL`.")
endif ()
if (DEFINED _vtk_encode_string_EXPORT_HEADER AND
NOT DEFINED _vtk_encode_string_EXPORT_SYMBOL)
message(WARNING
"Missing `EXPORT_SYMBOL` when using `EXPORT_HEADER`.")
endif ()
if (NOT _vtk_encode_string_BINARY AND _vtk_encode_string_NUL_TERMINATE)
message(FATAL_ERROR
"The `NUL_TERMINATE` flag only makes sense with the `BINARY` flag.")
endif ()
set(_vtk_encode_string_header
"${CMAKE_CURRENT_BINARY_DIR}/${_vtk_encode_string_NAME}.h")
set(_vtk_encode_string_source
"${CMAKE_CURRENT_BINARY_DIR}/${_vtk_encode_string_NAME}.cxx")
if (IS_ABSOLUTE "${_vtk_encode_string_INPUT}")
set(_vtk_encode_string_input
"${_vtk_encode_string_INPUT}")
else ()
set(_vtk_encode_string_input
"${CMAKE_CURRENT_SOURCE_DIR}/${_vtk_encode_string_INPUT}")
endif ()
add_custom_command(
OUTPUT ${_vtk_encode_string_header}
${_vtk_encode_string_source}
DEPENDS "${_vtkEncodeString_script_file}"
"${_vtk_encode_string_input}"
COMMAND "${CMAKE_COMMAND}"
"-Dsource_dir=${CMAKE_CURRENT_SOURCE_DIR}"
"-Dbinary_dir=${CMAKE_CURRENT_BINARY_DIR}"
"-Dsource_file=${_vtk_encode_string_input}"
"-Doutput_name=${_vtk_encode_string_NAME}"
"-Dexport_symbol=${_vtk_encode_string_EXPORT_SYMBOL}"
"-Dexport_header=${_vtk_encode_string_EXPORT_HEADER}"
"-Dbinary=${_vtk_encode_string_BINARY}"
"-Dnul_terminate=${_vtk_encode_string_NUL_TERMINATE}"
"-D_vtk_encode_string_run=ON"
-P "${_vtkEncodeString_script_file}")
if (DEFINED _vtk_encode_string_SOURCE_OUTPUT)
set("${_vtk_encode_string_SOURCE_OUTPUT}"
"${_vtk_encode_string_source}"
PARENT_SCOPE)
endif ()
if (DEFINED _vtk_encode_string_HEADER_OUTPUT)
set("${_vtk_encode_string_HEADER_OUTPUT}"
"${_vtk_encode_string_header}"
PARENT_SCOPE)
endif ()
endfunction ()
if (_vtk_encode_string_run AND CMAKE_SCRIPT_MODE_FILE)
set(output_header "${binary_dir}/${output_name}.h")
set(output_source "${binary_dir}/${output_name}.cxx")
file(WRITE "${output_header}" "")
file(WRITE "${output_source}" "")
file(APPEND "${output_header}"
"#ifndef ${output_name}_h\n#define ${output_name}_h\n\n")
if (export_symbol)
file(APPEND "${output_header}"
"#include \"${export_header}\"\n\n${export_symbol} ")
endif ()
if (IS_ABSOLUTE "${source_file}")
set(source_file_full "${source_file}")
else ()
set(source_file_full "${source_dir}/${source_file}")
endif ()
set(hex_arg)
if (binary)
set(hex_arg HEX)
endif ()
file(READ "${source_file_full}" original_content ${hex_arg})
if (binary)
if (nul_terminate)
string(APPEND original_content "00")
endif ()
string(LENGTH "${original_content}" output_size)
math(EXPR output_size "${output_size} / 2")
file(APPEND "${output_header}"
"extern const unsigned char ${output_name}[${output_size}];\n\n#endif\n")
file(APPEND "${output_source}"
"#include \"${output_name}.h\"\n\nconst unsigned char ${output_name}[${output_size}] = {\n")
string(REGEX REPLACE "\([0-9a-f][0-9a-f]\)" ",0x\\1" escaped_content "${original_content}")
# Hard line wrap the file.
string(REGEX REPLACE "\(..........................................................................,\)" "\\1\n" escaped_content "${escaped_content}")
# Remove the leading comma.
string(REGEX REPLACE "^," "" escaped_content "${escaped_content}")
file(APPEND "${output_source}"
"${escaped_content}\n")
file(APPEND "${output_source}"
"};\n")
else ()
file(APPEND "${output_header}"
"extern const char *${output_name};\n\n#endif\n")
# Escape literal backslashes.
string(REPLACE "\\" "\\\\" escaped_content "${original_content}")
# Escape literal double quotes.
string(REPLACE "\"" "\\\"" escaped_content "${escaped_content}")
# Turn newlines into newlines in the C string.
string(REPLACE "\n" "\\n\"\n\"" escaped_content "${escaped_content}")
file(APPEND "${output_source}"
"#include \"${output_name}.h\"\n\nconst char *${output_name} =\n")
file(APPEND "${output_source}"
"\"${escaped_content}\";\n")
endif ()
endif ()