Coverage for /pythoncovmergedfiles/medio/medio/usr/lib/python3.9/distutils/sysconfig.py: 3%

292 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:05 +0000

1"""Provide access to Python's configuration information. The specific 

2configuration variables available depend heavily on the platform and 

3configuration. The values may be retrieved using 

4get_config_var(name), and the list of variables is available via 

5get_config_vars().keys(). Additional convenience functions are also 

6available. 

7 

8Written by: Fred L. Drake, Jr. 

9Email: <fdrake@acm.org> 

10""" 

11 

12import _imp 

13import os 

14import re 

15import sys 

16import fnmatch 

17 

18from .errors import DistutilsPlatformError 

19 

20# These are needed in a couple of spots, so just compute them once. 

21PREFIX = os.path.normpath(sys.prefix) 

22EXEC_PREFIX = os.path.normpath(sys.exec_prefix) 

23BASE_PREFIX = os.path.normpath(sys.base_prefix) 

24BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) 

25 

26# Path to the base directory of the project. On Windows the binary may 

27# live in project/PCbuild/win32 or project/PCbuild/amd64. 

28# set for cross builds 

29if "_PYTHON_PROJECT_BASE" in os.environ: 

30 project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"]) 

31else: 

32 if sys.executable: 

33 project_base = os.path.dirname(os.path.abspath(sys.executable)) 

34 else: 

35 # sys.executable can be empty if argv[0] has been changed and Python is 

36 # unable to retrieve the real program name 

37 project_base = os.getcwd() 

38 

39 

40# python_build: (Boolean) if true, we're either building Python or 

41# building an extension with an un-installed Python, so we use 

42# different (hard-wired) directories. 

43def _is_python_source_dir(d): 

44 for fn in ("Setup", "Setup.local"): 

45 if os.path.isfile(os.path.join(d, "Modules", fn)): 

46 return True 

47 return False 

48 

49_sys_home = getattr(sys, '_home', None) 

50 

51if os.name == 'nt': 

52 def _fix_pcbuild(d): 

53 if d and os.path.normcase(d).startswith( 

54 os.path.normcase(os.path.join(PREFIX, "PCbuild"))): 

55 return PREFIX 

56 return d 

57 project_base = _fix_pcbuild(project_base) 

58 _sys_home = _fix_pcbuild(_sys_home) 

59 

60def _python_build(): 

61 if _sys_home: 

62 return _is_python_source_dir(_sys_home) 

63 return _is_python_source_dir(project_base) 

64 

65python_build = _python_build() 

66 

67 

68# Calculate the build qualifier flags if they are defined. Adding the flags 

69# to the include and lib directories only makes sense for an installation, not 

70# an in-source build. 

71build_flags = '' 

72try: 

73 if not python_build: 

74 build_flags = sys.abiflags 

75except AttributeError: 

76 # It's not a configure-based build, so the sys module doesn't have 

77 # this attribute, which is fine. 

78 pass 

79 

80def get_python_version(): 

81 """Return a string containing the major and minor Python version, 

82 leaving off the patchlevel. Sample return values could be '1.5' 

83 or '2.2'. 

84 """ 

85 return '%d.%d' % sys.version_info[:2] 

86 

87 

88def get_python_inc(plat_specific=0, prefix=None): 

89 """Return the directory containing installed Python header files. 

90 

91 If 'plat_specific' is false (the default), this is the path to the 

92 non-platform-specific header files, i.e. Python.h and so on; 

93 otherwise, this is the path to platform-specific header files 

94 (namely pyconfig.h). 

95 

96 If 'prefix' is supplied, use it instead of sys.base_prefix or 

97 sys.base_exec_prefix -- i.e., ignore 'plat_specific'. 

98 """ 

99 if prefix is None: 

100 prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX 

101 if os.name == "posix": 

102 if python_build: 

103 # Assume the executable is in the build directory. The 

104 # pyconfig.h file should be in the same directory. Since 

105 # the build directory may not be the source directory, we 

106 # must use "srcdir" from the makefile to find the "Include" 

107 # directory. 

108 if plat_specific: 

109 return _sys_home or project_base 

110 else: 

111 incdir = os.path.join(get_config_var('srcdir'), 'Include') 

112 return os.path.normpath(incdir) 

113 python_dir = 'python' + get_python_version() + build_flags 

114 if not python_build and plat_specific: 

