authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 12:44:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 12:44:42-07:00
logf5a32818773835bdeaa8f0db1d036a1506c69982
treecec14b3ed641e3916613e5ff24f9db7943177c18
parentf2a9b40231f982b10c4d098c60b47da890396c1f

when linking with libc use the C runtime library


9 files changed, 151 insertions(+), 114 deletions(-)

README.md+2-2
......@@ -61,7 +61,7 @@ compromises backward compatibility.
6161```
6262mkdir build
6363cd build
64cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
64cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_DIR=path/to/libc/dir
6565make
6666make install
6767./run_tests
......@@ -72,7 +72,7 @@ make install
7272```
7373mkdir build
7474cd build
75cmake .. -DCMAKE_BUILD_TYPE=Release
75cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_DIR=path/to/libc/dir
7676make
7777sudo make install
7878```
example/hello_world/hello_libc.zig+2-2
......@@ -6,7 +6,7 @@ extern {
66 fn exit(__status: i32) -> unreachable;
77}
88
9export fn _start() -> unreachable {
9export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 {
1010 printf(c"Hello, world!\n");
11 exit(0);
11 return 0;
1212}
src/analyze.hpp+3-1
......@@ -164,7 +164,9 @@ struct CodeGen {
164164 unsigned pointer_size_bytes;
165165 bool is_static;
166166 bool strip_debug_symbols;
167 bool insert_bootstrap_code;
167 bool have_exported_main;
168 bool link_libc;
169 Buf *libc_path;
168170 CodeGenBuildType build_type;
169171 LLVMTargetMachineRef target_machine;
170172 LLVMZigDIFile *dummy_di_file;
src/codegen.cpp+76-5
......@@ -58,6 +58,10 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
5858 g->root_out_name = out_name;
5959}
6060
61void codegen_set_libc_path(CodeGen *g, Buf *libc_path) {
62 g->libc_path = libc_path;
63}
64
6165static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
6266
6367
......@@ -1517,6 +1521,18 @@ static void init(CodeGen *g, Buf *source_path) {
15171521
15181522}
15191523
1524static bool directives_contains_link_libc(ZigList<AstNode*> *directives) {
1525 for (int i = 0; i < directives->length; i += 1) {
1526 AstNode *directive_node = directives->at(i);
1527 if (buf_eql_str(&directive_node->data.directive.name, "link") &&
1528 buf_eql_str(&directive_node->data.directive.param, "c"))
1529 {
1530 return true;
1531 }
1532 }
1533 return false;
1534}
1535
15201536static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) {
15211537 int err;
15221538 Buf *full_path = buf_alloc();
......@@ -1613,11 +1629,13 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src
16131629 assert(proto_node->type == NodeTypeFnProto);
16141630 Buf *proto_name = &proto_node->data.fn_proto.name;
16151631
1616 bool is_exported = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate);
1632 bool is_private = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModPrivate);
16171633
1618 if (buf_eql_str(proto_name, "main") && is_exported) {
1619 g->insert_bootstrap_code = true;
1634 if (buf_eql_str(proto_name, "main") && !is_private) {
1635 g->have_exported_main = true;
16201636 }
1637 } else if (top_level_decl->type == NodeTypeExternBlock) {
1638 g->link_libc = directives_contains_link_libc(top_level_decl->data.extern_block.directives);
16211639 }
16221640 }
16231641
......@@ -1633,7 +1651,7 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
16331651
16341652 g->root_import = codegen_add_code(g, src_dir, src_basename, source_code);
16351653
1636 if (g->insert_bootstrap_code) {
1654 if (g->have_exported_main && !g->link_libc && g->out_type != OutTypeLib) {
16371655 Buf *bootstrap_dir = buf_create_from_str(ZIG_STD_DIR);
16381656 Buf *bootstrap_basename = buf_create_from_str("bootstrap.zig");
16391657 Buf path_to_bootstrap_src = BUF_INIT;
......@@ -1788,6 +1806,22 @@ static void generate_h_file(CodeGen *g) {
17881806 zig_panic("unable to close h file: %s", strerror(errno));
17891807}
17901808
1809static void find_libc_path(CodeGen *g) {
1810 if (g->libc_path && buf_len(g->libc_path))
1811 return;
1812 g->libc_path = buf_create_from_str(ZIG_LIBC_DIR);
1813 if (g->libc_path && buf_len(g->libc_path))
1814 return;
1815 fprintf(stderr, "Unable to determine libc path. Consider using `--libc-path [path]`\n");
1816 exit(1);
1817}
1818
1819static const char *get_libc_file(CodeGen *g, const char *file) {
1820 Buf *out_buf = buf_alloc();
1821 os_path_join(g->libc_path, buf_create_from_str(file), out_buf);
1822 return buf_ptr(out_buf);
1823}
1824
17911825void codegen_link(CodeGen *g, const char *out_file) {
17921826 bool is_optimized = (g->build_type == CodeGenBuildTypeRelease);
17931827 if (is_optimized) {
......@@ -1826,6 +1860,9 @@ void codegen_link(CodeGen *g, const char *out_file) {
18261860 }
18271861
18281862 if (g->out_type == OutTypeObj) {
1863 if (g->verbose) {
1864 fprintf(stderr, "OK\n");
1865 }
18291866 return;
18301867 }
18311868
......@@ -1840,8 +1877,12 @@ void codegen_link(CodeGen *g, const char *out_file) {
18401877
18411878 // invoke `ld`
18421879 ZigList<const char *> args = {0};
1880 const char *crt1o;
18431881 if (g->is_static) {
18441882 args.append("-static");
1883 crt1o = "crt1.o";
1884 } else {
1885 crt1o = "Scrt1.o";
18451886 }
18461887
18471888 char *ZIG_NATIVE_DYNAMIC_LINKER = getenv("ZIG_NATIVE_DYNAMIC_LINKER");
......@@ -1868,8 +1909,21 @@ void codegen_link(CodeGen *g, const char *out_file) {
18681909 args.append("-o");
18691910 args.append(out_file);
18701911
1912 bool link_in_crt = (g->link_libc && g->out_type == OutTypeExe);
1913
1914 if (link_in_crt) {
1915 find_libc_path(g);
1916
1917 args.append(get_libc_file(g, crt1o));
1918 args.append(get_libc_file(g, "crti.o"));
1919 }
1920
18711921 args.append((const char *)buf_ptr(&out_file_o));
18721922
1923 if (link_in_crt) {
1924 args.append(get_libc_file(g, "crtn.o"));
1925 }
1926
18731927 auto it = g->link_table.entry_iterator();
18741928 for (;;) {
18751929 auto *entry = it.next();
......@@ -1880,7 +1934,24 @@ void codegen_link(CodeGen *g, const char *out_file) {
18801934 args.append(buf_ptr(arg));
18811935 }
18821936
1883 os_spawn_process("ld", args, false);
1937 if (g->verbose) {
1938 fprintf(stderr, "ld");
1939 for (int i = 0; i < args.length; i += 1) {
1940 fprintf(stderr, " %s", args.at(i));
1941 }
1942 fprintf(stderr, "\n");
1943 }
1944
1945 int return_code;
1946 Buf ld_stderr = BUF_INIT;
1947 Buf ld_stdout = BUF_INIT;
1948 os_exec_process("ld", args, &return_code, &ld_stderr, &ld_stdout);
1949
1950 if (return_code != 0) {
1951 fprintf(stderr, "ld failed with return code %d\n", return_code);
1952 fprintf(stderr, "%s\n", buf_ptr(&ld_stderr));
1953 exit(1);
1954 }
18841955
18851956 if (g->out_type == OutTypeLib) {
18861957 generate_h_file(g);
src/codegen.hpp+1
......@@ -33,6 +33,7 @@ void codegen_set_verbose(CodeGen *codegen, bool verbose);
3333void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
3434void codegen_set_out_type(CodeGen *codegen, OutType out_type);
3535void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
36void codegen_set_libc_path(CodeGen *codegen, Buf *libc_path);
3637
3738void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);
3839
src/config.h.in+1
......@@ -8,5 +8,6 @@
88
99#define ZIG_HEADERS_DIR "@CMAKE_INSTALL_PREFIX@/@C_HEADERS_DEST@"
1010#define ZIG_STD_DIR "@CMAKE_INSTALL_PREFIX@/@ZIG_STD_DEST@"
11#define ZIG_LIBC_DIR "@ZIG_LIBC_DIR@"
1112
1213#endif
src/main.cpp+6
......@@ -29,6 +29,7 @@ static int usage(const char *arg0) {
2929 " --output [file] override destination path\n"
3030 " --verbose turn on compiler debug output\n"
3131 " --color [auto|off|on] enable or disable colored error messages\n"
32 " --libc-path [path] set the C compiler data path\n"
3233 "Command: parseh target\n"
3334 " -isystem [dir] add additional search path for other .h files\n"
3435 " -dirafter [dir] same as -isystem but do it last\n"
......@@ -52,6 +53,7 @@ struct Build {
5253 const char *out_name;
5354 bool verbose;
5455 ErrColor color;
56 const char *libc_path;
5557};
5658
5759static int build(const char *arg0, int argc, char **argv) {
......@@ -99,6 +101,8 @@ static int build(const char *arg0, int argc, char **argv) {
99101 }
100102 } else if (strcmp(arg, "--name") == 0) {
101103 b.out_name = argv[i];
104 } else if (strcmp(arg, "--libc-path") == 0) {
105 b.libc_path = argv[i];
102106 } else {
103107 return usage(arg0);
104108 }
......@@ -142,6 +146,8 @@ static int build(const char *arg0, int argc, char **argv) {
142146 codegen_set_out_type(g, b.out_type);
143147 if (b.out_name)
144148 codegen_set_out_name(g, buf_create_from_str(b.out_name));
149 if (b.libc_path)
150 codegen_set_libc_path(g, buf_create_from_str(b.libc_path));
145151 codegen_set_verbose(g, b.verbose);
146152 codegen_set_errmsg_color(g, b.color);
147153 codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
src/os.cpp+3-1
......@@ -77,7 +77,9 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
7777
7878void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
7979 buf_init_from_buf(out_full_path, dirname);
80 buf_append_char(out_full_path, '/');
80 uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1);
81 if (c != '/')
82 buf_append_char(out_full_path, '/');
8183 buf_append_buf(out_full_path, basename);
8284}
8385
test/run_tests.cpp+57-103
......@@ -100,43 +100,34 @@ static void add_compiling_test_cases(void) {
100100 #link("c")
101101 extern {
102102 fn puts(s: &const u8) -> i32;
103 fn exit(code: i32) -> unreachable;
104103 }
105104
106 export fn _start() -> unreachable {
105 export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 {
107106 puts(c"Hello, world!");
108 exit(0);
107 return 0;
109108 }
110109 )SOURCE", "Hello, world!\n");
111110
112111 add_simple_case("function call", R"SOURCE(
113 #link("c")
114 extern {
115 fn puts(s: &const u8) -> i32;
116 fn exit(code: i32) -> unreachable;
117 }
112 use "std.zig";
118113
119114 fn empty_function_1() {}
120115 fn empty_function_2() { return; }
121116
122 export fn _start() -> unreachable {
117 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
123118 empty_function_1();
124119 empty_function_2();
125120 this_is_a_function();
126121 }
127122
128123 fn this_is_a_function() -> unreachable {
129 puts(c"OK");
124 print_str("OK\n" as string);
130125 exit(0);
131126 }
132127 )SOURCE", "OK\n");
133128
134129 add_simple_case("comments", R"SOURCE(
135 #link("c")
136 extern {
137 fn puts(s: &const u8) -> i32;
138 fn exit(code: i32) -> unreachable;
139 }
130 use "std.zig";
140131
141132 /**
142133 * multi line doc comment
......@@ -145,9 +136,9 @@ static void add_compiling_test_cases(void) {
145136
146137 /// this is a documentation comment
147138 /// doc comment line 2
148 export fn _start() -> unreachable {
149 puts(/* mid-line comment /* nested */ */ c"OK");
150 exit(0);
139 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
140 print_str(/* mid-line comment /* nested */ */ "OK\n" as string);
141 return 0;
151142 }
152143 )SOURCE", "OK\n");
153144
......@@ -156,7 +147,7 @@ static void add_compiling_test_cases(void) {
156147 use "libc.zig";
157148 use "foo.zig";
158149
159 export fn _start() -> unreachable {
150 export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 {
160151 private_function();
161152 }
162153
......@@ -190,180 +181,144 @@ static void add_compiling_test_cases(void) {
190181 }
191182
192183 add_simple_case("if statements", R"SOURCE(
193 #link("c")
194 extern {
195 fn puts(s: &const u8) -> i32;
196 fn exit(code: i32) -> unreachable;
197 }
184 use "std.zig";
198185
199 export fn _start() -> unreachable {
186 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
200187 if 1 != 0 {
201 puts(c"1 is true");
188 print_str("1 is true\n" as string);
202189 } else {
203 puts(c"1 is false");
190 print_str("1 is false\n" as string);
204191 }
205192 if 0 != 0 {
206 puts(c"0 is true");
193 print_str("0 is true\n" as string);
207194 } else if 1 - 1 != 0 {
208 puts(c"1 - 1 is true");
195 print_str("1 - 1 is true\n" as string);
209196 }
210197 if !(0 != 0) {
211 puts(c"!0 is true");
198 print_str("!0 is true\n" as string);
212199 }
213 exit(0);
200 return 0;
214201 }
215202 )SOURCE", "1 is true\n!0 is true\n");
216203
217204 add_simple_case("params", R"SOURCE(
218 #link("c")
219 extern {
220 fn puts(s: &const u8) -> i32;
221 fn exit(code: i32) -> unreachable;
222 }
205 use "std.zig";
223206
224207 fn add(a: i32, b: i32) -> i32 {
225208 a + b
226209 }
227210
228 export fn _start() -> unreachable {
211 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
229212 if add(22, 11) == 33 {
230 puts(c"pass");
213 print_str("pass\n" as string);
231214 }
232 exit(0);
215 return 0;
233216 }
234217 )SOURCE", "pass\n");
235218
236219 add_simple_case("goto", R"SOURCE(
237 #link("c")
238 extern {
239 fn puts(s: &const u8) -> i32;
240 fn exit(code: i32) -> unreachable;
241 }
220 use "std.zig";
242221
243222 fn loop(a : i32) {
244223 if a == 0 {
245224 goto done;
246225 }
247 puts(c"loop");
226 print_str("loop\n" as string);
248227 loop(a - 1);
249228
250229 done:
251230 return;
252231 }
253232
254 export fn _start() -> unreachable {
233 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
255234 loop(3);
256 exit(0);
235 return 0;
257236 }
258237 )SOURCE", "loop\nloop\nloop\n");
259238
260239 add_simple_case("local variables", R"SOURCE(
261#link("c")
262extern {
263 fn puts(s: &const u8) -> i32;
264 fn exit(code: i32) -> unreachable;
265}
240use "std.zig";
266241
267export fn _start() -> unreachable {
242pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
268243 const a : i32 = 1;
269244 const b = 2 as i32;
270245 if (a + b == 3) {
271 puts(c"OK");
246 print_str("OK\n" as string);
272247 }
273 exit(0);
248 return 0;
274249}
275250 )SOURCE", "OK\n");
276251
277252 add_simple_case("bool literals", R"SOURCE(
278#link("c")
279extern {
280 fn puts(s: &const u8) -> i32;
281 fn exit(code: i32) -> unreachable;
282}
253use "std.zig";
283254
284export fn _start() -> unreachable {
285 if (true) { puts(c"OK 1"); }
286 if (false) { puts(c"BAD 1"); }
287 if (!true) { puts(c"BAD 2"); }
288 if (!false) { puts(c"OK 2"); }
289 exit(0);
255pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
256 if (true) { print_str("OK 1\n" as string); }
257 if (false) { print_str("BAD 1\n" as string); }
258 if (!true) { print_str("BAD 2\n" as string); }
259 if (!false) { print_str("OK 2\n" as string); }
260 return 0;
290261}
291262 )SOURCE", "OK 1\nOK 2\n");
292263
293264 add_simple_case("separate block scopes", R"SOURCE(
294#link("c")
295extern {
296 fn puts(s: &const u8) -> i32;
297 fn exit(code: i32) -> unreachable;
298}
265use "std.zig";
299266
300export fn _start() -> unreachable {
267pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
301268 if (true) {
302269 const no_conflict : i32 = 5;
303 if (no_conflict == 5) { puts(c"OK 1"); }
270 if (no_conflict == 5) { print_str("OK 1\n" as string); }
304271 }
305272
306273 const c = {
307274 const no_conflict = 10 as i32;
308275 no_conflict
309276 };
310 if (c == 10) { puts(c"OK 2"); }
311 exit(0);
277 if (c == 10) { print_str("OK 2\n" as string); }
278 return 0;
312279}
313280 )SOURCE", "OK 1\nOK 2\n");
314281
315282 add_simple_case("void parameters", R"SOURCE(
316#link("c")
317extern {
318 fn puts(s: &const u8) -> i32;
319 fn exit(code: i32) -> unreachable;
320}
283use "std.zig";
321284
322export fn _start() -> unreachable {
285pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
323286 void_fun(1, void, 2);
324 exit(0);
287 return 0;
325288}
326289
327290fn void_fun(a : i32, b : void, c : i32) {
328291 const v = b;
329292 const vv : void = if (a == 1) {v} else {};
330 if (a + c == 3) { puts(c"OK"); }
293 if (a + c == 3) { print_str("OK\n" as string); }
331294 return vv;
332295}
333296 )SOURCE", "OK\n");
334297
335298 add_simple_case("mutable local variables", R"SOURCE(
336#link("c")
337extern {
338 fn puts(s: &const u8) -> i32;
339 fn exit(code: i32) -> unreachable;
340}
299use "std.zig";
341300
342export fn _start() -> unreachable {
301pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
343302 var zero : i32;
344 if (zero == 0) { puts(c"zero"); }
303 if (zero == 0) { print_str("zero\n" as string); }
345304
346305 var i = 0 as i32;
347306loop_start:
348307 if i == 3 {
349308 goto done;
350309 }
351 puts(c"loop");
310 print_str("loop\n" as string);
352311 i = i + 1;
353312 goto loop_start;
354313done:
355 exit(0);
314 return 0;
356315}
357316 )SOURCE", "zero\nloop\nloop\nloop\n");
358317
359318 add_simple_case("arrays", R"SOURCE(
360#link("c")
361extern {
362 fn puts(s: &const u8) -> i32;
363 fn exit(code: i32) -> unreachable;
364}
319use "std.zig";
365320
366export fn _start() -> unreachable {
321pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
367322 var array : [i32; 5];
368323
369324 var i : i32 = 0;
......@@ -391,10 +346,10 @@ loop_2_start:
391346loop_2_end:
392347
393348 if accumulator == 15 {
394 puts(c"OK");
349 print_str("OK\n" as string);
395350 }
396351
397 exit(0);
352 return 0;
398353}
399354 )SOURCE", "OK\n");
400355
......@@ -481,12 +436,11 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
481436#link("c")
482437extern {
483438 fn printf(__format: &const u8, ...) -> i32;
484 fn exit(__status: i32) -> unreachable;
485439}
486440
487export fn _start() -> unreachable {
441export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
488442 printf(c"0=%d\n", 0 as i32); // TODO: more tests
489 exit(0);
443 return 0;
490444}
491445 )SOURCE", "0=0\n");
492446