diff --git a/CMakeLists.txt b/CMakeLists.txt index c098cb1f43..a73098190c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,7 @@ include(AddBisonTarget) # Defines add_bison_target function include(AddFlexTarget) # Defines add_flex_target function include(BuildMetalib) # Defines add_component_library AND add_metalib include(CompositeSources) # Defines composite_sources function +include(Python) # Defines add_python_target AND install_python_package include(Interrogate) # Defines target_interrogate AND add_python_module include(RunPzip) # Defines run_pzip function include(Versioning) # Hooks 'add_library' to apply VERSION/SOVERSION @@ -174,7 +175,5 @@ except ImportError as err: file(WRITE "${PROJECT_BINARY_DIR}/pandac/__init__.py" "") # Now install ourselves: - install( - FILES "${PROJECT_BINARY_DIR}/pandac/__init__.py" "${PROJECT_BINARY_DIR}/pandac/PandaModules.py" - DESTINATION "${PYTHON_LIB_INSTALL_DIR}/pandac") + install_python_package("${PROJECT_BINARY_DIR}/pandac" LIB) endif() diff --git a/cmake/macros/Interrogate.cmake b/cmake/macros/Interrogate.cmake index 7b4d201936..291648e72d 100644 --- a/cmake/macros/Interrogate.cmake +++ b/cmake/macros/Interrogate.cmake @@ -300,43 +300,6 @@ function(add_python_module module) set(ALL_INTERROGATE_MODULES "${ALL_INTERROGATE_MODULES}" CACHE INTERNAL "Internal variable") endfunction(add_python_module) -# -# Function: add_python_target(target [source1 [source2 ...]]) -# Build the provided source(s) as a Python extension module, linked against the -# Python runtime library. -# -# Note that this also takes care of installation, unlike other target creation -# commands in CMake. -# -function(add_python_target target) - if(NOT HAVE_PYTHON) - return() - endif() - - string(REGEX REPLACE "^.*\\." "" basename "${target}") - set(sources ${ARGN}) - - add_library(${target} ${MODULE_TYPE} ${sources}) - target_link_libraries(${target} PKG::PYTHON) - - if(BUILD_SHARED_LIBS) - set_target_properties(${target} PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/panda3d" - OUTPUT_NAME "${basename}" - PREFIX "" - SUFFIX "${PYTHON_EXTENSION_SUFFIX}") - - install(TARGETS ${target} DESTINATION "${PYTHON_ARCH_INSTALL_DIR}/panda3d") - else() - set_target_properties(${target} PROPERTIES - OUTPUT_NAME "${basename}" - PREFIX "libpython_panda3d_") - - install(TARGETS ${target} DESTINATION lib) - endif() - -endfunction(add_python_target) - if(INTERROGATE_PYTHON_INTERFACE AND BUILD_SHARED_LIBS) # We have to create an __init__.py so that Python 2.x can recognize 'panda3d' @@ -345,5 +308,5 @@ if(INTERROGATE_PYTHON_INTERFACE AND BUILD_SHARED_LIBS) # 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") + install_python_package("${PROJECT_BINARY_DIR}/panda3d") endif() diff --git a/cmake/macros/Python.cmake b/cmake/macros/Python.cmake new file mode 100644 index 0000000000..b2457650f8 --- /dev/null +++ b/cmake/macros/Python.cmake @@ -0,0 +1,95 @@ +# Filename: Python.cmake +# +# Description: This file provides support functions for building/installing +# Python extension modules and/or pure-Python packages. +# +# Functions: +# add_python_target(target [source1 [source2 ...]]) +# install_python_package(path [ARCH/LIB]) +# + +# +# Function: add_python_target(target [source1 [source2 ...]]) +# Build the provided source(s) as a Python extension module, linked against the +# Python runtime library. +# +# Note that this also takes care of installation, unlike other target creation +# commands in CMake. +# +function(add_python_target target) + if(NOT HAVE_PYTHON) + return() + endif() + + string(REGEX REPLACE "^.*\\." "" basename "${target}") + set(sources ${ARGN}) + + add_library(${target} ${MODULE_TYPE} ${sources}) + target_link_libraries(${target} PKG::PYTHON) + + if(BUILD_SHARED_LIBS) + set_target_properties(${target} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/panda3d" + OUTPUT_NAME "${basename}" + PREFIX "" + SUFFIX "${PYTHON_EXTENSION_SUFFIX}") + + install(TARGETS ${target} DESTINATION "${PYTHON_ARCH_INSTALL_DIR}/panda3d") + else() + set_target_properties(${target} PROPERTIES + OUTPUT_NAME "${basename}" + PREFIX "libpython_panda3d_") + + install(TARGETS ${target} DESTINATION lib) + endif() + +endfunction(add_python_target) + +# +# Function: install_python_package(path [ARCH/LIB]) +# +# Installs the Python package which was built at `path`. +# +# Note that this handles more than just installation; it will also invoke +# Python's compileall utility to pregenerate .pyc/.pyo files. This will only +# happen if the Python interpreter is found. +# +# The ARCH or LIB keyword may be used to specify whether this package should be +# installed into Python's architecture-dependent or architecture-independent +# package path. The default, if unspecified, is LIB. +# +function(install_python_package path) + if(ARGN STREQUAL "ARCH") + set(type "ARCH") + elseif(ARGN STREQUAL "LIB") + set(type "LIB") + elseif(ARGN STREQUAL "") + set(type "LIB") + else() + message(FATAL_ERROR "install_python_package got unexpected argument: ${ARGN}") + endif() + + get_filename_component(package_name "${path}" NAME) + set(custom_target "bytecompile_${package_name}") + + file(RELATIVE_PATH relpath "${PROJECT_BINARY_DIR}" "${path}") + + if(PYTHON_EXECUTABLE) + add_custom_target(${custom_target} ALL) + add_custom_command( + TARGET ${custom_target} + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}" + COMMAND "${PYTHON_EXECUTABLE}" -m compileall -q "${relpath}") + add_custom_command( + TARGET ${custom_target} + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}" + COMMAND "${PYTHON_EXECUTABLE}" -OO -m compileall -q "${relpath}") + endif() + + set(dir ${PYTHON_${type}_INSTALL_DIR}) + if(dir) + install(DIRECTORY "${path}" DESTINATION "${dir}" + FILES_MATCHING REGEX "\\.py[co]?$") + endif() + +endfunction(install_python_package) diff --git a/direct/CMakeLists.txt b/direct/CMakeLists.txt index cfda39d6b0..b3cb42c78a 100644 --- a/direct/CMakeLists.txt +++ b/direct/CMakeLists.txt @@ -51,8 +51,5 @@ if(HAVE_PYTHON) file(WRITE "${PROJECT_BINARY_DIR}/direct/__init__.py" "") # Install all files - install( - DIRECTORY "${PROJECT_BINARY_DIR}/direct" - DESTINATION "${PYTHON_LIB_INSTALL_DIR}" - FILES_MATCHING REGEX "\\.py[co]?$") + install_python_package("${PROJECT_BINARY_DIR}/direct" LIB) endif()