I have a mainly c++ project that I use CMake to manage. After setting cmake_install_prefix
and configuring, it generates makefiles which can then be used to build and install with the very standard:
make
make install
At this point, my binaries end up in cmake_install_prefix
, and they can be executed with no additional work. Recently I've added some Python scripts to a few places in the source tree, and some of them depend on others. I can use CMake to copy the Python files+directory structure to the cmake_install_prefix
, but if I go into that path and try to use one of the scripts, Python cannot find the other scripts used as imports
because PYTHONPATH
does not contain cmake_install_prefix
. I know you can set an environment variable with CMake, but it doesn't persist across shells, so it's not really "setup" for the user for more than the current terminal session.
The solution seems to be to add a step to your software build instructions that says "set your PYTHONPATH". Is there any way to avoid this? Is this the standard practice for "installing" Python scripts as part of a bigger project? It seems to really complicate things like setting up continuous integration for the project, as something like Jenkins has to be manually configured to inject environment variables, whereas nothing special was required for it to build and execute executables built from c++ code.
Python provides sys.path
list, which is used for search modules with import
directives. You may adjust this list before include your modules:
script1.py:
# Do some things useful for other scripts
script2.py.in:
# Uses script1.py.
...
sys.path.insert(1, "@SCRIPT1_INSTALL_PATH@")
import script1
...
CMakeLists.txt:
...
# Installation path for script1. Depends from CMAKE_INSTALL_PREFIX.
set(SCRIPT1_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/<...>)
install(FILES script1.py DESTINATION ${SCRIPT1_INSTALL_PATH}
# Configure 'sys.path' in script2.py, so it may find script1.py.
configure_file("script2.py.in" "script2.py" @ONLY)
set(SCRIPT2_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/<...>)
install(FILES script2.py DESTINATION ${SCRIPT2_INSTALL_PATH}
...
If you want script2.py to work both in build tree and in install tree, you need to have two instances of it, one which works in build tree, and one which works after being installed. Both instances may be configured from single .in
file.
In case of compiled executables and libraries, similar mechanism is uses for help binaries to find libraries in non-standard locations. It is known as RPATH.
Because CMake
knows every binary created (it tracks add_executable
and add_library
calls),
knows linkage between binaries (target_link_libraries
call is also tracked),
has full control over linking procedure,
CMake is able to automatically adjust RPATH when install binaries.
In case of Python scripts CMake doesn't have such information, so adjusting linkage path should be performed manually.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With