Utilities.cmake 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #[[
  2. Various global utility functions for RmlUi.
  3. ]]
  4. #[[
  5. Format the RmlUi version as it should normally be displayed.
  6. Output:
  7. RMLUI_VERSION_SHORT: The RmlUi version as a string
  8. ]]
  9. function(generate_rmlui_version_string)
  10. if(NOT RMLUI_VERSION_RELEASE)
  11. set(RMLUI_VERSION_SUFFIX "-dev")
  12. endif()
  13. if(PROJECT_VERSION_PATCH GREATER 0)
  14. set(RMLUI_VERSION_PATCH ".${PROJECT_VERSION_PATCH}")
  15. endif()
  16. set(RMLUI_VERSION_SHORT
  17. "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${RMLUI_VERSION_PATCH}${RMLUI_VERSION_SUFFIX}"
  18. PARENT_SCOPE
  19. )
  20. endfunction()
  21. #[[
  22. Stop execution and print an error message for the dependency.
  23. Arguments:
  24. - friendly_name: Friendly name of the dependency
  25. - package_name: Name of the package to search for
  26. - target_name: Name of the CMake target the project will link against
  27. ]]
  28. function(report_dependency_not_found friendly_name package_name target_name)
  29. message(FATAL_ERROR
  30. "${friendly_name} could not be found.\n"
  31. "Please ensure that ${friendly_name} can be found by CMake, or linked to using \"${target_name}\" as its "
  32. "target name. The location of the build directory of the dependency can be provided by setting the "
  33. "\"${package_name}_ROOT\" CMake variable. If you are consuming RmlUi from another CMake project, you can "
  34. "create an ALIAS target to offer an alternative name for a CMake target."
  35. )
  36. endfunction()
  37. #[[
  38. Print a message for the dependency after being found.
  39. Arguments:
  40. - package_name: Name of the package to search for
  41. - target_name: Name of the CMake target the project will link against
  42. - success_message: Message to show when the target exists (optional)
  43. Note: The name and signature of this function should match the macro in `RmlUiConfig.cmake.in`.
  44. ]]
  45. function(report_dependency_found package_name target_name)
  46. set(message "")
  47. if(DEFINED ${package_name}_VERSION AND NOT ${package_name}_VERSION STREQUAL "UNKNOWN")
  48. set(message " v${${package_name}_VERSION}")
  49. endif()
  50. if(ARGC GREATER "2" AND ARGV2)
  51. set(message "${message} - ${ARGV2}")
  52. endif()
  53. message(STATUS "Found ${target_name}${message}")
  54. endfunction()
  55. #[[
  56. Verify that the target is found and print a message, otherwise stop execution.
  57. Arguments:
  58. - friendly_name: Friendly name of the dependency
  59. - package_name: Name of the package to search for
  60. - target_name: Name of the CMake target the project will link against
  61. - success_message [optional]: Message to show when the target exists
  62. Note: The name and signature of this function should match the macro in `RmlUiConfig.cmake.in`.
  63. ]]
  64. function(report_dependency_found_or_error friendly_name package_name target_name)
  65. if(NOT TARGET ${target_name})
  66. report_dependency_not_found(${friendly_name} ${package_name} ${target_name})
  67. endif()
  68. set(success_message "")
  69. if(ARGC GREATER "3" AND ARGV3)
  70. set(success_message "${ARGV3}")
  71. endif()
  72. report_dependency_found(${package_name} ${target_name} ${success_message})
  73. endfunction()
  74. #[[
  75. Returns a list of data directories for the current target.
  76. Arguments:
  77. - target: Name of the target
  78. - out_var: Name of the returned variable
  79. ]]
  80. function(get_data_dirs target out_var)
  81. set(data_dirs "")
  82. foreach(dir IN ITEMS "data" "lua")
  83. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
  84. list(APPEND data_dirs "${dir}")
  85. endif()
  86. endforeach()
  87. set(${out_var} ${data_dirs} PARENT_SCOPE)
  88. endfunction()
  89. #[[
  90. Set compiler options and features that are common to all RmlUi targets.
  91. Arguments:
  92. - target: The name of the target to set
  93. ]]
  94. function(set_common_target_options target)
  95. target_compile_features(${target} PUBLIC cxx_std_17)
  96. set_target_properties(${target} PROPERTIES C_EXTENSIONS OFF CXX_EXTENSIONS OFF)
  97. if(RMLUI_COMPILER_OPTIONS)
  98. if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
  99. target_compile_options(${target} PRIVATE -Wall -Wextra -pedantic)
  100. elseif(MSVC)
  101. target_compile_options(${target} PRIVATE /W4 /w44062 /wd4458 /wd4251 /permissive-)
  102. target_compile_definitions(${target} PRIVATE _CRT_SECURE_NO_WARNINGS)
  103. if(CMAKE_GENERATOR MATCHES "Visual Studio")
  104. target_compile_options(${target} PRIVATE /MP)
  105. endif()
  106. endif()
  107. endif()
  108. if(RMLUI_WARNINGS_AS_ERRORS)
  109. if(NOT RMLUI_COMPILER_OPTIONS)
  110. message(FATAL_ERROR "Option RMLUI_WARNINGS_AS_ERRORS requires RMLUI_COMPILER_OPTIONS=ON.")
  111. endif()
  112. if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
  113. target_compile_options(${target} PRIVATE -Werror)
  114. elseif(MSVC)
  115. target_compile_options(${target} PRIVATE /WX)
  116. else()
  117. message(FATAL_ERROR "Unknown compiler, cannot enable option RMLUI_WARNINGS_AS_ERRORS.")
  118. endif()
  119. endif()
  120. # Set Emscripten-specific properties and assets for samples and test executables.
  121. get_target_property(target_type ${target} TYPE)
  122. if(EMSCRIPTEN AND target_type STREQUAL "EXECUTABLE")
  123. # Make Emscripten generate the default HTML shell for the sample.
  124. set_property(TARGET ${target} PROPERTY SUFFIX ".html")
  125. # Enables Asyncify which we only need since the backend doesn't control the main loop. This enables us to yield
  126. # to the browser during the backend call to Backend::ProcessEvents(). Asyncify results in larger and slower
  127. # code, users are instead encouraged to use 'emscripten_set_main_loop()' and family.
  128. target_link_libraries(${target} PRIVATE "-sASYNCIFY")
  129. # We don't know the needed memory beforehand, allow it to grow.
  130. target_link_libraries(${target} PRIVATE "-sALLOW_MEMORY_GROWTH")
  131. # Add common assets.
  132. set(common_assets_dir "Samples/assets")
  133. target_link_libraries(${target} PRIVATE "--preload-file ${PROJECT_SOURCE_DIR}/${common_assets_dir}/@/${common_assets_dir}/")
  134. file(GLOB asset_files "${PROJECT_SOURCE_DIR}/${common_assets_dir}/*")
  135. # Add sample-specific assets.
  136. get_data_dirs(${target} data_dirs)
  137. foreach(source_relative_dir IN LISTS data_dirs)
  138. set(abs_dir "${CMAKE_CURRENT_SOURCE_DIR}/${source_relative_dir}")
  139. file(RELATIVE_PATH root_relative_dir "${PROJECT_SOURCE_DIR}" "${abs_dir}")
  140. target_link_libraries(${target} PRIVATE "--preload-file ${abs_dir}/@/${root_relative_dir}/")
  141. file(GLOB sample_data_files "${abs_dir}/*")
  142. list(APPEND asset_files "${sample_data_files}")
  143. endforeach()
  144. # Add a linker dependency to all asset files, so that the linker runs again if any asset is modified.
  145. set_target_properties(${target} PROPERTIES LINK_DEPENDS "${asset_files}")
  146. endif()
  147. endfunction()
  148. #[[
  149. Create installation rule for MSVC program database (PDB) files.
  150. Arguments:
  151. - target: The name of the target
  152. ]]
  153. function(install_target_pdb target)
  154. if(MSVC)
  155. if(BUILD_SHARED_LIBS)
  156. # The following only works for linker-generated PDBs, not compiler-generated PDBs produced in static builds.
  157. install(FILES "$<TARGET_PDB_FILE:${target}>"
  158. DESTINATION "${CMAKE_INSTALL_LIBDIR}"
  159. OPTIONAL
  160. )
  161. else()
  162. get_property(output_name TARGET ${target} PROPERTY OUTPUT_NAME)
  163. install(FILES "$<TARGET_FILE_DIR:${target}>/${output_name}.pdb"
  164. DESTINATION "${CMAKE_INSTALL_LIBDIR}"
  165. OPTIONAL
  166. )
  167. endif()
  168. endif()
  169. endfunction()
  170. #[[
  171. Create installation rules for sample targets.
  172. Arguments:
  173. - target: The name of the target
  174. ]]
  175. function(install_sample_target target)
  176. get_data_dirs(${target} data_dirs)
  177. file(RELATIVE_PATH sample_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
  178. install(TARGETS ${TARGET_NAME}
  179. ${RMLUI_RUNTIME_DEPENDENCY_SET_ARG}
  180. RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
  181. )
  182. set(install_dirs "src" ${data_dirs})
  183. install(DIRECTORY ${install_dirs}
  184. DESTINATION "${CMAKE_INSTALL_DATADIR}/${sample_path}"
  185. )
  186. endfunction()
  187. #[[
  188. Enable or disable a given configuration type for multi-configuration generators.
  189. Arguments:
  190. - name: The name of the new configuration
  191. - clone_config: The name of the configuration to clone compile flags from
  192. - enable: Enable or disable configuration
  193. ]]
  194. function(enable_configuration_type name clone_config enable)
  195. if(CMAKE_CONFIGURATION_TYPES)
  196. string(TOUPPER "${name}" name_upper)
  197. string(TOUPPER "${clone_config}" clone_config_upper)
  198. if(enable)
  199. list(APPEND CMAKE_CONFIGURATION_TYPES "${name}")
  200. list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES)
  201. set("CMAKE_MAP_IMPORTED_CONFIG_${name_upper}" "${name};${clone_config}" CACHE INTERNAL "" FORCE)
  202. set("CMAKE_C_FLAGS_${name_upper}" "${CMAKE_C_FLAGS_${clone_config_upper}}" CACHE INTERNAL "" FORCE)
  203. set("CMAKE_CXX_FLAGS_${name_upper}" "${CMAKE_CXX_FLAGS_${clone_config_upper}}" CACHE INTERNAL "" FORCE)
  204. set("CMAKE_EXE_LINKER_FLAGS_${name_upper}" "${CMAKE_EXE_LINKER_FLAGS_${clone_config_upper}}" CACHE INTERNAL "" FORCE)
  205. set("CMAKE_SHARED_LINKER_FLAGS_${name_upper}" "${CMAKE_SHARED_LINKER_FLAGS_${clone_config_upper}}" CACHE INTERNAL "" FORCE)
  206. else()
  207. list(REMOVE_ITEM CMAKE_CONFIGURATION_TYPES "${name}")
  208. endif()
  209. set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING "List of configurations to enable" FORCE)
  210. endif()
  211. endfunction()