Skip to content

Commit fb38f76

Browse files
naveen521kklazka
authored andcommitted
getpath.py: add support for mingw
- always normalize the PREFIX to an absolute path - use `/` when MSYSTEM is defined
1 parent c729b08 commit fb38f76

File tree

5 files changed

+71
-30
lines changed

5 files changed

+71
-30
lines changed

Include/pylifecycle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ PyAPI_FUNC(int) Py_IsInitialized(void);
2121
PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void);
2222
PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);
2323

24+
PyAPI_FUNC(wchar_t) Py_GetAltSepW(const wchar_t *);
2425
PyAPI_FUNC(wchar_t) Py_GetSepW(const wchar_t *);
2526
PyAPI_FUNC(char) Py_GetSepA(const char *);
2627

Modules/getpath.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ getpath_abspath(PyObject *Py_UNUSED(self), PyObject *args)
6868
if (path) {
6969
wchar_t *abs;
7070
if (_Py_abspath((const wchar_t *)_Py_normpath(path, -1), &abs) == 0 && abs) {
71+
abs = _Py_normpath(abs, -1);
7172
r = PyUnicode_FromWideChar(abs, -1);
7273
PyMem_RawFree((void *)abs);
7374
} else {
@@ -884,6 +885,11 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
884885
#else
885886
!decode_to_dict(dict, "os_name", "posix") ||
886887
#endif
888+
#ifdef __MINGW32__
889+
!int_to_dict(dict, "is_mingw", 1) ||
890+
#else
891+
!int_to_dict(dict, "is_mingw", 0) ||
892+
#endif
887893
#ifdef WITH_NEXT_FRAMEWORK
888894
!int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 1) ||
889895
#else
@@ -910,6 +916,9 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
910916
!funcs_to_dict(dict, config->pathconfig_warnings) ||
911917
#ifndef MS_WINDOWS
912918
PyDict_SetItemString(dict, "winreg", Py_None) < 0 ||
919+
#endif
920+
#ifdef __MINGW32__
921+
!env_to_dict(dict, "ENV_MSYSTEM", 0) ||
913922
#endif
914923
PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0
915924
) {

Modules/getpath.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
# ** Values known at compile time **
3232
# os_name -- [in] one of 'nt', 'posix', 'darwin'
33+
# is_mingw -- [in] True if targeting MinGW
3334
# PREFIX -- [in] sysconfig.get_config_var(...)
3435
# EXEC_PREFIX -- [in] sysconfig.get_config_var(...)
3536
# PYTHONPATH -- [in] sysconfig.get_config_var(...)
@@ -51,6 +52,7 @@
5152
# ENV_PYTHONHOME -- [in] getenv(...)
5253
# ENV_PYTHONEXECUTABLE -- [in] getenv(...)
5354
# ENV___PYVENV_LAUNCHER__ -- [in] getenv(...)
55+
# ENV_MSYSTEM -- [in] getenv(...)
5456

5557
# ** Values calculated at runtime **
5658
# config -- [in/out] dict of the PyConfig structure
@@ -185,8 +187,27 @@
185187
ZIP_LANDMARK = f'{platlibdir}/python{VERSION_MAJOR}{VERSION_MINOR}.zip'
186188
DELIM = ':'
187189
SEP = '/'
190+
ALTSEP = None
188191

189-
elif os_name == 'nt':
192+
elif os_name == 'nt' and is_mingw:
193+
BUILDDIR_TXT = 'pybuilddir.txt'
194+
BUILD_LANDMARK = 'Modules/Setup.local'
195+
DEFAULT_PROGRAM_NAME = f'python{VERSION_MAJOR}'
196+
STDLIB_SUBDIR = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}'
197+
STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}/os.py', f'{STDLIB_SUBDIR}/os.pyc']
198+
PLATSTDLIB_LANDMARK = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}/lib-dynload'
199+
BUILDSTDLIB_LANDMARKS = ['Lib/os.py']
200+
VENV_LANDMARK = 'pyvenv.cfg'
201+
ZIP_LANDMARK = f'{platlibdir}/python{VERSION_MAJOR}{VERSION_MINOR}.zip'
202+
DELIM = ';'
203+
if ENV_MSYSTEM:
204+
SEP = '/'
205+
ALTSEP = '\\'
206+
else:
207+
SEP = '\\'
208+
ALTSEP = '/'
209+
210+
elif os_name == 'nt': # MSVC
190211
BUILDDIR_TXT = 'pybuilddir.txt'
191212
BUILD_LANDMARK = f'{VPATH}\\Modules\\Setup.local'
192213
DEFAULT_PROGRAM_NAME = f'python'
@@ -199,6 +220,7 @@
199220
WINREG_KEY = f'SOFTWARE\\Python\\PythonCore\\{PYWINVER}\\PythonPath'
200221
DELIM = ';'
201222
SEP = '\\'
223+
ALTSEP = '/'
202224

203225

204226
# ******************************************************************************
@@ -263,10 +285,10 @@ def search_up(prefix, *landmarks, test=isfile):
263285
if not executable:
264286
executable = real_executable
265287

