diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a272f652c..45255c3254 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,18 +3,25 @@ cmake_minimum_required(VERSION 2.8.4) project(Panda3D) -# Set Panda's CMake module path +# Add generic modules to cmake module path, +# and add Panda3D specific modules to cmake module path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/macros/") -# This is where dtool_config.h gets generated. +# Include global modules +include(AutoInclude) # Implements automatic include_directories finding +include(AddBisonTarget) # Defines add_bison_target function +include(CompositeSources) # Defines composite_sources function +include(ConfigPackage) # Defines config_package function +include(Interrogate) # Defines target_interrogate AND add_python_module + +# Add the include path for source and header files generated by CMake include_directories("${CMAKE_BINARY_DIR}") # Configure Panda3D -include(dtool/PandaMacros.cmake) include(dtool/PandaVersion.cmake) -include(dtool/Packages.cmake) +include(dtool/Package.cmake) include(dtool/Config.cmake) -include(dtool/Interrogate.cmake) # Determine which trees to build. option(BUILD_DTOOL "Build the dtool source tree." ON) diff --git a/cmake/macros/AddBisonTarget.cmake b/cmake/macros/AddBisonTarget.cmake new file mode 100644 index 0000000000..45278db7de --- /dev/null +++ b/cmake/macros/AddBisonTarget.cmake @@ -0,0 +1,73 @@ +# Filename: AddBisonTarget.cmake +# Description: This file defines the function add_bison_target which instructs +# cmake to use bison on an input .yxx file. If bison is not available on +# the system, add_bison_target tries to use .prebuilt .cxx files instead. +# +# Usage: +# add_bison_target(output_cxx input_yxx [DEFINES output_h] [PREFIX prefix]) +# + +# Define add_bison_target() +function(add_bison_target output_cxx input_yxx) + set(arguments "") + set(outputs "${output_cxx}") + set(keyword "") + + # Parse the extra arguments to the function. + foreach(arg ${ARGN}) + if(arg STREQUAL "DEFINES") + set(keyword "DEFINES") + elseif(arg STREQUAL "PREFIX") + set(keyword "PREFIX") + + elseif(keyword STREQUAL "PREFIX") + set(arguments ${arguments} -p "${arg}") + elseif(keyword STREQUAL "DEFINES") + set(arguments ${arguments} --defines="${arg}") + list(APPEND outputs "${arg}") + + else() + message(SEND_ERROR "Unexpected argument ${arg} to add_bison_target") + endif() + endforeach() + + if(keyword STREQUAL arg AND NOT keyword STREQUAL "") + message(SEND_ERROR "Expected argument after ${keyword}") + endif() + + if(HAVE_BISON) + get_source_file_property(input_yxx "${input_yxx}" LOCATION) + + # If we have bison, we can of course just run it. + add_custom_command( + OUTPUT ${outputs} + COMMAND ${BISON_EXECUTABLE} + -o "${output_cxx}" ${arguments} + "${input_yxx}" + MAIN_DEPENDENCY "${input_yxx}" + ) + + else() + # Look for prebuilt versions of the outputs. + set(commands "") + set(depends "") + + foreach(output ${outputs}) + set(prebuilt_file "${output}.prebuilt") + get_filename_component(prebuilt_file "${prebuilt_file}" ABSOLUTE) + + if(NOT EXISTS "${prebuilt_file}") + message(SEND_ERROR "Bison was not found and ${prebuilt_file} does not exist!") + endif() + + list(APPEND depends "${prebuilt_file}") + set(commands ${commands} COMMAND ${CMAKE_COMMAND} -E copy ${prebuilt_file} ${output}) + endforeach() + + add_custom_command( + OUTPUT ${outputs} + ${commands} + DEPENDS ${depends} + ) + endif() +endfunction(add_bison_target) diff --git a/cmake/macros/CompositeSources.cmake b/cmake/macros/CompositeSources.cmake new file mode 100644 index 0000000000..f2fc29426d --- /dev/null +++ b/cmake/macros/CompositeSources.cmake @@ -0,0 +1,101 @@ +# Filename: CompositeSources.cmake +# Description: This file defines the function composite_sources which looks at +# a provided list of sources, generates _compositeN.cxx, and appends the +# composites to the list. The original files in the list are marked as headers +# so that they will be available in an IDE, but not compiled at build time. +# +# Usage: +# composite_sources(target source_var) +# +# Example: +# set(MY_SOURCES a.cxx b.cxx c.cxx) +# composite_sources(my_lib MY_SOURCES) +# add_library(my_lib ${MY_SOURCES}) +# +# TODO: Only supports .cxx files so far, not yet .mm files +# It should probably sort the files by extension (.c, .cxx, .mm) first. +# + + +# Settings for composite builds. Should be moved to Config.cmake? +set(COMPOSITE_SOURCE_LIMIT "30" CACHE STRING + "Setting this to a value higher than 1 will enable unity builds, also +known as SCU (single compilation unit). A high value will speed up the +build dramatically but will be more memory intensive than a low value.") + +set(COMPOSITE_SOURCE_EXTENSIONS "cxx;c;mm" CACHE STRING + "Only files of these extensions will be added to composite files.") + +set(COMPOSITE_GENERATOR "${CMAKE_SOURCE_DIR}/cmake/scripts/MakeComposite.cmake") + + +# Define composite_sources() +function(composite_sources target sources_var) + # How many sources were specified? + set(orig_sources ${${sources_var}}) + set(sources ${orig_sources}) + list(LENGTH sources num_sources) + + if(num_sources LESS 2 OR ${COMPOSITE_SOURCE_LIMIT} LESS 2) + # It's silly to do this for a single source. + return() + endif() + + set(composite_files "") + set(composite_sources "") + + while(num_sources GREATER 0) + # Pop the first element + list(GET sources 0 source) + list(REMOVE_AT sources 0) + list(LENGTH sources num_sources) + + # Check if we can safely add this to a composite file. + get_source_file_property(generated "${source}" GENERATED) + get_source_file_property(is_header "${source}" HEADER_FILE_ONLY) + + if(NOT generated AND NOT is_header) + # Add it to composite_sources. + list(APPEND composite_sources ${source}) + list(LENGTH composite_sources num_composite_sources) + + if(num_sources EQUAL 0 OR NOT num_composite_sources LESS ${COMPOSITE_SOURCE_LIMIT}) + + # It's pointless to make a composite source from just one file. + if(num_composite_sources GREATER 1) + + # Figure out the name of our composite file. + list(LENGTH composite_files index) + math(EXPR index "1+${index}") + set(composite_file "${CMAKE_CURRENT_BINARY_DIR}/${target}_composite${index}.cxx") + list(APPEND composite_files "${composite_file}") + + # Set HEADER_FILE_ONLY to prevent it from showing up in the + # compiler command, but still show up in the IDE environment. + set_source_files_properties(${composite_sources} PROPERTIES HEADER_FILE_ONLY ON) + + # We'll interrogate the composite files, so exclude the original sources. + set_source_files_properties(${composite_sources} PROPERTIES WRAP_EXCLUDE YES) + + # Finally, add the target that generates the composite file. + add_custom_command( + OUTPUT "${composite_file}" + COMMAND ${CMAKE_COMMAND} + -DCOMPOSITE_FILE="${composite_file}" + -DCOMPOSITE_SOURCES="${composite_sources}" + -P "${COMPOSITE_GENERATOR}" + DEPENDS ${composite_sources}) + + # Reset for the next composite file. + set(composite_sources "") + endif() + endif() + endif() + endwhile() + + #set_source_files_properties(${composite_files} PROPERTIES GENERATED YES) + + # The new files are added to the existing files, which means the old files + # are still there, but they won't be compiled due to the HEADER_FILE_ONLY setting. + set(${sources_var} ${orig_sources} ${composite_files} PARENT_SCOPE) +endfunction(composite_sources) diff --git a/cmake/modules/ConfigurePackage.cmake b/cmake/macros/ConfigPackage.cmake similarity index 97% rename from cmake/modules/ConfigurePackage.cmake rename to cmake/macros/ConfigPackage.cmake index 81551994f8..b4511faec2 100644 --- a/cmake/modules/ConfigurePackage.cmake +++ b/cmake/macros/ConfigPackage.cmake @@ -1,4 +1,4 @@ -# Filename: ConfigurePackage.cmake +# Filename: ConfigPackage.cmake # Author: kestred (30 Nov, 2013) # # This modules defines a function which finds and configures libraries @@ -6,6 +6,9 @@ # # Assumes the file has already been found with find_package(). # +# Usage: +# config_package(package_name) +# # The following variables can be set to override the cached values of USE_XYZZY # CONFIG_DISABLE_EVERYTHING - always set USE_XYZZY to false # CONFIG_DISABLE_MISSING - set USE_XYZZY to false if it was not found diff --git a/dtool/Interrogate.cmake b/cmake/macros/Interrogate.cmake similarity index 93% rename from dtool/Interrogate.cmake rename to cmake/macros/Interrogate.cmake index e7b3ad9103..a118b3f945 100644 --- a/dtool/Interrogate.cmake +++ b/cmake/macros/Interrogate.cmake @@ -1,9 +1,11 @@ +# Filename: Interrogate.cmake # -# dtool/Interrogate.cmake +# Description: This file contains macros and functions that are used to invoke +# interrogate, to generate wrappers for Python and/or other languages. # -# This file contains macros and functions that are used to invoke -# interrogate, in order to generate wrappers for Python and/or other -# languages. +# Functions: +# target_interrogate(target [ALL] [source1 [source2 ...]]) +# add_python_module(module [lib1 [lib2 ...]]) # set(IGATE_FLAGS ${INTERROGATE_OPTIONS} -DCPPPARSER -D__cplusplus -Dvolatile -Dmutable) diff --git a/cmake/macros/README.md b/cmake/macros/README.md new file mode 100644 index 0000000000..63d12981ec --- /dev/null +++ b/cmake/macros/README.md @@ -0,0 +1,9 @@ +Directory Info +-------------- +**Directory:** /cmake/macros +**License:** Unlicense +**Description:** This directory is used for CMake modules which may be _unsafe_ +to use outside of a Panda3D project. These modules may rely on Panda3D specific +cmake variables, Panda3D's directory structure, or some other dependency. +They are not intended to be included in other projects directly, though you +are free to copy and adapt them to your own needs. diff --git a/cmake/modules/AutoInclude.cmake b/cmake/modules/AutoInclude.cmake new file mode 100644 index 0000000000..3a2f2d74e0 --- /dev/null +++ b/cmake/modules/AutoInclude.cmake @@ -0,0 +1,50 @@ +# Filename: AutoInclude.cmake +# Description: This file backports the CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE +# introduced in CMake 2.8.11 to previous versions of cmake, and enables the +# behavior by default. +# + +# Emulate CMake 2.8.11's CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE behavior. +if(CMAKE_VERSION VERSION_LESS 2.8.11) + # Replace some built-in functions in order to extend their functionality. + function(add_library target) + _add_library(${target} ${ARGN}) + set_target_properties("${target}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}") + endfunction() + + function(add_executable target) + _add_executable(${target} ${ARGN}) + set_target_properties("${target}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}") + endfunction() + + function(target_link_libraries target) + set(interface_dirs) + get_target_property(target_interface_dirs "${target}" INTERFACE_INCLUDE_DIRECTORIES) + + foreach(lib ${ARGN}) + get_target_property(lib_interface_dirs "${lib}" INTERFACE_INCLUDE_DIRECTORIES) + + if(lib_interface_dirs) + list(APPEND interface_dirs ${lib_interface_dirs}) + endif() + endforeach() + + list(REMOVE_DUPLICATES interface_dirs) + + #NB. target_include_directories is new in 2.8.8. + #target_include_directories("${target}" ${interface_dirs}) + include_directories(${interface_dirs}) + + # Update this target's interface inc dirs. + set_target_properties("${target}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${target_interface_dirs};${interface_dirs}") + + # Call to the built-in function we are overriding. + _target_link_libraries(${target} ${ARGN}) + endfunction() + +else() + # 2.8.11 supports this natively. + set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) +endif() + +set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/cmake/modules/README.md b/cmake/modules/README.md new file mode 100644 index 0000000000..057b9cc95d --- /dev/null +++ b/cmake/modules/README.md @@ -0,0 +1,7 @@ +Directory Info +-------------- +**Directory:** /cmake/modules +**License:** Unlicense +**Description:** This directory is used for standard CMake modules which are safe +to use outside of a Panda3D project. This should be the normal location for +most FindXYZZY packages that are written for Panda3D. diff --git a/dtool/MakeComposite.cmake b/cmake/scripts/MakeComposite.cmake similarity index 58% rename from dtool/MakeComposite.cmake rename to cmake/scripts/MakeComposite.cmake index 242eb48ef2..11b618dad0 100644 --- a/dtool/MakeComposite.cmake +++ b/cmake/scripts/MakeComposite.cmake @@ -1,5 +1,13 @@ -# This script is invoked via add_custom_target, like this: -# cmake -P MakeComposite.cmake -D COMPOSITE_FILE="x_composite1.cxx" -D COMPOSITE_SOURCES="a.cxx b.cxx" +# Filename: MakeComposite.cmake +# +# Description: When run, creates a single C++ file which includes multiple +# other C++ files, to help facilitate unity builds. +# Unity builds provide significantly increased compile speed. +# +# Usage: +# This script is invoked via add_custom_target, like this: +# cmake -P MakeComposite.cmake -D COMPOSITE_FILE="x_composite1.cxx" -D COMPOSITE_SOURCES="a.cxx b.cxx" +# if(CMAKE_SCRIPT_MODE_FILE) #cmake_minimum_required(VERSION 2.8.4) diff --git a/cmake/scripts/README.md b/cmake/scripts/README.md new file mode 100644 index 0000000000..1f97423ab8 --- /dev/null +++ b/cmake/scripts/README.md @@ -0,0 +1,10 @@ +Directory Info +-------------- +**Directory:** /cmake/scripts +**License:** Unlicense +**Description:** This directory is used for cmake files which are not meant to +be included using CMake's normal include() directive. Typically, files in this +directory will be invoked as a custom command/target in the form of: +``` + cmake -P [... other options ...] +``` diff --git a/dtool/PandaMacros.cmake b/dtool/PandaMacros.cmake deleted file mode 100644 index 3c2d426ac4..0000000000 --- a/dtool/PandaMacros.cmake +++ /dev/null @@ -1,205 +0,0 @@ -# Settings for composite builds. Should be moved to Config.cmake? -set(COMPOSITE_SOURCE_LIMIT "30" CACHE STRING - "Setting this to a value higher than 1 will enable unity builds, also -known as SCU (single compilation unit). A high value will speed up the -build dramatically but will be more memory intensive than a low value.") - -set(COMPOSITE_SOURCE_EXTENSIONS "cxx;c;mm" CACHE STRING - "Only files of these extensions will be added to composite files.") - -set(COMPOSITE_GENERATOR "${CMAKE_CURRENT_LIST_DIR}/MakeComposite.cmake") - -# -# Macro: composite_sources(target sources_var) -# Looks at all the sources, generates _composite#.cxx and modifies the list. -# Usage: -# set(MY_SOURCES a.cxx b.cxx c.cxx) -# composite_sources(MY_SOURCES) -# add_library(my ${MY_SOURCES}) -# -#TODO: only supports .cxx files so far, not yet .mm files -# it should probably sort the files by extension (.c, .cxx, .mm) first. -# -function(composite_sources target sources_var) - # How many sources were specified? - set(orig_sources ${${sources_var}}) - set(sources ${orig_sources}) - list(LENGTH sources num_sources) - - if(num_sources LESS 2 OR ${COMPOSITE_SOURCE_LIMIT} LESS 2) - # It's silly to do this for a single source. - return() - endif() - - set(composite_files "") - set(composite_sources "") - - while(num_sources GREATER 0) - # Pop the first element - list(GET sources 0 source) - list(REMOVE_AT sources 0) - list(LENGTH sources num_sources) - - # Check if we can safely add this to a composite file. - get_source_file_property(generated "${source}" GENERATED) - get_source_file_property(is_header "${source}" HEADER_FILE_ONLY) - - if(NOT generated AND NOT is_header) - # Add it to composite_sources. - list(APPEND composite_sources ${source}) - list(LENGTH composite_sources num_composite_sources) - - if(num_sources EQUAL 0 OR NOT num_composite_sources LESS ${COMPOSITE_SOURCE_LIMIT}) - - # It's pointless to make a composite source from just one file. - if(num_composite_sources GREATER 1) - - # Figure out the name of our composite file. - list(LENGTH composite_files index) - math(EXPR index "1+${index}") - set(composite_file "${CMAKE_CURRENT_BINARY_DIR}/${target}_composite${index}.cxx") - list(APPEND composite_files "${composite_file}") - - # Set HEADER_FILE_ONLY to prevent it from showing up in the - # compiler command, but still show up in the IDE environment. - set_source_files_properties(${composite_sources} PROPERTIES HEADER_FILE_ONLY ON) - - # We'll interrogate the composite files, so exclude the original sources. - set_source_files_properties(${composite_sources} PROPERTIES WRAP_EXCLUDE YES) - - # Finally, add the target that generates the composite file. - add_custom_command( - OUTPUT "${composite_file}" - COMMAND ${CMAKE_COMMAND} - -DCOMPOSITE_FILE="${composite_file}" - -DCOMPOSITE_SOURCES="${composite_sources}" - -P "${COMPOSITE_GENERATOR}" - DEPENDS ${composite_sources}) - - # Reset for the next composite file. - set(composite_sources "") - endif() - endif() - endif() - endwhile() - - #set_source_files_properties(${composite_files} PROPERTIES GENERATED YES) - - # The new files are added to the existing files, which means the old files - # are still there, but they won't be compiled due to the HEADER_FILE_ONLY setting. - set(${sources_var} ${orig_sources} ${composite_files} PARENT_SCOPE) -endfunction(composite_sources) - -# -# Function: add_bison_target(output_cxx input_yxx [DEFINES output_h] [PREFIX prefix]) -# Takes .prebuilt files into account if BISON_FOUND is not true. -# -function(add_bison_target output_cxx input_yxx) - set(arguments "") - set(outputs "${output_cxx}") - set(keyword "") - - # Parse the extra arguments to the function. - foreach(arg ${ARGN}) - if(arg STREQUAL "DEFINES") - set(keyword "DEFINES") - elseif(arg STREQUAL "PREFIX") - set(keyword "PREFIX") - - elseif(keyword STREQUAL "PREFIX") - set(arguments ${arguments} -p "${arg}") - elseif(keyword STREQUAL "DEFINES") - set(arguments ${arguments} --defines="${arg}") - list(APPEND outputs "${arg}") - - else() - message(SEND_ERROR "Unexpected argument ${arg} to add_bison_target") - endif() - endforeach() - - if(keyword STREQUAL arg AND NOT keyword STREQUAL "") - message(SEND_ERROR "Expected argument after ${keyword}") - endif() - - if(HAVE_BISON) - get_source_file_property(input_yxx "${input_yxx}" LOCATION) - - # If we have bison, we can of course just run it. - add_custom_command( - OUTPUT ${outputs} - COMMAND ${BISON_EXECUTABLE} - -o "${output_cxx}" ${arguments} - "${input_yxx}" - MAIN_DEPENDENCY "${input_yxx}" - ) - - else() - # Look for prebuilt versions of the outputs. - set(commands "") - set(depends "") - - foreach(output ${outputs}) - set(prebuilt_file "${output}.prebuilt") - get_filename_component(prebuilt_file "${prebuilt_file}" ABSOLUTE) - - if(NOT EXISTS "${prebuilt_file}") - message(SEND_ERROR "Bison was not found and ${prebuilt_file} does not exist!") - endif() - - list(APPEND depends "${prebuilt_file}") - set(commands ${commands} COMMAND ${CMAKE_COMMAND} -E copy ${prebuilt_file} ${output}) - endforeach() - - add_custom_command( - OUTPUT ${outputs} - ${commands} - DEPENDS ${depends} - ) - endif() -endfunction(add_bison_target) - - -# Emulate CMake 2.8.11's CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE behavior. -if(CMAKE_VERSION VERSION_LESS 2.8.11) - # Replace some built-in functions in order to extend their functionality. - function(add_library target) - _add_library(${target} ${ARGN}) - set_target_properties("${target}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}") - endfunction() - - function(add_executable target) - _add_executable(${target} ${ARGN}) - set_target_properties("${target}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}") - endfunction() - - function(target_link_libraries target) - set(interface_dirs) - get_target_property(target_interface_dirs "${target}" INTERFACE_INCLUDE_DIRECTORIES) - - foreach(lib ${ARGN}) - get_target_property(lib_interface_dirs "${lib}" INTERFACE_INCLUDE_DIRECTORIES) - - if(lib_interface_dirs) - list(APPEND interface_dirs ${lib_interface_dirs}) - endif() - endforeach() - - list(REMOVE_DUPLICATES interface_dirs) - - #NB. target_include_directories is new in 2.8.8. - #target_include_directories("${target}" ${interface_dirs}) - include_directories(${interface_dirs}) - - # Update this target's interface inc dirs. - set_target_properties("${target}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${target_interface_dirs};${interface_dirs}") - - # Call to the built-in function we are overriding. - _target_link_libraries(${target} ${ARGN}) - endfunction() - -else() - # 2.8.11 supports this natively. - set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) -endif() - -set(CMAKE_INCLUDE_CURRENT_DIR ON)