Note: There are several similar questions, which I have seen and read. None of them are the precise problem I'm having, and none of their answers work for me.
I have installed several Python versions (Python 2.7, 3.8, 3.9, and 3.10) on my macOS Ventura system using Pyenv. The installed directories include a python-config file in /bin and an /include directory with many header files, so I do not need to install python-devel or similar:
$ ls -al /Users/williamsn/.pyenv/versions/3.10.9/bin/*-config
lrwxr-xr-x 1 williamsn staff 17 Dec 19 17:24
/Users/williamsn/.pyenv/versions/3.10.9/bin/python-config -> python3.10-config
lrwxr-xr-x 1 williamsn staff 17 Dec 19 17:24
/Users/williamsn/.pyenv/versions/3.10.9/bin/python3-config -> python3.10-config
-rwxr-xr-x 1 williamsn staff 2073 Dec 19 17:24
/Users/williamsn/.pyenv/versions/3.10.9/bin/python3.10-config
$ ls -al /Users/williamsn/.pyenv/versions/3.10.9/include/python3.10/
total 1192
drwxr-xr-x 86 williamsn staff 2752 Dec 19 17:24 .
drwxr-xr-x 3 williamsn staff 96 Dec 19 17:24 ..
-rw-r--r-- 1 williamsn staff 3224 Dec 19 17:24 Python.h
...
-rw-r--r-- 1 williamsn staff 3026 Dec 19 17:24 import.h
...
-rw-r--r-- 1 williamsn staff 48878 Dec 19 17:24 pyconfig.h
...
-rw-r--r-- 1 williamsn staff 2863 Dec 19 17:24 weakrefobject.h
As a best practice, I work exclusively in virtualenvs to keep the base Python installation clean and pristine. I create my virtualenvs using the venv module built in to Python 3:
$ python3.10 -m venv my_venv
After doing so, there are two problems:
- The
my_venv/includedirectory is empty (does not contain thepython3.10directory or any of the header files from the parent Python and does not symlink to the parent Python) - There is no
python-config/python3-config/python3.10-configinmy_venv/bin.
So, for things requiring the Python headers:
- If it tries to find the headers using
python-config(which many projects do), it will fail. - If it tries to find the headers using the Python prefix and adding
/includeto it (which many projects do, notably Boost), it will fail. - If it tries to find the headers by importing
sysconfigand callingsysconfig.get_paths(), it will succeed, albeit with paths outside the virtualenv.
Now, on a case-by-case basis, I can work around this, and already have. I can manually copy over python_config and then either export CPATH to add /Users/williamsn/.pyenv/versions/3.10.9/include/python3.10 or modify the virtualenv to symlink to /Users/williamsn/.pyenv/versions/3.10.9/include. These work, but they don't seem right to me. I can't make a global workaround anywhere (such as exporting CPATH in my Bash profile), because I'm working with multiple Python versions, and I'd end up with the wrong headers half the time. It seems to me like a virtualenv that has an empty include directory and is missing python-config when its parent has a full include directory and contains python-config is a broken virtualenv.
Is there an option I'm missing to include these pieces? Is this a bug I need to file against Python/venv?
I am afraid there is, and has ever been, no straightforward and universal measures for this issue so far (n.b., the current most-recent stable version is Python-3.12.2 at the time of writing). Considering that the issue was once long-standing since 2011 and closed in 2019 with no applicable solutions (Issue #169: python-config should be linked), the chance for the core developers of Python/
venvto provide the functionality for it in the future seems slim to me, unfortunately.Background
Here is my guess of why it is not supported by
venv. In short, there is no definitive and solid way.There is usually no direct or reliable way from a (statically compiled) Python (binary) command to find the corresponding include or (C-type) library paths. Instead, Python provides the utility command
python-config, which basically works on the assumption that the firstpython-configin your command-line search path corresponds to the Python command of your interest. This assumption may be unreliable in general, and this is particularly the case if you combinevenvwithpyenv.In the
pyenvenvironment,python-configis fixed at~/.pyenv/shims/python-config(providing you have installedpyenvin your home directory). The scriptpython-configofpyenv, which is a small-size wrapper script common to all Python versions, works fine as long as you stay in the purepyenvenvironment. However, it does not work as expected as soon as you get out of it withvenv. Examine the following situation, for example.As you see in the last line, the return value of
python-configdoes not correspond to the currently venv-activated Python. This is because venv does not create its ownpython-configin its path (which should come at the head of the command-line search path), so the firstpython-configin your command-line search path is the one managed withpyenv; and as far aspyenvis concerned, the currently-activated version of Python is 3.9.0, as opposed to venv-managing 3.12.2.To add, I am afraid there is no universally-applicable way for Python-
venvto know how to createpython-config. Rememberpyenv-controlledpython-configis, on its face value, just a very short shell script, and so simply copying it under avenv-controlled directory does not work. Of course, the Python core-developer team (including thevenvmaintainers) does not need to or perhaps does not care aboutpyenv, which is a mere third-party tool.As such, I am afraid it is tricky for
venvto provide an equivalent command topython-config.Potential measures
Therefore, the remedy for this issue should be (at least for now) case-by-case basis. One of the OP's way of setting the environmental variable(s)
CPATHor else appropriately is another. Or, depending on theconfigurescript, you may symlink the correct include and lib files or directoies to/under/Your/Venv/Dir/{include,lib}. Or, a past answer on Stackoverflow "Whypyvenvdoes not installpython-config?" provides one solution (I have not tested it personally).Or, an alternatively way is to employ the conda framework to replace
pyenvandvenvaltogether. In the conda framework, you can access the rightpython-configin your currently-activated Python environment. If you frequently need to compile user-modules of Python, this may be an easier solution.