266-
if not executable and SEP in program_name:
288+
if not executable and (SEP in program_name or
289+
(ALTSEP and ALTSEP in program_name)):
267290
# Resolve partial path program_name against current directory
268291
executable = abspath(program_name)
269-
270292
if not executable:
271293
# All platforms default to real_executable if known at this
272294
# stage. POSIX does not set this value.
@@ -497,15 +519,15 @@ def search_up(prefix, *landmarks, test=isfile):
497519
except (FileNotFoundError, PermissionError):
498520
if isfile(joinpath(real_executable_dir, BUILD_LANDMARK)):
499521
build_prefix = joinpath(real_executable_dir, VPATH)
500-
if os_name == 'nt':
522+
if os_name == 'nt' and not is_mingw:
501523
# QUIRK: Windows builds need platstdlib_dir to be the executable
502524
# dir. Normally the builddir marker handles this, but in this
503525
# case we need to correct manually.
504526
platstdlib_dir = real_executable_dir
505527

506528
if build_prefix:
507-
if os_name == 'nt':
508-
# QUIRK: No searching for more landmarks on Windows
529+
if os_name == 'nt' and not is_mingw:
530+
# QUIRK: No searching for more landmarks on MSVC
509531
build_stdlib_prefix = build_prefix
510532
else:
511533
build_stdlib_prefix = search_up(build_prefix, *BUILDSTDLIB_LANDMARKS)
@@ -597,7 +619,7 @@ def search_up(prefix, *landmarks, test=isfile):
597619

598620
# Detect exec_prefix by searching from executable for the platstdlib_dir
599621
if PLATSTDLIB_LANDMARK and not exec_prefix:
600-
if os_name == 'nt':
622+
if os_name == 'nt' and (not is_mingw):
601623
# QUIRK: Windows always assumed these were the same
602624
# gh-100320: Our PYDs are assumed to be relative to the Lib directory
603625
# (that is, prefix) rather than the executable (that is, executable_dir)
@@ -607,7 +629,7 @@ def search_up(prefix, *landmarks, test=isfile):
607629
if not exec_prefix and EXEC_PREFIX:
608630
exec_prefix = EXEC_PREFIX
609631
if not exec_prefix or not isdir(joinpath(exec_prefix, PLATSTDLIB_LANDMARK)):
610-
if os_name == 'nt':
632+
if os_name == 'nt' and (not is_mingw):
611633
# QUIRK: If DLLs is missing on Windows, don't warn, just assume
612634
# that they're in exec_prefix
613635
if not platstdlib_dir:
@@ -660,7 +682,7 @@ def search_up(prefix, *landmarks, test=isfile):
660682
pythonpath.append(abspath(p))
661683

662684
# Then add the default zip file
663-
if os_name == 'nt':
685+
if os_name == 'nt' and (not is_mingw):
664686
# QUIRK: Windows uses the library directory rather than the prefix
665687
if library:
666688
library_dir = dirname(library)
@@ -673,7 +695,7 @@ def search_up(prefix, *landmarks, test=isfile):
673695
else:
674696
pythonpath.append(joinpath(prefix, ZIP_LANDMARK))
675697

676-
if os_name == 'nt' and use_environment and winreg:
698+
if (not is_mingw) and os_name == 'nt' and use_environment and winreg:
677699
# QUIRK: Windows also lists paths in the registry. Paths are stored
678700
# as the default value of each subkey of
679701
# {HKCU,HKLM}\Software\Python\PythonCore\{winver}\PythonPath
@@ -714,7 +736,7 @@ def search_up(prefix, *landmarks, test=isfile):
714736
if not platstdlib_dir and exec_prefix:
715737
platstdlib_dir = joinpath(exec_prefix, PLATSTDLIB_LANDMARK)
716738

717-
if os_name == 'nt':
739+
if os_name == 'nt' and (not is_mingw):
718740
# QUIRK: Windows generates paths differently
719741
if platstdlib_dir:
720742
pythonpath.append(platstdlib_dir)
@@ -742,8 +764,8 @@ def search_up(prefix, *landmarks, test=isfile):
742764

743765
# QUIRK: Non-Windows replaces prefix/exec_prefix with defaults when running
744766
# in build directory. This happens after pythonpath calculation.
745-
if os_name != 'nt' and build_prefix:
746-
prefix = config.get('prefix') or PREFIX
767+
if (os_name != 'nt' or is_mingw) and build_prefix:
768+
prefix = config.get('prefix') or abspath(PREFIX)
747769
exec_prefix = config.get('exec_prefix') or EXEC_PREFIX or prefix
748770

749771

Python/fileutils.c

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,7 +2050,11 @@ _Py_abspath(const wchar_t *path, wchar_t **abspath_p)
20502050
}
20512051

