Skip to content

Commit d65cd73

Browse files
committed
add support to use zig as a linker driver
closes #243 I also added --grep to ./run_tests if you want to single out some specific tests
1 parent 8c10b6d commit d65cd73

File tree

9 files changed

+236
-91
lines changed

9 files changed

+236
-91
lines changed

src/all_types.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,7 @@ struct CodeGen {
14621462
ConstExprValue panic_msg_vals[PanicMsgIdCount];
14631463

14641464
Buf global_asm;
1465+
ZigList<Buf *> link_objects;
14651466
};
14661467

14671468
enum VarLinkage {

src/codegen.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3743,6 +3743,18 @@ static void do_code_gen(CodeGen *g) {
37433743
char *error = nullptr;
37443744
LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
37453745
#endif
3746+
3747+
char *err_msg = nullptr;
3748+
Buf *out_file_o = buf_create_from_buf(g->root_out_name);
3749+
const char *o_ext = target_o_file_ext(&g->zig_target);
3750+
buf_append_str(out_file_o, o_ext);
3751+
if (LLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(out_file_o),
3752+
LLVMObjectFile, &err_msg))
3753+
{
3754+
zig_panic("unable to write object file: %s", err_msg);
3755+
}
3756+
3757+
g->link_objects.append(out_file_o);
37463758
}
37473759

37483760
static const size_t int_sizes_in_bits[] = {
@@ -4550,6 +4562,10 @@ void codegen_add_root_assembly(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf
45504562
do_code_gen(g);
45514563
}
45524564

4565+
void codegen_add_object(CodeGen *g, Buf *object_path) {
4566+
g->link_objects.append(object_path);
4567+
}
4568+
45534569

45544570
static const char *c_int_type_names[] = {
45554571
[CIntTypeShort] = "short",

src/codegen.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt);
4848
PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);
4949
void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);
5050
void codegen_add_root_assembly(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);
51+
void codegen_add_object(CodeGen *g, Buf *object_path);
5152

5253
void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code);
5354
void codegen_render_ast(CodeGen *g, FILE *f, int indent_size);

src/link.cpp

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ struct LinkJob {
1616
Buf out_file;
1717
ZigList<const char *> args;
1818
bool link_in_crt;
19-
Buf out_file_o;
2019
HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table;
2120
};
2221

@@ -32,14 +31,6 @@ static const char *get_libc_static_file(CodeGen *g, const char *file) {
3231
return buf_ptr(out_buf);
3332
}
3433

35-
static const char *get_o_file_extension(CodeGen *g) {
36-
if (g->zig_target.env_type == ZigLLVM_MSVC) {
37-
return ".obj";
38-
} else {
39-
return ".o";
40-
}
41-
}
42-
4334
static Buf *build_o(CodeGen *parent_gen, const char *oname) {
4435
Buf *source_basename = buf_sprintf("%s.zig", oname);
4536

@@ -78,7 +69,7 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
7869
}
7970

8071
codegen_add_root_code(child_gen, parent_gen->zig_std_special_dir, source_basename, &source_code);
81-
const char *o_ext = get_o_file_extension(child_gen);
72+
const char *o_ext = target_o_file_ext(&child_gen->zig_target);
8273
Buf *o_out = buf_sprintf("%s%s", oname, o_ext);
8374
codegen_link(child_gen, buf_ptr(o_out));
8475

@@ -274,7 +265,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
274265
}
275266

276267
// .o files
277-
lj->args.append((const char *)buf_ptr(&lj->out_file_o));
268+
for (size_t i = 0; i < g->link_objects.length; i += 1) {
269+
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
270+
}
278271

