vtkEncodeString.cmake 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #[==[
  2. @file vtkEncodeString.cmake
  3. This module contains the @ref vtk_encode_string function which may be used to
  4. turn a file into a C string. This is primarily used within a program so that
  5. the content does not need to be retrieved from the filesystem at runtime, but
  6. can still be developed as a standalone file.
  7. #]==]
  8. set(_vtkEncodeString_script_file "${CMAKE_CURRENT_LIST_FILE}")
  9. include(CMakeParseArguments)
  10. #[==[
  11. @brief Encode a file as a C string at build time
  12. Adds a rule to turn a file into a C string. Note that any Unicode characters
  13. will not be replaced with escaping, so it is recommended to avoid their usage
  14. in the input.
  15. ~~~
  16. vtk_encode_string
  17. INPUT <input>
  18. [NAME <name>]
  19. [EXPORT_SYMBOL <symbol>]
  20. [EXPORT_HEADER <header>]
  21. [HEADER_OUTPUT <variable>]
  22. [SOURCE_OUTPUT <variable>]
  23. [BINARY] [NUL_TERMINATE])
  24. ~~~
  25. The only required variable is `INPUT`, however, it is likely that at least one
  26. of `HEADER_OUTPUT` or `SOURCE_OUTPUT` will be required to add them to a
  27. library.
  28. * `INPUT`: (Required) The path to the file to be embedded. If a relative path
  29. is given, it will be interpreted as being relative to
  30. `CMAKE_CURRENT_SOURCE_DIR`.
  31. * `NAME`: This is the base name of the files that will be generated as well
  32. as the variable name for the C string. It defaults to the basename of the
  33. input without extensions.
  34. * `EXPORT_SYMBOL`: The symbol to use for exporting the variable. By default,
  35. it will not be exported. If set, `EXPORT_HEADER` must also be set.
  36. * `EXPORT_HEADER`: The header to include for providing the given export
  37. symbol. If set, `EXPORT_SYMBOL` should also be set.
  38. * `HEADER_OUTPUT`: The variable to store the generated header path.
  39. * `SOURCE_OUTPUT`: The variable to store the generated source path.
  40. * `BINARY`: If given, the data will be written as an array of `unsigned char`
  41. bytes.
  42. * `NUL_TERMINATE`: If given, the binary data will be `NUL`-terminated. Only
  43. makes sense with the `BINARY` flag. This is intended to be used if
  44. embedding a file as a C string exceeds compiler limits on string literals
  45. in various compilers.
  46. #]==]
  47. function (vtk_encode_string)
  48. cmake_parse_arguments(_vtk_encode_string
  49. "BINARY;NUL_TERMINATE"
  50. "INPUT;NAME;EXPORT_SYMBOL;EXPORT_HEADER;HEADER_OUTPUT;SOURCE_OUTPUT"
  51. ""
  52. ${ARGN})
  53. if (_vtk_encode_string_UNPARSED_ARGUMENTS)
  54. message(FATAL_ERROR
  55. "Unrecognized arguments to vtk_encode_string: "
  56. "${_vtk_encode_string_UNPARSED_ARGUMENTS}")
  57. endif ()
  58. if (NOT DEFINED _vtk_encode_string_INPUT)
  59. message(FATAL_ERROR
  60. "Missing `INPUT` for vtk_encode_string.")
  61. endif ()
  62. if (NOT DEFINED _vtk_encode_string_NAME)
  63. get_filename_component(_vtk_encode_string_NAME
  64. "${_vtk_encode_string_INPUT}" NAME_WE)
  65. endif ()
  66. if (DEFINED _vtk_encode_string_EXPORT_SYMBOL AND
  67. NOT DEFINED _vtk_encode_string_EXPORT_HEADER)
  68. message(FATAL_ERROR
  69. "Missing `EXPORT_HEADER` when using `EXPORT_SYMBOL`.")
  70. endif ()
  71. if (DEFINED _vtk_encode_string_EXPORT_HEADER AND
  72. NOT DEFINED _vtk_encode_string_EXPORT_SYMBOL)
  73. message(WARNING
  74. "Missing `EXPORT_SYMBOL` when using `EXPORT_HEADER`.")
  75. endif ()
  76. if (NOT _vtk_encode_string_BINARY AND _vtk_encode_string_NUL_TERMINATE)
  77. message(FATAL_ERROR
  78. "The `NUL_TERMINATE` flag only makes sense with the `BINARY` flag.")
  79. endif ()
  80. set(_vtk_encode_string_header
  81. "${CMAKE_CURRENT_BINARY_DIR}/${_vtk_encode_string_NAME}.h")
  82. set(_vtk_encode_string_source
  83. "${CMAKE_CURRENT_BINARY_DIR}/${_vtk_encode_string_NAME}.cxx")
  84. if (IS_ABSOLUTE "${_vtk_encode_string_INPUT}")
  85. set(_vtk_encode_string_input
  86. "${_vtk_encode_string_INPUT}")
  87. else ()
  88. set(_vtk_encode_string_input
  89. "${CMAKE_CURRENT_SOURCE_DIR}/${_vtk_encode_string_INPUT}")
  90. endif ()
  91. add_custom_command(
  92. OUTPUT ${_vtk_encode_string_header}
  93. ${_vtk_encode_string_source}
  94. DEPENDS "${_vtkEncodeString_script_file}"
  95. "${_vtk_encode_string_input}"
  96. COMMAND "${CMAKE_COMMAND}"
  97. "-Dsource_dir=${CMAKE_CURRENT_SOURCE_DIR}"
  98. "-Dbinary_dir=${CMAKE_CURRENT_BINARY_DIR}"
  99. "-Dsource_file=${_vtk_encode_string_input}"
  100. "-Doutput_name=${_vtk_encode_string_NAME}"
  101. "-Dexport_symbol=${_vtk_encode_string_EXPORT_SYMBOL}"
  102. "-Dexport_header=${_vtk_encode_string_EXPORT_HEADER}"
  103. "-Dbinary=${_vtk_encode_string_BINARY}"
  104. "-Dnul_terminate=${_vtk_encode_string_NUL_TERMINATE}"
  105. "-D_vtk_encode_string_run=ON"
  106. -P "${_vtkEncodeString_script_file}")
  107. if (DEFINED _vtk_encode_string_SOURCE_OUTPUT)
  108. set("${_vtk_encode_string_SOURCE_OUTPUT}"
  109. "${_vtk_encode_string_source}"
  110. PARENT_SCOPE)
  111. endif ()
  112. if (DEFINED _vtk_encode_string_HEADER_OUTPUT)
  113. set("${_vtk_encode_string_HEADER_OUTPUT}"
  114. "${_vtk_encode_string_header}"
  115. PARENT_SCOPE)
  116. endif ()
  117. endfunction ()
  118. if (_vtk_encode_string_run AND CMAKE_SCRIPT_MODE_FILE)
  119. set(output_header "${binary_dir}/${output_name}.h")
  120. set(output_source "${binary_dir}/${output_name}.cxx")
  121. file(WRITE "${output_header}" "")
  122. file(WRITE "${output_source}" "")
  123. file(APPEND "${output_header}"
  124. "#ifndef ${output_name}_h\n#define ${output_name}_h\n\n")
  125. if (export_symbol)
  126. file(APPEND "${output_header}"
  127. "#include \"${export_header}\"\n\n${export_symbol} ")
  128. endif ()
  129. if (IS_ABSOLUTE "${source_file}")
  130. set(source_file_full "${source_file}")
  131. else ()
  132. set(source_file_full "${source_dir}/${source_file}")
  133. endif ()
  134. set(hex_arg)
  135. if (binary)
  136. set(hex_arg HEX)
  137. endif ()
  138. file(READ "${source_file_full}" original_content ${hex_arg})
  139. if (binary)
  140. if (nul_terminate)
  141. string(APPEND original_content "00")
  142. endif ()
  143. string(LENGTH "${original_content}" output_size)
  144. math(EXPR output_size "${output_size} / 2")
  145. file(APPEND "${output_header}"
  146. "extern const unsigned char ${output_name}[${output_size}];\n\n#endif\n")
  147. file(APPEND "${output_source}"
  148. "#include \"${output_name}.h\"\n\nconst unsigned char ${output_name}[${output_size}] = {\n")
  149. string(REGEX REPLACE "\([0-9a-f][0-9a-f]\)" ",0x\\1" escaped_content "${original_content}")
  150. # Hard line wrap the file.
  151. string(REGEX REPLACE "\(..........................................................................,\)" "\\1\n" escaped_content "${escaped_content}")
  152. # Remove the leading comma.
  153. string(REGEX REPLACE "^," "" escaped_content "${escaped_content}")
  154. file(APPEND "${output_source}"
  155. "${escaped_content}\n")
  156. file(APPEND "${output_source}"
  157. "};\n")
  158. else ()
  159. file(APPEND "${output_header}"
  160. "extern const char *${output_name};\n\n#endif\n")
  161. # Escape literal backslashes.
  162. string(REPLACE "\\" "\\\\" escaped_content "${original_content}")
  163. # Escape literal double quotes.
  164. string(REPLACE "\"" "\\\"" escaped_content "${escaped_content}")
  165. # Turn newlines into newlines in the C string.
  166. string(REPLACE "\n" "\\n\"\n\"" escaped_content "${escaped_content}")
  167. file(APPEND "${output_source}"
  168. "#include \"${output_name}.h\"\n\nconst char *${output_name} =\n")
  169. file(APPEND "${output_source}"
  170. "\"${escaped_content}\";\n")
  171. endif ()
  172. endif ()