CopyPython.cmake 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. # Filename: CopyPython.cmake
  2. #
  3. # Description: When run, copies Python files from a source directory to a
  4. # build directory located somewhere in the project's binary path. If
  5. # PYTHON_EXECUTABLES is provided, it will also invoke compileall in the
  6. # destination dir(s) to precache .pyc/.pyo files.
  7. #
  8. # Usage:
  9. # This script is invoked via add_custom_target, like this:
  10. # cmake -D OUTPUT_DIR="/out/dir/Release"
  11. # -D SOURCE_DIR="/panda3d/direct/src/"
  12. # -D PYTHON_EXECUTABLES="/usr/bin/python3.6"
  13. # -P CopyPython.cmake
  14. #
  15. if(NOT CMAKE_SCRIPT_MODE_FILE)
  16. message(FATAL_ERROR "CopyPython.cmake should not be included but run in script mode.")
  17. return()
  18. endif()
  19. if(NOT DEFINED OUTPUT_DIR)
  20. message(FATAL_ERROR "OUTPUT_DIR should be defined when running CopyPython.cmake!")
  21. return()
  22. endif()
  23. # Ensure OUTPUT_DIR exists
  24. file(MAKE_DIRECTORY ${OUTPUT_DIR})
  25. # If there's a SOURCE_DIR, glob for .py files and copy
  26. # (this is done by hand to avoid the CMake bug where it creates empty dirs)
  27. if(DEFINED SOURCE_DIR)
  28. file(GLOB_RECURSE py_files RELATIVE "${SOURCE_DIR}" "${SOURCE_DIR}/*.py")
  29. foreach(py_file ${py_files})
  30. get_filename_component(py_file_parent "${py_file}" DIRECTORY)
  31. file(TIMESTAMP "${SOURCE_DIR}/${py_file}" src_stamp)
  32. file(TIMESTAMP "${OUTPUT_DIR}/${py_file}" dst_stamp)
  33. # The file is only copied if:
  34. # - there's an __init__.py in its dir (i.e. file belongs to a package), and
  35. # - the modification timestamp differs (i.e. file changed or never copied)
  36. if(EXISTS "${SOURCE_DIR}/${py_file_parent}/__init__.py"
  37. AND NOT src_stamp STREQUAL dst_stamp)
  38. file(COPY "${SOURCE_DIR}/${py_file}" DESTINATION "${OUTPUT_DIR}/${py_file_parent}")
  39. set(changed YES)
  40. endif()
  41. endforeach(py_file)
  42. else()
  43. # No SOURCE_DIR; assume we're outdated since our caller might be populating
  44. # the OUTPUT_DIR themselves
  45. set(changed YES)
  46. endif()
  47. # Make sure Python recognizes OUTPUT_DIR as a package
  48. if(NOT EXISTS "${OUTPUT_DIR}/__init__.py")
  49. file(WRITE "${OUTPUT_DIR}/__init__.py" "")
  50. set(changed YES)
  51. endif()
  52. # Generate .pyc files for each Python version, if our caller wants
  53. if(changed AND DEFINED PYTHON_EXECUTABLES)
  54. foreach(interp ${PYTHON_EXECUTABLES})
  55. execute_process(
  56. COMMAND "${interp}" -m compileall .
  57. OUTPUT_QUIET
  58. WORKING_DIRECTORY "${OUTPUT_DIR}")
  59. execute_process(
  60. COMMAND "${interp}" -OO -m compileall .
  61. OUTPUT_QUIET
  62. WORKING_DIRECTORY "${OUTPUT_DIR}")
  63. endforeach(interp)
  64. endif()