Explore Enterprise Education Gitee Premium Gitee AI AI teammates
Fetch the repository succeeded.
Donate
Please sign in before you donate.
Scan WeChat QR to Pay
Cancel
Complete
Prompt
Switch to Alipay.
OK
Cancel
1 Star 0 Fork 0

decbe/python-build-standalone

Create your Gitee Account
Explore and code with more than 14 million developers,Free private repositories !:)
Sign up
Already have an account? Sign in
文件
main
Branches (89)
Tags (67)
main
zb/patch-uuid
zb/arm64
zb/uuid-patch
zb/14a7
zb/musl-ft
dependabot/pip/jinja2-3.1.6
latest-release
dependabot/cargo/tokio-1.43.1
zb/native-aarch64
zb/debug-keep-image
zb/musl-pgo
zb/aarch64-musl
zb/clangcl
zb/retry-count
indygreg/no-plt
dependabot/cargo/ring-0.17.13
zb/ref-static
zb/ref-static-triple
zb/jit-macos
20250409
20250317
20250311
20250212
20250205
20250115
20250106
20241219
20241206
20241205
20241016
20241008
20241002
20240909
20240814
20240726
20240725
20240713
20240415
20240224
main
Branches (89)
Tags (67)
main
zb/patch-uuid
zb/arm64
zb/uuid-patch
zb/14a7
zb/musl-ft
dependabot/pip/jinja2-3.1.6
latest-release
dependabot/cargo/tokio-1.43.1
zb/native-aarch64
zb/debug-keep-image
zb/musl-pgo
zb/aarch64-musl
zb/clangcl
zb/retry-count
indygreg/no-plt
dependabot/cargo/ring-0.17.13
zb/ref-static
zb/ref-static-triple
zb/jit-macos
20250409
20250317
20250311
20250212
20250205
20250115
20250106
20241219
20241206
20241205
20241016
20241008
20241002
20240909
20240814
20240726
20240725
20240713
20240415
20240224
Clone or Download
Clone/Download
Prompt
To download the code, please copy the following command and execute it in the terminal
To ensure that your submitted code identity is correctly recognized by Gitee, please execute the following command.
When using the SSH protocol for the first time to clone or push code, follow the prompts below to complete the SSH configuration.
1 Generate RSA keys.
2 Obtain the content of the RSA public key and configure it in SSH Public Keys
To use SVN on Gitee, please visit the usage guide
When using the HTTPS protocol, the command line will prompt for account and password verification as follows. For security reasons, Gitee recommends configure and use personal access tokens instead of login passwords for cloning, pushing, and other operations.
Username for 'https://gitee.com': userName
Password for 'https://userName@gitee.com': # Private Token
main
Branches (89)
Tags (67)
main
zb/patch-uuid
zb/arm64
zb/uuid-patch
zb/14a7
zb/musl-ft
dependabot/pip/jinja2-3.1.6
latest-release
dependabot/cargo/tokio-1.43.1
zb/native-aarch64
zb/debug-keep-image
zb/musl-pgo
zb/aarch64-musl
zb/clangcl
zb/retry-count
indygreg/no-plt
dependabot/cargo/ring-0.17.13
zb/ref-static
zb/ref-static-triple
zb/jit-macos
20250409
20250317
20250311
20250212
20250205
20250115
20250106
20241219
20241206
20241205
20241016
20241008
20241002
20240909
20240814
20240726
20240725
20240713
20240415
20240224
cpython.py 23.33 KB
Copy Edit Raw Blame History
Zanie Blue authored 2025年03月12日 00:50 +08:00 . Add dynamically linked musl distributions (#541)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import pathlib
import re
import tarfile
import jsonschema
import yaml
from pythonbuild.logging import log
EXTENSION_MODULE_SCHEMA = {
"type": "object",
"properties": {
"build-mode": {"type": "string"},
"config-c-only": {"type": "boolean"},
"defines": {"type": "array", "items": {"type": "string"}},
"defines-conditional": {
"type": "array",
"items": {
"type": "object",
"properties": {
"define": {"type": "string"},
"targets": {"type": "array", "items": {"type": "string"}},
"minimum-python-version": {"type": "string"},
"maximum-python-version": {"type": "string"},
},
"additionalProperties": False,
"required": ["define"],
},
},
"disabled-targets": {"type": "array", "items": {"type": "string"}},
"frameworks": {"type": "array", "items": {"type": "string"}},
"includes": {"type": "array", "items": {"type": "string"}},
"includes-conditional": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {"type": "string"},
"targets": {"type": "array", "items": {"type": "string"}},
"minimum-python-version": {"type": "string"},
"maximum-python-version": {"type": "string"},
},
"additionalProperties": False,
},
},
"includes-deps": {"type": "array", "items": {"type": "string"}},
"links": {"type": "array", "items": {"type": "string"}},
"links-conditional": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"targets": {"type": "array", "items": {"type": "string"}},
},
"additionalProperties": False,
},
},
"linker-args": {
"type": "array",
"items": {
"type": "object",
"properties": {
"args": {"type": "array", "items": {"type": "string"}},
"targets": {"type": "array", "items": {"type": "string"}},
},
"additionalProperties": False,
},
},
"minimum-python-version": {"type": "string"},
"maximum-python-version": {"type": "string"},
"required-targets": {"type": "array", "items": {"type": "string"}},
"setup-enabled": {"type": "boolean"},
"setup-enabled-conditional": {
"type": "array",
"items": {
"type": "object",
"properties": {
"enabled": {"type": "boolean"},
"minimum-python-version": {"type": "string"},
"maximum-python-version": {"type": "string"},
},
"additionalProperties": False,
"required": ["enabled"],
},
},
"sources": {"type": "array", "items": {"type": "string"}},
"sources-conditional": {
"type": "array",
"items": {
"type": "object",
"properties": {
"source": {"type": "string"},
"targets": {"type": "array", "items": {"type": "string"}},
"minimum-python-version": {"type": "string"},
"maximum-python-version": {"type": "string"},
},
"additionalProperties": False,
"required": ["source"],
},
},
},
"additionalProperties": False,
}
EXTENSION_MODULES_SCHEMA = {
"type": "object",
"patternProperties": {
"^[a-z_]+$": EXTENSION_MODULE_SCHEMA,
},
}
# Packages that define tests.
STDLIB_TEST_PACKAGES = {
"bsddb.test",
"ctypes.test",
"distutils.tests",
"email.test",
"idlelib.idle_test",
"json.tests",
"lib-tk.test",
"lib2to3.tests",
"sqlite3.test",
"test",
"tkinter.test",
"unittest.test",
}
def parse_setup_line(line: bytes, python_version: str):
"""Parse a line in a ``Setup.*`` file."""
if b"#" in line:
line = line[: line.index(b"#")].rstrip()
if not line:
return
words = line.split()
extension = words[0].decode("ascii")
objs = set()
links = set()
frameworks = set()
for i, word in enumerate(words):
# Arguments looking like C source files are converted to object files.
if word.endswith(b".c"):
# Object files are named according to the basename: parent
# directories they may happen to reside in are stripped out.
source_path = pathlib.Path(word.decode("ascii"))
# Python 3.11 changed the path of the object file.
if meets_python_minimum_version(python_version, "3.11") and b"/" in word:
obj_path = (
pathlib.Path("Modules")
/ source_path.parent
/ source_path.with_suffix(".o").name
)
else:
obj_path = pathlib.Path("Modules") / source_path.with_suffix(".o").name
objs.add(obj_path)
# Arguments looking like link libraries are converted to library
# dependencies.
elif word.startswith(b"-l"):
links.add(word[2:].decode("ascii"))
elif word.startswith(b"-hidden-l"):
links.add(word[len("-hidden-l") :].decode("ascii"))
elif word == b"-framework":
frameworks.add(words[i + 1].decode("ascii"))
return {
"extension": extension,
"line": line,
"posix_obj_paths": objs,
"links": links,
"frameworks": frameworks,
"variant": "default",
}
def link_for_target(lib: str, target_triple: str) -> str:
# TODO use -Wl,-hidden-lbz2?
# TODO use -Wl,--exclude-libs,libfoo.a?
if "-apple-" in target_triple:
# The -l:filename syntax doesn't appear to work on Apple.
# just give the library name and hope it turns out OK.
if lib.startswith(":lib") and lib.endswith(".a"):
return f"-Xlinker -hidden-l{lib[4:-2]}"
else:
return f"-Xlinker -hidden-l{lib}"
else:
return f"-l{lib}"
def meets_python_minimum_version(got: str, wanted: str) -> bool:
parts = got.split(".")
got_major, got_minor = int(parts[0]), int(parts[1])
parts = wanted.split(".")
wanted_major, wanted_minor = int(parts[0]), int(parts[1])
return (got_major, got_minor) >= (wanted_major, wanted_minor)
def meets_python_maximum_version(got: str, wanted: str) -> bool:
parts = got.split(".")
got_major, got_minor = int(parts[0]), int(parts[1])
parts = wanted.split(".")
wanted_major, wanted_minor = int(parts[0]), int(parts[1])
return (got_major, got_minor) <= (wanted_major, wanted_minor)
def derive_setup_local(
cpython_source_archive,
python_version,
target_triple,
build_options,
extension_modules,
):
"""Derive the content of the Modules/Setup.local file."""
# The first part of this function validates that our extension modules YAML
# based metadata is in sync with the various files declaring extension
# modules in the Python distribution.
disabled = set()
ignored = set()
setup_enabled_wanted = set()
config_c_only_wanted = set()
# Collect metadata about our extension modules as they relate to this
# Python target.
for name, info in sorted(extension_modules.items()):
python_min_match = meets_python_minimum_version(
python_version, info.get("minimum-python-version", "1.0")
)
python_max_match = meets_python_maximum_version(
python_version, info.get("maximum-python-version", "100.0")
)
if info.get("build-mode") not in (None, "shared", "static"):
raise Exception("unsupported build-mode for extension module %s" % name)
if not (python_min_match and python_max_match):
log(f"ignoring extension module {name} because Python version incompatible")
ignored.add(name)
continue
if targets := info.get("disabled-targets"):
if any(re.match(p, target_triple) for p in targets):
log(
"disabling extension module %s because disabled for this target triple"
% name
)
disabled.add(name)
if info.get("setup-enabled", False):
setup_enabled_wanted.add(name)
for entry in info.get("setup-enabled-conditional", []):
python_min_match_setup = meets_python_minimum_version(
python_version, entry.get("minimum-python-version", "1.0")
)
python_max_match_setup = meets_python_maximum_version(
python_version, entry.get("maximum-python-version", "100.0")
)
if entry.get("enabled", False) and (
python_min_match_setup and python_max_match_setup
):
setup_enabled_wanted.add(name)
if info.get("config-c-only"):
config_c_only_wanted.add(name)
# Parse more files in the distribution for their metadata.
with tarfile.open(str(cpython_source_archive)) as tf:
ifh = tf.extractfile("Python-%s/Modules/Setup" % python_version)
setup_lines = ifh.readlines()
try:
ifh = tf.extractfile(f"Python-{python_version}/Modules/Setup.bootstrap.in")
setup_bootstrap_in = ifh.readlines()
except KeyError:
setup_bootstrap_in = []
ifh = tf.extractfile("Python-%s/Modules/config.c.in" % python_version)
config_c_in = ifh.read()
dist_modules = set()
setup_enabled_actual = set()
setup_enabled_lines = {}
section = "static"
RE_VARIABLE = re.compile(rb"^[a-zA-Z_]+\s*=")
RE_EXTENSION_MODULE = re.compile(rb"^([a-z_]+)\s.*[a-zA-Z/_-]+\.c\b")
# Setup.bootstrap.in has a simple format.
for line in setup_bootstrap_in:
if b"#" in line:
line = line[: line.index(b"#")]
# There is special `@MODULE_<name>_TRUE@` syntax that gets elided or turned
# into a comment during Makefile expansion. For now, just pretend it always
# goes away. This assumption may not be valid in future Python versions. But
# as of 3.11 only pwd is defined this way.
if line.startswith(b"@") and line.count(b"@") == 2:
line = line.split(b"@")[-1]
line = line.strip()
if not line:
continue
if m := RE_EXTENSION_MODULE.match(line):
name = m.group(1).decode("ascii")
dist_modules.add(name)
setup_enabled_actual.add(name)
setup_enabled_lines[name] = line
for line in setup_lines:
line = line.rstrip()
if not line:
continue
# Looks like a variable assignment.
if RE_VARIABLE.match(line):
continue
# Look for extension syntax before and after comment.
for i, part in enumerate(line.split(b"#")):
if m := RE_EXTENSION_MODULE.match(part):
dist_modules.add(m.group(1).decode("ascii"))
if i == 0:
setup_enabled_actual.add(m.group(1).decode("ascii"))
break
# Now look for enabled extensions and stash away the line.
if line == b"*static*":
section = "static"
continue
elif line == b"*shared*":
section = "shared"
continue
elif line == b"*disabled*":
section = "disabled"
continue
if b"#" in line:
line = line[: line.index(b"#")].strip()
if line and section != "disabled":
setup_enabled_lines[line.split()[0].decode("ascii")] = line
config_c_extensions = parse_config_c(config_c_in.decode("utf-8"))
for extension in sorted(config_c_extensions):
dist_modules.add(extension)
# With ours and theirs extension module metadata collections, compare and
# make sure our metadata is comprehensive. This isn't strictly necessary.
# But it makes it drastically easier to catch bugs due to our metadata being
# out of sync with the distribution. This has historically caused several
# subtle and hard-to-diagnose bugs, which is why we do it.
missing = dist_modules - set(extension_modules.keys())
if missing:
raise Exception(
"missing extension modules from YAML: %s" % ", ".join(sorted(missing))
)
missing = setup_enabled_actual - setup_enabled_wanted
if missing:
raise Exception(
"Setup enabled extensions missing YAML setup-enabled annotation: %s"
% ", ".join(sorted(missing))
)
extra = setup_enabled_wanted - setup_enabled_actual
if extra:
raise Exception(
"YAML setup-enabled extensions not present in Setup: %s"
% ", ".join(sorted(extra))
)
if missing := set(config_c_extensions) - config_c_only_wanted:
raise Exception(
"config.c.in extensions missing YAML config-c-only annotation: %s"
% ", ".join(sorted(missing))
)
if extra := config_c_only_wanted - set(config_c_extensions):
raise Exception(
"YAML config-c-only extensions not present in config.c.in: %s"
% ", ".join(sorted(extra))
)
# And with verification out of way, now we generate a Setup.local file
# from our metadata. The verification above ensured that our metadata
# agrees fully with the distribution's knowledge of extensions. So we can
# treat our metadata as canonical.
RE_DEFINE = re.compile(rb"-D[^=]+=[^\s]+")
# Translate our YAML metadata into Setup lines.
section_lines = {
"disabled": [],
"shared": [],
"static": [],
}
# makesetup parses lines with = as extra config options. There appears
# to be no easy way to define e.g. -Dfoo=bar in Setup.local. We hack
# around this by producing a Makefile supplement that overrides the build
# rules for certain targets to include these missing values.
extra_cflags = {}
enabled_extensions = {}
for name, info in sorted(extension_modules.items()):
if name in ignored:
continue
if name in disabled:
section_lines["disabled"].append(name.encode("ascii"))
continue
enabled_extensions[name] = dict(info)
# The initialization function is usually PyInit_{extension}. But some
# config.c.in extensions don't follow this convention!
if name in config_c_extensions:
init_fn = config_c_extensions[name]
in_core = True
else:
init_fn = f"PyInit_{name}"
in_core = False
enabled_extensions[name]["init_fn"] = init_fn
enabled_extensions[name]["in_core"] = in_core
# config.c.in only extensions are part of core object files. There is
# nothing else to process.
if name in config_c_only_wanted:
log(f"extension {name} enabled through config.c")
enabled_extensions[name]["setup_line"] = name.encode("ascii")
continue
# Force static linking if we're doing a fully static build, otherwise,
# respect the `build-mode` falling back to `static` if not defined.
section = (
"static" if "static" in build_options else info.get("build-mode", "static")
)
enabled_extensions[name]["build-mode"] = section
# Presumably this means the extension comes from the distribution's
# Setup. Lack of sources means we don't need to derive a Setup.local
# line.
if "sources" not in info and "sources-conditional" not in info:
if name not in setup_enabled_lines:
raise Exception(
f"found a sourceless extension ({name}) with no Setup entry"
)
log(f"extension {name} enabled through distribution's Modules/Setup file")
# But we do record a placeholder Setup line in the returned metadata
# as this is what's used to derive PYTHON.json metadata.
enabled_extensions[name]["setup_line"] = setup_enabled_lines[name]
continue
log(f"extension {name} being configured via YAML metadata")
line = name
for source in info.get("sources", []):
line += " %s" % source
for entry in info.get("sources-conditional", []):
if targets := entry.get("targets", []):
target_match = any(re.match(p, target_triple) for p in targets)
else:
target_match = True
python_min_match = meets_python_minimum_version(
python_version, entry.get("minimum-python-version", "1.0")
)
python_max_match = meets_python_maximum_version(
python_version, entry.get("maximum-python-version", "100.0")
)
if target_match and (python_min_match and python_max_match):
if source := entry.get("source"):
line += f" {source}"
for source in entry.get("sources", []):
line += f" {source}"
for define in info.get("defines", []):
line += f" -D{define}"
for entry in info.get("defines-conditional", []):
if targets := entry.get("targets", []):
target_match = any(re.match(p, target_triple) for p in targets)
else:
target_match = True
python_min_match = meets_python_minimum_version(
python_version, entry.get("minimum-python-version", "1.0")
)
python_max_match = meets_python_maximum_version(
python_version, entry.get("maximum-python-version", "100.0")
)
if target_match and (python_min_match and python_max_match):
line += f" -D{entry['define']}"
for path in info.get("includes", []):
line += f" -I{path}"
for entry in info.get("includes-conditional", []):
if targets := entry.get("targets", []):
target_match = any(re.match(p, target_triple) for p in targets)
else:
target_match = True
python_min_match = meets_python_minimum_version(
python_version, entry.get("minimum-python-version", "1.0")
)
python_max_match = meets_python_maximum_version(
python_version, entry.get("maximum-python-version", "100.0")
)
if target_match and (python_min_match and python_max_match):
# TODO: Change to `include` and drop support for `path`
if include := entry.get("path"):
line += f" -I{include}"
for include in entry.get("includes", []):
line += f" -I{include}"
for path in info.get("includes-deps", []):
# Includes are added to global search path.
if "-apple-" in target_triple:
continue
line += f" -I/tools/deps/{path}"
for lib in info.get("links", []):
line += " %s" % link_for_target(lib, target_triple)
for entry in info.get("links-conditional", []):
if targets := entry.get("targets", []):
target_match = any(re.match(p, target_triple) for p in targets)
else:
target_match = True
python_min_match = meets_python_minimum_version(
python_version, entry.get("minimum-python-version", "1.0")
)
python_max_match = meets_python_maximum_version(
python_version, entry.get("maximum-python-version", "100.0")
)
if target_match and (python_min_match and python_max_match):
line += " %s" % link_for_target(entry["name"], target_triple)
if "-apple-" in target_triple:
for framework in info.get("frameworks", []):
line += f" -framework {framework}"
for entry in info.get("linker-args", []):
if any(re.match(p, target_triple) for p in entry["targets"]):
for arg in entry["args"]:
line += f" -Xlinker {arg}"
line = line.encode("ascii")
# This extra parse is a holder from older code and could likely be
# factored away.
parsed = parse_setup_line(line, python_version=python_version)
if not parsed:
raise Exception("we should always parse a setup line we generated")
# makesetup parses lines with = as extra config options. There appears
# to be no easy way to define e.g. -Dfoo=bar in Setup.local. We hack
# around this by detecting the syntax we'd like to support and move the
# variable defines to a Makefile supplement that overrides variables for
# specific targets.
for m in RE_DEFINE.finditer(parsed["line"]):
for obj_path in sorted(parsed["posix_obj_paths"]):
extra_cflags.setdefault(bytes(obj_path), []).append(m.group(0))
line = RE_DEFINE.sub(b"", line)
if b"=" in line:
raise Exception(
"= appears in EXTRA_MODULES line; will confuse "
"makesetup: %s" % line.decode("utf-8")
)
section_lines[section].append(line)
enabled_extensions[name]["setup_line"] = line
dest_lines = []
for section, lines in sorted(section_lines.items()):
if not lines:
continue
dest_lines.append(b"\n*%s*\n" % section.encode("ascii"))
dest_lines.extend(lines)
dest_lines.append(b"")
make_lines = []
for target in sorted(extra_cflags):
make_lines.append(
b"%s: PY_STDMODULE_CFLAGS += %s" % (target, b" ".join(extra_cflags[target]))
)
return {
"extensions": enabled_extensions,
"setup_local": b"\n".join(dest_lines),
"make_data": b"\n".join(make_lines),
}
RE_INITTAB_ENTRY = re.compile('\{"([^"]+)", ([^\}]+)\},')
def parse_config_c(s: str):
"""Parse the contents of a config.c file.
The file defines external symbols for module init functions and the
mapping of module name to module initializer function.
"""
# Some config.c files have #ifdef. We don't care about those because
# in all cases the condition is true.
extensions = {}
seen_inittab = False
for line in s.splitlines():
if line.startswith("struct _inittab"):
seen_inittab = True
if not seen_inittab:
continue
if "/* Sentinel */" in line:
break
m = RE_INITTAB_ENTRY.search(line)
if m:
extensions[m.group(1)] = m.group(2)
return extensions
def extension_modules_config(yaml_path: pathlib.Path):
"""Loads the extension-modules.yml file."""
with yaml_path.open("r", encoding="utf-8") as fh:
data = yaml.load(fh, Loader=yaml.SafeLoader)
jsonschema.validate(data, EXTENSION_MODULES_SCHEMA)
return data
Loading...
Report
Report success
We will send you the feedback within 2 working days through the letter!
Please fill in the reason for the report carefully. Provide as detailed a description as possible.
Please select a report type
Cancel
Send
误判申诉

此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。

如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。

取消
提交

About

No description
No labels
MPL-2.0
Use MPL-2.0
, MIT
Use MIT
, MIT
Use MIT
, Zlib
Use Zlib
, MIT
Use MIT
, MIT
Use MIT
, Apache-2.0
Use Apache-2.0
, BSD-3-Clause-Clear
Use BSD-3-Clause-Clear
Cancel

Releases

No release

Contributors

All

Activities

can not load any more
Edit
About
Homepage
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/decbe/python-build-standalone.git
git@gitee.com:decbe/python-build-standalone.git
decbe
python-build-standalone
python-build-standalone
main
Going to Help Center

Search

Comment
Repository Report
Back to the top
Login prompt
This operation requires login to the code cloud account. Please log in before operating.
Go to login
No account. Register

AltStyle によって変換されたページ (->オリジナル) /