20522052
#ifdef MS_WINDOWS
2053-
return _PyOS_getfullpathname(path, abspath_p);
2053+
if (_PyOS_getfullpathname(path, abspath_p) < 0){
2054+
return -1;
2055+
}
2056+
*abspath_p = _Py_normpath(*abspath_p, -1);
2057+
return 0;
20542058
#else
20552059
wchar_t cwd[MAXPATHLEN + 1];
20562060
cwd[Py_ARRAY_LENGTH(cwd) - 1] = 0;
@@ -2196,11 +2200,16 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
21962200
wchar_t *minP2 = path; // the beginning of the destination range
21972201
wchar_t lastC = L'\0'; // the last ljusted character, p2[-1] in most cases
21982202

2203+
const wchar_t sep = Py_GetSepW(NULL);
2204+
#ifdef ALTSEP
2205+
const wchar_t altsep = Py_GetAltSepW(NULL);
2206+
#endif
2207+
21992208
#define IS_END(x) (pEnd ? (x) == pEnd : !*(x))
22002209
#ifdef ALTSEP
2201-
#define IS_SEP(x) (*(x) == SEP || *(x) == ALTSEP)
2210+
#define IS_SEP(x) (*(x) == sep || *(x) == altsep)
22022211
#else
2203-
#define IS_SEP(x) (*(x) == SEP)
2212+
#define IS_SEP(x) (*(x) == sep)
22042213
#endif
22052214
#define SEP_OR_END(x) (IS_SEP(x) || IS_END(x))
22062215

@@ -2211,7 +2220,7 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
22112220
path++;
22122221
}
22132222
p1 = p2 = minP2 = path;
2214-
lastC = SEP;
2223+
lastC = sep;
22152224
}
22162225
#ifdef MS_WINDOWS
22172226
// Skip past drive segment and update minP2
@@ -2225,13 +2234,13 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
22252234
// and network paths, including the first segment.
22262235
else if (IS_SEP(&p1[0]) && IS_SEP(&p1[1])) {
22272236
int sepCount = 2;
2228-
*p2++ = SEP;
2229-
*p2++ = SEP;
2237+
*p2++ = sep;
2238+
*p2++ = sep;
22302239
p1 += 2;
22312240
for (; !IS_END(p1) && sepCount; ++p1) {
22322241
if (IS_SEP(p1)) {
22332242
--sepCount;
2234-
*p2++ = lastC = SEP;
2243+
*p2++ = lastC = sep;
22352244
} else {
22362245
*p2++ = lastC = *p1;
22372246
}
@@ -2244,26 +2253,26 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
22442253
*p2++ = *p1++;
22452254
*p2++ = *p1++;
22462255
minP2 = p2 - 1; // Absolute path has SEP at minP2
2247-
lastC = SEP;
2256+
lastC = sep;
22482257
}
22492258
#endif /* MS_WINDOWS */
22502259

22512260
/* if pEnd is specified, check that. Else, check for null terminator */
22522261
for (; !IS_END(p1); ++p1) {
22532262
wchar_t c = *p1;
22542263
#ifdef ALTSEP
2255-
if (c == ALTSEP) {
2256-
c = SEP;
2264+
if (c == altsep) {
2265+
c = sep;
22572266
}
22582267
#endif
2259-
if (lastC == SEP) {
2268+
if (lastC == sep) {
22602269
if (c == L'.') {
22612270
int sep_at_1 = SEP_OR_END(&p1[1]);
22622271
int sep_at_2 = !sep_at_1 && SEP_OR_END(&p1[2]);
22632272
if (sep_at_2 && p1[1] == L'.') {
22642273
wchar_t *p3 = p2;
2265-
while (p3 != minP2 && *--p3 == SEP) { }
2266-
while (p3 != minP2 && *(p3 - 1) != SEP) { --p3; }
2274+
while (p3 != minP2 && *--p3 == sep) { }
2275+
while (p3 != minP2 && *(p3 - 1) != sep) { --p3; }
22672276
if (p2 == minP2
22682277
|| (p3[0] == L'.' && p3[1] == L'.' && IS_SEP(&p3[2])))
22692278
{
@@ -2272,7 +2281,7 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
22722281
*p2++ = L'.';
22732282
*p2++ = L'.';
22742283
lastC = L'.';
2275-
} else if (p3[0] == SEP) {
2284+
} else if (p3[0] == sep) {
22762285
// Absolute path, so absorb segment
22772286
p2 = p3 + 1;
22782287
} else {
@@ -2283,7 +2292,7 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
22832292
} else {
22842293
*p2++ = lastC = c;
22852294
}
2286-
} else if (c == SEP) {
2295+
} else if (c == sep) {
22872296
} else {
22882297
*p2++ = lastC = c;
22892298
}
@@ -2293,7 +2302,7 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
22932302
}
22942303
*p2 = L'\0';
22952304
if (p2 != minP2) {
2296-
while (--p2 != minP2 && *p2 == SEP) {
2305+
while (--p2 != minP2 && *p2 == sep) {
22972306
*p2 = L'\0';
22982307
}
22992308
} else {

Python/pathconfig.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ Py_GetSepW(const wchar_t *name)
129129
return sep;
130130
}
131131

132-
static wchar_t
132+
wchar_t
133133
Py_GetAltSepW(const wchar_t *name)
134134
{
135135
char sep = Py_GetSepW(name);

0 commit comments

Comments
 (0)