Search code examples
pythonswigdistutils

How to get the path of the Python library from within Python


Initial situation:

I have a C/C++ library and provide bindings for different target languages. One of these languages is Python. I decided to use Swig because it provides good support for a lot of languages and its integration into CMake is straightforward.

In order to improve the usability of the Python binding and it's installation I would like to provide a setup.py. The idea is to run CMake from within the setup.py file because CMake contains all the logic of how to create the binding correctly.

What I currently got:

I'm able to run CMake and build the target of the Python binding from within setup.py.

By design of Swig the CMake file needs to distinguish between Python 2 and Python 3. While running CMake it detects the location of the Python installation and configures the environment. If the user installed both, Python 2 and Python 3 (with their development packages) CMake always takes Python 3.

According to: https://cmake.org/cmake/help/v3.0/module/FindPythonLibs.html the actual used Python version can be specified by setting PYTHON_LIBRARY and PYTHON_INCLUDE_DIR. For example I have to run:

cmake -DPYTHON_INCLUDE_DIR=/usr/include/python2.7 -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so

What is the problem:

If the user executes:

python setup.py build

the Python version of the executable 'python' might be 2 but CMake builds the binding using version 3 (see above).

According to Find python header path from within python? I'm able to get the location of the header file by using:

from distutils.sysconfig import get_python_inc
get_python_inc()

Unfortunately, I don't know how to get the path of the Python library. The solution provided by: Distribution independent libpython path doesn't work for me because it always returns '/usr/lib' instead of '/usr/lib/x86_64-linux-gnu/libpython2.7.so'

The Question:

How do I get the location (the full path) of the Python library from within Python.


Solution

  • I solved the problem on my own with a workaround. Maybe it helps others facing the same or at least a similar problem.

    First of all, I introduced the environment variables PYTHON_INCLUDE_DIR and PYTHON_LIBRARY which have the same names as the parameters from CMake used to configure the python paths: -DPYTHON_INCLUDE_DIR and -DPYTHON_LIBRARY. Furthermore, I added the following code to my CMake file

    if(DEFINED ENV{PYTHON_LIBRARY} AND DEFINED ENV{PYTHON_INCLUDE_DIR})
        message(STATUS "Using environment variables PYTHON_LIBRARY and PYTHON_INCLUDE_DIR")
        set(PYTHON_LIBRARY $ENV{PYTHON_LIBRARY})
        set(PYTHON_INCLUDE_DIR $ENV{PYTHON_INCLUDE_DIR})
    endif()
    

    which simply wraps the environment variables to the CMake parameters. Now the user can define these variables instead of the parameters before running CMake.

    PYTHON_INCLUDE_DIR=/usr/include/python2.7 PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so cmake
    

    Due to the reason that my setup.py simply calls CMake and CMake now is able to grab the environment variables and wrap them to the parameters respectively, the user also can configure the variables before running the setup.py (or pip, etc.).

    PYTHON_INCLUDE_DIR=/usr/include/python2.7 PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so pip install tinyspline
    

    To be honest, the user still needs to configure some paths but finally he/she is able to do so.