AtlatestRepositorycore-channel
core-channel / tree / src / core / packagesluajit.sgl
1
;;; LuaJIT.2
;;;3
;;; PROVENANCE: READ THIS BEFORE PUBLISHING OR SIGNING ANYTHING HERE.4
;;;5
;;; This package is pinned to a GIT COMMIT fetched as a GitHub auto-generated6
;;; archive, because LuaJIT PUBLISHES NO RELEASE TARBALL OF ANY KIND -- no7
;;; release assets, and luajit.org's download page links only to git8
;;; repositories. Its last tag is v2.1.0-beta3 from 2017; every distribution9
;;; pins a commit.10
;;;11
;;; That is a WEAKER provenance than anything else in this channel, and it is a12
;;; deliberate, scoped exception rather than a precedent. The rule it appears13
;;; to break -- that a synthetic archive whose bytes can be regenerated does14
;;; not belong on a critical path -- was set for a chain INTENDED TO SHIP.15
;;; This package and `core/swayimg` exist for a different reason: they are a16
;;; DISCOVERY EXERCISE whose product is knowledge about what this packaging17
;;; model can and cannot host. Two auto-generated archives are acceptable for18
;;; that and would not be acceptable for a shipped chain.19
;;;20
;;; SO: NEITHER THIS PACKAGE NOR `core/swayimg` SHOULD BE PUBLISHED OR SIGNED21
;;; ON THIS PROVENANCE WITHOUT REVISITING THE QUESTION. If LuaJIT is ever22
;;; wanted for real, the question to answer first is what artifact to pin, not23
;;; how to build it -- building it is solved, below.24
(define-library (core packages luajit)25
(import (sigil core)26
(core build-environments)27
(sigil env package)28
(sigil build external))29
(export luajit)30
(begin31
;; THE ONE THING THAT STOPPED IT BUILDING, and it is a property of the32
;; CHANNEL rather than of LuaJIT.33
;;34
;; Everything that looks hard about building a JIT under a foreign35
;; toolchain worked first time: minilua bootstrapped, DynASM generated36
;; x86-64 assembly, clang's integrated assembler consumed it, and37
;; `libluajit.a` linked. Only the FINAL EXECUTABLE link failed:38
;;39
;; ld.lld: error: undefined symbol: _Unwind_SetIP40
;; ld.lld: error: undefined symbol: _Unwind_GetIP41
;; ld.lld: error: undefined symbol: _Unwind_RaiseException42
;; ld.lld: error: undefined symbol: __register_frame43
;; ld.lld: error: undefined symbol: __deregister_frame44
;;45
;; The builder's LDFLAGS ships no DWARF unwinder. The toolchain HAS one46
;; (zig's `lib/libunwind`); it is simply not linked by default. All five47
;; symbols were confirmed present in `-lunwind` INDIVIDUALLY -- the last48
;; two are a different family, the GCC JIT frame-registration entry points,49
;; and a control on only the first would not have covered them.50
;; [[topics/core-channel-links-no-dwarf-unwinder]]51
;;52
;; `TARGET_XLIBS` is EXTENDED, not replaced: its default is `-lm`, and53
;; dropping that would break the link for a different reason.54
(define luajit55
(package56
name: "luajit"57
version: "2.1.1787165859"58
source: (external-source59
location: "https://codeload.github.com/LuaJIT/LuaJIT/tar.gz/1ee778a4e37122d8ca7d5733c590a47dafd6b15c"60
sha256: "512cdb23dafa39c6247763ae15f29341734b1596067b067db0c0387bbebc7c55")61
buildenv: core-buildenv62
phases: (list63
;; WHY `run` PHASES AND NOT `make`/`install` PHASES, which64
;; would be shorter.65
;;66
;; LuaJIT's src/Makefile:29 says `CC= $(DEFAULT_CC)`. A67
;; MAKEFILE assignment beats the ENVIRONMENT in make's68
;; precedence rules, so the builder's `CC` is silently69
;; ignored and LuaJIT compiles with its own default -- which70
;; is not the channel's target-explicit wrapper. Only a71
;; command-line assignment beats a makefile one.72
;;73
;; But a `make` phase's arguments are shell-quoted74
;; individually, so `CC=$CC` would be passed as that literal75
;; four-character string rather than expanded. And writing76
;; the compiler's NAME here would defeat the invariant that77
;; the compiler is DERIVED from the derivation's target --78
;; the same invariant `build-environment-assignments` refuses79
;; an `env: CC=` override to protect.80
;;81
;; A `run` phase with `sh -c` is the honest way out: the82
;; shell expands `$CC`, so this FORWARDS whatever the builder83
;; set without naming it. Note `$CC` and not `${CC}` --84
;; braces are intercepted by sigil's own interpolation before85
;; any shell sees them.86
(external-phase87
kind: 'run88
args: (list "sh" "-c"89
(string-append90
"set -eu\n"91
"echo \"LUAJIT-FORWARDED-CC=[$CC]\"\n"92
"make -j\"$(nproc 2>/dev/null || echo 4)\""93
" CC=\"$CC\" HOST_CC=\"$CC\""94
" BUILDMODE=static"95
" TARGET_XLIBS=\"-lm -lunwind\""96
;; `TARGET_STRIP=copy-strip` BECAUSE THE SEED HAS97
;; NO `strip`. LuaJIT's link rule ends with98
;; `$(TARGET_STRIP) $@`, which dies:99
;;100
;; make[1]: strip: No such file or directory101
;; make[1]: *** [Makefile:754: luajit] Error 127102
;;103
;; Another instance of the family this channel104
;; keeps meeting -- `yacc`, `file`, `gperf`,105
;; `python3` -- except this one fails LOUDLY with106
;; 127 rather than producing a confident wrong107
;; answer, which is the better direction.108
;;109
;; Nothing needs to be packaged for it: the110
;; binary is ALREADY stripped, because the111
;; builder's LDFLAGS carries `-s`. A second pass112
;; would be redundant even if the tool existed.113
;; `copy-strip` is the toolchain's own no-op114
;; stand-in for exactly this shape115
;; (toolchain/setup.sh writes it); invoked with a116
;; single argument and no `-o`, it validates the117
;; input and does nothing.118
" TARGET_STRIP=copy-strip"119
"\n"120
"echo LUAJIT-BUILT\n")))121
;; `install` re-enters make, whose INSTALL_DEP is122
;; `src/luajit` -- so it must be invoked with the same CC or123
;; a stale-dependency check could relink with the wrong124
;; compiler. Same forwarding, same reason.125
;;126
;; LuaJIT wants `PREFIX` (uppercase); the builder's `install`127
;; phase supplies lowercase `prefix`, which LuaJIT ignores.128
;; It does honour `DESTDIR`, which is derived here from the129
;; phase's cwd as everywhere else in this channel.130
(external-phase131
kind: 'run132
args: (list "sh" "-c"133
(string-append134
"set -eu\n"135
"d=\"$(dirname \"$PWD\")/install-root\"\n"136
"make install"137
" CC=\"$CC\" HOST_CC=\"$CC\""138
" BUILDMODE=static"139
" TARGET_XLIBS=\"-lm -lunwind\""140
" TARGET_STRIP=copy-strip"141
" PREFIX=\"${out}\" DESTDIR=\"$d\"\n"142
"echo LUAJIT-INSTALLED\n")))143
;; ASSERT THE ARTIFACT BEHAVIOURALLY, not by existence.144
;;145
;; `test -x bin/luajit` would pass on a binary that cannot146
;; run. What is actually in question for an147
;; assembly-generating build under a foreign toolchain is148
;; whether the JIT WORKS -- so run a loop big enough to be149
;; compiled and check the JIT is still enabled afterwards.150
;; `jit ~= nil` alone only proves the module exists.151
(external-phase152
kind: 'run153
args: (list "sh" "-c"154
(string-append155
"set -eu\n"156
"d=\"$(dirname \"$PWD\")/install-root\"\n"157
"lj=\"$d${out}/bin/luajit\"\n"158
"test -x \"$lj\"\n"159
"v=$(\"$lj\" -e 'io.write(6*7)')\n"160
"echo \"LUAJIT-ARITHMETIC=[$v]\"\n"161
"test \"$v\" = 42\n"162
"s=$(\"$lj\" -e 'local n=0 for i=1,2e6 do n=n+i end io.write(n,\"|\",tostring(jit.status()))')\n"163
"echo \"LUAJIT-HOTLOOP=[$s]\"\n"164
"test \"$s\" = '2000001000000|true'\n"165
;; The `.pc` matters: swayimg finds this through166
;; `dependency('luajit')`, and it must land in167
;; lib/pkgconfig because this channel composes168
;; PKG_CONFIG_PATH from exactly that directory.169
"test -f \"$d${out}/lib/pkgconfig/luajit.pc\"\n"170
"echo LUAJIT-VERIFIED\n"))))))))