BQN-based build system

This commit is contained in:
dzaima 2022-12-23 21:10:52 +02:00
parent efcc6a28be
commit d38316e670
12 changed files with 784 additions and 4 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ libcbqn.so
# build system things
/build/obj/
/build/obj2/
/build/singeliLocal
/build/replxxLocal
/build/bytecodeLocal

3
build/build Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
DIR="$(dirname $0)"
"$DIR/obj2/for_build" "$DIR/src/build.bqn" "$@"

View File

@ -13,7 +13,7 @@ depfile ← (At buildDir) •file.At filename∾".d"
prefix "si_" (`'.')/ •file.Name srcfile
# invoke singeli, which creates the result file
("-d" tmpfile "-o" resfile "-n" prefix srcfile) •Import siDir •file.At "singeli"
("-l", "gen=src/singeli/gen", "-d" tmpfile "-o" resfile "-n" prefix srcfile) •Import siDir •file.At "singeli"
# output dependency file
deps siDir•file.At¨ •file.Lines tmpfile

@ -1 +1 @@
Subproject commit 2fefe457b47005f1aff2e67f73bbef7eb9173833
Subproject commit f60a3c73450b8d5ae18bdc76f090b20437cf7ab2

545
build/src/build.bqn Executable file
View File

@ -0,0 +1,545 @@
#!build/obj2/for_build
# to emulate on makefile transition: NO_LDL → rm_lf=-ldl; no_fPIC → rm_f=-fPIC; something something PIE
Spawn, WaitForOne •Import "fork.bqn"
Serialize, Deserialize •Import "serialize.bqn"
# modes:
# 0: single string option
# 1: toggle
# 2: flag list
opts
0, "j", "4" # number of parallel jobs
1, "verbose", 0 # log more things
1, "rebuild", 0 # forcibly rebuild everything
# TODO clean
0, "CC", @ # the C compiler
0, "LD", @ # linker of the final binary; default 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 Singeli target deciding
0, "OUTPUT", "" # output location; default depends
2, "f", # C flags for CBQN files
2, "CCFLAGS", # flags for all C compiler & linker invocations
2, "lf", # linker flags
2, "LDFLAGS", # more linker flags (identical to lf)
2, "rm_f", # forcibly remove C compiler flag(s)
2, "rm_lf", # forcibly remove linker flag(s)
# also define the default OUTPUT value (default default being "BQN")
1, "shared", 0 # build a shared library; OUTPUT = "libcbqn.[so|dylib]"
1, "wasi", 0 # build with WASI; OUTPUT = "BQN.wasm"
1, "emcc", 0 # build with emscripten; OUTPUT = ".", is used as a directory
1, "FFI", @ # enable FFI through libffi; default ≡ ¬wasiemcc
1, "pkgconfig", 1 # attempt to use pkg-config to find libffi inclusion flags
1, "singeli", 0 # enable Singeli
1, "REPLXX", 0 # enable replxx
# TODO options for forcing around the bytecode/singeli/replxx directories
# CBQN toggles
1, "rtverify", 0
1, "heapverify", 0
1, "c", 0 # disable some default flags
1, "O3", @ # -O3; default ≡ ¬c
1, "g", @ # -g; default ≡ debug
1, "native", 0 # -march=native & use native arch as lower & upper bound for Singeli
1, "debug", 0 # -DDEBUG & -g
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] >opts
on Lowercase¨ on0
ot1 1=ot
ot2 2=ot
s1 '='¨ args # start of =
hs s1<¨args # has value
fl hs'+'=(0s1-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 -- "(¬kson)/ks}_assert_(´) kson
ci onks # index in option specification
{𝕊: "Error: Unexpected '+=' for '",ks˜/¬𝕩,"'"}_assert_(´) (ciot2)¬fl
Gr {(ot)ci𝕩}
gvs Gr vs # values for each option
{𝕊: "Error: Multiple values given for '",on˜/¬𝕩,"'"}_assert_(´) ot21¨gvs
{𝕊: "Error: Expected value to be provided for ",𝕩/ks}_assert_(¬´) (¬ciot1) ¬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<Lowercase 𝕩)gvs}
}
SH {
coe •SH{𝕊: 𝕩 {𝕊: "Error: Failed to spawn ",𝕨}_assert_ 0} 𝕩
Log(×) e
𝕩 {𝕊: "Error: ",𝕨," exited with error code ",•Repr 𝕩}_assert_(0=) c
o
}
rootDir •file.Parent2 •file.path
AtRoot rootDir•file.At
po { # parsed options
verbose, j, rebuildAll, output,
os, arch, native,
emcc, wasm, replxx, singeli,
bytecodeDir, replxxDir, singeliDir,
CBQNc, REPLXXc, Linker
custom GetOpt "c"
DOpt {@,𝕨 GetOpt 𝕩}
j •BQN GetOpt "j"
rebuildAll GetOpt "rebuild"
{𝕊: _verboseLog {Log𝕨𝔽𝕩𝕩}} verboseGetOpt "verbose"
Max1 {𝕩 {𝕊: ab2𝕩/𝕨 "Error: '",a,"' and '",b,"' cannot both be enabled"}_assert_(1+´) GetOpt¨ 𝕩}
Max1 "REPLXX""shared""wasi""emcc"
shared GetOpt "shared"
native GetOpt "native"
emcc GetOpt "emcc"
wasi GetOpt "wasi"
wasm wasiemcc
cc {emcc? "emcc"; "clang"} DOpt "CC"
cxx GetOpt "CXX"
ffi (¬wasm) DOpt "FFI"
debug GetOpt "debug"
singeli GetOpt "singeli"
replxx GetOpt "REPLXX"
uname ""{𝕊: Lowercase 1•SH1"""" "uname""-sm"} ´ (@GetOpt)¨ "os""arch"
InUname {𝕊: ´ 𝕩uname}
os Lowercase {InUname"linux"? "linux"; InUname"darwin"? "macos"; InUname"bsd"? "bsd"; "linux"} DOpt "os"
linuxbsdmacos os¨ {𝕊: "Error: Unsupported OS; options:"1", "¨𝕩}_assert_(os<) "linux""bsd""macos"
arch {'-'¨(('_'=𝕩)/)𝕩} Lowercase {InUname"x86_64"? "x86-64"; ´InUname¨"aarch64""arm64"? "aarch64"; "generic"} DOpt "arch"
{𝕊: "Error: Unsupported arch; options:"1", "¨𝕩}_assert_(arch <) "x86-64""aarch64""generic"
{𝕊: "Error: Cannot use Singeli on x86-64 without 'native'"}_assert_¬ (arch"x86-64")singeli¬native
{𝕊: "Error: Cannot use Singeli on generic arch"}_assert_¬ singeli arch"generic"
output GetOpt "OUTPUT"
output •wdpath•file.At {𝕊:
wasi? "BQN.wasm";
emcc? ".";
shared? "libcbqn." macos"so""dylib";
"BQN"
}("") output
exportSymbols ffishared
GetLibs { 𝕊:
getLibs {
¬ffi? ,;
GetOpt "pkgconfig"? 0= •SH1 "pkg-config""--exists""libffi"?
{SepArgs ¯1SH"pkg-config",𝕩,"libffi"}¨ "--cflags", "--libs";
, "-lffi"
}
}
SubmoduleDir "build"•file.At(@) {𝕨0?@; •file.Exists rAtRoot "build"•file.At 𝕩"Local"? r; 𝕩"Submodule"}
LogDir {𝕩@? 𝕨": not used"; 𝕨" directory: "AtRoot 𝕩}_verboseLog
bytecodeDir 1 SubmoduleDir "bytecode" "Bytecode" LogDir bytecodeDir
replxxDir replxx SubmoduleDir "replxx" "REPLXX" LogDir replxxDir
singeliDir singeli SubmoduleDir "singeli" "Singeli" LogDir singeliDir
{𝕊: "Output location: "𝕩}_verboseLog output
CBQNc { 𝕊:
isClang ´"clang"SH cc"--version" # TODO exclude from hash?
args
cc,
"-std=gnu11",
"-Wall", "-Wno-unused-function",
"-fms-extensions", "-ffp-contract=off", "-fno-math-errno", "-fvisibility=hidden",
"-DBYTECODE_DIR="•file.Name bytecodeDir,
"-DSINGELI="•Repr singeli,
"-DFFI="•Repr 2×ffi
args isClang
"-Wno-parentheses"
"-Wno-microsoft-anon-tag", "-Wno-bitwise-instead-of-logical", "-Wno-unknown-warning-option"
args 0GetLibs@
args GetOpt "f"
args GetOpt "CCFLAGS"
args ( wasm) / "-DWASM"
args ( wasi) / "-DWASI", "-DNO_MMAP", "-DCATCH_ERRORS=0", "-D_WASI_EMULATED_MMAN", "--target=wasm32-wasi"
args ( emcc) / "-DEMCC", "-O3"
args ( replxx) / "-DUSE_REPLXX", "-I"replxxDir"/include" # TODO maybe move to main.c only, and have it be in its own separate cache dir, so that adding replxx doesn't recompile everything?
args ( debug DOpt "g") / "-g"
args ((¬custom) DOpt "O3") / "-O3"
args ( native) / "-march=native"
args ( debug) / "-DDEBUG"
args ( GetOpt "color") / isClang"-fdiagnostics-color=always""-fcolor-diagnostics" # TODO exclude from hash?
args ( GetOpt "rtverify") / "-DRT_VERIFY", "-DEEQUAL_NEGZERO"
args (GetOpt "heapverify") / "-DHEAP_VERIFY"
args ( exportSymbols) / "-DCBQN_EXPORT"
args ( shared) / "-DCBQN_SHARED", "-shared", "-fPIC"
args args (¬/) GetOpt "rm_f"
{"CBQN C compiler: "•Repr 𝕩} _verboseLog args
cbqnc args
}
REPLXXc { 𝕊:
args cxx, "-DREPLXX_STATIC=1", "-I"replxxDir"/include"
args GetOpt "REPLXX_FLAGS"
{"REPLXX C++ compiler: "•Repr 𝕩} _verboseLog args
replxxc args
}
Linker { 𝕊:
args {replxx? cxx; cc} DOpt "LD", "-lm"
args 1GetLibs@
args (¬bsd) / "-ldl"
args GetOpt "lf"
args GetOpt "LDFLAGS"
args ( wasi) / "-lwasi-emulated-mman", "--target=wasm32-wasi", "-Wl,-z,stack-size=8388608", "-Wl,--initial-memory=67108864"
args ( emcc) / "-s", "EXPORTED_FUNCTIONS=_main,_cbqn_runLine,_cbqn_evalSrc", "-s", "EXPORTED_RUNTIME_METHODS=ccall,cwrap", "-s", "ALLOW_MEMORY_GROWTH=1"
args ( exportSymbols) / "-rdynamic"
args ( linux arch"x86-64") / "-no-pie"
args args (¬/) GetOpt "rm_lf"
{"linker: "•Repr 𝕩} _verboseLog args
linker args
}
{𝕊: CBQNc@ REPLXXcreplxx @ Linker@} verbose
}
Hash {(32"0a"+¨1026)˜{𝕨+2×𝕩}˝5321•bit._cast(4)•Hash¨<𝕩}
MkDir {•file.Exists𝕩?@; •file.CreateDir𝕩}
allObjDir "build/obj2"
MkDir AtRoot allObjDir
isFileTheSame {
ksvs
{
i ks<𝕨
i<ks? 𝕩 ivs;
ks <𝕨
vs <t•file.Modified 𝕨
𝕩 t
}
}
updateSubmodule {
done
{
𝕩@? @;
"Local"¯5𝕩? @;
𝕩<done? @;
done <𝕩
SH "git", "submodule", "update", "--init", AtRoot 𝕩
}
}
# gets/creates a directory of cacheable objects; key is the unique identifier of when it can be reused
GetCache { 𝕊 basenamedesckey:
hash Hash key
folder allObjDir•file.At basename"-"hash
MkDir AtRoot folder
File folder•file.At
{𝕊: desc": "AtRoot𝕩} _verboseLog folder
dataPath AtRoot File "data"
prevKsprevVs •file.Exists, {Deserialize 8'c',8•bit._cast •FBytes 𝕩} dataPath
IsUpToDate { 𝕊:
i prevKs<𝕩
i<prevKs?
{@:0; ´ AtRootIsFileTheSame´¨𝕩} iprevVs;
0
}
newKsnewVs
Update {key𝕊data: newKs <key newVs <data} # data≡@ means failed to build
onExitList {{ 𝕊:
jKs newKsprevKs
jVs newVsprevVs
dataPath •FBytes 8,8'c'•bit._cast Serialize (<jKs) /¨ jKsjVs
}{𝕊: 0newKs}}
}
ruleKsruleVs
AddRule { 𝕊 cachecacheKeydstGetCMDdispcustomDeps:
ruleKs <dst
ruleVs {
cache cache
cacheKey cacheKey
disp disp
CMD GetCMD
ruleDeps customDeps
}
}
# dependency resolution & thread management
Run { 𝕊:
ruleDeps {𝕩.ruleDeps}¨ ruleVs
ruleSrcs0 ruleKsruleDeps
! ´ ruleSrcs0<ruleKs
ruleSrcs ((˜¨/)ruleDeps) ruleSrcs0
req
ruleN 0¨ ruleKs # number of children (i.e. how many have this in their ruleP list)
ruleP ¨ ruleKs # parent rules (i.e. which ones require this)
rebuildAll po.rebuildAll
Require {
v 𝕩ruleVs
rebuild rebuildAll
chi 𝕩ruleSrcs
chr Require¨ chi
rebuild ´ chr
# rebuild↩ ¬•file.Exists AtRoot 𝕩⊑ruleKs # not really needed unless someone deletes a specific file without deleting the data file
rebuild ¬v.cache.IsUpToDate v.cacheKey
{
ruleN (+´chr)+(𝕩)
ruleP 𝕩¨((chr/chi))
req 𝕩
}rebuild 𝕩
rebuild
}
anyRebuilt Require ruleKs<𝕩
left (reqruleN=0)/req
RequestJob { 𝕊:
0=left? @;
(left˜ ¯1) ¯1left
}
FinishJob { i𝕊tb:
v iruleVs
Log(×) 1tb
{ 𝕊:
v.cacheKey v.cache.Update @
}
{ 𝕊:
v.cacheKey v.cache.Update 3tb
ps iruleP
ruleN -1(ps)
left (0=psruleN)/ps
}
tb
tb
}
threads Spawn(•file.At "runner.bqn")¨ (req)po.j
work
free threads
Ts {𝕩.t}¨
storedOut
Log {storedOut <𝕩@+10}
# Log ↩ {𝕊:1}
currLive
e @+27
UpdateLive {
•term.OutRaw ((0¯1+currLive)<(e"[2K"e"[1F")) (•ToUTF8 storedOut) 1((@+10)•ToUTF8)¨ 𝕩
•term.Flush @
currLive 𝕩
storedOut
}
FmtTime {{("""0" ¯1𝕩)'.'¯1𝕩} •Repr 0.5+ 10×𝕩}
onExitList {{𝕊: UpdateLive }}
tmap # threads in the order they're displayed on-screen (dynamically calculated so that if there's only ever only one job in parallel, there are no pointless empty lines)
doneCount 0
stopping 0
Fail {stopping1 Log 𝕩}
t0 •MonoTime@
DoneLine {𝕊: •Repr doneCount, "/", •Repr req}
{ 𝕊:
{𝕊:
t ¯1free free˜ ¯1
i RequestJob@ viruleVs
t.Request v.CMD@
work {tt, ii, vv, t0•MonoTime@}
}•_while_{𝕊: ´0<¨ leftfree}¬ stopping
t1 •MonoTime@
tmap tmapTs work
UpdateLive (<DoneLine@){
𝕩work? "";
o 𝕩work
"[", FmtTime t1-o.t0, "] ", o.v.disp
}¨ (Ts work) tmap
dm 0.1 WaitForOne Ts work
lm ¬dm
{𝕊: Fail "Error: Fork died" dmlm<dm¯1} ´dm=¯1
done dm/work
work lm/work
{𝕩.i FinishJob 𝕩.t.Take@? doneCount+1; Fail "Error: During '"𝕩.v.disp"'"}¨ done
free Ts done
}•_while_{𝕊: (0<work) (¬stopping)0<left}@
Log DoneLine@, " in ", FmtTime t0-˜•MonoTime@, "s", stopping/"; failed to build"
¬stopping
}
MakeCCInv { 𝕊 GetArgsInitcacheidsrccustomDeps: # src should be CBQN-base-dir-relative, so that cache doesn't store
key id
dst cache.File key".o"
GetCMD { 𝕊:
Init @
dep AtRoot cache.File id".d"
"sh", rootDir, (GetArgs@)"-MT", "o", "-MMD", "-MF", dep, "-o", AtRoot dst, "-c", src, dep
}
AddRule cache, key, dst, GetCMD, •file.Name src, customDeps
}
MakeSingeliInv { 𝕊 argsInitcacheidsrccustomDeps: # src should be CBQN-base-dir-relative, so that cache doesn't store
key id
dst cache.File key".c"
GetCMD { 𝕊:
Init @
dep AtRoot cache.File id".d"
"singeli", rootDir, AtRoot dst, AtRoot po.singeliDir, args, AtRoot src, dep
}
AddRule cache, key, dst, GetCMD, •file.Name src, customDeps
}
MakeLinkerInv { 𝕊 GetArgscachenamesrcs:
dst cache.File name
GetCMD { 𝕊:
args GetArgs@
"sh", rootDir, args, "-o", dstsrcs1args, @
}
AddRule cache, name, dst, GetCMD, "link", srcs
}
# actual CBQN/Singeli/REPLXX definitions
cachedBinlinkerCache {
Shorten {r {𝕩˜¯1-'.'˜𝕩}¨ •file.Name¨ 𝕩 ! ´ r r}
cbqnSrc {(𝕩)•file.At¨ 1𝕩}¨
"src/builtins/", "arithd.c", "arithm.c", "cmp.c", "sfns.c", "squeeze.c", "select.c", "slash.c", "group.c", "sort.c", "search.c", "selfsearch.c", "fold.c", "scan.c", "md1.c", "md2.c", "fns.c", "sysfn.c", "internal.c", "inverse.c"
"src/core/", "tyarr.c", "harr.c", "fillarr.c", "stuff.c", "derv.c", "mm.c", "heap.c"
"src/", "load.c", "main.c", "rtwrap.c", "vm.c", "ns.c", "nfns.c", "ffi.c"
"src/jit/", "nvm.c"
"src/utils/", "utf.c", "hash.c", "file.c", "mut.c", "each.c", "bits.c"
singeliMap
"src/core/stuff.c""equal", "src/utils/mut.c""copy", "src/utils/bits.c""bits"
"src/builtins/arithd.c""dyarith", "src/builtins/cmp.c""cmp", "src/builtins/squeeze.c""squeeze"
"src/builtins/select.c""select", "src/builtins/fold.c""fold", "src/builtins/scan.c""scan"
"src/builtins/scan.c""neq", "src/builtins/slash.c""slash", "src/builtins/slash.c""constrep"
objs
replxxCache {
¬po.replxx? @;
replxxCache GetCache "replxx", "REPLXX object file location", po.REPLXXc@
replxxSrc (po.replxxDir•file.At"src")•file.At¨"ConvertUTF.cpp", "wcwidth.cpp", "conversion.cxx", "escape.cxx", "history.cxx", "prompt.cxx", "replxx.cxx", "replxx_impl.cxx", "terminal.cxx", "util.cxx", "windows.cxx"
objs {𝕩.dst}¨ (Shorten replxxSrc) {MakeCCInv po.REPLXXc, , replxxCache, 𝕨, 𝕩, }¨ replxxSrc
replxxCache
}
singeliObjs @
singeliCache {
¬po.singeli? @;
singeliCache GetCache "singeli", "Singeli generated code location", po.native, po.arch
# genArithTables
ga "src/singeli/src/genArithTables.bqn"
gaDefs singeliCache.File "arDefs.singeli"
gaTables singeliCache.File "arTables.c"
AddRule
singeliCache, "genArithTables",
gaDefs, # am cheating and only using arDefs.singeli as destination; ¯\_(ツ)_/¯
{𝕊: "runbqn", rootdir, AtRoot ga, AtRoot¨ gaDefsgaTables, ga},
•file.Name ga,
singeliArgs "-l", "gen="singeliCache.folder{
po.native? ;
"-a" {"x86-64":"X86_64"; "aarch64":"AARCH64"} po.arch
}
singeliObjs {𝕩.dst}¨ {MakeSingeliInv singeliArgs, {𝕊:UpdateSubmodule po.singeliDir}, singeliCache, 𝕩, "src/singeli/src/"•file.At 𝕩".singeli", (𝕩"dyarith")/gaDefs}¨ 1¨singeliMap
singeliCache
}
cbqnCache {
cbqnCache GetCache "cbqn", "CBQN object file location", po.CBQNc@, {po.singeli? singeliCache.hash; @}
ruleDeps {
¬po.singeli? ¨ cbqnSrc;
((cbqnSrc) ˜ cbqnSrc¨singeliMap) singeliObjs
}
singeliArgs {po.singeli? "-DSINGELI_DIR="•file.Name singeliCache.folder; }
objs {𝕩.dst}¨ {abc: MakeCCInv po.CBQNcsingeliArgs˙, {𝕊:UpdateSubmodule po.bytecodeDir UpdateSubmodule po.replxxDir}, cbqnCache, a, b, c}¨ <˘[Shorten cbqnSrc, cbqnSrc, ruleDeps] # updates replxx because needs replxx.h
cbqnCache
}
linkerCache GetCache "linker", "linker cached result location",
po.Linker@,
cbqnCache.hash,
{po.replxx? replxxCache.hash; @}
{po.singeli? singeliCache.hash; @}
res MakeLinkerInv po.Linker, linkerCache, {po.emcc? "BQN.js"; "res"}, objs
res.dst linkerCache
}
outPath •wdpath •file.At po.output
{ 𝕊:
po.emcc?
SH "cp", AtRoot cachedBin, outPath •file.At •file.Name cachedBin
SH "cp", AtRoot linkerCache.File "BQN.wasm", outPath •file.At "BQN.wasm"
;
SH "cp", AtRoot cachedBin, outPath
} Run cachedBin
OnExit@

110
build/src/fork.bqn Normal file
View File

@ -0,0 +1,110 @@
sz"u64" ssz"i64" nfdssz
libc_fork @ •FFI "i32""fork"
libc_pipe @ •FFI "i32""pipe"">&i32"
libc_read @ •FFI ssz"read""i32""&i8"sz
libc_write @ •FFI ssz"write""i32""*i8"sz
libc_close @ •FFI "i32""close"">i32"
libc_poll @ •FFI "i32""poll""&i16"nfds"i32"
Pipe { 𝕊: readfdwritefd
c, readfdwritefd Libc_pipe 00
! c=0
Write {Libc_write writefd, 𝕩, 𝕩}
Read {nb Libc_read readfd, 𝕩0, 𝕩 !n0 nb}
}
BiDiFork { 𝕊:
p1 Pipe@
p2 Pipe@
pid Libc_fork@
! pid0
parent pid=0
CloseWR {! ¬´ Libc_close¨ {𝕨.writefd𝕩.readfd}´ parent 𝕩}
CloseWR p1p2
rw parent p1p2
Readreadfd r
Writewritefd w
Close CloseWRp2p1
}
FFn { 𝕊 fn:
f BiDiFork@
{f.parent? Fn f f.Close@ •Exit 0; f}
}
WriteAll {p𝕊x: {𝕩-p.Write 𝕩-x}•_while_× x}
_readAll {p E _𝕣 n: (¬=) {vp.Read n-𝕩 0<v? 𝕩v; <E"eof"}•_while_(=n) 0}
WriteSz {
𝕨 WriteAll (328•bit._cast 𝕩)𝕩
}
_readSz { 𝔽_𝕣 s:
r s <𝔽 _readAll 4
{
=r? n 832•bit._cast r s !_readAll n;
r
}
}
SerializeDeserialize •Import "serialize.bqn"
c_make 1
c_request 2
c_take 3
c_one 4
control FFn {{ 𝕊 control:
pidsprocs ˜
{𝕊:
tycmd Deserialize •Exit _readSz control
ty !
{ 𝕊program: # c_make
p FFn {{ 𝕊 p:
f •file.Parent program, •file.Name program •BQN •FChars program
{𝕊: p WriteSz Serialize F Deserialize •Exit _readSz p}•_while_ 1@
}}
control WriteAll 328•bit._cast p.pid
pids <p.pid
procs <p
}
{ 𝕊piddata: # c_request
p (pidspid)procs
p WriteSz data
}
{ 𝕊pid: # c_take
p (pidspid)procs
control WriteSz !_readSz p
}
{ 𝕊limitsel: # c_one
ms limit×1e3
"poll time limit too large" ! (ms) ms<231
p (pidssel)procs
fds {𝕩.readfd}¨ p
retres Libc_poll 10˘ 3216•bit._cast ˘fds fds ¯1 ms
! ret0
control WriteSz Serialize {¯1¨((¬𝕩01)/)𝕩} ¯1˘4res
}
cmd
}•_while_ 1@
}}
AskControl {control WriteSz Serialize 𝕨𝕩}
Spawn {
c_make AskControl 𝕩
pid 832•bit._cast control !_readAll 4
{
pidpid
Request {c_request AskControl pidSerialize 𝕩}
Take {𝕊: c_take AskControl pid Deserialize !_readSz control}
}
}
# 𝕩: list of spawn results to wait on
# 𝕨: if present, maximum time to wait; 0 to return immediately
# result: boolean mask of which have finished (if 𝕨 isn't given, guaranteed to have at least one `1`)
WaitForOne {
c_one AskControl 𝕨 {𝕩.pid}¨ 𝕩
Deserialize !_readSz control
}

57
build/src/runner.bqn Normal file
View File

@ -0,0 +1,57 @@
chdir @•FFI"i32""chdir"">*u8:c8"
Split {𝕩˜(-˜+`׬)𝕩=𝕨}
SimplifyPath {
1'/'¨ {(××) ` +` ¬- ".."¨𝕩}/ "."¨/ '/'Split𝕩
}
Good { 𝕊 dirt0t1oedeps:
1, oe, t1-t0, deps ¨ (•file.Modified dir•file.At)¨ deps
}
_runSingeli_ { runArgs GetDeps _𝕣_ dir runFile:
t0 •MonoTime@
e@ deps@
{𝕊:
runArgs •Import runFile
deps GetDeps@
}{𝕊: e•CurrentError@} @
t1 •MonoTime@
{
e@? 0, e;
Good dir,t0,t1,"","",deps
}
}
{
"sh"dircmddepf:
t0 •MonoTime@
Chdir @˜ •ToUTF8 dir
coe •SH cmd
t1 •MonoTime@
{
0: @depf?
Good dir,t0,t1,o,e,;
0:
deps •FLines depf
deps {𝕩/˜1»`'\'=¯1¨𝕩} # remove all but the initial rule
deps {𝕩˜1+𝕩':'} # remove rule name
deps ¯1¨(¯1) # remove trailing backslashes
deps ({𝕩/˜¬`𝕩=' '})2¨ # trim whitespace from both sides
deps (' 'Split¨) # split each on spaces
deps {¬´"/build/obj2/"𝕩}¨/ # remove autogenerated dependencies, those are handled manually
deps SimplifyPath¨ # remove "."s & ".."s
deps {dir<𝕩? dir(dir)𝕩? (dir)𝕩; 𝕩}¨ # relativize
Good dir,t0,t1,o,e,deps;
# c≠0:
0, oe
} c
;
"singeli"dirdstsingeliDirargssrcdep:
prefix "si_" (`'.')/ •file.Name src
argsFinal args"-d" dep "-o" dst "-n" prefix src
argsFinal {𝕊: src< SimplifyPath¨ singeliDir•file.At¨ •FLines dep}_runSingeli_ dir singeliDir •file.At "singeli"
;
"runbqn"dirfileargsdeps:
args deps _runSingeli_ dir file
;
0"unknown command"
}

54
build/src/serialize.bqn Normal file
View File

@ -0,0 +1,54 @@
eltype2bit 1,8,16,32,64,8'c',16'c',32'c'
eltypeWidth 1,1,2,4,8,1,2,4
SStep •Type
{
𝕩 •internal.Squeeze
eltype •internal.ElType𝕩
ר/
0, eltype
328•bit._cast =𝕩
648•bit._cast 𝕩
{
eltype=8? SStep¨ 𝕩;
eltypeeltype2bit, 8•bit._cast (8×·÷8˙)(0=eltype) 𝕩
}𝕩
}
{ 1, 648•bit._cast𝕩 }
{ 2, 328•bit._cast𝕩 }
{𝕊:!"Cannot serialize functions"}
{𝕊:!"Cannot serialize 1-modifiers"}
{𝕊:!"Cannot serialize 2-modifiers"}
{𝕊:!"Cannot serialize namespaces"}
Serialize {
lists
{0=•Type𝕩? 𝕊¨𝕩; lists<𝕩 1} SStep 𝕩
lists
}
Deserialize {
s𝕩
off0
Next {r𝕩offs off+𝕩 r}
Read { 𝕊:
type Next 1
type
{𝕊:
et Next 1
rank 832•bit._cast Next 4
shape 864•bit._cast Next rank×8
shape{
et=8? Read¨ ×´shape;
8, eteltype2bit•bit._cast Next (÷8)(0=et) (eteltypeWidth)×´shape
}
}
{𝕊: 8, 64 •bit._cast Next 8}
{𝕊: 8, 32'c'•bit._cast Next 4}
@
}
r Read@
off=s? r;
! "invalid input: data after end"
}

View File

@ -37,6 +37,8 @@ shared-o3:
@${MAKE} i_OUTPUT=libcbqn.so i_SHARED=1 i_t=shared_o3 i_f="-O3" run_incremental_0
shared-c:
@${MAKE} i_OUTPUT=libcbqn.so i_SHARED=1 custom=1 run_incremental_0
forbuild:
@${MAKE} i_singeli=0 i_t=forbuild i_f="-O2" i_FFI=2 i_OUTPUT=build/obj2/for_build i_f='-DFOR_BUILD' run_incremental_0
c:
@${MAKE} custom=1 run_incremental_0
@ -179,6 +181,9 @@ single-c:
# actual build
run_incremental_0:
ifeq ($(i_t),forbuild)
mkdir -p build/obj2
endif
ifeq ($(verbose),1)
@echo "build directory: $$(${MAKE} builddir)"
@echo " bytecode: build/$(BYTECODE_DIR)"

View File

@ -352,4 +352,5 @@ static NOINLINE B or_SA(B t, B w, B x) {
return r;
}
#include "../gen/arTables.c"
#define SINGELI_FILE arTables
#include "../../utils/includeSingeli.h"

View File

@ -189,4 +189,4 @@ andBytes{vw}(r: *u8, x: *u8, maskU64:u64, len:u64) : void = {
'avx2_andBytes'=andBytes{256}
'orSAc_f64_f64_f64'=arithSA{2,bqn_or,0,f64,f64,f64}
include './../gen/arDefs'
include 'gen/arDefs'

View File

@ -19,7 +19,11 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#ifdef SINGELI_DIR
#include SINGELI_FILE1(../../build/obj2/SINGELI_DIR/SINGELI_FILE.c)
#else
#include SINGELI_FILE1(../singeli/gen/SINGELI_FILE.c)
#endif
#pragma GCC diagnostic pop
#undef SINGELI_FILE