Commit 0dbee2300e
Changed files (15)
doc
vim
syntax
example
hello_world
test
doc/vim/syntax/zig.vim
@@ -7,8 +7,8 @@ if exists("b:current_syntax")
finish
endif
-syn keyword zigKeyword fn return mut const extern unreachable export pub as use while
-syn keyword zigKeyword if else let void goto type enum struct continue break match
+syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm
+syn keyword zigKeyword if else let void goto type enum struct continue break match volatile
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
syn keyword zigConstant null
doc/langref.md
@@ -70,7 +70,15 @@ VariableDeclaration : token(Let) option(token(Mut)) token(Symbol) (token(Eq) Exp
Expression : BlockExpression | NonBlockExpression
-NonBlockExpression : ReturnExpression | AssignmentExpression
+NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
+
+AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
+
+AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
+
+AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
+
+AsmClobbers: token(Colon) list(token(String), token(Comma))
AssignmentExpression : BoolOrExpression token(Equal) BoolOrExpression | BoolOrExpression
example/hello_world/hello2.zig
@@ -0,0 +1,11 @@
+export executable "hello";
+
+#link("c")
+extern {
+ fn printf(__format: *const u8, ...) -> i32;
+}
+
+export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
+ printf("argc = %zu\n", argc);
+ return 0;
+}
src/analyze.cpp
@@ -43,6 +43,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeIfExpr:
case NodeTypeLabel:
case NodeTypeGoto:
+ case NodeTypeAsmExpr:
return node;
}
zig_panic("unreachable");
@@ -205,8 +206,26 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
AstNode *directive_node = node->data.fn_proto.directives->at(i);
Buf *name = &directive_node->data.directive.name;
- add_node_error(g, directive_node,
- buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
+
+ if (buf_eql_str(name, "attribute")) {
+ Buf *attr_name = &directive_node->data.directive.param;
+ if (fn_table_entry->fn_def_node) {
+ if (buf_eql_str(attr_name, "naked")) {
+ fn_table_entry->fn_attr_list.append(FnAttrIdNaked);
+ } else if (buf_eql_str(attr_name, "alwaysinline")) {
+ fn_table_entry->fn_attr_list.append(FnAttrIdAlwaysInline);
+ } else {
+ add_node_error(g, directive_node,
+ buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
+ }
+ } else {
+ add_node_error(g, directive_node,
+ buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
+ }
+ } else {
+ add_node_error(g, directive_node,
+ buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
+ }
}
for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
@@ -338,6 +357,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
resolve_function_proto(g, proto_node, fn_table_entry);
+
assert(!proto_node->codegen_node);
proto_node->codegen_node = allocate<CodeGenNode>(1);
proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
@@ -415,6 +435,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
case NodeTypeIfExpr:
case NodeTypeLabel:
case NodeTypeGoto:
+ case NodeTypeAsmExpr:
zig_unreachable();
}
}
@@ -626,6 +647,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
return_type = g->builtin_types.entry_unreachable;
break;
}
+ case NodeTypeAsmExpr:
+ {
+ return_type = g->builtin_types.entry_void;
+ break;
+ }
case NodeTypeBinOpExpr:
{
switch (node->data.bin_op_expr.bin_op) {
@@ -1004,6 +1030,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
case NodeTypeIfExpr:
case NodeTypeLabel:
case NodeTypeGoto:
+ case NodeTypeAsmExpr:
zig_unreachable();
}
}
src/analyze.hpp
@@ -82,6 +82,11 @@ struct LabelTableEntry {
bool entered_from_fallthrough;
};
+enum FnAttrId {
+ FnAttrIdNaked,
+ FnAttrIdAlwaysInline,
+};
+
struct FnTableEntry {
LLVMValueRef fn_value;
AstNode *proto_node;
@@ -90,6 +95,7 @@ struct FnTableEntry {
bool internal_linkage;
unsigned calling_convention;
ImportTableEntry *import_entry;
+ ZigList<FnAttrId> fn_attr_list;
// reminder: hash tables must be initialized before use
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
@@ -113,6 +119,7 @@ struct CodeGen {
TypeTableEntry *entry_bool;
TypeTableEntry *entry_u8;
TypeTableEntry *entry_i32;
+ TypeTableEntry *entry_isize;
TypeTableEntry *entry_f32;
TypeTableEntry *entry_string_literal;
TypeTableEntry *entry_void;
@@ -124,6 +131,7 @@ struct CodeGen {
unsigned pointer_size_bytes;
bool is_static;
bool strip_debug_symbols;
+ bool insert_bootstrap_code;
CodeGenBuildType build_type;
LLVMTargetMachineRef target_machine;
bool is_native_target;
src/codegen.cpp
@@ -609,6 +609,41 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
return return_value;
}
+static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeAsmExpr);
+
+ Buf *src_template = &node->data.asm_expr.asm_template;
+
+ Buf llvm_template = BUF_INIT;
+ buf_resize(&llvm_template, 0);
+
+ for (int token_i = 0; token_i < node->data.asm_expr.token_list.length; token_i += 1) {
+ AsmToken *asm_token = &node->data.asm_expr.token_list.at(token_i);
+ switch (asm_token->id) {
+ case AsmTokenIdTemplate:
+ for (int offset = asm_token->start; offset < asm_token->end; offset += 1) {
+ uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
+ if (c == '$') {
+ buf_append_str(&llvm_template, "$$");
+ } else {
+ buf_append_char(&llvm_template, c);
+ }
+ }
+ break;
+ case AsmTokenIdPercent:
+ buf_append_char(&llvm_template, '%');
+ break;
+ }
+ }
+
+ LLVMTypeRef function_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false);
+
+ LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), "", true, false);
+
+ add_debug_source_node(g, node);
+ return LLVMBuildCall(g->builder, asm_fn, nullptr, 0, "");
+}
+
static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
switch (node->type) {
case NodeTypeBinOpExpr:
@@ -663,6 +698,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
return LLVMConstNull(LLVMInt1Type());
case NodeTypeIfExpr:
return gen_if_expr(g, node);
+ case NodeTypeAsmExpr:
+ return gen_asm_expr(g, node);
case NodeTypeNumberLiteral:
{
Buf *number_str = &node->data.number;
@@ -762,6 +799,16 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro
return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);
}
+static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) {
+ switch (attr_id) {
+ case FnAttrIdNaked:
+ return LLVMNakedAttribute;
+ case FnAttrIdAlwaysInline:
+ return LLVMAlwaysInlineAttribute;
+ }
+ zig_unreachable();
+}
+
static void do_code_gen(CodeGen *g) {
assert(!g->errors.length);
@@ -789,6 +836,11 @@ static void do_code_gen(CodeGen *g) {
LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);
LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_proto->name), function_type);
+ for (int attr_i = 0; attr_i < fn_table_entry->fn_attr_list.length; attr_i += 1) {
+ FnAttrId attr_id = fn_table_entry->fn_attr_list.at(attr_i);
+ LLVMAddFunctionAttr(fn, to_llvm_fn_attr(attr_id));
+ }
+
LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage);
if (type_is_unreachable(g, fn_proto->return_type)) {
@@ -966,6 +1018,19 @@ static void define_primitive_types(CodeGen *g) {
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_i32 = entry;
}
+ {
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
+ entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
+ buf_init_from_str(&entry->name, "isize");
+ entry->size_in_bits = g->pointer_size_bytes * 8;
+ entry->align_in_bits = g->pointer_size_bytes * 8;
+ entry->data.integral.is_signed = true;
+ entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+ entry->size_in_bits, entry->align_in_bits,
+ LLVMZigEncoding_DW_ATE_signed());
+ g->type_table.put(&entry->name, entry);
+ g->builtin_types.entry_isize = entry;
+ }
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
entry->type_ref = LLVMFloatType();
@@ -1121,20 +1186,30 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *sou
assert(import_entry->root->type == NodeTypeRoot);
for (int decl_i = 0; decl_i < import_entry->root->data.root.top_level_decls.length; decl_i += 1) {
AstNode *top_level_decl = import_entry->root->data.root.top_level_decls.at(decl_i);
- if (top_level_decl->type != NodeTypeUse)
- continue;
- auto entry = g->import_table.maybe_get(&top_level_decl->data.use.path);
- if (!entry) {
- Buf full_path = BUF_INIT;
- os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
- Buf *import_code = buf_alloc();
- if ((err = os_fetch_file_path(&full_path, import_code))) {
- add_node_error(g, top_level_decl,
- buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
- break;
+ if (top_level_decl->type == NodeTypeUse) {
+ auto entry = g->import_table.maybe_get(&top_level_decl->data.use.path);
+ if (!entry) {
+ Buf full_path = BUF_INIT;
+ os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
+ Buf *import_code = buf_alloc();
+ if ((err = os_fetch_file_path(&full_path, import_code))) {
+ add_node_error(g, top_level_decl,
+ buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
+ break;
+ }
+ codegen_add_code(g, &top_level_decl->data.use.path, import_code);
+ }
+ } else if (top_level_decl->type == NodeTypeFnDef) {
+ AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
+ assert(proto_node->type == NodeTypeFnProto);
+ Buf *proto_name = &proto_node->data.fn_proto.name;
+
+ bool is_exported = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModExport);
+
+ if (buf_eql_str(proto_name, "main") && is_exported) {
+ g->insert_bootstrap_code = true;
}
- codegen_add_code(g, &top_level_decl->data.use.path, import_code);
}
}
@@ -1146,6 +1221,17 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
g->root_import = codegen_add_code(g, source_path, source_code);
+ if (g->insert_bootstrap_code) {
+ Buf *path_to_bootstrap_src = buf_sprintf("%s/bootstrap.zig", ZIG_STD_DIR);
+ Buf *import_code = buf_alloc();
+ int err;
+ if ((err = os_fetch_file_path(path_to_bootstrap_src, import_code))) {
+ zig_panic("unable to open '%s': %s", buf_ptr(path_to_bootstrap_src), err_str(err));
+ }
+
+ codegen_add_code(g, path_to_bootstrap_src, import_code);
+ }
+
if (g->verbose) {
fprintf(stderr, "\nSemantic Analysis:\n");
fprintf(stderr, "--------------------\n");
@@ -1185,6 +1271,9 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
} else if (type_entry == g->builtin_types.entry_i32) {
g->c_stdint_used = true;
buf_init_from_str(out_buf, "int32_t");
+ } else if (type_entry == g->builtin_types.entry_isize) {
+ g->c_stdint_used = true;
+ buf_init_from_str(out_buf, "intptr_t");
} else if (type_entry == g->builtin_types.entry_f32) {
buf_init_from_str(out_buf, "float");
} else if (type_entry == g->builtin_types.entry_unreachable) {
src/config.h.in
@@ -7,5 +7,6 @@
#define ZIG_VERSION_STRING "@ZIG_VERSION@"
#define ZIG_HEADERS_DIR "@CMAKE_INSTALL_PREFIX@/@C_HEADERS_DEST@"
+#define ZIG_STD_DIR "@CMAKE_INSTALL_PREFIX@/@ZIG_STD_DEST@"
#endif
src/parser.cpp
@@ -104,6 +104,8 @@ const char *node_type_str(NodeType node_type) {
return "Label";
case NodeTypeGoto:
return "Label";
+ case NodeTypeAsmExpr:
+ return "AsmExpr";
}
zig_unreachable();
}
@@ -290,6 +292,9 @@ void ast_print(AstNode *node, int indent) {
case NodeTypeGoto:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));
break;
+ case NodeTypeAsmExpr:
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ break;
}
}
@@ -360,6 +365,71 @@ static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) {
buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos);
}
+static void parse_asm_template(ParseContext *pc, AstNode *node) {
+ Buf *asm_template = &node->data.asm_expr.asm_template;
+
+ enum State {
+ StateStart,
+ StatePercent,
+ StateTemplate,
+ };
+
+ ZigList<AsmToken> *tok_list = &node->data.asm_expr.token_list;
+ assert(tok_list->length == 0);
+
+ AsmToken *cur_tok = nullptr;
+
+ enum State state = StateStart;
+
+ for (int i = 0; i < buf_len(asm_template); i += 1) {
+ uint8_t c = *((uint8_t*)buf_ptr(asm_template) + i);
+ switch (state) {
+ case StateStart:
+ if (c == '%') {
+ tok_list->add_one();
+ cur_tok = &tok_list->last();
+ cur_tok->id = AsmTokenIdPercent;
+ cur_tok->start = i;
+ state = StatePercent;
+ } else {
+ tok_list->add_one();
+ cur_tok = &tok_list->last();
+ cur_tok->id = AsmTokenIdTemplate;
+ cur_tok->start = i;
+ state = StateTemplate;
+ }
+ break;
+ case StatePercent:
+ if (c == '%') {
+ cur_tok->end = i;
+ state = StateStart;
+ } else {
+ zig_panic("TODO handle assembly tokenize error");
+ }
+ break;
+ case StateTemplate:
+ if (c == '%') {
+ cur_tok->end = i;
+ i -= 1;
+ cur_tok = nullptr;
+ state = StateStart;
+ }
+ break;
+ }
+ }
+
+ switch (state) {
+ case StateStart:
+ break;
+ case StatePercent:
+ zig_panic("TODO handle assembly tokenize error eof");
+ break;
+ case StateTemplate:
+ cur_tok->end = buf_len(asm_template);
+ break;
+ }
+}
+
static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf) {
// skip the double quotes at beginning and end
// convert escape sequences
@@ -1264,7 +1334,50 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
}
/*
-NonBlockExpression : ReturnExpression | AssignmentExpression
+AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
+*/
+static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mandatory) {
+ Token *asm_token = &pc->tokens->at(*token_index);
+
+ if (asm_token->id != TokenIdKeywordAsm) {
+ if (mandatory) {
+ ast_invalid_token_error(pc, asm_token);
+ } else {
+ return nullptr;
+ }
+ }
+
+ AstNode *node = ast_create_node(pc, NodeTypeAsmExpr, asm_token);
+
+ *token_index += 1;
+ Token *lparen_tok = &pc->tokens->at(*token_index);
+
+ if (lparen_tok->id == TokenIdKeywordVolatile) {
+ node->data.asm_expr.is_volatile = true;
+
+ *token_index += 1;
+ lparen_tok = &pc->tokens->at(*token_index);
+ }
+
+ ast_expect_token(pc, lparen_tok, TokenIdLParen);
+ *token_index += 1;
+
+ Token *template_tok = &pc->tokens->at(*token_index);
+ ast_expect_token(pc, template_tok, TokenIdStringLiteral);
+ *token_index += 1;
+
+ parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template);
+ parse_asm_template(pc, node);
+
+ Token *rparen_tok = &pc->tokens->at(*token_index);
+ ast_expect_token(pc, rparen_tok, TokenIdRParen);
+ *token_index += 1;
+
+ return node;
+}
+
+/*
+NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
*/
static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -1277,6 +1390,10 @@ static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, boo
if (ass_expr)
return ass_expr;
+ AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);
+ if (asm_expr)
+ return asm_expr;
+
if (mandatory)
ast_invalid_token_error(pc, token);
src/parser.hpp
@@ -16,6 +16,7 @@
struct AstNode;
struct CodeGenNode;
struct ImportTableEntry;
+struct AsmToken;
enum NodeType {
NodeTypeRoot,
@@ -45,6 +46,7 @@ enum NodeType {
NodeTypeIfExpr,
NodeTypeLabel,
NodeTypeGoto,
+ NodeTypeAsmExpr,
};
struct AstNodeRoot {
@@ -203,6 +205,12 @@ struct AstNodeGoto {
Buf name;
};
+struct AstNodeAsmExpr {
+ bool is_volatile;
+ Buf asm_template;
+ ZigList<AsmToken> token_list;
+};
+
struct AstNode {
enum NodeType type;
int line;
@@ -231,6 +239,7 @@ struct AstNode {
AstNodeIfExpr if_expr;
AstNodeLabel label;
AstNodeGoto go_to;
+ AstNodeAsmExpr asm_expr;
Buf number;
Buf string;
Buf symbol;
@@ -238,6 +247,17 @@ struct AstNode {
} data;
};
+enum AsmTokenId {
+ AsmTokenIdTemplate,
+ AsmTokenIdPercent,
+};
+
+struct AsmToken {
+ enum AsmTokenId id;
+ int start;
+ int end;
+};
+
__attribute__ ((format (printf, 2, 3)))
void ast_token_error(Token *token, const char *format, ...);
src/tokenizer.cpp
@@ -197,6 +197,10 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordElse;
} else if (mem_eql_str(token_mem, token_len, "goto")) {
t->cur_tok->id = TokenIdKeywordGoto;
+ } else if (mem_eql_str(token_mem, token_len, "volatile")) {
+ t->cur_tok->id = TokenIdKeywordVolatile;
+ } else if (mem_eql_str(token_mem, token_len, "asm")) {
+ t->cur_tok->id = TokenIdKeywordAsm;
}
t->cur_tok = nullptr;
@@ -637,6 +641,8 @@ static const char * token_name(Token *token) {
case TokenIdKeywordIf: return "If";
case TokenIdKeywordElse: return "Else";
case TokenIdKeywordGoto: return "Goto";
+ case TokenIdKeywordVolatile: return "Volatile";
+ case TokenIdKeywordAsm: return "Asm";
case TokenIdLParen: return "LParen";
case TokenIdRParen: return "RParen";
case TokenIdComma: return "Comma";
@@ -687,3 +693,40 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {
fprintf(stderr, "\n");
}
}
+
+bool is_printable(uint8_t c) {
+ switch (c) {
+ default:
+ return false;
+ case DIGIT:
+ case ALPHA:
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case '-':
+ case '.':
+ case '/':
+ case ':':
+ case ';':
+ case '<':
+ case '=':
+ case '>':
+ case '?':
+ case '@':
+ case '^':
+ case '_':
+ case '`':
+ case '~':
+ case ' ':
+ return true;
+ }
+}
+
src/tokenizer.hpp
@@ -30,6 +30,8 @@ enum TokenId {
TokenIdKeywordIf,
TokenIdKeywordElse,
TokenIdKeywordGoto,
+ TokenIdKeywordAsm,
+ TokenIdKeywordVolatile,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,
@@ -90,4 +92,6 @@ void tokenize(Buf *buf, Tokenization *out_tokenization);
void print_tokens(Buf *buf, ZigList<Token> *tokens);
+bool is_printable(uint8_t c);
+
#endif
std/bootstrap.zig
@@ -0,0 +1,16 @@
+
+// TODO conditionally compile this differently for non-ELF
+#attribute("naked")
+export fn _start() -> unreachable {
+ // TODO conditionally compile this differently for other architectures and other OSes
+ asm volatile ("
+ mov (%%rsp), %%rdi // first parameter is argc
+ lea 0x8(%%rsp), %%rsi // second parameter is argv
+ lea 0x10(%%rsp,%%rdi,8), %%rdx // third paremeter is env
+ callq main
+ mov %%rax, %%rdi // return value is the parameter to exit syscall
+ mov $60, %%rax // 60 is exit syscall number
+ syscall
+ ");
+ unreachable
+}
test/run_tests.cpp
@@ -397,6 +397,7 @@ loop_2_end:
exit(0);
}
)SOURCE", "OK\n");
+
}
static void add_compile_failure_test_cases(void) {
CMakeLists.txt
@@ -115,7 +115,12 @@ set(C_HEADERS
"${CMAKE_SOURCE_DIR}/c_headers/xtestintrin.h"
)
+set(ZIG_STD_SRC
+ "${CMAKE_SOURCE_DIR}/std/bootstrap.zig"
+)
+
set(C_HEADERS_DEST "lib/zig/include")
+set(ZIG_STD_DEST "lib/zig/std")
set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
configure_file (
"${CMAKE_SOURCE_DIR}/src/config.h.in"
@@ -142,6 +147,7 @@ target_link_libraries(zig LINK_PUBLIC
install(TARGETS zig DESTINATION bin)
install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
+install(FILES ${ZIG_STD_SRC} DESTINATION ${ZIG_STD_DEST})
add_executable(run_tests ${TEST_SOURCES})
target_link_libraries(run_tests)
README.md
@@ -58,7 +58,6 @@ compromises backward compatibility.
* structs
* loops
* enums
- * inline assembly and syscalls
* conditional compilation and ability to check target platform and architecture
* main function with command line arguments
* void pointer constant
@@ -83,10 +82,23 @@ compromises backward compatibility.
## Building
+### Debug / Development Build
+
```
mkdir build
cd build
-cmake ..
+cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
make
+make install
./run_tests
```
+
+### Release / Install Build
+
+```
+mkdir build
+cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make
+sudo make install
+```