| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- # Filename: Interrogate.cmake
- #
- # Description: This file contains macros and functions that are used to invoke
- # interrogate, 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 -DCPPPARSER -D__cplusplus -Dvolatile -Dmutable -python-native)
- # In addition, Interrogate needs to know if this is a 64-bit build:
- include(CheckTypeSize)
- check_type_size(long CMAKE_SIZEOF_LONG)
- if(CMAKE_SIZEOF_LONG EQUAL 8)
- list(APPEND IGATE_FLAGS "-D_LP64")
- endif()
- # This is a list of regexes that are applied to every filename. If one of the
- # regexes matches, that file will not be passed to Interrogate.
- set(INTERROGATE_EXCLUDE_REGEXES
- ".*\\.I$"
- ".*\\.N$"
- ".*\\.lxx$"
- ".*\\.yxx$"
- ".*_src\\..*")
- if(WIN32)
- list(APPEND IGATE_FLAGS -longlong __int64 -D_X86_ -D__STDC__=1 -DWIN32_VC -D "_declspec(param)=" -D "__declspec(param)=" -D_near -D_far -D__near -D__far -D_WIN32 -D__stdcall -DWIN32)
- endif()
- if(INTERROGATE_VERBOSE)
- list(APPEND IGATE_FLAGS "-v")
- endif()
- set(IMOD_FLAGS -python-native)
- # This stores the names of every module added to the Interrogate system:
- set(ALL_INTERROGATE_MODULES CACHE INTERNAL "Internal variable")
- #
- # Function: target_interrogate(target [ALL] [source1 [source2 ...]])
- # NB. This doesn't actually invoke interrogate, but merely adds the
- # sources to the list of scan sources associated with the target.
- # Interrogate will be invoked when add_python_module is called.
- # If ALL is specified, all of the sources from the associated
- # target are added.
- #
- function(target_interrogate target)
- if(HAVE_PYTHON AND HAVE_INTERROGATE)
- set(sources)
- set(want_all OFF)
- foreach(arg ${ARGN})
- if(arg STREQUAL "ALL")
- set(want_all ON)
- else()
- list(APPEND sources "${arg}")
- endif()
- endforeach()
- # If ALL was specified, pull in all sources from the target.
- if(want_all)
- get_target_property(target_sources "${target}" SOURCES)
- list(APPEND sources ${target_sources})
- endif()
- list(REMOVE_DUPLICATES sources)
- # Now let's get everything's absolute path, so that it can be passed
- # through a property while still preserving the reference.
- set(absolute_sources)
- foreach(source ${sources})
- get_source_file_property(exclude "${source}" WRAP_EXCLUDE)
- if(NOT exclude)
- get_source_file_property(location "${source}" LOCATION)
- list(APPEND absolute_sources ${location})
- endif()
- endforeach(source)
- set_target_properties("${target}" PROPERTIES IGATE_SOURCES
- "${absolute_sources}")
- # CMake has no property for determining the source directory where the
- # target was originally added. interrogate_sources makes use of this
- # property (if it is set) in order to make all paths on the command-line
- # relative to it, thereby shortening the command-line even more.
- # Since this is not an Interrogate-specific property, it is not named with
- # an IGATE_ prefix.
- set_target_properties("${target}" PROPERTIES TARGET_SRCDIR
- "${CMAKE_CURRENT_SOURCE_DIR}")
- # HACK HACK HACK -- this is part of the below hack.
- target_link_libraries(${target} ${target}_igate)
- endif()
- endfunction(target_interrogate)
- #
- # Function: interrogate_sources(target output database module)
- #
- # This function actually runs a component-level interrogation against 'target'.
- # It generates the outfile.cxx (output) and dbfile.in (database) files, which
- # can then be used during the interrogate_module step to produce language
- # bindings.
- #
- # The target must first have had sources selected with target_interrogate.
- # Failure to do so will result in an error.
- #
- function(interrogate_sources target output database module)
- if(HAVE_PYTHON AND HAVE_INTERROGATE)
- get_target_property(sources "${target}" IGATE_SOURCES)
- if(NOT sources)
- message(FATAL_ERROR
- "Cannot interrogate ${target} unless it's run through target_interrogate first!")
- endif()
- get_target_property(srcdir "${target}" TARGET_SRCDIR)
- if(NOT srcdir)
- # No TARGET_SRCDIR was set, so we'll do everything relative to our
- # current binary dir instead:
- set(srcdir "${CMAKE_CURRENT_BINARY_DIR}")
- endif()
- set(scan_sources)
- set(nfiles)
- foreach(source ${sources})
- get_filename_component(source_basename "${source}" NAME)
- # Only certain sources should actually be scanned by Interrogate. The
- # rest are merely dependencies. This uses the exclusion regex above in
- # order to determine what files are okay:
- set(exclude OFF)
- foreach(regex ${INTERROGATE_EXCLUDE_REGEXES})
- if("${source_basename}" MATCHES "${regex}")
- set(exclude ON)
- endif()
- endforeach(regex)
- if(NOT exclude)
- # This file is to be scanned by Interrogate. In order to avoid
- # cluttering up the command line, we should first make it relative:
- file(RELATIVE_PATH rel_source "${srcdir}" "${source}")
- list(APPEND scan_sources "${rel_source}")
- # Also see if this file has a .N counterpart, which has directives
- # specific for Interrogate. If there is a .N file, we add it as a dep,
- # so that CMake will rerun Interrogate if the .N files are modified:
- get_filename_component(source_path "${source}" PATH)
- get_filename_component(source_name_we "${source}" NAME_WE)
- set(nfile "${source_path}/${source_name_we}.N")
- if(EXISTS "${nfile}")
- list(APPEND nfiles "${nfile}")
- endif()
- endif()
- endforeach(source)
- # Interrogate also needs the include paths, so we'll extract them from the
- # target:
- set(include_flags)
- get_target_property(include_dirs "${target}" INTERFACE_INCLUDE_DIRECTORIES)
- foreach(include_dir ${include_dirs})
- # To keep the command-line small, also make this relative:
- # Note that Interrogate does NOT handle -I paths relative to -srcdir, so
- # we make them relative to the directory where it's invoked.
- file(RELATIVE_PATH rel_include_dir "${CMAKE_CURRENT_BINARY_DIR}" "${include_dir}")
- list(APPEND include_flags "-I${rel_include_dir}")
- endforeach(include_dir)
- # The above must also be included when compiling the resulting _igate.cxx file:
- include_directories(${include_dirs})
- # Get the compiler definition flags. These must be passed to Interrogate
- # in the same way that they are passed to the compiler so that Interrogate
- # will preprocess each file in the same way.
- set(define_flags)
- get_target_property(target_defines "${target}" COMPILE_DEFINITIONS)
- if(target_defines)
- foreach(target_define ${target_defines})
- list(APPEND define_flags "-D${target_define}")
- # And add the same definition when we compile the _igate.cxx file:
- add_definitions("-D${target_define}")
- endforeach(target_define)
- endif()
- # If this is a release build that has NDEBUG defined, we need that too:
- string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
- if("${CMAKE_CXX_FLAGS_${build_type}}" MATCHES ".*NDEBUG.*")
- list(APPEND define_flags "-DNDEBUG")
- endif()
- # CMake offers no way to directly depend on the composite files from here,
- # because the composite files are created in a different directory from
- # where CMake itself is run. Therefore, we need to depend on the
- # TARGET_composite target, if it exists.
- if(TARGET ${target}_composite)
- set(sources ${target}_composite ${sources})
- endif()
- add_custom_command(
- OUTPUT "${output}" "${database}"
- COMMAND interrogate
- -oc "${output}"
- -od "${database}"
- -srcdir "${srcdir}"
- -module ${module} -library ${target}
- ${INTERROGATE_OPTIONS}
- ${IGATE_FLAGS}
- ${define_flags}
- -S "${PROJECT_BINARY_DIR}/include"
- -S "${PROJECT_SOURCE_DIR}/dtool/src/parser-inc"
- -S "${PROJECT_BINARY_DIR}/include/parser-inc"
- ${include_flags}
- ${scan_sources}
- DEPENDS interrogate ${sources} ${nfiles}
- COMMENT "Interrogating ${target}"
- )
- endif()
- endfunction(interrogate_sources)
- #
- # Function: add_python_module(module [lib1 [lib2 ...]] [LINK lib1 ...])
- # Uses interrogate to create a Python module. If the LINK keyword is specified,
- # the Python module is linked against the specified libraries instead of those
- # listed before.
- #
- function(add_python_module module)
- if(HAVE_PYTHON AND HAVE_INTERROGATE)
- set(targets)
- set(link_targets)
- set(infiles)
- set(sources)
- set(HACKlinklibs)
- set(link_keyword OFF)
- foreach(arg ${ARGN})
- if(arg STREQUAL "LINK")
- set(link_keyword ON)
- elseif(link_keyword)
- list(APPEND link_targets "${arg}")
- else()
- list(APPEND targets "${arg}")
- endif()
- endforeach(arg)
- if(NOT link_keyword)
- set(link_targets ${targets})
- endif()
- foreach(target ${targets})
- interrogate_sources(${target} "${target}_igate.cxx" "${target}.in" "${module}")
- list(APPEND infiles "${target}.in")
- #list(APPEND sources "${target}_igate.cxx")
- # HACK HACK HACK:
- # Currently, the codebase has dependencies on the Interrogate-generated
- # code when HAVE_PYTHON is enabled. rdb is working to remove this, but
- # until then, the generated code must somehow be made available to the
- # modules themselves. The workaround here is to put the _igate.cxx into
- # its own micro-library, which is linked both here on the module and
- # against the component library in question.
- add_library(${target}_igate ${target}_igate.cxx)
- list(APPEND HACKlinklibs "${target}_igate")
- install(TARGETS ${target}_igate DESTINATION lib)
- get_target_property(target_links "${target}" LINK_LIBRARIES)
- target_link_libraries(${target}_igate ${target_links})
- endforeach(target)
- add_custom_command(
- OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${module}_module.cxx"
- COMMAND interrogate_module
- -oc "${CMAKE_CURRENT_BINARY_DIR}/${module}_module.cxx"
- -module ${module} -library ${module}
- ${INTERROGATE_MODULE_OPTIONS}
- ${IMOD_FLAGS} ${infiles}
- DEPENDS interrogate_module ${infiles}
- COMMENT "Generating module ${module}"
- )
- add_library(${module} MODULE "${module}_module.cxx" ${sources})
- target_link_libraries(${module}
- ${link_targets} ${PYTHON_LIBRARIES} p3interrogatedb)
- target_link_libraries(${module} ${HACKlinklibs})
- set_target_properties(${module} PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/panda3d"
- PREFIX ""
- )
- if(WIN32 AND NOT CYGWIN)
- set_target_properties(${module} PROPERTIES SUFFIX ".pyd")
- endif()
- install(TARGETS ${module} DESTINATION "${PYTHON_ARCH_INSTALL_DIR}/panda3d")
- list(APPEND ALL_INTERROGATE_MODULES "${module}")
- set(ALL_INTERROGATE_MODULES "${ALL_INTERROGATE_MODULES}" CACHE INTERNAL "Internal variable")
- endif()
- endfunction(add_python_module)
- if(HAVE_PYTHON)
- # We have to create an __init__.py so that Python 2.x can recognize 'panda3d'
- # as a package.
- file(WRITE "${PROJECT_BINARY_DIR}/panda3d/__init__.py" "")
- # The Interrogate path needs to be installed to the architecture-dependent
- # Python directory.
- install(FILES "${PROJECT_BINARY_DIR}/panda3d/__init__.py" DESTINATION "${PYTHON_ARCH_INSTALL_DIR}/panda3d")
- endif()
|