CompositeSources.cmake 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. # Filename: CompositeSources.cmake
  2. # Description: This file defines the function composite_sources which looks at
  3. # a provided list of sources, generates _compositeN.cxx, and appends the
  4. # composites to the list. The original files in the list are marked as headers
  5. # so that they will be available in an IDE, but not compiled at build time.
  6. #
  7. # Usage:
  8. # composite_sources(target source_var)
  9. #
  10. # Example:
  11. # set(MY_SOURCES a.cxx b.cxx c.cxx)
  12. # composite_sources(my_lib MY_SOURCES)
  13. # add_library(my_lib ${MY_SOURCES})
  14. #
  15. # Settings for composite builds. Should be moved to Config.cmake?
  16. set(CMAKE_UNITY_BUILD "ON" CACHE BOOL
  17. "Enable unity builds; Panda defaults this to on.")
  18. set(CMAKE_UNITY_BUILD_BATCH_SIZE "30" CACHE STRING
  19. "How many source files to build at a time through the unity build mechanism.
  20. A high value will speed up the build dramatically but will be more memory
  21. intensive than a low value.")
  22. set(COMPOSITE_SOURCE_EXTENSIONS ".cxx;.mm;.c" CACHE STRING
  23. "Only files of these extensions will be composited.")
  24. set(COMPOSITE_SOURCE_EXCLUSIONS "" CACHE STRING
  25. "A list of targets to skip when compositing sources. This is mainly
  26. desirable for CI builds.")
  27. set(COMPOSITE_GENERATOR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/scripts/MakeComposite.cmake")
  28. # Define composite_sources()
  29. function(composite_sources target sources_var)
  30. if(NOT CMAKE_VERSION VERSION_LESS "3.16")
  31. # CMake 3.16+ implements CMAKE_UNITY_BUILD* natively; no need to continue!
  32. # Actually - <=3.16.2 has difficulty with multi-language support, so only
  33. # allow .cxx in. Hopefully this can be removed soon.
  34. foreach(_source ${${sources_var}})
  35. get_filename_component(_source_ext "${_source}" EXT)
  36. if(NOT _source_ext STREQUAL ".cxx")
  37. set_source_files_properties(${_source} PROPERTIES
  38. SKIP_UNITY_BUILD_INCLUSION YES)
  39. endif()
  40. endforeach(_source)
  41. return()
  42. endif()
  43. if(NOT CMAKE_UNITY_BUILD)
  44. # We've been turned off
  45. return()
  46. endif()
  47. # How many sources were specified?
  48. set(orig_sources ${${sources_var}})
  49. set(sources ${orig_sources})
  50. list(LENGTH sources num_sources)
  51. # Don't composite if in the list of exclusions, and don't bother compositing
  52. # with too few sources
  53. list (FIND COMPOSITE_SOURCE_EXCLUSIONS ${target} _index)
  54. if(num_sources LESS 2 OR ${CMAKE_UNITY_BUILD_BATCH_SIZE} LESS 2 OR ${_index} GREATER -1)
  55. return()
  56. endif()
  57. # Sort each source file into a list.
  58. foreach(source ${sources})
  59. get_filename_component(extension "${source}" EXT)
  60. get_source_file_property(generated "${source}" GENERATED)
  61. get_source_file_property(is_header "${source}" HEADER_FILE_ONLY)
  62. get_source_file_property(skip_compositing "${source}" SKIP_UNITY_BUILD_INCLUSION)
  63. # Check if we can safely add this to a composite file.
  64. if(NOT generated AND NOT is_header AND NOT skip_compositing AND
  65. ";${COMPOSITE_SOURCE_EXTENSIONS};" MATCHES ";${extension};")
  66. if(NOT DEFINED sources_${extension})
  67. set(sources_${extension})
  68. endif()
  69. # Append it to one of the lists.
  70. list(APPEND sources_${extension} "${source}")
  71. endif()
  72. endforeach(source)
  73. # Now, put it all into one big list!
  74. set(sorted_sources)
  75. foreach(extension ${COMPOSITE_SOURCE_EXTENSIONS})
  76. if(DEFINED sources_${extension})
  77. list(APPEND sorted_sources ${sources_${extension}})
  78. endif()
  79. endforeach(extension)
  80. set(composite_files)
  81. set(composite_sources)
  82. # Fill in composite_ext so we can kick off the loop.
  83. list(GET sorted_sources 0 first_source)
  84. get_filename_component(first_source_ext "${first_source}" EXT)
  85. set(composite_ext ${first_source_ext})
  86. while(num_sources GREATER 0)
  87. # Pop the first element and adjust the sorted_sources length accordingly.
  88. list(GET sorted_sources 0 source)
  89. list(REMOVE_AT sorted_sources 0)
  90. list(LENGTH sorted_sources num_sources)
  91. # Add this file to our composite_sources buffer.
  92. list(APPEND composite_sources ${source})
  93. list(LENGTH composite_sources num_composite_sources)
  94. # Get the next source file's extension, so we can see if we're done with
  95. # this set of source files.
  96. if(num_sources GREATER 0)
  97. list(GET sorted_sources 0 next_source)
  98. get_filename_component(next_extension "${next_source}" EXT)
  99. else()
  100. set(next_extension "")
  101. endif()
  102. # Check if this is the point where we should cut the file.
  103. if(num_sources EQUAL 0 OR NOT num_composite_sources LESS ${CMAKE_UNITY_BUILD_BATCH_SIZE}
  104. OR NOT composite_ext STREQUAL next_extension)
  105. # It's pointless to make a composite source from just one file.
  106. if(num_composite_sources GREATER 1)
  107. # Figure out the name of our composite file.
  108. list(LENGTH composite_files index)
  109. math(EXPR index "1+${index}")
  110. set(composite_file "${CMAKE_CURRENT_BINARY_DIR}/${target}_composite${index}${composite_ext}")
  111. list(APPEND composite_files "${composite_file}")
  112. # Set HEADER_FILE_ONLY to prevent it from showing up in the
  113. # compiler command, but still show up in the IDE environment.
  114. set_source_files_properties(${composite_sources} PROPERTIES HEADER_FILE_ONLY ON)
  115. # We'll interrogate the composite files, so exclude the original sources.
  116. set_source_files_properties(${composite_sources} PROPERTIES WRAP_EXCLUDE YES)
  117. # Finally, add the target that generates the composite file.
  118. add_custom_command(
  119. OUTPUT "${composite_file}"
  120. COMMAND ${CMAKE_COMMAND}
  121. -DCOMPOSITE_FILE="${composite_file}"
  122. -DCOMPOSITE_SOURCES="${composite_sources}"
  123. -P "${COMPOSITE_GENERATOR}"
  124. DEPENDS ${composite_sources})
  125. endif()
  126. # Reset for the next composite file.
  127. set(composite_sources "")
  128. set(composite_ext ${next_extension})
  129. endif()
  130. endwhile()
  131. set_source_files_properties(${composite_files} PROPERTIES GENERATED YES)
  132. # The new files are added to the existing files, which means the old files
  133. # are still there, but they won't be compiled due to the HEADER_FILE_ONLY setting.
  134. set(${sources_var} ${orig_sources} ${composite_files} PARENT_SCOPE)
  135. endfunction(composite_sources)