CopyPython.cmake 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  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 (or file is in the root) (i.e. file belongs to a package), and
  35. # - the modification timestamp differs (i.e. file changed or never copied)
  36. if((py_file_parent STREQUAL "." OR NOT py_file_parent
  37. OR EXISTS "${SOURCE_DIR}/${py_file_parent}/__init__.py")
  38. AND NOT src_stamp STREQUAL dst_stamp)
  39. file(COPY "${SOURCE_DIR}/${py_file}" DESTINATION "${OUTPUT_DIR}/${py_file_parent}")
  40. set(changed YES)
  41. endif()
  42. endforeach(py_file)
  43. else()
  44. # No SOURCE_DIR; assume we're outdated since our caller might be populating
  45. # the OUTPUT_DIR themselves
  46. set(changed YES)
  47. endif()
  48. # Make sure Python recognizes OUTPUT_DIR as a package
  49. if(NOT EXISTS "${OUTPUT_DIR}/__init__.py")
  50. file(WRITE "${OUTPUT_DIR}/__init__.py" "")
  51. set(changed YES)
  52. endif()
  53. # Generate .pyc files for each Python version, if our caller wants
  54. if(changed AND DEFINED PYTHON_EXECUTABLES)
  55. foreach(interp ${PYTHON_EXECUTABLES})
  56. execute_process(
  57. COMMAND "${interp}" -m compileall .
  58. OUTPUT_QUIET
  59. WORKING_DIRECTORY "${OUTPUT_DIR}")
  60. execute_process(
  61. COMMAND "${interp}" -O -m compileall .
  62. OUTPUT_QUIET
  63. WORKING_DIRECTORY "${OUTPUT_DIR}")
  64. endforeach(interp)
  65. endif()