-
-
Notifications
You must be signed in to change notification settings - Fork 30.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sysconfig confused by relative paths #59569
Comments
With unix, and a source build, sysconfig.get_config_var('srcdir') and sysconfig.get_path('include') misbehave: user@mint-vm ~/Repos/cpython $ cd /
user@mint-vm / $ ~/Repos/cpython/python
Python 3.3.0b1 (default:671894ae19a2, Jul 16 2012, 10:43:27)
[GCC 4.5.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sysconfig
>>> sysconfig.get_config_var('srcdir')
'/'
>>> sysconfig.get_path('include')
'//Include' The problem seems to be the else clause of if 'srcdir' not in _CONFIG_VARS:
_CONFIG_VARS['srcdir'] = _PROJECT_BASE
else:
_CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) The else clause (in slightly modified form) was introduced in 356d0ea8ea34, and it turns a relative path into an absolute path, using the current working directory as a base. For me, simply removing the line allows the absolute path to be calculated correctly a few lines later on. I don't know what problem 356d0ea8ea34 was intended to fix. |
I don't recall what the issue was the resulted in the check-in that you mention. Sadly enough it is not-trivial to find that check-in I mention due to the migration from Subversion to Mercurial. How was python itself configured (configure command line)? What OS are you running on? Given the shell prompt I'd say Mint Linux. And finally, is '~/Repos/cpython/python' a checkout or installed location (that is, did you run 'make install')? Based on code inspection I'd say that your change is correct, and my change only works when running from the build directory. |
I think it was http://bugs.python.org/issue8577. The issue was about having srcdir != builddir. The initial patch caused a test failure, and 356d0ea8ea34 fixed (or at least silenced) the failure.
I tried it with both ./configure and mdkir release It fails with both.
Yes (in a VM).
It is a checkout. The argument passed to _safe_realpath() (either "." or ".." in my case) should be interpreted relative to the directory containing the Makefile. But os.path.realpath() assumes that its argument is either absolute or relative to os.getcwd(). It therefore returns the wrong absolute path. |
It is actually simple to find the revision: http://hg.python.org/lookup/r81999 :) |
I have to add that I’m quite confused by srcdir vs. projectbase. There are a handful of open bugs related to sysconfig and built but uninstalled Pythons, and many commits changing code to use srcdir or projectbase after empirical testing or buildbot failures. :/ |
srcdir vs. project base is quite easy: srcdir is the directory containing the source files, the project base is where you ran configure. These are the same if you run configure in the root of a checkout, but don't have to be, for example when you do: $ mkdir buildroot
$ cd buildroot
$ ../configure # ... Now de base directory is the 'buildroot' directory, while srcdir is its parent directory. |
bpo-15322 is a recently filed bug regarding srcdir: "sysconfig.get_config_var('srcdir') returns unexpected value" |
In the attached patch _safe_realpath() is only called after calculating the absolute path for srcdir. |
Updated patch which clarifies that for an installed python on a posix system, get_config_var('srcdir') == get_path('stdlib'). Eg, if sys.executable == '/usr/local/bin/python3.3' then get_config_var('srcdir') == '/usr/local/lib/python3.3'. This is a little arbitrary, but seems as sensible a value as any other. (Or maybe it would be better to have get_config_var('srcdir') == None instead.) |
'srcdir' is problematic for any installed build. Once "make install" has been performed, there is no obligation to keep the original source and build dirs around anymore. For Pythons installed on other machines via a binary installer, like the python.org OS X ones, some of the paths returned by sysconfig are not meaningful on the installed machine. For an OS X framework build, the Makefile and friends are copied into a 'config' directory that is created within the installed framework. So, with the patch, the contents of that directory (returned by the patched 'srcdir' value) is: Is that a meaningful surrogate for the build 'srcdir'? Beyond that, I don't understand why the patch behavior depends on whether the srcdir is an absolute path or not. I often use absolute paths to configure a build. If not in a build directory, 'srcdir' should always return either the proposed value based on what get_makefile_filename() returns or it should return None. I don't have a strong opinion at the moment about which. One factor should be an inspection and running of all of the tests. A quick grep of Lib/ didn't find many references to 'srcdir'. One other point: distutils still has its own copy of sysconfig. Strong consideration should be given to making a similar change there. |
The os.path.isabs() test is actually redundant since os.path.join(base, srcdir) == srcdir if srcdir is an absolute path. I only added that test to be explicit about what happens if the original value is an absolute path.
Removing the isabs() test would not change the calculated value as I indicated above. Using None would be the sanest option, but I don't know if any current code depends on the value being a string.
For a source build, distutils.sysconfig.get_config_var('srcdir') gives the right answer as an absolute path, *except* when the current working directory contains sys.executable. I think it should always return an absolute path. The fact that currently it does not probably explains the "mysteriously" comment below from distutils/test/support.py: def _get_xxmodule_path():
srcdir = sysconfig.get_config_var('srcdir')
candidates = [
# use installed copy if available
os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
# otherwise try using copy from build directory
os.path.join(srcdir, 'Modules', 'xxmodule.c'),
# srcdir mysteriously can be $srcdir/Lib/distutils/tests when
# this file is run from its parent directory, so walk up the
# tree to find the real srcdir
os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
]
for path in candidates:
if os.path.exists(path):
return path BTW, I was wrong in my earlier message when I claimed that srcdir == get_path('stdlib') for an installed python. That is only true if the relative srcdir is '..'. The attached patch removes that check from the unit tests. |
Upon further consideration, while it sounds appealing, perhaps returning None is not the better choice. As far as I know, up until now all config vars are either of type str or type int. Adding None to the mix might be asking for trouble. With no patch, running from an installed framework build:
>>> sys.executable
'/py/dev/default/b10.7_t10.7_x4.3_cclang_d/fw/root/bin/python3.3'
>>> import sysconfig as sc, distutils.sysconfig as dsc
>>> sc.is_python_build()
False
>>> sc.get_config_var('srcdir')
'/py/dev/default/b10.7_t10.7_x4.3_cclang_d'
>>> dsc.get_config_var('srcdir')
'.'
With the latest patch, as above:
>>> sys.executable
'/py/dev/default/b10.7_t10.7_x4.3_cclang_d/fw/root/bin/python3.3'
>>> import sysconfig as sc, distutils.sysconfig as dsc
>>> sc.is_python_build()
False
>>> sc.get_config_var('srcdir')
'/py/dev/default/b10.7_t10.7_x4.3_cclang_d/fw/root/Library/Frameworks/pytest_10_7.framework/Versions/3.3/lib/python3.3/config-3.3dm'
>>> dsc.get_config_var('srcdir')
'.' The patched results looks OK except, of course, for the discrepancy with distutils.sysconfig. I think we should fix that and get this all into 3.3.0. Otherwise we'll be stuck with the current broken behavior until 3.4 at the earliest. One nit comment on the currrent patch: s/"will not effect it"/"will not affect it" (one of those gotchas in English). |
I should have noted that, in the above tests, distutils.sysconfig.get_makefile_filename() is already doing the right thing: >>> dsc.get_makefile_filename()
'/py/dev/default/b10.7_t10.7_x4.3_cclang_d/fw/root/Library/Frameworks/pytest_10_7.framework/Versions/3.3/lib/python3.3/config-3.3dm/Makefile'
[70312 refs]
>>> sc.get_makefile_filename() == dsc.get_makefile_filename()
True |
Agree on fixing this for 3.3, if it’s not possible to backport to all stable branches. Will review. |
Here is an updated patch which also modifies distutils.sysconfig. For "installed" pythons on posix systems it makes
(The older patches would give the same result only if the relative srcdir was '.') |
Forgot to remove some unnecessary code in patch. |
I'd make get_config_var('srcdir') to be None for installed systems, because the source tree is not available there. The advantage of making the value None is that this is easy to test for and would quickly break path manipulation code that tries to construct a path to a specific file in the source tree. Making the value to be the name of the directory containing Makefile would still break code that tries to access files relative to the source tree, but could that breakage could be harder to track. BTW. sysconfig really needs a better description of which variables are supposed to be available, it currently exports every definition in the Makefile and pyconfig.h, and not all of those definitions are usable outside of CPython's build process. |
While playing with a version of the patch which returns None for non-source builds, I found that distutils.support._get_xxmodule_path() depends on get_config_var('srcdir') always returning a string: def _get_xxmodule_path():
srcdir = sysconfig.get_config_var('srcdir')
candidates = [
os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
os.path.join(srcdir, 'Modules', 'xxmodule.c'),
os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
]
for path in candidates:
if os.path.exists(path):
return path It is easy enough to modify _get_xxmodule_path() to check for None. But this does suggest that returning None might break some currently working 3rd party code. |
Any objection if I commit the last patch before the next beta? This is the one which on installed Pythons have
on posix systems. |
LGTM |
Does get_config_var('srcdir') always return a string or sometimes None? |
Always a string. distutils.support._get_xxmodule_path() is one place which (currently) would throw an exception if it returned None. |
New changeset d2f448dbc30d by Richard Oudkerk in branch 'default': |
Okay, so LGTM. Let’s ask the RMs if this is a new behavior or a bugfix. |
The current patch should be fine, although it is IMHO not the long-term solution. For installed python's get_config_var('srcdir') still lies, but now at least returns slightly more sane path. As I noted before the real problem is that it is not clear which config_vars are usable in which situations. One example is 'srcdir': this value is only useful in the build tree and there currently is no clean way to signal that you are retrieving a value that is not useful. Another example is 'RUNSHARED', that's also only useable when building python. I'm not sure what the right solution for the larger issue is. It might be good enough to document generally useful config_vars and warn that other's might exist but might not be safe to use, on the other hand it might be better to explicitly reduce the set of config_vars to something sane (and document which those are and when they can be used) |
New changeset c2618b916081 by Ned Deily in branch 'default': |
In the particular case of 'srcdir', sysconfig.is_python_build() tells you whether the value is useful. Concerns about sysconfig often returning values which are meaningless for the current configuration can be discussed in another issue. Unless there are objections I will close. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: