AtlatestRepositorycore-channel

core-channel / tree / src / core / packagespython.sgl

1;;; CPython, packaged as a BUILD TOOL for this channel and nothing else.
2;;;
3;;; WHY A CHANNEL WITH NO PYTHON PROGRAMS IN IT NEEDS PYTHON. Three
4;;; independent consumers, and no choice of build system removes the first:
5;;;
6;;; 1. foot's own `meson.build` runs `python3` in three UNCONDITIONAL
7;;; custom_targets -- scripts/generate-builtin-terminfo.py,
8;;; scripts/generate-emoji-variation-sequences.py and the srgb generator.
9;;; They emit headers that foot then compiles. No option turns them off.
10;;; 2. meson is CPython.
11;;; 3. fontconfig's configure.ac is `AM_PATH_PYTHON([3])`.
12;;;
13;;; That is why muon -- the C reimplementation of meson -- was considered and
14;;; rejected. It removes consumer 2 and leaves 1 and 3.
15(define-library (core packages python)
16 (import (sigil core)
17 (core build-environments)
18 (core packages compression)
19 (sigil env package)
20 (sigil build external))
21 (export python)
22 (begin
23 (define python
24 (package
25 name: "python"
26 version: "3.13.7"
27 source: (external-source
28 location: "https://www.python.org/ftp/python/3.13.7/Python-3.13.7.tar.xz"
29 sha256: "5462f9099dfd30e238def83c71d91897d8caa5ff6ebc7a50f14d4802cdaaa79a")
30 buildenv: core-buildenv
31 ;; zlib is the one optional module worth having: `zipfile`, `shutil`'s
32 ;; archive support and `gzip` all reach for it, and it is already in
33 ;; the channel. Every other optional module -- ssl, readline, curses,
34 ;; sqlite3, ctypes, bz2, lzma -- is left to fail its probe, and in this
35 ;; sandbox that is an HONEST absence: there is no host filesystem for a
36 ;; probe to find something in, so nothing can be silently absorbed.
37 dependencies: (list zlib)
38 env: (list
39 ;; ---------------------------------------------------------
40 ;; STATIC MODULES. Everything this channel builds is linked
41 ;; statically and a static binary cannot dlopen. CPython's
42 ;; default is to build each stdlib extension as a shared object
43 ;; and load it at import, so left alone the interpreter starts
44 ;; and then dies on `import re` -- at RUN time, inside some
45 ;; other package's build, a very long way from here.
46 ;;
47 ;; Both switches are read from the ENVIRONMENT by configure,
48 ;; which is what makes this expressible without patching
49 ;; CPython:
50 ;;
51 ;; configure.ac:7684 MODULE_BUILDTYPE=${MODULE_BUILDTYPE:-shared}
52 ;; configure.ac:5156 if test -z "$DYNLOADFILE" ...
53 ;;
54 ;; Neither name is builder-owned, so neither is refused.
55 (cons "MODULE_BUILDTYPE" "static")
56 (cons "DYNLOADFILE" "dynload_stub.o")
57 ;; ---------------------------------------------------------
58 ;; THE -O2 / __DATE__ COLLISION, WHICH IS A PROPERTY OF THIS
59 ;; CHANNEL AND NOT OF CPYTHON. The builder hands every compile
60 ;; a response file whose first line is `-O2`, and zig cc turns
61 ;; ON -Werror=date-time whenever it optimizes. So ANY package
62 ;; here whose sources expand __DATE__ or __TIME__ fails to
63 ;; compile. CPython is merely the first one that does
64 ;; (Modules/getbuildinfo.c:14,22).
65 ;;
66 ;; Narrowed by elimination against this toolchain rather than
67 ;; guessed: `-g0`, `-ffile-prefix-map` and `-fdebug-prefix-map`
68 ;; each produce 0 date-time diagnostics; `-O2` alone produces 2,
69 ;; on the command line and inside a response file alike.
70 ;;
71 ;; Suppressing the guard is safe HERE, and the reason is
72 ;; measured: zig cc expands __DATE__ to "Jan 1 1970" and
73 ;; __TIME__ to "00:00:00" UNCONDITIONALLY. It does not honour
74 ;; SOURCE_DATE_EPOCH -- set to 1000000000 it still emits
75 ;; Jan 1 1970 -- and two independent compiles produced
76 ;; byte-identical executables. The macros are already
77 ;; deterministic and the diagnostic is a false positive. It
78 ;; exists for compilers where they are not.
79 ;;
80 ;; CFLAGS is builder-owned but APPENDABLE, and the package's
81 ;; value is emitted after the builder's, so this beats the
82 ;; response file's -O2 rather than replacing the dependency
83 ;; include flags.
84 (cons "CFLAGS" "-Wno-error=date-time")
85 ;; LDFLAGS, same append rule. Static because the sandbox binds
86 ;; no loader for a build input.
87 (cons "LDFLAGS" "-static"))
88 phases: (list
89 ;; THE SUPPRESSION ABOVE IS PAIRED WITH A CHECK THAT ASSERTS
90 ;; THE PROPERTY IT RELIES ON. Turning off a reproducibility
91 ;; diagnostic on the strength of "the toolchain pins those
92 ;; macros" is only honest if something notices when it stops.
93 ;; If a future toolchain emits the real date, this fails
94 ;; loudly and prints what it saw, rather than quietly
95 ;; producing an unreproducible interpreter -- which is
96 ;; exactly the failure -Wdate-time exists to prevent.
97 (external-phase
98 kind: 'run
99 args: (list "sh" "-c"
100 (string-append
101 "set -eu\n"
102 "echo '#include <stdio.h>' > dtcheck.c\n"
103 "echo 'int main(void){ printf(\"%s|%s\", __DATE__, __TIME__); return 0; }' >> dtcheck.c\n"
104 ;; ARM 1 -- COMPILED WITH $CFLAGS, which is the
105 ;; whole point. An earlier version of this gate
106 ;; ran a bare `$CC`, so it carried no
107 ;; `@compiler.flags` response file and therefore
108 ;; no `-O2` -- it vouched for a configuration
109 ;; CPython is not built in, while the comment
110 ;; above names `-O2` as the trigger. A gate that
111 ;; compiles under different flags than the code it
112 ;; certifies is asserting its author's
113 ;; expectations rather than the product.
114 "$CC $CFLAGS -Wno-error=date-time dtcheck.c -o dtcheck\n"
115 "v=$(./dtcheck)\n"
116 "echo \"TOOLCHAIN-DATE-MACROS=[$v]\"\n"
117 "test \"$v\" = \"Jan 1 1970|00:00:00\"\n"
118 ;; ARM 2 -- THE ARM THAT SEPARATES THE TWO
119 ;; EXPLANATIONS. The builder sets
120 ;; SOURCE_DATE_EPOCH=0, and epoch 0 renders as
121 ;; exactly "Jan 1 1970" / "00:00:00" -- the
122 ;; literal arm 1 compares against. So arm 1 alone
123 ;; is green under BOTH hypotheses: "the toolchain
124 ;; pins these macros unconditionally" (which is
125 ;; what licenses the -Wno-error above) and "clang
126 ;; is honouring the builder's epoch" (which would
127 ;; not license it, because the guarantee would
128 ;; then belong to a variable a future builder
129 ;; could stop setting).
130 ;;
131 ;; Overriding the epoch to a DIFFERENT instant
132 ;; discriminates: if the output moves, the macros
133 ;; track SOURCE_DATE_EPOCH and this package's
134 ;; justification is wrong.
135 "w=$(SOURCE_DATE_EPOCH=1000000000 ./dtcheck)\n"
136 "printf 'DATE-MACROS-UNDER-EPOCH-1000000000=[%s]\\n' \"$w\"\n"
137 "e=$(SOURCE_DATE_EPOCH=1000000000 $CC $CFLAGS -Wno-error=date-time dtcheck.c -o dtcheck2 && ./dtcheck2)\n"
138 "echo \"DATE-MACROS-RECOMPILED-UNDER-EPOCH=[$e]\"\n"
139 "test \"$e\" = \"Jan 1 1970|00:00:00\"\n"
140 "rm -f dtcheck dtcheck2 dtcheck.c\n"
141 "echo DATE-MACRO-PINNING-CONFIRMED\n")))
142 (external-phase
143 kind: 'configure
144 args: (list "--prefix=${out}"
145 "--disable-shared"
146 "--disable-test-modules"
147 "--with-ensurepip=no"))
148 (external-phase kind: 'make)
149 (external-phase kind: 'install))))))