115 import sysconfig 

116 return sysconfig.get_path('platinclude') 

117 return os.path.join(prefix, "include", python_dir) 

118 elif os.name == "nt": 

119 if python_build: 

120 # Include both the include and PC dir to ensure we can find 

121 # pyconfig.h 

122 return (os.path.join(prefix, "include") + os.path.pathsep + 

123 os.path.join(prefix, "PC")) 

124 return os.path.join(prefix, "include") 

125 else: 

126 raise DistutilsPlatformError( 

127 "I don't know where Python installs its C header files " 

128 "on platform '%s'" % os.name) 

129 

130 

131def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): 

132 """Return the directory containing the Python library (standard or 

133 site additions). 

134 

135 If 'plat_specific' is true, return the directory containing 

136 platform-specific modules, i.e. any module from a non-pure-Python 

137 module distribution; otherwise, return the platform-shared library 

138 directory. If 'standard_lib' is true, return the directory 

139 containing standard Python library modules; otherwise, return the 

140 directory for site-specific modules. 

141 

142 If 'prefix' is supplied, use it instead of sys.base_prefix or 

143 sys.base_exec_prefix -- i.e., ignore 'plat_specific'. 

144 """ 

145 is_default_prefix = not prefix or os.path.normpath(prefix) in ('/usr', '/usr/local') 

146 if prefix is None: 

147 if standard_lib: 

148 prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX 

149 else: 

150 prefix = plat_specific and EXEC_PREFIX or PREFIX 

151 

152 if os.name == "posix": 

153 if plat_specific or standard_lib: 

154 # Platform-specific modules (any module from a non-pure-Python 

155 # module distribution) or standard Python library modules. 

156 libdir = sys.platlibdir 

157 else: 

158 # Pure Python 

159 libdir = "lib" 

160 libpython = os.path.join(prefix, libdir, 

161 "python" + get_python_version()) 

162 if standard_lib: 

163 return libpython 

164 elif (is_default_prefix and 

165 'PYTHONUSERBASE' not in os.environ and 

166 'VIRTUAL_ENV' not in os.environ and 

167 'real_prefix' not in sys.__dict__ and 

168 sys.prefix == sys.base_prefix): 

169 return os.path.join(prefix, "lib", "python3", "dist-packages") 

170 else: 

171 return os.path.join(libpython, "site-packages") 

172 elif os.name == "nt": 

173 if standard_lib: 

174 return os.path.join(prefix, "Lib") 

175 else: 

176 return os.path.join(prefix, "Lib", "site-packages") 

177 else: 

178 raise DistutilsPlatformError( 

179 "I don't know where Python installs its library " 

180 "on platform '%s'" % os.name) 

181 

182 

183 

184def customize_compiler(compiler): 

185 """Do any platform-specific customization of a CCompiler instance. 

186 

187 Mainly needed on Unix, so we can plug in the information that 

188 varies across Unices and is stored in Python's Makefile. 

189 """ 

190 if compiler.compiler_type == "unix": 

191 if sys.platform == "darwin": 

192 # Perform first-time customization of compiler-related 

193 # config vars on OS X now that we know we need a compiler. 

194 # This is primarily to support Pythons from binary 

195 # installers. The kind and paths to build tools on 

196 # the user system may vary significantly from the system 

197 # that Python itself was built on. Also the user OS 

198 # version and build tools may not support the same set 

199 # of CPU architectures for universal builds. 

200 global _config_vars 

201 # Use get_config_var() to ensure _config_vars is initialized. 

202 if not get_config_var('CUSTOMIZED_OSX_COMPILER'): 

203 import _osx_support 

204 _osx_support.customize_compiler(_config_vars) 

205 _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' 

206 

207 (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags, 

208 configure_cppflags, configure_cflags, configure_ldflags) = \ 

209 get_config_vars('CC', 'CXX', 'CFLAGS', 

210 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS', 

211 'CONFIGURE_CPPFLAGS', 'CONFIGURE_CFLAGS', 'CONFIGURE_LDFLAGS') 

212 

213 if 'CC' in os.environ: 

214 newcc = os.environ['CC'] 

215 if (sys.platform == 'darwin' 

216 and 'LDSHARED' not in os.environ 

217 and ldshared.startswith(cc)): 

218 # On OS X, if CC is overridden, use that as the default 

