CMake: Modify install_python_package() so it keeps the build-dir copy up-to-date too

This commit is contained in:
Sam Edwards 2019-04-29 19:18:21 -06:00
parent f744951d25
commit 49865c103a
4 changed files with 113 additions and 43 deletions

View File

@ -80,9 +80,12 @@ function(add_python_target target)
endfunction(add_python_target)
#
# Function: install_python_package(path [ARCH/LIB] [COMPONENT component])
# Function: install_python_package(name [SOURCE path] [ARCH/LIB] [COMPONENT component])
#
# Installs the Python package which was built at `path`.
# Installs the Python package `name` (which may have its source at `path`).
#
# The package is copied to (or created in) the build directory so that the user
# may import it before the install step.
#
# Note that this handles more than just installation; it will also invoke
# Python's compileall utility to pregenerate .pyc/.pyo files. This will only
@ -96,10 +99,11 @@ endfunction(add_python_target)
# documentation for more information on what this does). The default is
# "Python".
#
function(install_python_package path)
function(install_python_package package_name)
set(type "LIB")
unset(keyword)
set(component "Python")
set(component_keyword OFF)
unset(src_path)
foreach(arg ${ARGN})
if(arg STREQUAL "ARCH")
set(type "ARCH")
@ -108,11 +112,18 @@ function(install_python_package path)
set(type "LIB")
elseif(arg STREQUAL "COMPONENT")
set(component_keyword ON)
set(keyword "${arg}")
elseif(component_keyword)
elseif(keyword STREQUAL "COMPONENT")
set(component "${arg}")
set(component_keyword OFF)
unset(keyword)
elseif(arg STREQUAL "SOURCE")
set(keyword "${arg}")
elseif(keyword STREQUAL "SOURCE")
set(src_path "${arg}")
unset(keyword)
else()
message(FATAL_ERROR "install_python_package got unexpected argument: ${ARGN}")
@ -120,26 +131,21 @@ function(install_python_package path)
endif()
endforeach(arg)
get_filename_component(package_name "${path}" NAME)
set(custom_target "bytecompile_${package_name}")
set(path "${PROJECT_BINARY_DIR}/${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}")
set(args -D "OUTPUT_DIR=${path}")
if(src_path)
list(APPEND args -D "SOURCE_DIR=${src_path}")
endif()
if(PYTHON_EXECUTABLE)
list(APPEND args -D "PYTHON_EXECUTABLES=${PYTHON_EXECUTABLE}")
endif()
add_custom_target(${package_name} ALL
COMMAND ${CMAKE_COMMAND}
${args}
-P "${CMAKE_SOURCE_DIR}/cmake/scripts/CopyPython.cmake")
ensure_python_init("${path}")
set(dir ${PYTHON_${type}_INSTALL_DIR})
set(dir "${PYTHON_${type}_INSTALL_DIR}")
if(dir)
install(DIRECTORY "${path}" DESTINATION "${dir}"
COMPONENT "${component}"

View File

@ -0,0 +1,78 @@
# Filename: CopyPython.cmake
#
# Description: When run, copies Python files from a source directory to a
# build directory located somewhere in the project's binary path. If
# PYTHON_EXECUTABLES is provided, it will also invoke compileall in the
# destination dir(s) to precache .pyc/.pyo files.
#
# Usage:
# This script is invoked via add_custom_target, like this:
# cmake -D OUTPUT_DIR="/out/dir/Release"
# -D SOURCE_DIR="/panda3d/direct/src/"
# -D PYTHON_EXECUTABLES="/usr/bin/python3.6"
# -P CopyPython.cmake
#
if(NOT CMAKE_SCRIPT_MODE_FILE)
message(FATAL_ERROR "CopyPython.cmake should not be included but run in script mode.")
return()
endif()
if(NOT DEFINED OUTPUT_DIR)
message(FATAL_ERROR "OUTPUT_DIR should be defined when running CopyPython.cmake!")
return()
endif()
# Ensure OUTPUT_DIR exists
file(MAKE_DIRECTORY ${OUTPUT_DIR})
# If there's a SOURCE_DIR, glob for .py files and copy
# (this is done by hand to avoid the CMake bug where it creates empty dirs)
if(DEFINED SOURCE_DIR)
file(GLOB_RECURSE py_files RELATIVE "${SOURCE_DIR}" "${SOURCE_DIR}/*.py")
foreach(py_file ${py_files})
get_filename_component(py_file_parent "${py_file}" DIRECTORY)
if(NOT EXISTS "${SOURCE_DIR}/${py_file_parent}/__init__.py")
# The source file isn't part of a Python package, even though it is a .py
# file. Skip it.
continue()
endif()
file(TIMESTAMP "${SOURCE_DIR}/${py_file}" src_stamp)
file(TIMESTAMP "${OUTPUT_DIR}/${py_file}" dst_stamp)
if(NOT src_stamp STREQUAL dst_stamp)
file(COPY "${SOURCE_DIR}/${py_file}" DESTINATION "${OUTPUT_DIR}/${py_file_parent}")
set(changed YES)
endif()
endforeach(py_file)
else()
# No SOURCE_DIR; assume we're outdated since our caller might be populating
# the OUTPUT_DIR themselves
set(changed YES)
endif()
# Make sure Python recognizes OUTPUT_DIR as a package
if(NOT EXISTS "${OUTPUT_DIR}/__init__.py")
file(WRITE "${OUTPUT_DIR}/__init__.py" "")
set(changed YES)
endif()
# Generate .pyc files for each Python version, if our caller wants
if(changed AND DEFINED PYTHON_EXECUTABLES)
foreach(interp ${PYTHON_EXECUTABLES})
execute_process(
COMMAND "${interp}" -m compileall .
OUTPUT_QUIET
WORKING_DIRECTORY "${OUTPUT_DIR}")
execute_process(
COMMAND "${interp}" -OO -m compileall .
OUTPUT_QUIET
WORKING_DIRECTORY "${OUTPUT_DIR}")
endforeach(interp)
endif()

View File

@ -42,21 +42,7 @@ if(HAVE_PYTHON)
p3motiontrail p3showbase LINK p3direct IMPORT panda3d.core COMPONENT Direct)
# Copy Python source files into the build directory
set(DIRECT_INSTALL_DIRECTORIES
actor cluster controls directbase directdevices directnotify directscripts
directtools directutil dist distributed extensions_native filter
fsm gui interval leveleditor motiontrail p3d particles physics
showbase showutil stdpy task tkpanels tkwidgets wxwidgets)
foreach(dir ${DIRECT_INSTALL_DIRECTORIES})
file(COPY
DIRECTORY "src/${dir}"
DESTINATION "${PROJECT_BINARY_DIR}/direct"
FILES_MATCHING PATTERN "*.py")
endforeach()
# Install all files
install_python_package("${PROJECT_BINARY_DIR}/direct" LIB COMPONENT Direct)
install_python_package(direct SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/src" LIB COMPONENT Direct)
# This bit is to generate the 'pandac' compatibility shim. It's deprecated now,
# but in older versions of Panda3D, one would use
@ -64,13 +50,13 @@ if(HAVE_PYTHON)
# instead of
# from panda3d.FOO import *
# Generate PandaModules:
file(WRITE "${PROJECT_BINARY_DIR}/pandac/PandaModules.py"
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pandac/PandaModules.py"
"\"This module is deprecated. Import from panda3d.core and other panda3d.* modules instead.\"
print(\"Warning: pandac.PandaModules is deprecated, import from panda3d.core instead\")\n")
foreach(module ${ALL_INTERROGATE_MODULES})
file(APPEND "${PROJECT_BINARY_DIR}/pandac/PandaModules.py" "
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pandac/PandaModules.py" "
try:
from ${module} import *
except ImportError as err:
@ -80,7 +66,7 @@ except ImportError as err:
endforeach()
# Now install ourselves:
install_python_package("${PROJECT_BINARY_DIR}/pandac" LIB COMPONENT Direct)
install_python_package(pandac SOURCE "${CMAKE_CURRENT_BINARY_DIR}/pandac" LIB COMPONENT Direct)
endif()
# "Direct" component contains both the Python stuff and the non-Python stuff,

View File

@ -107,7 +107,7 @@ if(INTERROGATE_PYTHON_INTERFACE)
add_python_module(panda3d.core ${CORE_MODULE_COMPONENTS} LINK panda)
if(BUILD_SHARED_LIBS)
install_python_package("${PROJECT_BINARY_DIR}/panda3d" ARCH)
install_python_package(panda3d ARCH)
endif()
if(HAVE_BULLET)