t0g ← •MonoTime@ #!build/obj2/for_build # to emulate on makefile transition: NO_LDL → rm_lf=-ldl; no_fPIC → rm_f=-fPIC; something something PIE # todo: # clean # clangd commands generation # forcing bytecode/singeli/replxx directories to whatever's applicable # when adding `make forbuild` in build/build, make it run a sanity check of the output before copying to build/obj2/for_build ⟨Spawn, WaitForOne⟩ ← ⟨⟩ •Import "fork.bqn" ⟨Serialize, Deserialize⟩ ← •Import "serialize.bqn" # modes: # 0: single string option # 1: toggle # 2: flag list opts ← ⟨ ⟨0, "j", @, "Number of parallel jobs"⟩ ⟨1, "verbose", 0, "Log more things"⟩ ⟨1, "rebuild", 0, "Forcibly rebuild everything"⟩ ⟨1, "notui", 0, "disable live-updating status display"∾@+10⟩ ⟨0, "CC", @, "The used C compiler"⟩ ⟨0, "LD", @, "Linker of the final binary; defaults to CC, or CXX if REPLXX=1"⟩ ⟨1, "color", 1, "Whether to enable colored diagnostics"⟩ ⟨0, "os", @, "Target OS (linux, bsd, macos)"⟩ # used for .so vs .dylib, and changing linker flags for bsd ⟨0, "arch", @, "Target architecture (x86-64, aarch64, generic)"⟩ # used for selecting Singeli target ⟨1, "pie", @, "Position-independent executable; default based on OS & arch"∾@+10⟩ ⟨0, "OUTPUT", "", "Output location; defaults to ./BQN for regular builds"⟩ ⟨2, "f", ⟨⟩, "C flags for CBQN files"⟩ ⟨2, "CCFLAGS", ⟨⟩, "flags for all C compiler & linker invocations"⟩ ⟨2, "lf", ⟨⟩, "linker flags"⟩ ⟨2, "sf", ⟨⟩, "Singeli flags"⟩ ⟨2, "LDFLAGS", ⟨⟩, @⟩ ⟨2, "rm_f", ⟨⟩, "forcibly remove C compiler flag(s)"⟩ ⟨2, "rm_lf", ⟨⟩, "forcibly remove linker flag(s)"⟩ ⟨0, "v", @, "Version to report by --version; 'v=' to use git commit"∾@+10⟩ ⟨1, "shared", 0, "build a shared library; default output is libcbqn.[so|dylib]"⟩ ⟨1, "wasi", 0, "build with WASI; default output name is BQN.wasm"⟩ ⟨1, "emcc", 0, "build with emscripten; outputs BQN.wasm & BQN.js in a folder"⟩ ⟨1, "FFI", @, "Enable FFI through libffi; On by default, except for WASM builds"⟩ ⟨1, "pkgconfig", 1, "Attempt to use pkg-config to find libffi flags"⟩ ⟨1, "singeli", 0, "Enable compilation with Singeli"⟩ ⟨1, "replxx", 0, "Enable REPLXX"∾@+10⟩ ⟨1, "c", 0, "Disable some default flags"⟩ ⟨1, "O3", @, "Use '-O3'; On by default unless 'c=1'"⟩ ⟨1, "native", @, "Use '-march=native'"∾@+10⟩ ⟨1, "debug", 0, "Debug: '-DDEBUG -g'; enables various sanity checks"⟩ ⟨1, "g", @, "Debug: '-g'; enable debug symbols"⟩ ⟨1, "rtverify", 0, "Debug: compare builtin results with the self-hosted runtime"⟩ ⟨1, "heapverify", 0, "Debug: check reference count correctness"∾@+10⟩ ⟨0, "CXX", "c++", "C++ compiler (for replxx)"⟩ ⟨2, "REPLXX_FLAGS", ⟨"-std=c++11", "-Os"⟩, "default replxx C++ build flags"⟩ ⟩ Log ← •Out _verboseLog ← {𝔽_𝕣:⊢} onExitList ← ⟨⟩ OnExit ← {𝕊: {𝕏@}¨ onExitList} _assert_ ← { 𝔾𝕩?𝕩; Log 𝕨𝔽𝕩 ⋄ OnExit@ ⋄ •Exit 1} SepArgs ← {' ' ((¬-˜⊢×·+`»⊸>)∘≠⊔⊢) 𝕩} Lowercase ← {𝕩 - (-´"Aa")×(𝕩≥'A')∧𝕩≤'Z'} getOpt ← { args ← ×∘≠¨⊸/ •args [ot, on0, od, oh] ← ⍉>opts on ← Lowercase¨ on0 {𝕊: •Out "Usage: path/to/cbqn/build/build [options] Options are specified as arguments of 'key=value'. Keys are case-insensitive. Toggles without a value implicitly enable it; e.g. 'singeli' is 'singeli=1'. For flag lists, 'k=v' will split on spaces, i.e. 'f=-a -b' adds two flags, whereas 'f+=-a -b' adds one flag that contains a space. Options: "∾∾oh {" "∾𝕩∾" "∾𝕨∾@+10}¨○((@≢¨oh)⊸/) (⌈´≠¨)⊸(↑¨)on0 •Exit 0 }⍟⊢ ∨´ "help"‿"h"‿"?"∊'-'⊸≠⊸/¨ •args ot1 ← 1=ot ot2 ← 2=ot s1 ← ⊑∘⊐⟜'='¨ args # start of = hs ← s1<≠¨args # has value fl ← hs∧'+'=(0⌈s1-1)⊑¨args # is appended flag, i.e. "f+=a b c" s0 ← s1-fl # end of key ks ← s0↑¨args # keys ks Lowercase¨↩ # lowercase keys vs ← (1+s1)↓¨args # values {𝕊: ∾⟨"Unknown option -- '",⊑(¬ks∊on)/ks, "'; see --help for options"⟩}_assert_(∧´) ks∊on ci ← on⊐ks # index in option specification {𝕊: ∾⟨"Error: Unexpected '+=' for '",ks⊑˜⊑/¬𝕩,"'"⟩}_assert_(∧´) (ci⊏ot2)∨¬fl Gr ← {(≠ot)↑ci⊔𝕩} gvs ← Gr vs # values for each option {𝕊: ∾⟨"Error: Multiple values given for '",on⊑˜⊑/¬𝕩,"'"⟩}_assert_(∧´) ot2∨1≥≠¨gvs {𝕊: ∾⟨"Error: Expected value to be provided for ",⊑𝕩/ks⟩}_assert_(¬∨´) (¬ci⊏ot1) ∧ ¬hs # f='a b' f+='c d' → "a" "b" "c d" gvs ↩ (Gr fl) (∾{𝕨?⋈𝕩;×≠𝕩?SepArgs 𝕩;⋈⟨⟩}¨)¨⌾(ot2⊸/) gvs # map toggles to their actual values, error on invalid gvs ↩ on {𝕨{𝕊: ∾⟨"Error: Invalid value for '",𝕨,"'"⟩}_assert_⊢ ∧´𝕩∊""‿"0"‿"1" ⋄ ≠◶⊢‿(⋈"0"≢⊑) 𝕩}¨⌾(ot1⊸/) gvs gvs ↩ ((¬ot2) ⋈∘⊢⍟⊣¨ od) {×≠𝕩?𝕩;𝕨}¨ gvs # map in defaults gvs ↩ (¬ot2) ⋈⁼∘⊢⍟⊣¨ gvs # disclose options with only one expected result # •Show [ks, fl, hs, ci, vs] # •Show {𝕩/˜×(≠1⊑⊢)˘𝕩} ⍉[on, gvs] {(⊑on⊐nextRedraw-0.02 dm ← (0.1⌊nextRedraw-t1) WaitForOne Ts work lm ← ¬dm {𝕊: Fail "Error: Fork died" ⋄ dm‿lm∧↩