# build.ludic — building the toolchain binaries and user programs. # # Replaces build-cli.sh (the ludicc/ludic front-end) and build.sh (compiling a # Ludic program to a native app). All toolchain binaries land in bin/. # compile a Ludic source to a native binary in bin/ via ludicc + clang (-O2). # Returns true on success. Used for x itself and the editor tools. function build_tool(name: pointer, src: pointer) -> bool { let ll = `build/{name}.ll` if not shq(`bin/ludicc {src} --emit-llvm -o {ll} 2>/dev/null`) { print(`build failed: {name} (compile)`); return false } # write to a temp then move, so a running bin/x can rebuild itself in place if not shq(`{cc()} -O2 {ll} -o bin/{name}.tmp`) { print(`build failed: {name} (link)`); return false } run(`mv -f bin/{name}.tmp bin/{name} && rm -f {ll}`) return true } # ---- build-cli: the self-hosted front-end binaries --------------------------- # Both ludicc and ludic are the SAME multi-call binary assembled from the IR seed # with clang alone; invoked as `ludic` it compiles-and-runs, as `ludicc` it just # compiles. function cmd_build_cli() -> int { run("mkdir -p bin build") print("cc: selfhost/ludicc.seed.ll -> bin/ludicc, bin/ludic (from the IR seed, no C compiler)") if not shq(`{cc()} selfhost/ludicc.seed.ll -o bin/ludicc`) { err("x: seed did not assemble\n"); return 1 } run("cp bin/ludicc bin/ludic && chmod +x bin/ludicc bin/ludic") print("done. built bin/ludicc and bin/ludic") return 0 } # ---- build: the whole toolchain (ludicc, ludic, x, ludic-fmt, ludic-lsp) ----- function cmd_build() -> int { if cmd_build_cli() != 0 { return 1 } print("ludicc: tools/x/main.ludic -> bin/x (the task runner rebuilds itself)") if not build_tool("x", "tools/x/main.ludic") { return 1 } print("ludicc: tools/ludic-tools/fmt.ludic -> bin/ludic-fmt") if not build_tool("ludic-fmt", "tools/ludic-tools/fmt.ludic") { return 1 } print("ludicc: tools/ludic-tools/lsp.ludic -> bin/ludic-lsp") if not build_tool("ludic-lsp", "tools/ludic-tools/lsp.ludic") { return 1 } sync_vscode_grammar() print("done. toolchain in bin/ (ludicc, ludic, x, ludic-fmt, ludic-lsp)") return 0 } # ---- app: compile a Ludic program to a native app ---------------------------- # usage: x app [--headless|--windowed] [--save-temps] # windowed is the default for a game; headless renders the last frame to out.ppm. function cmd_app() -> int { ensure_ludicc() var src = null var mode = 1 # 1 = windowed, 2 = headless var save = false var ai = 2 while ai < arg_count() { let a = arg(ai) if (a == "--headless") { mode = 2 } else if (a == "--windowed") { mode = 1 } else if (a == "--save-temps") { save = true } else if (a[0] != 45) { src = a } # 45 = '-', so skip other flags ai = ai + 1 } if (src == null) { err("usage: x app [--headless] [--save-temps]\n"); return 1 } let name = capture_line(`basename {src} .ludic`) if (mode == 2) { let outbin = `build/{name}_headless` let ll = `{outbin}.ll` print(`ludicc: {src} -> {outbin} (renders the last frame to out.ppm)`) if not shq(`bin/ludicc --headless {src} > {ll}`) { return 1 } if not shq(`{cc()} -O2 {ll} -o {outbin}`) { return 1 } if not save { run(`rm -f {ll}`) } print(`done. run: printf 'ddss' | ./{outbin} && open out.ppm`) return 0 } let outbin = `build/{name}` let ll = `{outbin}.ll` print(`ludicc: {src} -> {outbin} (Ludic-written compiler -> LLVM IR -> windowed binary)`) if not shq(`bin/ludicc --windowed {src} > {ll}`) { return 1 } if not shq(`{cc()} -O2 {ll} runtime/native/cocoa.ll -framework Cocoa -Wl,-rpath,@loader_path -o {outbin}`) { return 1 } if not save { run(`rm -f {ll}`) } print(`done. run: ./{outbin} (from the repo root, so assets/ resolves)`) return 0 } # Remove every generated artifact and leave the tracked source untouched: the # whole build/ tree (IR, objects, compiled apps), the headless render dropped in # the root (out.ppm), and any stray *.tmp/*.ll left behind by a failed build. # The toolchain binaries in bin/ are kept so the running `x` survives; rebuild # them any time with `x build`. function cmd_clean() -> int { run("rm -rf build") run("rm -f out.ppm bin/*.tmp") print("cleaned: build/, out.ppm, bin/*.tmp (bin/ toolchain kept — `x build` to rebuild)") return 0 }