279272
if (g->is_test_build) {
280273
Buf *test_runner_o_path = build_o(g, "test_runner");
@@ -417,7 +410,9 @@ static void construct_linker_job_coff(LinkJob *lj) {
417410
lj->args.append(buf_ptr(g->libc_static_lib_dir));
418411
}
419412

420-
lj->args.append((const char *)buf_ptr(&lj->out_file_o));
413+
for (size_t i = 0; i < g->link_objects.length; i += 1) {
414+
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
415+
}
421416

422417
if (g->is_test_build) {
423418
Buf *test_runner_o_path = build_o(g, "test_runner");
@@ -681,7 +676,9 @@ static void construct_linker_job_macho(LinkJob *lj) {
681676
lj->args.append(lib_dir);
682677
}
683678

684-
lj->args.append((const char *)buf_ptr(&lj->out_file_o));
679+
for (size_t i = 0; i < g->link_objects.length; i += 1) {
680+
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
681+
}
685682

686683
if (g->is_test_build) {
687684
Buf *test_runner_o_path = build_o(g, "test_runner");
@@ -776,19 +773,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
776773
buf_append_str(&lj.out_file, get_exe_file_extension(g));
777774
}
778775
}
779-
buf_init_from_buf(&lj.out_file_o, &lj.out_file);
780-
781-
if (g->out_type != OutTypeObj || !override_out_file) {
782-
const char *o_ext = get_o_file_extension(g);
783-
buf_append_str(&lj.out_file_o, o_ext);
784-
}
785-
786-
char *err_msg = nullptr;
787-
if (LLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(&lj.out_file_o),
788-
LLVMObjectFile, &err_msg))
789-
{
790-
zig_panic("unable to write object file: %s", err_msg);
791-
}
792776

