GodotCPPModule.cmake 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #[=======================================================================[.rst:
  2. GodotCPPModule.cmake
  3. ---------------------
  4. This file contains functions and tests which may be needed by consumers.
  5. * Generate Trimmed API
  6. * Generate File List
  7. * Generate Bindings
  8. If you want to use these functions in your project extend the CMAKE_MODULE_PATH
  9. by adding these two lines into your CMakeLists.txt after the inclusion
  10. godot-cpp
  11. .. highlight:: cmake
  12. list(APPEND CMAKE_MODULE_PATH "${godot-cpp_SOURCE_DIR}/cmake")
  13. include( GodotCPPModule )
  14. ]=======================================================================]
  15. find_package(Python3 3.4 REQUIRED) # pathlib should be present
  16. #[[ Generate Trimmed API
  17. The build_profile.py has a __main__ and is used as a tool
  18. Its usage is listed as:
  19. $ python build_profile.py BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]
  20. ]]
  21. function( build_profile_generate_trimmed_api BUILD_PROFILE INPUT_JSON OUTPUT_JSON )
  22. execute_process(
  23. COMMAND "${Python3_EXECUTABLE}"
  24. "${godot-cpp_SOURCE_DIR}/build_profile.py"
  25. "${BUILD_PROFILE}"
  26. "${INPUT_JSON}"
  27. "${OUTPUT_JSON}"
  28. WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
  29. )
  30. endfunction( )
  31. #[[ Generate File List
  32. Use the binding_generator.py Python script to determine the list of files that
  33. will be passed to the code generator using extension_api.json.
  34. NOTE: This happens for every configure.]]
  35. function( binding_generator_get_file_list OUT_VAR_NAME API_FILEPATH OUTPUT_DIR )
  36. # This code snippet will be squashed into a single line
  37. # The two strings make this a list, in CMake lists are semicolon delimited strings.
  38. set( PYTHON_SCRIPT
  39. "from binding_generator import print_file_list"
  40. "print_file_list( api_filepath='${API_FILEPATH}',
  41. output_dir='${OUTPUT_DIR}',
  42. headers=True,
  43. sources=True)")
  44. message( DEBUG "Python:\n${PYTHON_SCRIPT}" )
  45. # Strip newlines and whitespace to make it a one-liner.
  46. string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" )
  47. execute_process( COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
  48. WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
  49. OUTPUT_VARIABLE GENERATED_FILES_LIST
  50. OUTPUT_STRIP_TRAILING_WHITESPACE
  51. )
  52. # Debug output
  53. message( DEBUG "FileList-Begin" )
  54. foreach( PATH ${GENERATED_FILES_LIST} )
  55. message( DEBUG ${PATH} )
  56. endforeach()
  57. # Error out if the file list generator returned no files.
  58. list( LENGTH GENERATED_FILES_LIST LIST_LENGTH )
  59. if( NOT LIST_LENGTH GREATER 0 )
  60. message( FATAL_ERROR "File List Generation Failed")
  61. endif()
  62. message( STATUS "There are ${LIST_LENGTH} Files to generate" )
  63. set( ${OUT_VAR_NAME} ${GENERATED_FILES_LIST} PARENT_SCOPE )
  64. endfunction( )
  65. #[[ Generate Bindings
  66. Using the generated file list, use the binding_generator.py to generate the
  67. godot-cpp bindings. This will run at build time only if there are files
  68. missing. ]]
  69. function( binding_generator_generate_bindings API_FILE USE_TEMPLATE_GET_NODE, BITS, PRECISION, OUTPUT_DIR )
  70. # This code snippet will be squashed into a single line
  71. set( PYTHON_SCRIPT
  72. "from binding_generator import generate_bindings"
  73. "generate_bindings(
  74. api_filepath='${API_FILE}',
  75. use_template_get_node='${USE_TEMPLATE_GET_NODE}',
  76. bits='${BITS}',
  77. precision='${PRECISION}',
  78. output_dir='${OUTPUT_DIR}')")
  79. message( DEBUG "Python:\n${PYTHON_SCRIPT}" )
  80. # Strip newlines and whitespace to make it a one-liner.
  81. string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" )
  82. add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
  83. COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
  84. VERBATIM
  85. WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
  86. MAIN_DEPENDENCY ${GODOTCPP_GDEXTENSION_API_FILE}
  87. DEPENDS ${godot-cpp_SOURCE_DIR}/binding_generator.py
  88. COMMENT "Generating bindings"
  89. )
  90. endfunction( )
  91. #[[ Generate doc_data.cpp
  92. The documentation displayed in the Godot editor is compiled into the extension.
  93. It takes a list of XML source files, and transforms them into a cpp file that
  94. is added to the sources list.]]
  95. function( generate_doc_source OUTPUT_PATH SOURCES )
  96. # Transform SOURCES CMake LIST
  97. # quote each path with ''
  98. # join with , to transform into a python list minus the surrounding []
  99. set( PYTHON_LIST "${SOURCES}")
  100. list( TRANSFORM PYTHON_LIST REPLACE "(.*\.xml)" "'\\1'" )
  101. list( JOIN PYTHON_LIST "," PYTHON_LIST )
  102. get_filename_component(OUTPUT_DIR "${OUTPUT_PATH}" DIRECTORY)
  103. file(MAKE_DIRECTORY ${OUTPUT_DIR} )
  104. # Python one-liner to run our command
  105. # lists in CMake are just strings delimited by ';', so this works.
  106. set( PYTHON_SCRIPT "from doc_source_generator import generate_doc_source"
  107. "generate_doc_source( '${OUTPUT_PATH}', [${PYTHON_LIST}] )" )
  108. add_custom_command( OUTPUT "${OUTPUT_PATH}"
  109. COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
  110. VERBATIM
  111. WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
  112. DEPENDS
  113. "${godot-cpp_SOURCE_DIR}/doc_source_generator.py"
  114. "${SOURCES}"
  115. COMMENT "Generating: ${OUTPUT_PATH}"
  116. )
  117. endfunction()
  118. #[[ target_doc_sources
  119. A simpler interface to add xml files as doc source to a output target.
  120. TARGET: The gdexension library target
  121. SOURCES: a list of xml files to use for source generation and inclusion.
  122. This function also adds a doc_gen target to test source generation.]]
  123. function( target_doc_sources TARGET SOURCES )
  124. # set the generated file name
  125. set( DOC_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen/doc_source.cpp" )
  126. # Create the file generation target, this won't be triggered unless a target
  127. # that depends on DOC_SOURCE_FILE is built
  128. generate_doc_source( "${DOC_SOURCE_FILE}" ${SOURCES} )
  129. # Add DOC_SOURCE_FILE as a dependency to TARGET
  130. target_sources( ${TARGET} PRIVATE "${DOC_SOURCE_FILE}" )
  131. # Create a dummy target that depends on the source so that users can
  132. # test the file generation task.
  133. if( TARGET doc_gen )
  134. else()
  135. add_custom_target( doc_gen )
  136. endif()
  137. target_sources( doc_gen PRIVATE "${DOC_SOURCE_FILE}" )
  138. endfunction()