Skip to content

Commit b60e292

Browse files
committed
Refactor static / dynamic linking into build options
1 parent 2a9167e commit b60e292

File tree

5 files changed

+72
-33
lines changed

5 files changed

+72
-33
lines changed

ci-targets.yaml

+12-12
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,9 @@ linux:
257257
- "3.12"
258258
- "3.13"
259259
build_options:
260-
- debug
261-
- noopt
262-
- lto
260+
- debug+static
261+
- noopt+static
262+
- lto+static
263263
run: true
264264

265265
x86_64_v2-unknown-linux-musl:
@@ -273,9 +273,9 @@ linux:
273273
- "3.12"
274274
- "3.13"
275275
build_options:
276-
- debug
277-
- noopt
278-
- lto
276+
- debug+static
277+
- noopt+static
278+
- lto+static
279279
run: true
280280

281281
x86_64_v3-unknown-linux-musl:
@@ -289,9 +289,9 @@ linux:
289289
- "3.12"
290290
- "3.13"
291291
build_options:
292-
- debug
293-
- noopt
294-
- lto
292+
- debug+static
293+
- noopt+static
294+
- lto+static
295295
run: true
296296

297297
x86_64_v4-unknown-linux-musl:
@@ -305,9 +305,9 @@ linux:
305305
- "3.12"
306306
- "3.13"
307307
build_options:
308-
- debug
309-
- noopt
310-
- lto
308+
- debug+static
309+
- noopt+static
310+
- lto+static
311311
run: true
312312

313313
windows:

cpython-unix/build-cpython.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ CONFIGURE_FLAGS="
381381
--without-ensurepip
382382
${EXTRA_CONFIGURE_FLAGS}"
383383

384-
if [ "${CC}" = "musl-clang" ]; then
384+
if [ -n "${CPYTHON_STATIC}" ]; then
385385
CFLAGS="${CFLAGS} -static"
386386
CPPFLAGS="${CPPFLAGS} -static"
387387
LDFLAGS="${LDFLAGS} -static"

cpython-unix/build-main.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def main():
4545
print("Unsupported build platform: %s" % sys.platform)
4646
return 1
4747

48+
# Note these arguments must be synced with `build.py`
4849
parser = argparse.ArgumentParser()
4950

5051
parser.add_argument(
@@ -54,10 +55,17 @@ def main():
5455
help="Target host triple to build for",
5556
)
5657

57-
optimizations = {"debug", "noopt", "pgo", "lto", "pgo+lto"}
58+
# Construct possible options, we use a set here for canonical ordering
59+
options = set()
60+
options.update({"debug", "noopt", "pgo", "lto", "pgo+lto"})
61+
options.update({f"freethreaded+{option}" for option in options})
62+
link_modes = {"static", "shared"}
63+
options.update(
64+
{f"{option}+{link_mode}" for link_mode in link_modes for option in options}
65+
)
5866
parser.add_argument(
5967
"--options",
60-
choices=optimizations.union({f"freethreaded+{o}" for o in optimizations}),
68+
choices=options,
6169
default="noopt",
6270
help="Build options to apply when compiling Python",
6371
)
@@ -138,6 +146,10 @@ def main():
138146

139147
env = dict(os.environ)
140148

149+
# Default to dynamic linking if no link mode is specified
150+
if not any(link_mode in args.options for link_mode in link_modes):
151+
args.options += "+shared"
152+
141153
env["PYBUILD_HOST_PLATFORM"] = host_platform
142154
env["PYBUILD_TARGET_TRIPLE"] = target_triple
143155
env["PYBUILD_BUILD_OPTIONS"] = args.options

cpython-unix/build.py

+39-12
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ def python_build_info(
488488
target_triple,
489489
musl,
490490
lto,
491+
static,
491492
extensions,
492493
extra_metadata,
493494
):
@@ -506,7 +507,7 @@ def python_build_info(
506507
)
507508
)
508509