793777
if (g->out_type == OutTypeObj) {
794778
if (g->want_h_file) {

src/main.cpp

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ static int usage(const char *arg0) {
2424
" build_exe [source] create executable from source\n"
2525
" build_lib [source] create library from source\n"
2626
" build_obj [source] create object from source\n"
27+
" link_exe [objects] create executable from objects\n"
28+
" link_lib [objects] create library from objects\n"
2729
" parseh [source] convert a c header file to zig extern declarations\n"
2830
" targets list available compilation targets\n"
2931
" test [source] create and run a test build\n"
@@ -108,6 +110,7 @@ enum Cmd {
108110
CmdParseH,
109111
CmdTargets,
110112
CmdAsm,
113+
CmdLink,
111114
};
112115

113116
int main(int argc, char **argv) {
@@ -147,6 +150,7 @@ int main(int argc, char **argv) {
147150
const char *linker_script = nullptr;
148151
ZigList<const char *> rpath_list = {0};
149152
bool each_lib_rpath = false;
153+
ZigList<const char *> objects = {0};
150154

151155
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
152156
const char *zig_exe_path = arg0;
@@ -304,6 +308,12 @@ int main(int argc, char **argv) {
304308
} else if (strcmp(arg, "build_lib") == 0) {
305309
cmd = CmdBuild;
306310
out_type = OutTypeLib;
311+
} else if (strcmp(arg, "link_lib") == 0) {
312+
cmd = CmdLink;
313+
out_type = OutTypeLib;
314+
} else if (strcmp(arg, "link_exe") == 0) {
315+
cmd = CmdLink;
316+
out_type = OutTypeExe;
307317
} else if (strcmp(arg, "version") == 0) {
308318
cmd = CmdVersion;
309319
} else if (strcmp(arg, "parseh") == 0) {
@@ -330,6 +340,9 @@ int main(int argc, char **argv) {
330340
return usage(arg0);
331341
}
332342
break;
343+
case CmdLink:
344+
objects.append(arg);
345+
break;
333346
case CmdVersion:
334347
case CmdTargets:
335348
return usage(arg0);
@@ -344,11 +357,24 @@ int main(int argc, char **argv) {
344357
case CmdParseH:
345358
case CmdTest:
346359
case CmdAsm:
360+
case CmdLink:
347361
{
348-
if (!in_file)
349-
return usage(arg0);
362+
bool one_source_input = (cmd == CmdBuild || cmd == CmdParseH || cmd == CmdTest || cmd == CmdAsm);
363+
if (one_source_input) {
364+
if (!in_file) {
365+
fprintf(stderr, "Expected source file argument.\n");
366+
return usage(arg0);
367+
}
368+
} else if (cmd == CmdLink) {
369+
if (objects.length == 0) {
370+
fprintf(stderr, "Expected one or more object arguments.\n");
371+
return usage(arg0);
372+
}
373+
} else {
374+
zig_unreachable();
375+
}
350376

351-
assert(cmd != CmdBuild || out_type != OutTypeUnknown);
377+
assert((cmd != CmdBuild && cmd != CmdLink) || out_type != OutTypeUnknown);
352378

353379
init_all_targets();
354380

@@ -379,37 +405,45 @@ int main(int argc, char **argv) {
379405
}
380406
}
381407

382-
bool need_name = (cmd == CmdBuild || cmd == CmdAsm);
408+
bool need_name = (cmd == CmdBuild || cmd == CmdAsm || cmd == CmdLink);
383409

384410
Buf in_file_buf = BUF_INIT;
385-
buf_init_from_str(&in_file_buf, in_file);
386411

387412
Buf root_source_dir = BUF_INIT;
388413
Buf root_source_code = BUF_INIT;
389414
Buf root_source_name = BUF_INIT;
390415

391416
Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
392417
(out_name == nullptr) ? nullptr : buf_create_from_str(out_name);
393-
if (buf_eql_str(&in_file_buf, "-")) {
394-
os_get_cwd(&root_source_dir);
395-
if ((err = os_fetch_file(stdin, &root_source_code))) {
396-
fprintf(stderr, "unable to read stdin: %s\n", err_str(err));
397-
return 1;
398-
}
399-
buf_init_from_str(&root_source_name, "");
400418

401-
} else {
402-
os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
403-
if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) {
404-
fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err));
405-
return 1;
406-
}
419+
if (one_source_input) {
420+
buf_init_from_str(&in_file_buf, in_file);
421+
422+
if (buf_eql_str(&in_file_buf, "-")) {
423+
os_get_cwd(&root_source_dir);
424+
if ((err = os_fetch_file(stdin, &root_source_code))) {
425+
fprintf(stderr, "unable to read stdin: %s\n", err_str(err));
426+
return 1;
427+
}
428+
buf_init_from_str(&root_source_name, "");
407429

408-
if (need_name && buf_out_name == nullptr) {
409-
buf_out_name = buf_alloc();
410-
Buf ext_name = BUF_INIT;
411-
os_path_extname(&root_source_name, buf_out_name, &ext_name);
430+
} else {
431+
os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
432+
if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) {
433+
fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err));
434+
return 1;
435+
}
436+
437+
if (need_name && buf_out_name == nullptr) {
438+
buf_out_name = buf_alloc();
439+
Buf ext_name = BUF_INIT;
440+
os_path_extname(&root_source_name, buf_out_name, &ext_name);
441+
}
412442
}
443+
} else if (cmd == CmdLink) {
444+
os_get_cwd(&root_source_dir);
445+
} else {
446+
zig_unreachable();
413447
}
414448

415449
if (need_name && buf_out_name == nullptr) {
@@ -484,6 +518,12 @@ int main(int argc, char **argv) {
484518
codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
485519
codegen_link(g, out_file);
486520
return EXIT_SUCCESS;
521+
} else if (cmd == CmdLink) {
522+
for (size_t i = 0; i < objects.length; i += 1) {
523+
codegen_add_object(g, buf_create_from_str(objects.at(i)));
524+
}
525+
codegen_link(g, out_file);
526+
return EXIT_SUCCESS;
487527
} else if (cmd == CmdAsm) {
488528
codegen_add_root_assembly(g, &root_source_dir, &root_source_name, &root_source_code);
489529
codegen_link(g, out_file);

src/os.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,20 @@ int os_delete_file(Buf *path);
5454

5555
int os_file_exists(Buf *full_path, bool *result);
5656

57+
#if defined(__APPLE__)
58+
#define ZIG_OS_DARWIN
59+
#elif defined(_WIN32)
60+
#define ZIG_OS_WINDOWS
61+
#elif defined(__linux__)
62+
#define ZIG_OS_LINUX
63+
#else
64+
#define ZIG_OS_UNKNOWN
65+
#endif
66+
67+
#if defined(__x86_64__)
68+
#define ZIG_ARCH_X86_64
69+
#else
70+
#define ZIG_ARCH_UNKNOWN
71+
#endif
72+
5773
#endif

src/target.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,3 +527,12 @@ int get_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
527527
}
528528
zig_unreachable();
529529
}
530+
531+
const char *target_o_file_ext(ZigTarget *target) {
532+
if (target->env_type == ZigLLVM_MSVC) {
533+
return ".obj";
534+
} else {
535+
return ".o";
536+
}
537+
}
538+

src/target.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,6 @@ void resolve_target_object_format(ZigTarget *target);
7272

7373
int get_c_type_size_in_bits(const ZigTarget *target, CIntType id);
7474

75+
const char *target_o_file_ext(ZigTarget *target);
76+
7577
#endif

0 commit comments

Comments
 (0)