CompositeSources.cmake 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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. # TODO: Only supports .cxx files so far, not yet .mm files
  16. # It should probably sort the files by extension (.c, .cxx, .mm) first.
  17. #
  18. # Settings for composite builds. Should be moved to Config.cmake?
  19. set(COMPOSITE_SOURCE_LIMIT "30" CACHE STRING
  20. "Setting this to a value higher than 1 will enable unity builds, also
  21. known as SCU (single compilation unit). A high value will speed up the
  22. build dramatically but will be more memory intensive than a low value.")
  23. set(COMPOSITE_SOURCE_EXTENSIONS "cxx;c;mm" CACHE STRING
  24. "Only files of these extensions will be added to composite files.")
  25. set(COMPOSITE_GENERATOR "${CMAKE_SOURCE_DIR}/cmake/scripts/MakeComposite.cmake")
  26. # Define composite_sources()
  27. function(composite_sources target sources_var)
  28. # How many sources were specified?
  29. set(orig_sources ${${sources_var}})
  30. set(sources ${orig_sources})
  31. list(LENGTH sources num_sources)
  32. if(num_sources LESS 2 OR ${COMPOSITE_SOURCE_LIMIT} LESS 2)
  33. # It's silly to do this for a single source.
  34. return()
  35. endif()
  36. set(composite_files "")
  37. set(composite_sources "")
  38. while(num_sources GREATER 0)
  39. # Pop the first element
  40. list(GET sources 0 source)
  41. list(REMOVE_AT sources 0)
  42. list(LENGTH sources num_sources)
  43. # Check if we can safely add this to a composite file.
  44. get_source_file_property(generated "${source}" GENERATED)
  45. get_source_file_property(is_header "${source}" HEADER_FILE_ONLY)
  46. if(NOT generated AND NOT is_header)
  47. # Add it to composite_sources.
  48. list(APPEND composite_sources ${source})
  49. list(LENGTH composite_sources num_composite_sources)
  50. if(num_sources EQUAL 0 OR NOT num_composite_sources LESS ${COMPOSITE_SOURCE_LIMIT})
  51. # It's pointless to make a composite source from just one file.
  52. if(num_composite_sources GREATER 1)
  53. # Figure out the name of our composite file.
  54. list(LENGTH composite_files index)
  55. math(EXPR index "1+${index}")
  56. set(composite_file "${CMAKE_CURRENT_BINARY_DIR}/${target}_composite${index}.cxx")
  57. list(APPEND composite_files "${composite_file}")
  58. # Set HEADER_FILE_ONLY to prevent it from showing up in the
  59. # compiler command, but still show up in the IDE environment.
  60. set_source_files_properties(${composite_sources} PROPERTIES HEADER_FILE_ONLY ON)
  61. # We'll interrogate the composite files, so exclude the original sources.
  62. set_source_files_properties(${composite_sources} PROPERTIES WRAP_EXCLUDE YES)
  63. # Finally, add the target that generates the composite file.
  64. add_custom_command(
  65. OUTPUT "${composite_file}"
  66. COMMAND ${CMAKE_COMMAND}
  67. -DCOMPOSITE_FILE="${composite_file}"
  68. -DCOMPOSITE_SOURCES="${composite_sources}"
  69. -P "${COMPOSITE_GENERATOR}"
  70. DEPENDS ${composite_sources})
  71. # Reset for the next composite file.
  72. set(composite_sources "")
  73. endif()
  74. endif()
  75. endif()
  76. endwhile()
  77. # This exists for Interrogate's benefit, which needs the composite files to
  78. # exist before it can run. Unfortunately, CMake does not expose the
  79. # add_custom_command outputs as targets outside of the directory, so we have
  80. # to create our own pseudotarget that gets exposed.
  81. add_custom_target(${target}_composite DEPENDS ${composite_files})
  82. #set_source_files_properties(${composite_files} PROPERTIES GENERATED YES)
  83. # The new files are added to the existing files, which means the old files
  84. # are still there, but they won't be compiled due to the HEADER_FILE_ONLY setting.
  85. set(${sources_var} ${orig_sources} ${composite_files} PARENT_SCOPE)
  86. endfunction(composite_sources)