219 # command for LDSHARED as well 

220 ldshared = newcc + ldshared[len(cc):] 

221 cc = newcc 

222 if 'CXX' in os.environ: 

223 cxx = os.environ['CXX'] 

224 if fnmatch.filter([cc, cxx], '*-4.[0-8]'): 

225 configure_cflags = configure_cflags.replace('-fstack-protector-strong', '-fstack-protector') 

226 ldshared = ldshared.replace('-fstack-protector-strong', '-fstack-protector') 

227 cflags = cflags.replace('-fstack-protector-strong', '-fstack-protector') 

228 if 'LDSHARED' in os.environ: 

229 ldshared = os.environ['LDSHARED'] 

230 if 'CPP' in os.environ: 

231 cpp = os.environ['CPP'] 

232 else: 

233 cpp = cc + " -E" # not always 

234 if 'LDFLAGS' in os.environ: 

235 ldshared = ldshared + ' ' + os.environ['LDFLAGS'] 

236 elif configure_ldflags: 

237 ldshared = ldshared + ' ' + configure_ldflags 

238 if 'CFLAGS' in os.environ: 

239 cflags = cflags + ' ' + os.environ['CFLAGS'] 

240 ldshared = ldshared + ' ' + os.environ['CFLAGS'] 

241 elif configure_cflags: 

242 cflags = cflags + ' ' + configure_cflags 

243 ldshared = ldshared + ' ' + configure_cflags 

244 if 'CPPFLAGS' in os.environ: 

245 cpp = cpp + ' ' + os.environ['CPPFLAGS'] 

246 cflags = cflags + ' ' + os.environ['CPPFLAGS'] 

247 ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] 

248 elif configure_cppflags: 

249 cpp = cpp + ' ' + configure_cppflags 

250 cflags = cflags + ' ' + configure_cppflags 

251 ldshared = ldshared + ' ' + configure_cppflags 

252 if 'AR' in os.environ: 

253 ar = os.environ['AR'] 

254 if 'ARFLAGS' in os.environ: 

255 archiver = ar + ' ' + os.environ['ARFLAGS'] 

256 else: 

257 archiver = ar + ' ' + ar_flags 

258 

259 cc_cmd = cc + ' ' + cflags 

260 compiler.set_executables( 

261 preprocessor=cpp, 

262 compiler=cc_cmd, 

263 compiler_so=cc_cmd + ' ' + ccshared, 

264 compiler_cxx=cxx, 

265 linker_so=ldshared, 

266 linker_exe=cc, 

267 archiver=archiver) 

268 

269 compiler.shared_lib_extension = shlib_suffix 

270 

271 

272def get_config_h_filename(): 

273 """Return full pathname of installed pyconfig.h file.""" 

274 if python_build: 

275 if os.name == "nt": 

276 inc_dir = os.path.join(_sys_home or project_base, "PC") 

277 else: 

278 inc_dir = _sys_home or project_base 

279 else: 

280 inc_dir = get_python_inc(plat_specific=1) 

281 

282 return os.path.join(inc_dir, 'pyconfig.h') 

283 

284 

285def get_makefile_filename(): 

286 """Return full pathname of installed Makefile from the Python build.""" 

287 if python_build: 

288 return os.path.join(_sys_home or project_base, "Makefile") 

289 lib_dir = get_python_lib(plat_specific=0, standard_lib=1) 

290 config_file = 'config-{}{}'.format(get_python_version(), build_flags) 

291 if hasattr(sys.implementation, '_multiarch'): 

292 config_file += '-%s' % sys.implementation._multiarch 

293 return os.path.join(lib_dir, config_file, 'Makefile') 

294 

295 

296def parse_config_h(fp, g=None): 

297 """Parse a config.h-style file. 

298 

299 A dictionary containing name/value pairs is returned. If an 

300 optional dictionary is passed in as the second argument, it is 

301 used instead of a new dictionary. 

302 """ 

303 if g is None: 

304 g = {} 

305 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") 

306 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") 

307 # 

308 while True: 

309 line = fp.readline() 

310 if not line: 

311 break 

312 m = define_rx.match(line) 

313 if m: 

314 n, v = m.group(1, 2) 

315 try: v = int(v) 

316 except ValueError: pass 

317 g[n] = v 

318 else: 

319 m = undef_rx.match(line) 

320 if m: 

321 g[m.group(1)] = 0 