509-
if not musl:
510+
if not static:
510511
bi["core"]["shared_lib"] = "install/lib/libpython%s%s.so.1.0" % (
511512
version,
512513
binary_suffix,
@@ -735,6 +736,7 @@ def build_cpython(
735736
python_archive,
736737
python_version=python_version,
737738
target_triple=target_triple,
739+
build_options=parsed_build_options,
738740
extension_modules=ems,
739741
)
740742

@@ -825,6 +827,8 @@ def build_cpython(
825827
env["CPYTHON_OPTIMIZED"] = "1"
826828
if "lto" in parsed_build_options:
827829
env["CPYTHON_LTO"] = "1"
830+
if "static" in parsed_build_options:
831+
env["CPYTHON_STATIC"] = "1"
828832

829833
add_target_env(env, host_platform, target_triple, build_env)
830834

@@ -834,19 +838,26 @@ def build_cpython(
834838
crt_features = []
835839

836840
if host_platform == "linux64":
837-
if "musl" in target_triple:
841+
if "static" in parsed_build_options:
838842
crt_features.append("static")
839843
else:
840844
extension_module_loading.append("shared-library")
841-
crt_features.append("glibc-dynamic")
842845

843-
glibc_max_version = build_env.get_file("glibc_version.txt").strip()
844-
if not glibc_max_version:
845-
raise Exception("failed to retrieve glibc max symbol version")
846+
if "musl" in target_triple:
847+
crt_features.append("musl-dynamic")
848+
# TODO: Determine the dynamic musl libc version
846849

847-
crt_features.append(
848-
"glibc-max-symbol-version:%s" % glibc_max_version.decode("ascii")
849-
)
850+
else:
851+
crt_features.append("glibc-dynamic")
852+
853+
glibc_max_version = build_env.get_file("glibc_version.txt").strip()
854+
if not glibc_max_version:
855+
raise Exception("failed to retrieve glibc max symbol version")
856+
857+
crt_features.append(
858+
"glibc-max-symbol-version:%s"
859+
% glibc_max_version.decode("ascii")
860+
)
850861

851862
python_symbol_visibility = "global-default"
852863

@@ -874,7 +885,9 @@ def build_cpython(
874885
"python_stdlib_test_packages": sorted(STDLIB_TEST_PACKAGES),
875886
"python_symbol_visibility": python_symbol_visibility,
876887
"python_extension_module_loading": extension_module_loading,
877-
"libpython_link_mode": "static" if "musl" in target_triple else "shared",
888+
"libpython_link_mode": (
889+
"static" if "static" in parsed_build_options else "shared"
890+
),
878891
"crt_features": crt_features,
879892
"run_tests": "build/run_tests.py",
880893
"build_info": python_build_info(
@@ -884,6 +897,7 @@ def build_cpython(
884897
target_triple,
885898
"musl" in target_triple,
886899
"lto" in parsed_build_options,
900+
"static" in parsed_build_options,
887901
enabled_extensions,
888902
extra_metadata,
889903
),
@@ -946,6 +960,7 @@ def main():
946960
print("unable to connect to Docker: %s" % e, file=sys.stderr)
947961
return 1
948962

963+
# Note these arguments must be synced with `build-main.py`
949964
parser = argparse.ArgumentParser()
950965
parser.add_argument(
951966
"--host-platform", required=True, help="Platform we are building from"
@@ -955,13 +970,25 @@ def main():
955970
required=True,
956971
help="Host triple that we are building Python for",
957972
)
958-
optimizations = {"debug", "noopt", "pgo", "lto", "pgo+lto"}
973+
974+
# Construct possible options
975+
options = set()
976+
options.update({"debug", "noopt", "pgo", "lto", "pgo+lto"})
977+
options.update({f"freethreaded+{option}" for option in options})
978+
options.update(
979+
{
980+
f"{option}+{link_mode}"
981+
for link_mode in {"static", "shared"}
982+
for option in options
983+
}
984+
)
959985
parser.add_argument(
960986
"--options",
961-
choices=optimizations.union({f"freethreaded+{o}" for o in optimizations}),
987+
choices=options,
962988
default="noopt",
963989
help="Build options to apply when compiling Python",
964990
)
991+
965992
parser.add_argument(
966993
"--toolchain",
967994
action="store_true",

pythonbuild/cpython.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ def derive_setup_local(
227227
cpython_source_archive,
228228
python_version,
229229
target_triple,
230+
build_options,
230231
extension_modules,
231232
):
232233
"""Derive the content of the Modules/Setup.local file."""
@@ -466,12 +467,11 @@ def derive_setup_local(
466467
enabled_extensions[name]["setup_line"] = name.encode("ascii")
467468
continue
468469

469-
# musl is static only. Ignore build-mode override.
470-
if "musl" in target_triple:
471-
section = "static"
472-
else:
473-
section = info.get("build-mode", "static")
474-
470+
# Force static linking if we're doing a fully static build, otherwise,
471+
# respect the `build-mode` falling back to `static` if not defined.
472+
section = (
473+
"static" if "static" in build_options else info.get("build-mode", "static")
474+
)
475475
enabled_extensions[name]["build-mode"] = section
476476

477477
# Presumably this means the extension comes from the distribution's

0 commit comments

Comments
 (0)