build.c (14228B)
1 /* Build orchestration API entries. 2 * 3 * The batch-compile and ordered-link tier over the public compile/link/cg 4 * surface: kit_build_compile_one/kit_build_compile drive the per-source and 5 * batched compile paths, and kit_build_link/kit_build_link_with_lto build a 6 * link session, add inputs in command-line order, and emit. Every entry is 7 * written purely against public kit_* calls. */ 8 9 #include <kit/build.h> 10 11 #include <kit/asm_emit.h> 12 #include <kit/cg.h> 13 #include <string.h> 14 15 static KitStatus build_compile_cg_run(KitCompiler* compiler, 16 const KitCodeOptions* code, 17 const KitDiagnosticOptions* diagnostics, 18 const KitBuildSource* src, KitCg* cg) { 19 KitCompileSessionOptions sopts; 20 KitCompileSession* session = NULL; 21 KitSourceInput sin; 22 KitStatus st; 23 24 if (!compiler || !code || !diagnostics || !src || !cg) return KIT_INVALID; 25 memset(&sopts, 0, sizeof(sopts)); 26 sopts.lang = src->lang; 27 sopts.compile.code = *code; 28 sopts.compile.diagnostics = *diagnostics; 29 if (src->pp) sopts.compile.preprocess = *src->pp; 30 sopts.compile.language_options = src->lang_extra; 31 32 memset(&sin, 0, sizeof(sin)); 33 sin.name = src->name; 34 sin.bytes = src->bytes; 35 sin.lang = src->lang; 36 37 st = kit_compile_session_new(compiler, &sopts, &session); 38 if (st == KIT_OK) st = kit_compile_session_compile_cg(session, &sin, cg); 39 kit_compile_session_free(session); 40 return st; 41 } 42 43 KitStatus kit_build_compile_one(KitCompiler* compiler, KitLanguage lang, 44 const KitCodeOptions* code, 45 const KitDiagnosticOptions* diagnostics, 46 const KitPreprocessOptions* pp, 47 const void* lang_extra, KitSlice name, 48 const KitSlice* bytes, KitWriter* emit_out, 49 KitObjBuilder** obj_out) { 50 KitCompileSessionOptions sopts; 51 KitCompileSession* session = NULL; 52 KitSourceInput sin; 53 KitObjBuilder* ob = NULL; 54 KitCodeOptions code_copy = *code; 55 KitStatus st; 56 57 if (obj_out) *obj_out = NULL; 58 59 /* For the in-CG emit modes the output writer is consumed during codegen, so 60 * wire it onto the code options before the session runs. */ 61 if (emit_out && code_copy.emit_c_source) code_copy.c_source_writer = emit_out; 62 if (emit_out && code_copy.emit_ir) code_copy.ir_dump_writer = emit_out; 63 64 memset(&sopts, 0, sizeof(sopts)); 65 sopts.lang = lang; 66 sopts.compile.code = code_copy; 67 sopts.compile.diagnostics = *diagnostics; 68 if (pp) sopts.compile.preprocess = *pp; 69 sopts.compile.language_options = lang_extra; 70 71 memset(&sin, 0, sizeof(sin)); 72 sin.name = name; 73 sin.bytes = *bytes; 74 sin.lang = lang; 75 76 st = kit_compile_session_new(compiler, &sopts, &session); 77 if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &ob); 78 kit_compile_session_free(session); 79 if (st != KIT_OK) return st; 80 81 if (obj_out) { 82 *obj_out = ob; 83 return KIT_OK; 84 } 85 86 /* emit_out path: serialize by output mode. The in-CG modes already wrote 87 * through the wired writer above. */ 88 if (code_copy.emit_c_source || code_copy.emit_ir) { 89 /* nothing to serialize here */ 90 } else if (code_copy.emit_asm_source) { 91 st = kit_obj_builder_emit_asm(ob, emit_out); 92 } else { 93 st = kit_obj_builder_emit(ob, emit_out); 94 } 95 kit_obj_builder_free(ob); 96 return st; 97 } 98 99 static int build_compile_lto_enabled(const KitCodeOptions* code) { 100 return code && code->lto && !code->check_only && !code->emit_c_source && 101 !code->emit_ir && !code->emit_asm_source; 102 } 103 104 static KitStatus build_start_lto(KitCompiler* compiler, 105 const KitCodeOptions* code, 106 KitObjBuilder** ob_out, KitCg** cg_out) { 107 KitObjBuilder* ob = NULL; 108 KitCg* cg = NULL; 109 KitStatus st; 110 111 if (ob_out) *ob_out = NULL; 112 if (cg_out) *cg_out = NULL; 113 if (!compiler || !code || !ob_out || !cg_out) return KIT_INVALID; 114 st = kit_obj_builder_new(compiler, &ob); 115 if (st == KIT_OK) st = kit_cg_new(compiler, &cg); 116 if (st == KIT_OK) st = kit_cg_begin(cg, ob, code); 117 if (st != KIT_OK) { 118 kit_cg_free(cg); 119 kit_obj_builder_free(ob); 120 return st; 121 } 122 *ob_out = ob; 123 *cg_out = cg; 124 return KIT_OK; 125 } 126 127 KitStatus kit_build_lto_finish(KitBuildPendingLto* pending, 128 const KitBuildBatchOptions* batch, 129 const KitCgSym* preserved_symbols, 130 uint32_t npreserved_symbols) { 131 KitCgFinishOptions finish; 132 KitStatus st; 133 134 if (!pending || !pending->active) return KIT_OK; 135 if (!pending->obj || !pending->cg) { 136 kit_build_lto_abort(pending); 137 return KIT_INVALID; 138 } 139 140 memset(&finish, 0, sizeof finish); 141 finish.output_kind = batch ? batch->output_kind : KIT_CG_OUTPUT_RELOCATABLE; 142 finish.interposition_policy = 143 batch ? batch->interposition_policy : KIT_CG_INTERPOSITION_DEFAULT; 144 finish.preserved_symbols = preserved_symbols; 145 finish.npreserved_symbols = npreserved_symbols; 146 147 st = kit_cg_finish(pending->cg, &finish); 148 if (st == KIT_OK) st = kit_cg_detach(pending->cg); 149 if (st == KIT_OK) st = kit_obj_builder_finalize(pending->obj); 150 151 kit_cg_free(pending->cg); 152 pending->cg = NULL; 153 pending->active = 0; 154 return st; 155 } 156 157 void kit_build_lto_abort(KitBuildPendingLto* pending) { 158 if (!pending || !pending->active) return; 159 kit_cg_free(pending->cg); 160 pending->cg = NULL; 161 pending->active = 0; 162 } 163 164 KitStatus kit_build_compile(KitCompiler* compiler, const KitCodeOptions* code, 165 const KitDiagnosticOptions* diagnostics, 166 const KitBuildSource* sources, uint32_t nsources, 167 const KitBuildBatchOptions* batch, 168 KitBuildObjects* out) { 169 KitBuildPendingLto pending_lto; 170 int lto_order_emitted = 0; 171 int lto_enabled = build_compile_lto_enabled(code); 172 KitStatus st = KIT_OK; 173 174 if (!compiler || !code || !diagnostics || (!sources && nsources) || !out || 175 !out->objs || !out->source_obj_index || !out->source_order_keep) { 176 return KIT_INVALID; 177 } 178 memset(&pending_lto, 0, sizeof pending_lto); 179 out->nobjs = 0; 180 if (out->pending_lto) memset(out->pending_lto, 0, sizeof(*out->pending_lto)); 181 for (uint32_t i = 0; i < nsources; ++i) { 182 out->source_obj_index[i] = (uint32_t)-1; 183 out->source_order_keep[i] = 0; 184 } 185 186 for (uint32_t i = 0; i < nsources; ++i) { 187 const KitBuildSource* src = &sources[i]; 188 KitFrontendCaps caps; 189 int stage_cg = 0; 190 191 memset(&caps, 0, sizeof caps); 192 if (lto_enabled) { 193 st = kit_frontend_caps(compiler, src->lang, &caps); 194 if (st != KIT_OK) goto out; 195 stage_cg = caps.lto_mode == KIT_FRONTEND_LTO_CG; 196 } 197 198 if (stage_cg) { 199 if (!pending_lto.active) { 200 st = build_start_lto(compiler, code, &pending_lto.obj, &pending_lto.cg); 201 if (st != KIT_OK) goto out; 202 pending_lto.obj_index = out->nobjs; 203 pending_lto.active = 1; 204 out->objs[out->nobjs++] = pending_lto.obj; 205 } 206 out->source_obj_index[i] = pending_lto.obj_index; 207 if (!lto_order_emitted) { 208 out->source_order_keep[i] = 1; 209 lto_order_emitted = 1; 210 } 211 st = build_compile_cg_run(compiler, code, diagnostics, src, 212 pending_lto.cg); 213 if (st != KIT_OK) goto out; 214 continue; 215 } 216 217 { 218 KitObjBuilder* ob = NULL; 219 st = kit_build_compile_one(compiler, src->lang, code, diagnostics, 220 src->pp, src->lang_extra, src->name, 221 &src->bytes, NULL, &ob); 222 if (st != KIT_OK) goto out; 223 out->source_obj_index[i] = out->nobjs; 224 out->source_order_keep[i] = 1; 225 out->objs[out->nobjs++] = ob; 226 } 227 } 228 229 if (pending_lto.active) { 230 if (batch && batch->defer_lto_finish) { 231 if (!out->pending_lto) { 232 st = KIT_INVALID; 233 goto out; 234 } 235 *out->pending_lto = pending_lto; 236 memset(&pending_lto, 0, sizeof pending_lto); 237 } else { 238 st = kit_build_lto_finish(&pending_lto, batch, NULL, 0); 239 if (st != KIT_OK) goto out; 240 } 241 } 242 243 out: 244 if (pending_lto.active) kit_build_lto_abort(&pending_lto); 245 return st; 246 } 247 248 KitStatus kit_build_emit_c(KitCompiler* compiler, const KitCodeOptions* code, 249 const KitDiagnosticOptions* diagnostics, 250 const KitBuildSource* sources, uint32_t nsources, 251 const KitBuildBatchOptions* batch, KitWriter* out) { 252 KitCodeOptions emit_code; 253 KitObjBuilder* ob = NULL; 254 KitCg* cg = NULL; 255 KitCgFinishOptions finish; 256 KitStatus st = KIT_OK; 257 258 if (!compiler || !code || !diagnostics || !sources || nsources == 0 || 259 !out || (batch && batch->defer_lto_finish)) 260 return KIT_INVALID; 261 262 emit_code = *code; 263 emit_code.check_only = false; 264 emit_code.emit_asm_source = false; 265 emit_code.emit_c_source = true; 266 emit_code.emit_ir = false; 267 emit_code.c_source_writer = out; 268 emit_code.ir_dump_writer = NULL; 269 270 for (uint32_t i = 0; i < nsources; ++i) { 271 KitFrontendCaps caps; 272 memset(&caps, 0, sizeof caps); 273 st = kit_frontend_caps(compiler, sources[i].lang, &caps); 274 if (st != KIT_OK) return st; 275 if (caps.lto_mode != KIT_FRONTEND_LTO_CG) return KIT_UNSUPPORTED; 276 } 277 278 st = kit_obj_builder_new(compiler, &ob); 279 if (st == KIT_OK) st = kit_cg_new(compiler, &cg); 280 if (st == KIT_OK) st = kit_cg_begin(cg, ob, &emit_code); 281 282 for (uint32_t i = 0; st == KIT_OK && i < nsources; ++i) 283 st = build_compile_cg_run(compiler, &emit_code, diagnostics, &sources[i], 284 cg); 285 286 if (st == KIT_OK) { 287 memset(&finish, 0, sizeof finish); 288 finish.output_kind = 289 batch ? batch->output_kind : KIT_CG_OUTPUT_RELOCATABLE; 290 finish.interposition_policy = 291 batch ? batch->interposition_policy : KIT_CG_INTERPOSITION_DEFAULT; 292 st = kit_cg_finish(cg, &finish); 293 } 294 295 kit_cg_free(cg); 296 kit_obj_builder_free(ob); 297 return st; 298 } 299 300 typedef struct BuildPreservedVec { 301 KitHeap* heap; 302 KitCgSym* syms; 303 uint32_t nsyms; 304 uint32_t cap; 305 int oom; 306 } BuildPreservedVec; 307 308 static void build_preserved_vec_add(void* user, KitCgSym sym) { 309 BuildPreservedVec* v = (BuildPreservedVec*)user; 310 KitCgSym* ns; 311 uint32_t ncap; 312 if (!v || v->oom) return; 313 if (v->nsyms == v->cap) { 314 ncap = v->cap ? v->cap * 2u : 32u; 315 ns = (KitCgSym*)v->heap->realloc( 316 v->heap, v->syms, sizeof(*v->syms) * v->cap, sizeof(*v->syms) * ncap, 317 _Alignof(KitCgSym)); 318 if (!ns) { 319 v->oom = 1; 320 return; 321 } 322 v->syms = ns; 323 v->cap = ncap; 324 } 325 v->syms[v->nsyms++] = sym; 326 } 327 328 static KitStatus build_link_add_inputs(KitLinkSession* link, 329 const KitLinkInputs* in) { 330 KitStatus st = KIT_OK; 331 uint32_t i; 332 if (!link || !in) return KIT_INVALID; 333 334 for (i = 0; i < in->norder && st == KIT_OK; ++i) { 335 const KitLinkInputOrder* ord = &in->order[i]; 336 switch ((KitLinkInputOrderKind)ord->kind) { 337 case KIT_LINK_INPUT_OBJ: 338 st = kit_link_session_add_obj(link, in->objs[ord->index]); 339 break; 340 case KIT_LINK_INPUT_OBJ_BYTES: 341 st = kit_link_session_add_obj_bytes(link, in->obj_names[ord->index], 342 &in->obj_bytes[ord->index]); 343 break; 344 case KIT_LINK_INPUT_ARCHIVE: 345 st = 346 kit_link_session_add_archive_bytes(link, &in->archives[ord->index]); 347 break; 348 case KIT_LINK_INPUT_DSO: 349 st = kit_link_session_add_dso_bytes(link, in->dso_names[ord->index], 350 &in->dso_bytes[ord->index]); 351 break; 352 } 353 } 354 return st; 355 } 356 357 KitStatus kit_build_link_with_lto_report( 358 KitCompiler* compiler, const KitLinkSessionOptions* lopts, 359 const KitLinkInputs* in, KitBuildPendingLto* pending_lto, 360 const KitBuildBatchOptions* batch, KitWriter* out, 361 KitStatus (*on_linked)(void* user, KitLinkSession* link), void* user) { 362 KitLinkSession* link = NULL; 363 BuildPreservedVec preserved; 364 KitStatus st; 365 366 if (!compiler || !lopts || !in || !out) { 367 if (pending_lto && pending_lto->active) kit_build_lto_abort(pending_lto); 368 return KIT_INVALID; 369 } 370 memset(&preserved, 0, sizeof preserved); 371 preserved.heap = kit_compiler_context(compiler)->heap; 372 st = kit_link_session_new(compiler, lopts, &link); 373 if (st == KIT_OK) st = build_link_add_inputs(link, in); 374 if (st == KIT_OK && pending_lto && pending_lto->active) { 375 st = kit_link_session_visit_lto_preserved( 376 link, pending_lto->obj, pending_lto->cg, build_preserved_vec_add, 377 &preserved); 378 if (st == KIT_OK && preserved.oom) st = KIT_NOMEM; 379 if (st == KIT_OK) { 380 st = kit_build_lto_finish(pending_lto, batch, preserved.syms, 381 preserved.nsyms); 382 } 383 } 384 if (st == KIT_OK) st = kit_link_session_emit(link, out); 385 /* Side reports (cref/memory-usage/map/symbols) need the resolved session, so 386 * write them here while `link` is still live. */ 387 if (st == KIT_OK && on_linked) st = on_linked(user, link); 388 kit_link_session_free(link); 389 if (preserved.syms) 390 preserved.heap->free(preserved.heap, preserved.syms, 391 sizeof(*preserved.syms) * preserved.cap); 392 if (st != KIT_OK && pending_lto && pending_lto->active) 393 kit_build_lto_abort(pending_lto); 394 return st; 395 } 396 397 KitStatus kit_build_link_with_lto(KitCompiler* compiler, 398 const KitLinkSessionOptions* lopts, 399 const KitLinkInputs* in, 400 KitBuildPendingLto* pending_lto, 401 const KitBuildBatchOptions* batch, 402 KitWriter* out) { 403 return kit_build_link_with_lto_report(compiler, lopts, in, pending_lto, batch, 404 out, NULL, NULL); 405 } 406 407 KitStatus kit_build_link(KitCompiler* compiler, 408 const KitLinkSessionOptions* lopts, 409 const KitLinkInputs* in, KitWriter* out) { 410 return kit_build_link_with_lto(compiler, lopts, in, NULL, NULL, out); 411 }