322 return g 

323 

324 

325# Regexes needed for parsing Makefile (and similar syntaxes, 

326# like old-style Setup files). 

327_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") 

328_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") 

329_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") 

330 

331def parse_makefile(fn, g=None): 

332 """Parse a Makefile-style file. 

333 

334 A dictionary containing name/value pairs is returned. If an 

335 optional dictionary is passed in as the second argument, it is 

336 used instead of a new dictionary. 

337 """ 

338 from distutils.text_file import TextFile 

339 fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape") 

340 

341 if g is None: 

342 g = {} 

343 done = {} 

344 notdone = {} 

345 

346 while True: 

347 line = fp.readline() 

348 if line is None: # eof 

349 break 

350 m = _variable_rx.match(line) 

351 if m: 

352 n, v = m.group(1, 2) 

353 v = v.strip() 

354 # `$$' is a literal `$' in make 

355 tmpv = v.replace('$$', '') 

356 

357 if "$" in tmpv: 

358 notdone[n] = v 

359 else: 

360 try: 

361 v = int(v) 

362 except ValueError: 

363 # insert literal `$' 

364 done[n] = v.replace('$$', '$') 

365 else: 

366 done[n] = v 

367 

368 # Variables with a 'PY_' prefix in the makefile. These need to 

369 # be made available without that prefix through sysconfig. 

370 # Special care is needed to ensure that variable expansion works, even 

371 # if the expansion uses the name without a prefix. 

372 renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') 

373 

374 # do variable interpolation here 

375 while notdone: 

376 for name in list(notdone): 

377 value = notdone[name] 

378 m = _findvar1_rx.search(value) or _findvar2_rx.search(value) 

379 if m: 

380 n = m.group(1) 

381 found = True 

382 if n in done: 

383 item = str(done[n]) 

384 elif n in notdone: 

385 # get it on a subsequent round 

386 found = False 

387 elif n in os.environ: 

388 # do it like make: fall back to environment 

389 item = os.environ[n] 

390 

391 elif n in renamed_variables: 

392 if name.startswith('PY_') and name[3:] in renamed_variables: 

393 item = "" 

394 

395 elif 'PY_' + n in notdone: 

396 found = False 

397 

398 else: 

399 item = str(done['PY_' + n]) 

400 else: 

401 done[n] = item = "" 

402 if found: 

403 after = value[m.end():] 

404 value = value[:m.start()] + item + after 

405 if "$" in after: 

406 notdone[name] = value 

407 else: 

408 try: value = int(value) 

409 except ValueError: 

410 done[name] = value.strip() 

411 else: 

412 done[name] = value 

413 del notdone[name] 

414 

415 if name.startswith('PY_') \ 

416 and name[3:] in renamed_variables: 

417 

418 name = name[3:] 

419 if name not in done: 

420 done[name] = value 

421 else: 

422 # bogus variable reference; just drop it since we can't deal 

423 del notdone[name] 

424 

425 fp.close() 

426 

427 # strip spurious spaces 

428 for k, v in done.items(): 

429 if isinstance(v, str): 

430 done[k] = v.strip() 

431 

432 # save the results in the global dictionary 

433 g.update(done) 

434 return g 

435 

436 

437def expand_makefile_vars(s, vars): 

438 """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in 

439 'string' according to 'vars' (a dictionary mapping variable names to 

440 values). Variables not present in 'vars' are silently expanded to the 

441 empty string. The variable values in 'vars' should not contain further 

442 variable expansions; if 'vars' is the output of 'parse_makefile()', 

443 you're fine. Returns a variable-expanded version of 's'. 

444 """ 

445 

446 # This algorithm does multiple expansion, so if vars['foo'] contains 

447 # "${bar}", it will expand ${foo} to ${bar}, and then expand 

448 # ${bar}... and so forth. This is fine as long as 'vars' comes from 

449 # 'parse_makefile()', which takes care of such expansions eagerly, 

450 # according to make's variable expansion semantics. 

451 

452 while True: 

453 m = _findvar1_rx.search(s) or _findvar2_rx.search(s) 

454 if m: 

455 (beg, end) = m.span() 

456 s = s[0:beg] + vars.get(m.group(1)) + s[end:] 

457 else: 

458 break 

459 return s 

460 

461 

462_config_vars = None 

463 

464def _init_posix(): 

