run.sh (12704B)
1 #!/bin/sh 2 # Driver-level checks for the kit-native build verbs `build-exe` / `build-lib` / 3 # `build-obj` (the trio that replaced `compile`). Self-checking (no golden 4 # files): we assert exit status, output existence, symbol/text markers, ld -r 5 # parity, and — for build-exe — native execution of the produced binary. 6 # 7 # Coverage: 8 # build-obj : per-language compile (C / toy / wasm), --emit=obj|asm|c|ir, 9 # -fsyntax-only, default output naming, -o - to stdout, the 10 # -X<lang> frontend-flag router, target features, the multi-source 11 # relocatable combine (with ld -r parity), and the negative paths. 12 # build-lib : static .a from mixed sources, then link against it. 13 # build-exe : polyglot relocatable combine, native link+exec, --group scoping 14 # (verified through the produced exit code), and -L/-l. 15 16 set -u 17 18 script_dir=$(cd "$(dirname "$0")" && pwd) 19 repo_root=$(cd "$script_dir/../.." && pwd) 20 21 KIT="${KIT:-$repo_root/build/kit}" 22 23 if [ ! -x "$KIT" ]; then 24 echo "build: kit binary not found at $KIT" >&2 25 exit 2 26 fi 27 28 work=$(mktemp -d "${TMPDIR:-/tmp}/kit-build-test.XXXXXX") 29 trap 'rm -rf "$work"' EXIT 30 31 KIT_KIT_DIR="$repo_root/test/lib" 32 . "$repo_root/test/lib/kit_sh_kit.sh" 33 kit_report_init 34 35 # ---- fixtures (all local to $work so default-name tests are isolated) ------- 36 mkdir -p "$work/inc" 37 printf '#define ZERO 0\n' > "$work/inc/h.h" 38 printf '#include "h.h"\nint helper(void);\nint main(void){return ZERO+helper();}\n' > "$work/hello.c" 39 printf 'int helper(void){return 0;}\n' > "$work/helper.c" 40 printf '#include <stdint.h>\nint32_t f(void){return 1;}\n' > "$work/std.c" 41 cp "$(ls "$repo_root"/test/toy/cases/*.toy | head -1)" "$work/prog.toy" 42 cp "$repo_root/test/wasm/cases/if_return.wat" "$work/prog.wat" 43 printf 'int wasm_add(int a, int b);\nint wasm_main(void){return wasm_add(1,2)==3?0:1;}\n' > "$work/wasm_main.c" 44 printf 'int wasm_add(int a, int b){return a+b;}\n' > "$work/wasm_helper.c" 45 printf 'int wexe_add(int a, int b);\nint test_main(void){return wexe_add(2,3)==5?0:1;}\n' > "$work/wexe_main.c" 46 printf 'int wexe_add(int a, int b){return a+b;}\nint dead_fn(void){return 99;}\n' > "$work/wexe_add.c" 47 48 cd "$work" 49 50 # =========================================================================== 51 # build-obj — the compile replacement 52 # =========================================================================== 53 54 # ---- C: preprocessor flags + object output --------------------------------- 55 run_ok bo-c-obj "$KIT" build-obj -c -Iinc -DUNUSED=1 hello.c -o hello.o 56 assert_file_exists bo-c-obj-exists hello.o 57 "$KIT" nm hello.o > nm.out 2>/dev/null 58 contains bo-c-obj-has-main nm.out main 59 60 # C freestanding system header (<stdint.h>) resolves via the rt include set. 61 run_ok bo-c-freestanding-header "$KIT" build-obj -c std.c -o std.o 62 63 # Default output name: <basename>.o next to cwd when -o is omitted. 64 run_ok bo-c-default-name "$KIT" build-obj -c -Iinc hello.c 65 assert_file_exists bo-c-default-name-file hello.o 66 67 # ---- toy + wasm: non-C frontends through the generic driver ----------------- 68 run_ok bo-toy "$KIT" build-obj -c prog.toy -o prog_toy.o 69 assert_file_exists bo-toy-exists prog_toy.o 70 run_ok bo-wasm "$KIT" build-obj -c prog.wat -o prog_wat.o 71 assert_file_exists bo-wasm-exists prog_wat.o 72 73 # Target-owned option: the driver lowers feature flags into KitTargetOptions. 74 run_ok bo-wasm-target-feature "$KIT" build-obj -target wasm32-none -c \ 75 -mattr=-tail-calls prog.wat -o prog_wat2.o 76 77 # Per-language frontend flag via -X<lang> (routed to the wasm frontend parser). 78 run_ok bo-Xwasm "$KIT" build-obj -target wasm32-none -c \ 79 -Xwasm -mno-feature=tail-calls prog.wat -o prog_wat3.o 80 81 # ---- emit modes ------------------------------------------------------------ 82 run_ok bo-emit-asm "$KIT" build-obj -S -Iinc hello.c -o hello.s 83 contains bo-emit-asm-text hello.s .text 84 run_ok bo-emit-asm-long "$KIT" build-obj --emit=asm -Iinc hello.c -o hello2.s 85 run_ok bo-emit-c "$KIT" build-obj --emit=c prog.toy -o prog.c 86 assert_file_exists bo-emit-c-file prog.c 87 run_ok bo-emit-ir "$KIT" build-obj --emit=ir -O1 prog.toy -o prog.ir 88 assert_file_exists bo-emit-ir-file prog.ir 89 90 # -o - sends the emit to stdout (reusing the cc stdout writer). 91 "$KIT" build-obj --emit=ir -O1 prog.toy -o - > ir.stdout 2>/dev/null 92 if [ -s ir.stdout ]; then ok bo-emit-ir-stdout; else not_ok bo-emit-ir-stdout; fi 93 94 # ---- check-only writes no object ------------------------------------------- 95 rm -f hello.o 96 run_ok bo-check-only "$KIT" build-obj -fsyntax-only -Iinc hello.c helper.c 97 if [ ! -f hello.o ]; then ok bo-check-no-output; else not_ok bo-check-no-output; fi 98 99 # ---- multi-source relocatable combine (ld -r) ------------------------------ 100 run_ok bo-reloc-combine "$KIT" build-obj -Iinc hello.c helper.c -o combined.o 101 assert_file_exists bo-reloc-combine-file combined.o 102 "$KIT" nm combined.o > combined.nm 2>/dev/null 103 contains bo-reloc-has-helper combined.nm helper 104 contains bo-reloc-has-main combined.nm main 105 106 # ld -r parity: the in-memory combine matches a separate compile + `ld -r`. 107 "$KIT" build-obj -c -Iinc hello.c -o sep_hello.o 2>/dev/null 108 "$KIT" build-obj -c helper.c -o sep_helper.o 2>/dev/null 109 "$KIT" ld -r sep_hello.o sep_helper.o -o ldr.o 2>/dev/null 110 "$KIT" nm combined.o | sort > combine.sorted 2>/dev/null 111 "$KIT" nm ldr.o | sort > ldr.sorted 2>/dev/null 112 same_file bo-reloc-ld-r-parity ldr.sorted combine.sorted 113 114 # Polyglot combine: C + toy in one relocatable object. 115 run_ok bo-polyglot-combine "$KIT" build-obj -Iinc helper.c prog.toy -o poly.o 116 117 # ---- wasm multi-source combine (CG-merge path) ----------------------------- 118 # Two C files merged into one .wasm module (magic \0asm + non-empty content). 119 run_ok bo-wasm-multi "$KIT" build-obj -target wasm32-none \ 120 wasm_main.c wasm_helper.c -o multi.wasm 121 assert_file_exists bo-wasm-multi-file multi.wasm 122 # Wasm magic (\0asm = 00 61 73 6d): check first 4 bytes via od (avoids null-byte 123 # issues with cmp on BSD). 124 _wasm_hdr=$(od -A n -t x1 -N 4 multi.wasm | tr -d ' \t\n') 125 [ "$_wasm_hdr" = "0061736d" ] \ 126 && ok bo-wasm-multi-magic || not_ok bo-wasm-multi-magic 127 # Non-trivial module: size must exceed the 8-byte magic+version stub. 128 _wasm_size=$(wc -c < multi.wasm | tr -d ' ') 129 [ "$_wasm_size" -gt 8 ] \ 130 && ok bo-wasm-multi-nontrivial || not_ok bo-wasm-multi-nontrivial 131 132 # Polyglot wasm: C + toy in one .wasm module. 133 run_ok bo-wasm-polyglot "$KIT" build-obj -target wasm32-none \ 134 wasm_helper.c prog.toy -o poly.wasm 135 assert_file_exists bo-wasm-polyglot-file poly.wasm 136 _poly_hdr=$(od -A n -t x1 -N 4 poly.wasm | tr -d ' \t\n') 137 [ "$_poly_hdr" = "0061736d" ] \ 138 && ok bo-wasm-polyglot-magic || not_ok bo-wasm-polyglot-magic 139 140 # Negative: duplicate strong symbol definition must be rejected (at -O1 the 141 # optimizer runs opt_resolve_duplicate_funcs which fires the ODR check). 142 printf 'int wasm_add(int a, int b){return a-b;}\n' > wasm_dup.c 143 run_fail bo-wasm-dup "$KIT" build-obj -O1 -target wasm32-none \ 144 wasm_helper.c wasm_dup.c -o dup.wasm 145 contains bo-wasm-dup-diag "$work/bo-wasm-dup.err" "duplicate definition" 146 147 # ---- negative paths -------------------------------------------------------- 148 # A frontend with an unknown -X flag is rejected by that frontend's parser. 149 run_fail bo-neg-bad-Xflag "$KIT" build-obj -c -Xtoy --bogus prog.toy -o x.o 150 # The target parser rejects an unknown feature name. 151 run_fail bo-neg-bad-feature "$KIT" build-obj -target wasm32-none \ 152 -mattr=+nope -c prog.wat -o x.o 153 # build-obj never links: object/archive inputs are refused. 154 run_fail bo-neg-link-input "$KIT" build-obj hello.o 155 # --emit=c needs an explicit destination. 156 run_fail bo-neg-emit-c-needs-o "$KIT" build-obj --emit=c prog.toy 157 # IR is only available with the optimizer on. 158 run_fail bo-neg-ir-needs-opt "$KIT" build-obj --emit=ir prog.toy -o x.ir 159 # -o cannot fan out across multiple sources in a per-source emit. 160 run_fail bo-neg-o-multi-asm "$KIT" build-obj -S -Iinc hello.c std.c -o both.s 161 # A per-output flag is not allowed inside a --group. 162 run_fail bo-neg-global-in-group "$KIT" build-obj -Iinc --group -O2 -- hello.c 163 # A missing -x argument before a --group source separator should not treat `--` 164 # as a language name. 165 run_fail bo-neg-group-x-missing-arg "$KIT" build-obj --group -x -- hello.c 166 contains bo-neg-group-x-missing-arg-diag "$work/bo-neg-group-x-missing-arg.err" \ 167 "requires an argument" 168 # -dynamic is a build-lib concept. 169 run_fail bo-neg-dynamic "$KIT" build-obj -dynamic prog.toy 170 # unknown flag. 171 run_fail bo-neg-unknown-flag "$KIT" build-obj --nope -c prog.toy -o x.o 172 173 # =========================================================================== 174 # build-lib — static archive 175 # =========================================================================== 176 177 run_ok bl-static "$KIT" build-lib -Iinc -o libmix.a helper.c std.c prog.toy 178 assert_file_exists bl-static-file libmix.a 179 "$KIT" nm libmix.a > libmix.nm 2>/dev/null 180 contains bl-static-has-helper libmix.nm helper 181 # -o is required (no obvious base name across N sources). 182 run_fail bl-neg-needs-o "$KIT" build-lib helper.c std.c 183 # build-lib takes only sources. 184 run_fail bl-neg-link-input "$KIT" build-lib -o x.a helper.o 185 # Dynamic/shared libraries are not yet supported. 186 run_fail bl-neg-dynamic "$KIT" build-lib -dynamic -o x.a helper.c 187 188 # =========================================================================== 189 # build-exe — native link + exec (the headline path) 190 # =========================================================================== 191 192 # A hosted executable (-lc) that returns 0; build, then run it. 193 run_ok be-link "$KIT" build-exe -lc -Iinc hello.c helper.c -o app 194 is_executable be-link-exec app 195 run_ok be-run ./app 196 197 # build-exe should reject the shared-library spelling instead of ignoring it. 198 run_fail be-neg-shared "$KIT" build-exe -shared -lc -Iinc hello.c helper.c \ 199 -o shared-nope 200 contains be-neg-shared-diag "$work/be-neg-shared.err" "shared" 201 202 # Default output name a.out when -o is omitted. 203 run_ok be-default-name "$KIT" build-exe -lc -Iinc hello.c helper.c 204 assert_file_exists be-default-name-file a.out 205 206 # -no-pie must cancel an earlier -pie for build-exe's link state. 207 printf 'void _start(void) { for (;;) {} }\n' > no_pie_start.c 208 run_ok be-no-pie "$KIT" build-exe -target x86_64-linux -nostdlib \ 209 -pie -no-pie no_pie_start.c -o no-pie-exe 210 e_type=$(od -An -tx1 -j 16 -N 2 no-pie-exe | tr -d ' \n') 211 if [ "$e_type" = "0200" ]; then ok be-no-pie-et-exec; else 212 printf 'e_type bytes=%s want=0200\n' "$e_type" \ 213 > "$work/be-no-pie-et-exec.diag" 214 not_ok be-no-pie-et-exec "$work/be-no-pie-et-exec.diag" 215 fi 216 217 # --group scoping is observable through the program's exit code: the bare TU 218 # sees -DRET=0 (global), the grouped TU overrides it to a non-zero value. 219 printf '#ifndef RET\n#define RET 7\n#endif\nint ret_val(void){return RET;}\n' > rv.c 220 printf 'int ret_val(void);\nint main(void){return ret_val();}\n' > rmain.c 221 run_ok be-group-link "$KIT" build-exe -lc -DRET=0 rmain.c \ 222 --group -DRET=3 -- rv.c -o appg 223 if ./appg; then code=0; else code=$?; fi 224 if [ "$code" -eq 3 ]; then ok be-group-scope; else 225 echo "expected exit 3 from grouped -DRET, got $code" > "$work/be-group-scope.diag" 226 not_ok be-group-scope "$work/be-group-scope.diag" 227 fi 228 229 # Link against the static library built above via -L/-l, then run. 230 printf 'int helper(void);\nint main(void){return helper();}\n' > usemix.c 231 run_ok be-link-archive "$KIT" build-exe -lc usemix.c -L. -lmix -o app2 232 run_ok be-run-archive ./app2 233 234 # =========================================================================== 235 # build-exe — wasm target 236 # =========================================================================== 237 238 # Multi-source: produces a .wasm with DCE/internalization, runnable via kit run. 239 run_ok be-wasm-exe "$KIT" build-exe -target wasm32-none \ 240 wexe_main.c wexe_add.c -e test_main -o wexe.wasm 241 assert_file_exists be-wasm-exe-file wexe.wasm 242 _wexe_hdr=$(od -A n -t x1 -N 4 wexe.wasm | tr -d ' \t\n') 243 [ "$_wexe_hdr" = "0061736d" ] && ok be-wasm-exe-magic || not_ok be-wasm-exe-magic 244 run_ok be-wasm-exe-run "$KIT" run -e test_main wexe.wasm 245 246 # Default output name a.wasm when -o is omitted. 247 run_ok be-wasm-exe-default-name "$KIT" build-exe -target wasm32-none \ 248 wexe_main.c wexe_add.c -e test_main 249 assert_file_exists be-wasm-exe-default-name-file a.wasm 250 251 # kit run without -e reads the kit-entry custom section from the module. 252 run_ok be-wasm-exe-autoentry "$KIT" run wexe.wasm 253 254 # Unknown entry symbol is rejected with a clear diagnostic. 255 run_fail be-wasm-exe-bad-entry "$KIT" build-exe -target wasm32-none \ 256 wexe_main.c wexe_add.c -e no_such_fn -o bad_entry.wasm 257 contains be-wasm-exe-bad-entry-diag "$work/be-wasm-exe-bad-entry.err" \ 258 "entry symbol" 259 260 kit_summary build-driver 261 kit_exit