authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-29 17:28:28-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-29 18:02:20-07:00
log9b477230e0142e46d1276873d739cd7bac8b4e86
treed2612fca2ac6a85bf5b5aceaedaf7b773309c9cb
parentf4721857ed140add1f57badd1dc284fb24021ae0

ability to generate shared library and h file


4 files changed, 171 insertions(+), 23 deletions(-)

example/math.zig deleted-5
......@@ -1,5 +0,0 @@
1export library "math";
2
3export fn add(a: i32, b: i32) -> i32 {
4 return a + b;
5}
example/mathtest.zig created+5
......@@ -0,0 +1,5 @@
1export library "mathtest";
2
3export fn add(a: i32, b: i32) -> i32 {
4 return a + b;
5}
src/buffer.hpp+7
......@@ -12,6 +12,7 @@
1212
1313#include <assert.h>
1414#include <stdint.h>
15#include <ctype.h>
1516
1617#define BUF_INIT {{0}}
1718
......@@ -147,4 +148,10 @@ static inline uint32_t buf_hash(Buf *buf) {
147148 return h;
148149}
149150
151static inline void buf_upcase(Buf *buf) {
152 for (int i = 0; i < buf_len(buf); i += 1) {
153 buf_ptr(buf)[i] = toupper(buf_ptr(buf)[i]);
154 }
155}
156
150157#endif
src/codegen.cpp+159-18
......@@ -77,7 +77,8 @@ struct CodeGen {
7777 ZigList<FnTableEntry *> fn_defs;
7878 Buf *out_name;
7979 OutType out_type;
80 LLVMValueRef cur_fn;
80 FnTableEntry *cur_fn;
81 bool c_stdint_used;
8182};
8283
8384struct TypeNode {
......@@ -87,6 +88,7 @@ struct TypeNode {
8788struct FnDefNode {
8889 bool add_implicit_return;
8990 bool skip;
91 LLVMValueRef *params;
9092};
9193
9294struct CodeGenNode {
......@@ -639,6 +641,23 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {
639641 return global_value;
640642}
641643
644static LLVMValueRef get_variable_value(CodeGen *g, Buf *name) {
645 assert(g->cur_fn->proto_node->type == NodeTypeFnProto);
646 int param_count = g->cur_fn->proto_node->data.fn_proto.params.length;
647 for (int i = 0; i < param_count; i += 1) {
648 AstNode *param_decl_node = g->cur_fn->proto_node->data.fn_proto.params.at(i);
649 assert(param_decl_node->type == NodeTypeParamDecl);
650 Buf *param_name = &param_decl_node->data.param_decl.name;
651 if (buf_eql_buf(name, param_name)) {
652 CodeGenNode *codegen_node = g->cur_fn->fn_def_node->codegen_node;
653 assert(codegen_node);
654 FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;
655 return codegen_fn_def->params[i];
656 }
657 }
658 zig_unreachable();
659}
660
642661static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
643662 assert(node->type == NodeTypeFnCallExpr);
644663
......@@ -797,9 +816,9 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
797816 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
798817
799818 // block for when val1 == true
800 LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn, "BoolAndTrue");
819 LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue");
801820 // block for when val1 == false (don't even evaluate the second part)
802 LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn, "BoolAndFalse");
821 LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndFalse");
803822
804823 LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1));
805824 add_debug_source_node(g, node);
......@@ -828,9 +847,9 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
828847 LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1);
829848
830849 // block for when val1 == false
831 LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn, "BoolOrFalse");
850 LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse");
832851 // block for when val1 == true (don't even evaluate the second part)
833 LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn, "BoolOrTrue");
852 LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrTrue");
834853
835854 LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1));
836855 add_debug_source_node(g, expr_node);
......@@ -933,6 +952,11 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
933952 LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, "");
934953 return ptr_val;
935954 }
955 case NodeTypeSymbol:
956 {
957 Buf *name = &node->data.symbol;
958 return get_variable_value(g, name);
959 }
936960 case NodeTypeRoot:
937961 case NodeTypeRootExportDecl:
938962 case NodeTypeFnProto:
......@@ -943,7 +967,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
943967 case NodeTypeBlock:
944968 case NodeTypeExternBlock:
945969 case NodeTypeDirective:
946 case NodeTypeSymbol:
947970 zig_unreachable();
948971 }
949972 zig_unreachable();
......@@ -1047,7 +1070,7 @@ void code_gen(CodeGen *g) {
10471070 FnTableEntry *fn_table_entry = g->fn_defs.at(i);
10481071 AstNode *fn_def_node = fn_table_entry->fn_def_node;
10491072 LLVMValueRef fn = fn_table_entry->fn_value;
1050 g->cur_fn = fn;
1073 g->cur_fn = fn_table_entry;
10511074
10521075 AstNode *proto_node = fn_table_entry->proto_node;
10531076 assert(proto_node->type == NodeTypeFnProto);
......@@ -1072,7 +1095,12 @@ void code_gen(CodeGen *g) {
10721095
10731096 CodeGenNode *codegen_node = fn_def_node->codegen_node;
10741097 assert(codegen_node);
1075 bool add_implicit_return = codegen_node->data.fn_def_node.add_implicit_return;
1098
1099 FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;
1100 codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn));
1101 LLVMGetParams(fn, codegen_fn_def->params);
1102
1103 bool add_implicit_return = codegen_fn_def->add_implicit_return;
10761104 gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return);
10771105
10781106 g->block_scopes.pop();
......@@ -1216,15 +1244,113 @@ static Buf *get_dynamic_linker(CodeGen *g) {
12161244 }
12171245}
12181246
1219/*
1247static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
1248 assert(type_node->type == NodeTypeType);
1249 assert(type_node->codegen_node);
12201250
1221# static link into libfoo.a
1222ar cq libfoo.a foo1.o foo2.o
1251 TypeTableEntry *type_entry = type_node->codegen_node->data.type_node.entry;
1252 assert(type_entry);
12231253
1224# dynamic link into libfoo.so
1225gcc -fPIC -g -Werror -pedantic -shared -Wl,-soname,libsoundio.so.1 -o libsoundio.so.1.0.3 foo1.o foo2.o -ljack -lpulse -lasound -lpthread
1254 switch (type_entry->id) {
1255 case TypeIdUserDefined:
1256 zig_panic("TODO");
1257 break;
1258 case TypeIdPointer:
1259 zig_panic("TODO");
1260 break;
1261 case TypeIdU8:
1262 g->c_stdint_used = true;
1263 return buf_create_from_str("uint8_t");
1264 case TypeIdI32:
1265 g->c_stdint_used = true;
1266 return buf_create_from_str("int32_t");
1267 case TypeIdVoid:
1268 zig_panic("TODO");
1269 break;
1270 case TypeIdUnreachable:
1271 zig_panic("TODO");
1272 break;
1273 }
1274 zig_unreachable();
1275}
1276
1277static void generate_h_file(CodeGen *g) {
1278 Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->out_name));
1279 FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb");
1280 if (!out_h)
1281 zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno));
1282
1283 Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->out_name));
1284 buf_upcase(export_macro);
1285
1286 Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->out_name));
1287 buf_upcase(extern_c_macro);
1288
1289 Buf h_buf = BUF_INIT;
1290 buf_resize(&h_buf, 0);
1291 for (int fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) {
1292 FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i);
1293 AstNode *proto_node = fn_table_entry->proto_node;
1294 assert(proto_node->type == NodeTypeFnProto);
1295 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
1296
1297 if (fn_proto->visib_mod != FnProtoVisibModExport)
1298 continue;
1299
1300 buf_appendf(&h_buf, "%s %s %s(",
1301 buf_ptr(export_macro),
1302 buf_ptr(to_c_type(g, fn_proto->return_type)),
1303 buf_ptr(&fn_proto->name));
1304
1305 if (fn_proto->params.length) {
1306 for (int param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
1307 AstNode *param_decl_node = fn_proto->params.at(param_i);
1308 AstNode *param_type = param_decl_node->data.param_decl.type;
1309 buf_appendf(&h_buf, "%s %s",
1310 buf_ptr(to_c_type(g, param_type)),
1311 buf_ptr(&param_decl_node->data.param_decl.name));
1312 if (param_i < fn_proto->params.length - 1)
1313 buf_appendf(&h_buf, ", ");
1314 }
1315 buf_appendf(&h_buf, ");\n");
1316 } else {
1317 buf_appendf(&h_buf, "void);\n");
1318 }
1319 }
1320
1321 Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", buf_ptr(g->out_name), buf_ptr(g->out_name));
1322 buf_upcase(ifdef_dance_name);
1323
1324 fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name));
1325 fprintf(out_h, "#define %s\n\n", buf_ptr(ifdef_dance_name));
1326
1327 if (g->c_stdint_used)
1328 fprintf(out_h, "#include <stdint.h>\n");
1329
1330 fprintf(out_h, "\n");
1331
1332 fprintf(out_h, "#ifdef __cplusplus\n");
1333 fprintf(out_h, "#define %s extern \"C\"\n", buf_ptr(extern_c_macro));
1334 fprintf(out_h, "#else\n");
1335 fprintf(out_h, "#define %s\n", buf_ptr(extern_c_macro));
1336 fprintf(out_h, "#endif\n");
1337 fprintf(out_h, "\n");
1338 fprintf(out_h, "#if defined(_WIN32)\n");
1339 fprintf(out_h, "#define %s %s __declspec(dllimport)\n", buf_ptr(export_macro), buf_ptr(extern_c_macro));
1340 fprintf(out_h, "#else\n");
1341 fprintf(out_h, "#define %s %s __attribute__((visibility (\"default\")))\n",
1342 buf_ptr(export_macro), buf_ptr(extern_c_macro));
1343 fprintf(out_h, "#endif\n");
1344 fprintf(out_h, "\n");
1345
1346 fprintf(out_h, "%s", buf_ptr(&h_buf));
1347
1348 fprintf(out_h, "\n#endif\n");
1349
1350 if (fclose(out_h))
1351 zig_panic("unable to close h file: %s", strerror(errno));
1352}
12261353
1227*/
12281354void code_gen_link(CodeGen *g, const char *out_file) {
12291355 if (!out_file) {
12301356 out_file = buf_ptr(g->out_name);
......@@ -1250,6 +1376,9 @@ void code_gen_link(CodeGen *g, const char *out_file) {
12501376
12511377 if (g->out_type == OutTypeLib && g->is_static) {
12521378 // invoke `ar`
1379 // example:
1380 // # static link into libfoo.a
1381 // ar cq libfoo.a foo1.o foo2.o
12531382 zig_panic("TODO invoke ar");
12541383 return;
12551384 }
......@@ -1260,10 +1389,6 @@ void code_gen_link(CodeGen *g, const char *out_file) {
12601389 args.append("-static");
12611390 }
12621391
1263 if (g->out_type == OutTypeLib) {
1264 zig_panic("TODO add ld commands for shared library");
1265 }
1266
12671392 char *ZIG_NATIVE_DYNAMIC_LINKER = getenv("ZIG_NATIVE_DYNAMIC_LINKER");
12681393 if (g->is_native_target && ZIG_NATIVE_DYNAMIC_LINKER) {
12691394 if (ZIG_NATIVE_DYNAMIC_LINKER[0] != 0) {
......@@ -1275,6 +1400,18 @@ void code_gen_link(CodeGen *g, const char *out_file) {
12751400 args.append(buf_ptr(get_dynamic_linker(g)));
12761401 }
12771402
1403 if (g->out_type == OutTypeLib) {
1404 int major = 1;
1405 int minor = 0;
1406 int patch = 0;
1407 Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", buf_ptr(g->out_name), major, minor, patch);
1408 Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), major);
1409 args.append("-shared");
1410 args.append("-soname");
1411 args.append(buf_ptr(soname));
1412 out_file = buf_ptr(out_lib_so);
1413 }
1414
12781415 args.append("-o");
12791416 args.append(out_file);
12801417
......@@ -1291,6 +1428,10 @@ void code_gen_link(CodeGen *g, const char *out_file) {
12911428 }
12921429
12931430 os_spawn_process("ld", args, false);
1431
1432 if (g->out_type == OutTypeLib) {
1433 generate_h_file(g);
1434 }
12941435}
12951436
12961437