465 """Initialize the module as appropriate for POSIX systems.""" 

466 # _sysconfigdata is generated at build time, see the sysconfig module 

467 name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME', 

468 '_sysconfigdata_{abi}_{multiarch}'.format( 

469 abi=sys.abiflags, 

470 multiarch=getattr(sys.implementation, '_multiarch', ''), 

471 )) 

472 _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) 

473 build_time_vars = _temp.build_time_vars 

474 global _config_vars 

475 _config_vars = {} 

476 _config_vars.update(build_time_vars) 

477 

478 

479def _init_nt(): 

480 """Initialize the module as appropriate for NT""" 

481 g = {} 

482 # set basic install directories 

483 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) 

484 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) 

485 

486 # XXX hmmm.. a normal install puts include files here 

487 g['INCLUDEPY'] = get_python_inc(plat_specific=0) 

488 

489 g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] 

490 g['EXE'] = ".exe" 

491 g['VERSION'] = get_python_version().replace(".", "") 

492 g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) 

493 

494 global _config_vars 

495 _config_vars = g 

496 

497 

498def get_config_vars(*args): 

499 """With no arguments, return a dictionary of all configuration 

500 variables relevant for the current platform. Generally this includes 

501 everything needed to build extensions and install both pure modules and 

502 extensions. On Unix, this means every variable defined in Python's 

503 installed Makefile; on Windows it's a much smaller set. 

504 

505 With arguments, return a list of values that result from looking up 

506 each argument in the configuration variable dictionary. 

507 """ 

508 global _config_vars 

509 if _config_vars is None: 

510 func = globals().get("_init_" + os.name) 

511 if func: 

512 func() 

513 else: 

514 _config_vars = {} 

515 

516 # Normalized versions of prefix and exec_prefix are handy to have; 

517 # in fact, these are the standard versions used most places in the 

518 # Distutils. 

519 _config_vars['prefix'] = PREFIX 

520 _config_vars['exec_prefix'] = EXEC_PREFIX 

521 

522 # For backward compatibility, see issue19555 

523 SO = _config_vars.get('EXT_SUFFIX') 

524 if SO is not None: 

525 _config_vars['SO'] = SO 

526 

527 # Always convert srcdir to an absolute path 

528 srcdir = _config_vars.get('srcdir', project_base) 

529 if os.name == 'posix': 

530 if python_build: 

531 # If srcdir is a relative path (typically '.' or '..') 

532 # then it should be interpreted relative to the directory 

533 # containing Makefile. 

534 base = os.path.dirname(get_makefile_filename()) 

535 srcdir = os.path.join(base, srcdir) 

536 else: 

537 # srcdir is not meaningful since the installation is 

538 # spread about the filesystem. We choose the 

539 # directory containing the Makefile since we know it 

540 # exists. 

541 srcdir = os.path.dirname(get_makefile_filename()) 

542 _config_vars['srcdir'] = os.path.abspath(os.path.normpath(srcdir)) 

543 

544 # Convert srcdir into an absolute path if it appears necessary. 

545 # Normally it is relative to the build directory. However, during 

546 # testing, for example, we might be running a non-installed python 

547 # from a different directory. 

548 if python_build and os.name == "posix": 

549 base = project_base 

550 if (not os.path.isabs(_config_vars['srcdir']) and 

551 base != os.getcwd()): 

552 # srcdir is relative and we are not in the same directory 

553 # as the executable. Assume executable is in the build 

554 # directory and make srcdir absolute. 

555 srcdir = os.path.join(base, _config_vars['srcdir']) 

556 _config_vars['srcdir'] = os.path.normpath(srcdir) 

557 

558 # OS X platforms require special customization to handle 

559 # multi-architecture, multi-os-version installers 

560 if sys.platform == 'darwin': 

561 import _osx_support 

562 _osx_support.customize_config_vars(_config_vars) 

563 

564 if args: 

565 vals = [] 

566 for name in args: 

567 vals.append(_config_vars.get(name)) 

568 return vals 

569 else: 

570 return _config_vars 

571 

572def get_config_var(name): 

573 """Return the value of a single variable using the dictionary 

574 returned by 'get_config_vars()'. Equivalent to 

575 get_config_vars().get(name) 

576 """ 

577 if name == 'SO': 

578 import warnings 

579 warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2) 

580 return get_config_vars().get(name)