progress toward windows hello world working
This commit is contained in:
parent
199bbb6292
commit
6a93dda3e1
@ -244,7 +244,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_S
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}/special")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
|
||||
if (ZIG_TEST_COVERAGE)
|
||||
add_custom_target(coverage
|
||||
|
@ -23,9 +23,9 @@ ContainerField = Symbol option(":" Expression) ","
|
||||
|
||||
UseDecl = "use" Expression ";"
|
||||
|
||||
ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
|
||||
ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
|
||||
|
||||
FnProto = option("coldcc" | "nakedcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
|
||||
FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
|
||||
|
||||
VisibleMod = "pub" | "export"
|
||||
|
||||
|
@ -304,12 +304,14 @@ struct TldVar {
|
||||
Buf *section_name;
|
||||
AstNode *set_global_linkage_node;
|
||||
GlobalLinkageId linkage;
|
||||
Buf *extern_lib_name;
|
||||
};
|
||||
|
||||
struct TldFn {
|
||||
Tld base;
|
||||
|
||||
FnTableEntry *fn_entry;
|
||||
Buf *extern_lib_name;
|
||||
};
|
||||
|
||||
struct TldContainer {
|
||||
@ -387,6 +389,14 @@ struct AstNodeRoot {
|
||||
ZigList<AstNode *> top_level_decls;
|
||||
};
|
||||
|
||||
enum CallingConvention {
|
||||
CallingConventionUnspecified,
|
||||
CallingConventionC,
|
||||
CallingConventionCold,
|
||||
CallingConventionNaked,
|
||||
CallingConventionStdcall,
|
||||
};
|
||||
|
||||
struct AstNodeFnProto {
|
||||
VisibMod visib_mod;
|
||||
Buf *name;
|
||||
@ -395,9 +405,10 @@ struct AstNodeFnProto {
|
||||
bool is_var_args;
|
||||
bool is_extern;
|
||||
bool is_inline;
|
||||
bool is_coldcc;
|
||||
bool is_nakedcc;
|
||||
CallingConvention cc;
|
||||
AstNode *fn_def_node;
|
||||
// populated if this is an extern declaration
|
||||
Buf *lib_name;
|
||||
};
|
||||
|
||||
struct AstNodeFnDef {
|
||||
@ -451,6 +462,8 @@ struct AstNodeVariableDeclaration {
|
||||
// one or both of type and expr will be non null
|
||||
AstNode *type;
|
||||
AstNode *expr;
|
||||
// populated if this is an extern declaration
|
||||
Buf *lib_name;
|
||||
};
|
||||
|
||||
struct AstNodeErrorValueDecl {
|
||||
@ -879,9 +892,7 @@ struct FnTypeId {
|
||||
size_t param_count;
|
||||
size_t next_param_index;
|
||||
bool is_var_args;
|
||||
bool is_naked;
|
||||
bool is_cold;
|
||||
bool is_extern;
|
||||
CallingConvention cc;
|
||||
};
|
||||
|
||||
uint32_t fn_type_id_hash(FnTypeId*);
|
||||
@ -1013,7 +1024,6 @@ struct TypeTableEntryFn {
|
||||
FnGenParamInfo *gen_param_info;
|
||||
|
||||
LLVMTypeRef raw_type_ref;
|
||||
LLVMCallConv calling_convention;
|
||||
|
||||
TypeTableEntry *bound_fn_parent;
|
||||
};
|
||||
@ -1316,6 +1326,13 @@ enum BuildMode {
|
||||
BuildModeSafeRelease,
|
||||
};
|
||||
|
||||
struct LinkLib {
|
||||
Buf *name;
|
||||
Buf *path;
|
||||
ZigList<Buf *> symbols; // the list of symbols that we depend on from this lib
|
||||
bool provided_explicitly;
|
||||
};
|
||||
|
||||
struct CodeGen {
|
||||
LLVMModuleRef module;
|
||||
ZigList<ErrorMsg*> errors;
|
||||
@ -1324,7 +1341,9 @@ struct CodeGen {
|
||||
ZigLLVMDICompileUnit *compile_unit;
|
||||
ZigLLVMDIFile *compile_unit_file;
|
||||
|
||||
ZigList<Buf *> link_libs; // non-libc link libs
|
||||
ZigList<LinkLib *> link_libs_list;
|
||||
LinkLib *libc_link_lib;
|
||||
|
||||
// add -framework [name] args to linker
|
||||
ZigList<Buf *> darwin_frameworks;
|
||||
// add -rpath [name] args to linker
|
||||
@ -1344,6 +1363,7 @@ struct CodeGen {
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
|
||||
|
||||
|
||||
ZigList<ImportTableEntry *> import_queue;
|
||||
size_t import_queue_index;
|
||||
ZigList<Tld *> resolve_queue;
|
||||
@ -1402,7 +1422,6 @@ struct CodeGen {
|
||||
bool have_pub_main;
|
||||
bool have_c_main;
|
||||
bool have_pub_panic;
|
||||
bool link_libc;
|
||||
Buf *libc_lib_dir;
|
||||
Buf *libc_static_lib_dir;
|
||||
Buf *libc_include_dir;
|
||||
|
170
src/analyze.cpp
170
src/analyze.cpp
@ -802,6 +802,21 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) {
|
||||
return bound_fn_type;
|
||||
}
|
||||
|
||||
bool calling_convention_does_first_arg_return(CallingConvention cc) {
|
||||
return cc == CallingConventionUnspecified;
|
||||
}
|
||||
|
||||
static const char *calling_convention_name(CallingConvention cc) {
|
||||
switch (cc) {
|
||||
case CallingConventionUnspecified: return "undefined";
|
||||
case CallingConventionC: return "ccc";
|
||||
case CallingConventionCold: return "coldcc";
|
||||
case CallingConventionNaked: return "nakedcc";
|
||||
case CallingConventionStdcall: return "stdcallcc";
|
||||
default: zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
|
||||
if (table_entry) {
|
||||
@ -813,30 +828,29 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
fn_type->is_copyable = true;
|
||||
fn_type->data.fn.fn_type_id = *fn_type_id;
|
||||
|
||||
if (fn_type_id->is_cold) {
|
||||
// cold calling convention only works on x86.
|
||||
// but we can add the cold attribute later.
|
||||
if (g->zig_target.arch.arch == ZigLLVM_x86 ||
|
||||
g->zig_target.arch.arch == ZigLLVM_x86_64)
|
||||
{
|
||||
fn_type->data.fn.calling_convention = LLVMColdCallConv;
|
||||
} else {
|
||||
fn_type->data.fn.calling_convention = LLVMFastCallConv;
|
||||
}
|
||||
} else if (fn_type_id->is_extern) {
|
||||
fn_type->data.fn.calling_convention = LLVMCCallConv;
|
||||
} else {
|
||||
fn_type->data.fn.calling_convention = LLVMFastCallConv;
|
||||
}
|
||||
|
||||
bool skip_debug_info = false;
|
||||
|
||||
// populate the name of the type
|
||||
buf_resize(&fn_type->name, 0);
|
||||
const char *extern_str = fn_type_id->is_extern ? "extern " : "";
|
||||
const char *naked_str = fn_type_id->is_naked ? "nakedcc " : "";
|
||||
const char *cold_str = fn_type_id->is_cold ? "coldcc " : "";
|
||||
buf_appendf(&fn_type->name, "%s%s%sfn(", extern_str, naked_str, cold_str);
|
||||
const char *cc_str;
|
||||
switch (fn_type->data.fn.fn_type_id.cc) {
|
||||
case CallingConventionUnspecified:
|
||||
cc_str = "";
|
||||
break;
|
||||
case CallingConventionC:
|
||||
cc_str = "extern ";
|
||||
break;
|
||||
case CallingConventionCold:
|
||||
cc_str = "coldcc ";
|
||||
break;
|
||||
case CallingConventionNaked:
|
||||
cc_str = "nakedcc ";
|
||||
break;
|
||||
case CallingConventionStdcall:
|
||||
cc_str = "stdcallcc ";
|
||||
break;
|
||||
}
|
||||
buf_appendf(&fn_type->name, "%sfn(", cc_str);
|
||||
for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
|
||||
FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
|
||||
|
||||
@ -861,7 +875,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
// next, loop over the parameters again and compute debug information
|
||||
// and codegen information
|
||||
if (!skip_debug_info) {
|
||||
bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type);
|
||||
bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
|
||||
handle_is_ptr(fn_type_id->return_type);
|
||||
// +1 for maybe making the first argument the return value
|
||||
LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);
|
||||
// +1 because 0 is the return type and +1 for maybe making first arg ret val
|
||||
@ -1013,9 +1028,13 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
|
||||
|
||||
fn_type_id->is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
|
||||
fn_type_id->is_naked = fn_proto->is_nakedcc;
|
||||
fn_type_id->is_cold = fn_proto->is_coldcc;
|
||||
if (fn_proto->cc == CallingConventionUnspecified) {
|
||||
bool extern_abi = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
|
||||
fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified;
|
||||
} else {
|
||||
fn_type_id->cc = fn_proto->cc;
|
||||
}
|
||||
|
||||
fn_type_id->param_count = fn_proto->params.length;
|
||||
fn_type_id->param_info = allocate_nonzero<FnTypeParamInfo>(param_count_alloc);
|
||||
fn_type_id->next_param_index = 0;
|
||||
@ -1037,18 +1056,24 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
bool param_is_var_args = param_node->data.param_decl.is_var_args;
|
||||
|
||||
if (param_is_comptime) {
|
||||
if (fn_type_id.is_extern) {
|
||||
if (fn_type_id.cc != CallingConventionUnspecified) {
|
||||
add_node_error(g, param_node,
|
||||
buf_sprintf("comptime parameter not allowed in extern function"));
|
||||
buf_sprintf("comptime parameter not allowed in function with calling convention '%s'",
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
return get_generic_fn_type(g, &fn_type_id);
|
||||
} else if (param_is_var_args) {
|
||||
if (fn_type_id.is_extern) {
|
||||
if (fn_type_id.cc == CallingConventionC) {
|
||||
fn_type_id.param_count = fn_type_id.next_param_index;
|
||||
continue;
|
||||
} else {
|
||||
} else if (fn_type_id.cc == CallingConventionUnspecified) {
|
||||
return get_generic_fn_type(g, &fn_type_id);
|
||||
} else {
|
||||
add_node_error(g, param_node,
|
||||
buf_sprintf("var args not allowed in function with calling convention '%s'",
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1066,9 +1091,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
case TypeTableEntryIdVar:
|
||||
if (fn_type_id.is_extern) {
|
||||
if (fn_type_id.cc != CallingConventionUnspecified) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
buf_sprintf("parameter of type 'var' not allowed in extern function"));
|
||||
buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'",
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
return get_generic_fn_type(g, &fn_type_id);
|
||||
@ -1097,7 +1123,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
ensure_complete_type(g, type_entry);
|
||||
if (!fn_type_id.is_extern && !type_is_copyable(g, type_entry)) {
|
||||
if (fn_type_id.cc == CallingConventionUnspecified && !type_is_copyable(g, type_entry)) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
@ -1130,10 +1156,11 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
if (fn_type_id.is_extern) {
|
||||
if (fn_type_id.cc != CallingConventionUnspecified) {
|
||||
add_node_error(g, fn_proto->return_type,
|
||||
buf_sprintf("return type '%s' not allowed in extern function",
|
||||
buf_ptr(&fn_type_id.return_type->name)));
|
||||
buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
|
||||
buf_ptr(&fn_type_id.return_type->name),
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
return get_generic_fn_type(g, &fn_type_id);
|
||||
@ -1947,7 +1974,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
|
||||
if (buf_eql_str(&fn_table_entry->symbol_name, "main")) {
|
||||
g->main_fn = fn_table_entry;
|
||||
|
||||
if (!g->link_libc && tld_fn->base.visib_mod != VisibModExport) {
|
||||
if (g->libc_link_lib == nullptr && tld_fn->base.visib_mod != VisibModExport) {
|
||||
TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
|
||||
TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
|
||||
if (actual_return_type != err_void) {
|
||||
@ -2109,6 +2136,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
VisibMod visib_mod = node->data.variable_declaration.visib_mod;
|
||||
TldVar *tld_var = allocate<TldVar>(1);
|
||||
init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base);
|
||||
tld_var->extern_lib_name = node->data.variable_declaration.lib_name;
|
||||
add_top_level_decl(g, decls_scope, &tld_var->base);
|
||||
break;
|
||||
}
|
||||
@ -2124,6 +2152,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
VisibMod visib_mod = node->data.fn_proto.visib_mod;
|
||||
TldFn *tld_fn = allocate<TldFn>(1);
|
||||
init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base);
|
||||
tld_fn->extern_lib_name = node->data.fn_proto.lib_name;
|
||||
add_top_level_decl(g, decls_scope, &tld_fn->base);
|
||||
|
||||
ImportTableEntry *import = get_scope_import(&decls_scope->base);
|
||||
@ -2497,13 +2526,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
|
||||
if (expected_type->id == TypeTableEntryIdFn &&
|
||||
actual_type->id == TypeTableEntryIdFn)
|
||||
{
|
||||
if (expected_type->data.fn.fn_type_id.is_extern != actual_type->data.fn.fn_type_id.is_extern) {
|
||||
return false;
|
||||
}
|
||||
if (expected_type->data.fn.fn_type_id.is_naked != actual_type->data.fn.fn_type_id.is_naked) {
|
||||
return false;
|
||||
}
|
||||
if (expected_type->data.fn.fn_type_id.is_cold != actual_type->data.fn.fn_type_id.is_cold) {
|
||||
if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
|
||||
return false;
|
||||
}
|
||||
if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
|
||||
@ -2780,11 +2803,6 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
|
||||
add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
|
||||
}
|
||||
|
||||
if (fn_type_id->is_extern && handle_is_ptr(param_type)) {
|
||||
add_node_error(g, param_decl_node,
|
||||
buf_sprintf("byvalue types not yet supported on extern function parameters"));
|
||||
}
|
||||
|
||||
VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
|
||||
param_name, true, create_const_runtime(param_type), nullptr);
|
||||
var->src_arg_index = i;
|
||||
@ -2849,12 +2867,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
|
||||
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
||||
assert(!fn_type->data.fn.is_generic);
|
||||
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
|
||||
|
||||
if (fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type)) {
|
||||
add_node_error(g, return_type_node,
|
||||
buf_sprintf("byvalue types not yet supported on extern function return values"));
|
||||
}
|
||||
|
||||
ir_gen_fn(g, fn_table_entry);
|
||||
if (fn_table_entry->ir_executable.invalid) {
|
||||
@ -3018,7 +3030,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a
|
||||
g->have_pub_panic = true;
|
||||
}
|
||||
} else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "main") &&
|
||||
g->link_libc)
|
||||
g->libc_link_lib != nullptr)
|
||||
{
|
||||
g->have_c_main = true;
|
||||
}
|
||||
@ -3189,9 +3201,7 @@ bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b) {
|
||||
|
||||
uint32_t fn_type_id_hash(FnTypeId *id) {
|
||||
uint32_t result = 0;
|
||||
result += id->is_extern ? (uint32_t)3349388391 : 0;
|
||||
result += id->is_naked ? (uint32_t)608688877 : 0;
|
||||
result += id->is_cold ? (uint32_t)3605523458 : 0;
|
||||
result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
|
||||
result += id->is_var_args ? (uint32_t)1931444534 : 0;
|
||||
result += hash_ptr(id->return_type);
|
||||
for (size_t i = 0; i < id->param_count; i += 1) {
|
||||
@ -3203,9 +3213,7 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
|
||||
}
|
||||
|
||||
bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
|
||||
if (a->is_extern != b->is_extern ||
|
||||
a->is_naked != b->is_naked ||
|
||||
a->is_cold != b->is_cold ||
|
||||
if (a->cc != b->cc ||
|
||||
a->return_type != b->return_type ||
|
||||
a->is_var_args != b->is_var_args ||
|
||||
a->param_count != b->param_count)
|
||||
@ -4344,8 +4352,7 @@ FnTableEntry *get_extern_panic_fn(CodeGen *g) {
|
||||
return g->extern_panic_fn;
|
||||
|
||||
FnTypeId fn_type_id = {0};
|
||||
fn_type_id.is_extern = true;
|
||||
fn_type_id.is_cold = true;
|
||||
fn_type_id.cc = CallingConventionCold;
|
||||
fn_type_id.param_count = 2;
|
||||
fn_type_id.param_info = allocate<FnTypeParamInfo>(2);
|
||||
fn_type_id.next_param_index = 0;
|
||||
@ -4525,3 +4532,42 @@ const char *type_id_name(TypeTableEntryId id) {
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
LinkLib *create_link_lib(Buf *name) {
|
||||
LinkLib *link_lib = allocate<LinkLib>(1);
|
||||
link_lib->name = name;
|
||||
return link_lib;
|
||||
}
|
||||
|
||||
LinkLib *add_link_lib(CodeGen *g, Buf *name) {
|
||||
bool is_libc = buf_eql_str(name, "c");
|
||||
|
||||
if (is_libc && g->libc_link_lib != nullptr)
|
||||
return g->libc_link_lib;
|
||||
|
||||
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
LinkLib *existing_lib = g->link_libs_list.at(i);
|
||||
if (buf_eql_buf(existing_lib->name, name)) {
|
||||
return existing_lib;
|
||||
}
|
||||
}
|
||||
|
||||
LinkLib *link_lib = create_link_lib(name);
|
||||
g->link_libs_list.append(link_lib);
|
||||
|
||||
if (is_libc)
|
||||
g->libc_link_lib = link_lib;
|
||||
|
||||
return link_lib;
|
||||
}
|
||||
|
||||
void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name) {
|
||||
LinkLib *link_lib = add_link_lib(g, lib_name);
|
||||
for (size_t i = 0; i < link_lib->symbols.length; i += 1) {
|
||||
Buf *existing_symbol_name = link_lib->symbols.at(i);
|
||||
if (buf_eql_buf(existing_symbol_name, symbol_name)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
link_lib->symbols.append(symbol_name);
|
||||
}
|
||||
|
@ -168,5 +168,9 @@ size_t type_id_len();
|
||||
size_t type_id_index(TypeTableEntryId id);
|
||||
TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
|
||||
bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
|
||||
LinkLib *create_link_lib(Buf *name);
|
||||
bool calling_convention_does_first_arg_return(CallingConvention cc);
|
||||
LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
|
||||
void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name);
|
||||
|
||||
#endif
|
||||
|
@ -118,6 +118,17 @@ static const char *extern_string(bool is_extern) {
|
||||
return is_extern ? "extern " : "";
|
||||
}
|
||||
|
||||
static const char *calling_convention_string(CallingConvention cc) {
|
||||
switch (cc) {
|
||||
case CallingConventionUnspecified: return "";
|
||||
case CallingConventionC: return "extern ";
|
||||
case CallingConventionCold: return "coldcc ";
|
||||
case CallingConventionNaked: return "nakedcc ";
|
||||
case CallingConventionStdcall: return "stdcallcc ";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static const char *inline_string(bool is_inline) {
|
||||
return is_inline ? "inline " : "";
|
||||
}
|
||||
@ -951,10 +962,8 @@ static void ast_render_tld_fn(AstRender *ar, Buf *name, TldFn *tld_fn) {
|
||||
FnTableEntry *fn_entry = tld_fn->fn_entry;
|
||||
FnTypeId *fn_type_id = &fn_entry->type_entry->data.fn.fn_type_id;
|
||||
const char *visib_mod_str = visib_mod_string(tld_fn->base.visib_mod);
|
||||
const char *extern_str = extern_string(fn_type_id->is_extern);
|
||||
const char *coldcc_str = fn_type_id->is_cold ? "coldcc " : "";
|
||||
const char *nakedcc_str = fn_type_id->is_naked ? "nakedcc " : "";
|
||||
fprintf(ar->f, "%s%s%s%sfn %s(", visib_mod_str, extern_str, coldcc_str, nakedcc_str, buf_ptr(&fn_entry->symbol_name));
|
||||
const char *cc_str = calling_convention_string(fn_type_id->cc);
|
||||
fprintf(ar->f, "%s%sfn %s(", visib_mod_str, cc_str, buf_ptr(&fn_entry->symbol_name));
|
||||
for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
|
||||
FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
|
||||
if (i != 0) {
|
||||
|
@ -138,8 +138,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
|
||||
g->zig_target.os == ZigLLVM_MacOSX ||
|
||||
g->zig_target.os == ZigLLVM_IOS)
|
||||
{
|
||||
g->link_libc = true;
|
||||
g->link_libs.append(buf_create_from_str("c"));
|
||||
g->libc_link_lib = create_link_lib(buf_create_from_str("c"));
|
||||
}
|
||||
|
||||
return g;
|
||||
@ -234,13 +233,8 @@ void codegen_add_rpath(CodeGen *g, const char *name) {
|
||||
g->rpath_list.append(buf_create_from_str(name));
|
||||
}
|
||||
|
||||
void codegen_add_link_lib(CodeGen *g, const char *lib) {
|
||||
if (strcmp(lib, "c") == 0) {
|
||||
if (g->link_libc)
|
||||
return;
|
||||
g->link_libc = true;
|
||||
}
|
||||
g->link_libs.append(buf_create_from_str(lib));
|
||||
LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) {
|
||||
return add_link_lib(g, name);
|
||||
}
|
||||
|
||||
void codegen_add_framework(CodeGen *g, const char *framework) {
|
||||
@ -334,6 +328,33 @@ static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linka
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
|
||||
switch (cc) {
|
||||
case CallingConventionUnspecified: return LLVMFastCallConv;
|
||||
case CallingConventionC: return LLVMCCallConv;
|
||||
case CallingConventionCold:
|
||||
// cold calling convention only works on x86.
|
||||
if (g->zig_target.arch.arch == ZigLLVM_x86 ||
|
||||
g->zig_target.arch.arch == ZigLLVM_x86_64)
|
||||
{
|
||||
return LLVMColdCallConv;
|
||||
} else {
|
||||
return LLVMCCallConv;
|
||||
}
|
||||
break;
|
||||
case CallingConventionNaked:
|
||||
zig_unreachable();
|
||||
case CallingConventionStdcall:
|
||||
// stdcall calling convention only works on x86.
|
||||
if (g->zig_target.arch.arch == ZigLLVM_x86) {
|
||||
return LLVMX86StdcallCallConv;
|
||||
} else {
|
||||
return LLVMCCallConv;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
if (fn_table_entry->llvm_value)
|
||||
return fn_table_entry->llvm_value;
|
||||
@ -355,6 +376,16 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
}
|
||||
fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);
|
||||
|
||||
//if (buf_eql_str(&fn_table_entry->symbol_name, "ExitProcess") ||
|
||||
// buf_eql_str(&fn_table_entry->symbol_name, "GetConsoleMode") ||
|
||||
// buf_eql_str(&fn_table_entry->symbol_name, "GetStdHandle") ||
|
||||
// buf_eql_str(&fn_table_entry->symbol_name, "GetFileInformationByHandleEx") ||
|
||||
// buf_eql_str(&fn_table_entry->symbol_name, "GetLastError") ||
|
||||
// buf_eql_str(&fn_table_entry->symbol_name, "WriteFile"))
|
||||
//{
|
||||
// LLVMSetDLLStorageClass(fn_table_entry->llvm_value, LLVMDLLImportStorageClass);
|
||||
//}
|
||||
|
||||
switch (fn_table_entry->fn_inline) {
|
||||
case FnInlineAlways:
|
||||
addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");
|
||||
@ -366,8 +397,14 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
case FnInlineAuto:
|
||||
break;
|
||||
}
|
||||
if (fn_type->data.fn.fn_type_id.is_naked) {
|
||||
|
||||
if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) {
|
||||
addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
|
||||
} else {
|
||||
LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
|
||||
if (fn_type->data.fn.fn_type_id.cc == CallingConventionCold) {
|
||||
ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
|
||||
}
|
||||
}
|
||||
|
||||
switch (fn_table_entry->linkage) {
|
||||
@ -393,17 +430,13 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
if (fn_table_entry->body_node != nullptr) {
|
||||
bool want_fn_safety = g->build_mode != BuildModeFastRelease && !fn_table_entry->def_scope->safety_off;
|
||||
if (want_fn_safety) {
|
||||
if (g->link_libc) {
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
|
||||
addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention);
|
||||
if (fn_type->data.fn.fn_type_id.is_cold) {
|
||||
ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
|
||||
}
|
||||
addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
|
||||
if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
|
||||
ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
|
||||
@ -700,7 +733,8 @@ static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len
|
||||
FnTableEntry *panic_fn = get_extern_panic_fn(g);
|
||||
LLVMValueRef fn_val = fn_llvm_value(g, panic_fn);
|
||||
LLVMValueRef args[] = { msg_ptr, msg_len };
|
||||
ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, false, "");
|
||||
LLVMCallConv llvm_cc = get_llvm_cc(g, panic_fn->type_entry->data.fn.fn_type_id.cc);
|
||||
ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, false, "");
|
||||
LLVMBuildUnreachable(g->builder);
|
||||
}
|
||||
|
||||
@ -1100,15 +1134,14 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
|
||||
static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
|
||||
LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
|
||||
TypeTableEntry *return_type = return_instruction->value->value.type;
|
||||
bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern;
|
||||
if (handle_is_ptr(return_type)) {
|
||||
if (is_extern) {
|
||||
LLVMValueRef by_val_value = LLVMBuildLoad(g->builder, value, "");
|
||||
LLVMBuildRet(g->builder, by_val_value);
|
||||
} else {
|
||||
if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
|
||||
assert(g->cur_ret_ptr);
|
||||
gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
|
||||
LLVMBuildRetVoid(g->builder);
|
||||
} else {
|
||||
LLVMValueRef by_val_value = LLVMBuildLoad(g->builder, value, "");
|
||||
LLVMBuildRet(g->builder, by_val_value);
|
||||
}
|
||||
} else {
|
||||
LLVMBuildRet(g->builder, value);
|
||||
@ -2059,9 +2092,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
bool want_always_inline = (instruction->fn_entry != nullptr &&
|
||||
instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline;
|
||||
|
||||
LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
|
||||
LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
|
||||
gen_param_values, (unsigned)gen_param_index, fn_type->data.fn.calling_convention,
|
||||
want_always_inline, "");
|
||||
gen_param_values, (unsigned)gen_param_index, llvm_cc, want_always_inline, "");
|
||||
|
||||
for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
|
||||
FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
|
||||
@ -3893,7 +3926,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
{
|
||||
addLLVMAttr(fn_val, 0, "nonnull");
|
||||
} else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&
|
||||
!fn_type->data.fn.fn_type_id.is_extern)
|
||||
calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
|
||||
{
|
||||
addLLVMArgAttr(fn_val, 0, "sret");
|
||||
addLLVMArgAttr(fn_val, 0, "nonnull");
|
||||
@ -4648,15 +4681,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
||||
buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ);
|
||||
buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
|
||||
buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
|
||||
|
||||
{
|
||||
buf_appendf(contents, "pub const link_libs = [][]const u8 {\n");
|
||||
for (size_t i = 0; i < g->link_libs.length; i += 1) {
|
||||
Buf *link_lib_buf = g->link_libs.at(i);
|
||||
buf_appendf(contents, " \"%s\",\n", buf_ptr(link_lib_buf));
|
||||
}
|
||||
buf_appendf(contents, "};\n");
|
||||
}
|
||||
buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
|
||||
|
||||
buf_appendf(contents, "pub const __zig_panic_implementation_provided = %s; // overwritten later\n",
|
||||
bool_to_str(false));
|
||||
|
@ -33,7 +33,7 @@ void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
|
||||
void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
|
||||
void codegen_set_windows_unicode(CodeGen *g, bool municode);
|
||||
void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
|
||||
void codegen_add_link_lib(CodeGen *codegen, const char *lib);
|
||||
LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
|
||||
void codegen_add_framework(CodeGen *codegen, const char *name);
|
||||
void codegen_add_rpath(CodeGen *codegen, const char *name);
|
||||
void codegen_set_mlinker_version(CodeGen *g, Buf *darwin_linker_version);
|
||||
|
26
src/ir.cpp
26
src/ir.cpp
@ -9044,7 +9044,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
|
||||
if (comptime_fn_call) {
|
||||
// No special handling is needed for compile time evaluation of generic functions.
|
||||
if (!fn_entry || fn_entry->type_entry->data.fn.fn_type_id.is_extern) {
|
||||
if (!fn_entry || fn_entry->body_node == nullptr) {
|
||||
ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
@ -10129,6 +10129,10 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
|
||||
{
|
||||
TldVar *tld_var = (TldVar *)tld;
|
||||
VariableTableEntry *var = tld_var->var;
|
||||
if (tld_var->extern_lib_name != nullptr) {
|
||||
add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);
|
||||
}
|
||||
|
||||
return ir_analyze_var_ptr(ira, source_instruction, var, false, false);
|
||||
}
|
||||
case TldIdFn:
|
||||
@ -10147,6 +10151,10 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
|
||||
const_val->type = fn_entry->type_entry;
|
||||
const_val->data.x_fn.fn_entry = fn_entry;
|
||||
|
||||
if (tld_fn->extern_lib_name != nullptr) {
|
||||
add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);
|
||||
}
|
||||
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry,
|
||||
@ -13167,13 +13175,15 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
|
||||
|
||||
bool param_is_var_args = param_node->data.param_decl.is_var_args;
|
||||
if (param_is_var_args) {
|
||||
if (fn_type_id.is_extern) {
|
||||
if (fn_type_id.cc == CallingConventionC) {
|
||||
fn_type_id.param_count = fn_type_id.next_param_index;
|
||||
continue;
|
||||
} else {
|
||||
} else if (fn_type_id.cc == CallingConventionUnspecified) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
|
||||
@ -13484,6 +13494,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
|
||||
if (type_is_invalid(var_ptr->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (tld_var->extern_lib_name != nullptr) {
|
||||
add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);
|
||||
}
|
||||
|
||||
if (lval.is_ptr) {
|
||||
ir_link_new_instruction(var_ptr, &instruction->base);
|
||||
return var_ptr->value.type;
|
||||
@ -13499,6 +13513,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
|
||||
FnTableEntry *fn_entry = tld_fn->fn_entry;
|
||||
assert(fn_entry->type_entry);
|
||||
|
||||
if (tld_fn->extern_lib_name != nullptr) {
|
||||
add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);
|
||||
}
|
||||
|
||||
IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
|
||||
instruction->base.source_node, fn_entry);
|
||||
if (lval.is_ptr) {
|
||||
@ -13896,7 +13914,7 @@ FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableE
|
||||
assert(src_fn_type->id == TypeTableEntryIdFn);
|
||||
|
||||
FnTypeId new_fn_type = src_fn_type->data.fn.fn_type_id;
|
||||
new_fn_type.is_extern = false;
|
||||
new_fn_type.cc = CallingConventionUnspecified;
|
||||
|
||||
fn_entry->type_entry = get_fn_type(codegen, &new_fn_type);
|
||||
|
||||
|
80
src/link.cpp
80
src/link.cpp
@ -38,12 +38,6 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
|
||||
|
||||
ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target;
|
||||
CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode);
|
||||
child_gen->link_libc = parent_gen->link_libc;
|
||||
|
||||
child_gen->link_libs.resize(parent_gen->link_libs.length);
|
||||
for (size_t i = 0; i < parent_gen->link_libs.length; i += 1) {
|
||||
child_gen->link_libs.items[i] = parent_gen->link_libs.items[i];
|
||||
}
|
||||
|
||||
codegen_set_omit_zigrt(child_gen, true);
|
||||
child_gen->want_h_file = false;
|
||||
@ -215,13 +209,13 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
if (g->each_lib_rpath) {
|
||||
for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
|
||||
const char *lib_dir = g->lib_dirs.at(i);
|
||||
for (size_t i = 0; i < g->link_libs.length; i += 1) {
|
||||
Buf *link_lib = g->link_libs.at(i);
|
||||
if (buf_eql_str(link_lib, "c")) {
|
||||
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
LinkLib *link_lib = g->link_libs_list.at(i);
|
||||
if (buf_eql_str(link_lib->name, "c")) {
|
||||
continue;
|
||||
}
|
||||
bool does_exist;
|
||||
Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib));
|
||||
Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib->name));
|
||||
if (os_file_exists(test_path, &does_exist) != ErrorNone) {
|
||||
zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path));
|
||||
}
|
||||
@ -239,7 +233,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
lj->args.append(lib_dir);
|
||||
}
|
||||
|
||||
if (g->link_libc) {
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
lj->args.append("-L");
|
||||
lj->args.append(buf_ptr(g->libc_lib_dir));
|
||||
|
||||
@ -265,7 +259,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
|
||||
}
|
||||
|
||||
if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
|
||||
if (g->libc_link_lib == nullptr && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
|
||||
Buf *builtin_o_path = build_o(g, "builtin");
|
||||
lj->args.append(buf_ptr(builtin_o_path));
|
||||
|
||||
@ -273,25 +267,25 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
lj->args.append(buf_ptr(compiler_rt_o_path));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < g->link_libs.length; i += 1) {
|
||||
Buf *link_lib = g->link_libs.at(i);
|
||||
if (buf_eql_str(link_lib, "c")) {
|
||||
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
LinkLib *link_lib = g->link_libs_list.at(i);
|
||||
if (buf_eql_str(link_lib->name, "c")) {
|
||||
continue;
|
||||
}
|
||||
Buf *arg;
|
||||
if (buf_starts_with_str(link_lib, "/") || buf_ends_with_str(link_lib, ".a") ||
|
||||
buf_ends_with_str(link_lib, ".so"))
|
||||
if (buf_starts_with_str(link_lib->name, "/") || buf_ends_with_str(link_lib->name, ".a") ||
|
||||
buf_ends_with_str(link_lib->name, ".so"))
|
||||
{
|
||||
arg = link_lib;
|
||||
arg = link_lib->name;
|
||||
} else {
|
||||
arg = buf_sprintf("-l%s", buf_ptr(link_lib));
|
||||
arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
|
||||
}
|
||||
lj->args.append(buf_ptr(arg));
|
||||
}
|
||||
|
||||
|
||||
// libc dep
|
||||
if (g->link_libc) {
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
if (g->is_static) {
|
||||
lj->args.append("--start-group");
|
||||
lj->args.append("-lgcc");
|
||||
@ -394,7 +388,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));
|
||||
}
|
||||
|
||||
if (g->link_libc) {
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
|
||||
}
|
||||
@ -403,7 +397,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
|
||||
}
|
||||
|
||||
if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
|
||||
if (g->libc_link_lib == nullptr && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
|
||||
Buf *builtin_o_path = build_o(g, "builtin");
|
||||
lj->args.append(buf_ptr(builtin_o_path));
|
||||
|
||||
@ -411,17 +405,35 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
lj->args.append(buf_ptr(compiler_rt_o_path));
|
||||
}
|
||||
|
||||
|
||||
for (size_t i = 0; i < g->link_libs.length; i += 1) {
|
||||
Buf *link_lib = g->link_libs.at(i);
|
||||
if (buf_eql_str(link_lib, "c")) {
|
||||
Buf *def_contents = buf_alloc();
|
||||
for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
|
||||
LinkLib *link_lib = g->link_libs_list.at(lib_i);
|
||||
if (buf_eql_str(link_lib->name, "c")) {
|
||||
continue;
|
||||
}
|
||||
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));
|
||||
lj->args.append(buf_ptr(arg));
|
||||
if (link_lib->provided_explicitly) {
|
||||
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
|
||||
lj->args.append(buf_ptr(arg));
|
||||
} else {
|
||||
buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name));
|
||||
for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) {
|
||||
Buf *symbol_name = link_lib->symbols.at(exp_i);
|
||||
buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name));
|
||||
}
|
||||
buf_appendf(def_contents, "\n");
|
||||
}
|
||||
}
|
||||
if (buf_len(def_contents) != 0) {
|
||||
Buf *dll_path = buf_alloc();
|
||||
os_path_join(g->cache_dir, buf_create_from_str("all.dll"), dll_path);
|
||||
ZigLLDDefToLib(def_contents, dll_path);
|
||||
|
||||
Buf *all_lib_path = buf_alloc();
|
||||
os_path_join(g->cache_dir, buf_create_from_str("all.lib"), all_lib_path);
|
||||
lj->args.append(buf_ptr(all_lib_path));
|
||||
}
|
||||
|
||||
if (g->link_libc) {
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
if (g->is_static) {
|
||||
lj->args.append("--start-group");
|
||||
}
|
||||
@ -664,12 +676,12 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < g->link_libs.length; i += 1) {
|
||||
Buf *link_lib = g->link_libs.at(i);
|
||||
if (buf_eql_str(link_lib, "c")) {
|
||||
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
LinkLib *link_lib = g->link_libs_list.at(i);
|
||||
if (buf_eql_str(link_lib->name, "c")) {
|
||||
continue;
|
||||
}
|
||||
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));
|
||||
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
|
||||
lj->args.append(buf_ptr(arg));
|
||||
}
|
||||
|
||||
@ -771,7 +783,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
||||
return;
|
||||
}
|
||||
|
||||
lj.link_in_crt = (g->link_libc && g->out_type == OutTypeExe);
|
||||
lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe);
|
||||
|
||||
construct_linker_job(&lj);
|
||||
|
||||
|
@ -601,7 +601,8 @@ int main(int argc, char **argv) {
|
||||
codegen_add_lib_dir(g, lib_dirs.at(i));
|
||||
}
|
||||
for (size_t i = 0; i < link_libs.length; i += 1) {
|
||||
codegen_add_link_lib(g, link_libs.at(i));
|
||||
LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
|
||||
link_lib->provided_explicitly = true;
|
||||
}
|
||||
for (size_t i = 0; i < frameworks.length; i += 1) {
|
||||
codegen_add_framework(g, frameworks.at(i));
|
||||
|
@ -477,8 +477,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
|
||||
}
|
||||
|
||||
FnTypeId fn_type_id = {0};
|
||||
fn_type_id.is_naked = false;
|
||||
fn_type_id.is_extern = true;
|
||||
fn_type_id.cc = CallingConventionC;
|
||||
fn_type_id.is_var_args = fn_proto_ty->isVariadic();
|
||||
fn_type_id.param_count = fn_proto_ty->getNumParams();
|
||||
|
||||
@ -619,7 +618,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
|
||||
buf_init_from_buf(&fn_entry->symbol_name, fn_name);
|
||||
fn_entry->type_entry = fn_type;
|
||||
|
||||
assert(!fn_type->data.fn.fn_type_id.is_naked);
|
||||
assert(fn_type->data.fn.fn_type_id.cc != CallingConventionNaked);
|
||||
|
||||
size_t arg_count = fn_type->data.fn.fn_type_id.param_count;
|
||||
fn_entry->param_names = allocate<Buf *>(arg_count);
|
||||
|
@ -2123,25 +2123,29 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
|
||||
}
|
||||
|
||||
/*
|
||||
FnProto = option("coldcc" | "nakedcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
|
||||
FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
|
||||
*/
|
||||
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
Token *fn_token;
|
||||
|
||||
bool is_coldcc = false;
|
||||
bool is_nakedcc = false;
|
||||
CallingConvention cc;
|
||||
if (first_token->id == TokenIdKeywordColdCC) {
|
||||
*token_index += 1;
|
||||
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
|
||||
is_coldcc = true;
|
||||
cc = CallingConventionCold;
|
||||
} else if (first_token->id == TokenIdKeywordNakedCC) {
|
||||
*token_index += 1;
|
||||
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
|
||||
is_nakedcc = true;
|
||||
cc = CallingConventionNaked;
|
||||
} else if (first_token->id == TokenIdKeywordStdcallCC) {
|
||||
*token_index += 1;
|
||||
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
|
||||
cc = CallingConventionStdcall;
|
||||
} else if (first_token->id == TokenIdKeywordFn) {
|
||||
fn_token = first_token;
|
||||
*token_index += 1;
|
||||
cc = CallingConventionUnspecified;
|
||||
} else if (mandatory) {
|
||||
ast_expect_token(pc, first_token, TokenIdKeywordFn);
|
||||
zig_unreachable();
|
||||
@ -2151,8 +2155,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
|
||||
node->data.fn_proto.visib_mod = visib_mod;
|
||||
node->data.fn_proto.is_coldcc = is_coldcc;
|
||||
node->data.fn_proto.is_nakedcc = is_nakedcc;
|
||||
node->data.fn_proto.cc = cc;
|
||||
|
||||
Token *fn_name = &pc->tokens->at(*token_index);
|
||||
if (fn_name->id == TokenIdSymbol) {
|
||||
@ -2220,7 +2223,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man
|
||||
}
|
||||
|
||||
/*
|
||||
ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
|
||||
ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
|
||||
*/
|
||||
static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
|
||||
Token *extern_kw = &pc->tokens->at(*token_index);
|
||||
@ -2233,11 +2236,19 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
|
||||
}
|
||||
*token_index += 1;
|
||||
|
||||
Token *lib_name_tok = &pc->tokens->at(*token_index);
|
||||
Buf *lib_name = nullptr;
|
||||
if (lib_name_tok->id == TokenIdStringLiteral) {
|
||||
lib_name = token_buf(lib_name_tok);
|
||||
*token_index += 1;
|
||||
}
|
||||
|
||||
AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, visib_mod);
|
||||
if (fn_proto_node) {
|
||||
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||
|
||||
fn_proto_node->data.fn_proto.is_extern = true;
|
||||
fn_proto_node->data.fn_proto.lib_name = lib_name;
|
||||
|
||||
return fn_proto_node;
|
||||
}
|
||||
@ -2247,6 +2258,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
|
||||
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||
|
||||
var_decl_node->data.variable_declaration.is_extern = true;
|
||||
var_decl_node->data.variable_declaration.lib_name = lib_name;
|
||||
|
||||
return var_decl_node;
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = {
|
||||
{"packed", TokenIdKeywordPacked},
|
||||
{"pub", TokenIdKeywordPub},
|
||||
{"return", TokenIdKeywordReturn},
|
||||
{"stdcallcc", TokenIdKeywordStdcallCC},
|
||||
{"struct", TokenIdKeywordStruct},
|
||||
{"switch", TokenIdKeywordSwitch},
|
||||
{"test", TokenIdKeywordTest},
|
||||
@ -1471,6 +1472,7 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdKeywordPacked: return "packed";
|
||||
case TokenIdKeywordPub: return "pub";
|
||||
case TokenIdKeywordReturn: return "return";
|
||||
case TokenIdKeywordStdcallCC: return "stdcallcc";
|
||||
case TokenIdKeywordStruct: return "struct";
|
||||
case TokenIdKeywordSwitch: return "switch";
|
||||
case TokenIdKeywordTest: return "test";
|
||||
|
@ -71,6 +71,7 @@ enum TokenId {
|
||||
TokenIdKeywordPacked,
|
||||
TokenIdKeywordPub,
|
||||
TokenIdKeywordReturn,
|
||||
TokenIdKeywordStdcallCC,
|
||||
TokenIdKeywordStruct,
|
||||
TokenIdKeywordSwitch,
|
||||
TokenIdKeywordTest,
|
||||
|
149
src/zig_llvm.cpp
149
src/zig_llvm.cpp
@ -38,6 +38,7 @@
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/TargetParser.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/Support/COFF.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Transforms/IPO.h>
|
||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||
@ -791,3 +792,151 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
// workaround for LLD not exposing ability to convert .def to .lib
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace lld {
|
||||
namespace coff {
|
||||
|
||||
class SymbolBody;
|
||||
class StringChunk;
|
||||
struct Symbol;
|
||||
|
||||
struct Export {
|
||||
StringRef Name; // N in /export:N or /export:E=N
|
||||
StringRef ExtName; // E in /export:E=N
|
||||
SymbolBody *Sym = nullptr;
|
||||
uint16_t Ordinal = 0;
|
||||
bool Noname = false;
|
||||
bool Data = false;
|
||||
bool Private = false;
|
||||
|
||||
// If an export is a form of /export:foo=dllname.bar, that means
|
||||
// that foo should be exported as an alias to bar in the DLL.
|
||||
// ForwardTo is set to "dllname.bar" part. Usually empty.
|
||||
StringRef ForwardTo;
|
||||
StringChunk *ForwardChunk = nullptr;
|
||||
|
||||
// True if this /export option was in .drectves section.
|
||||
bool Directives = false;
|
||||
StringRef SymbolName;
|
||||
StringRef ExportName; // Name in DLL
|
||||
|
||||
bool operator==(const Export &E) {
|
||||
return (Name == E.Name && ExtName == E.ExtName &&
|
||||
Ordinal == E.Ordinal && Noname == E.Noname &&
|
||||
Data == E.Data && Private == E.Private);
|
||||
}
|
||||
};
|
||||
|
||||
enum class DebugType {
|
||||
None = 0x0,
|
||||
CV = 0x1, /// CodeView
|
||||
PData = 0x2, /// Procedure Data
|
||||
Fixup = 0x4, /// Relocation Table
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
enum ManifestKind { SideBySide, Embed, No };
|
||||
llvm::COFF::MachineTypes Machine = llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
|
||||
bool Verbose = false;
|
||||
llvm::COFF::WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
|
||||
SymbolBody *Entry = nullptr;
|
||||
bool NoEntry = false;
|
||||
std::string OutputFile;
|
||||
bool DoGC = true;
|
||||
bool DoICF = true;
|
||||
bool Relocatable = true;
|
||||
bool Force = false;
|
||||
bool Debug = false;
|
||||
bool WriteSymtab = true;
|
||||
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
|
||||
StringRef PDBPath;
|
||||
|
||||
// Symbols in this set are considered as live by the garbage collector.
|
||||
std::set<SymbolBody *> GCRoot;
|
||||
|
||||
std::set<StringRef> NoDefaultLibs;
|
||||
bool NoDefaultLibAll = false;
|
||||
|
||||
// True if we are creating a DLL.
|
||||
bool DLL = false;
|
||||
StringRef Implib;
|
||||
std::vector<Export> Exports;
|
||||
std::set<std::string> DelayLoads;
|
||||
std::map<std::string, int> DLLOrder;
|
||||
SymbolBody *DelayLoadHelper = nullptr;
|
||||
|
||||
// Used for SafeSEH.
|
||||
Symbol *SEHTable = nullptr;
|
||||
Symbol *SEHCount = nullptr;
|
||||
|
||||
// Used for /opt:lldlto=N
|
||||
unsigned LTOOptLevel = 2;
|
||||
|
||||
// Used for /opt:lldltojobs=N
|
||||
unsigned LTOJobs = 1;
|
||||
|
||||
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
|
||||
std::map<StringRef, StringRef> Merge;
|
||||
|
||||
// Used for /section=.name,{DEKPRSW} to set section attributes.
|
||||
std::map<StringRef, uint32_t> Section;
|
||||
|
||||
// Options for manifest files.
|
||||
ManifestKind Manifest = SideBySide;
|
||||
int ManifestID = 1;
|
||||
StringRef ManifestDependency;
|
||||
bool ManifestUAC = true;
|
||||
std::vector<std::string> ManifestInput;
|
||||
StringRef ManifestLevel = "'asInvoker'";
|
||||
StringRef ManifestUIAccess = "'false'";
|
||||
StringRef ManifestFile;
|
||||
|
||||
// Used for /failifmismatch.
|
||||
std::map<StringRef, StringRef> MustMatch;
|
||||
|
||||
// Used for /alternatename.
|
||||
std::map<StringRef, StringRef> AlternateNames;
|
||||
|
||||
uint64_t ImageBase = -1;
|
||||
uint64_t StackReserve = 1024 * 1024;
|
||||
uint64_t StackCommit = 4096;
|
||||
uint64_t HeapReserve = 1024 * 1024;
|
||||
uint64_t HeapCommit = 4096;
|
||||
uint32_t MajorImageVersion = 0;
|
||||
uint32_t MinorImageVersion = 0;
|
||||
uint32_t MajorOSVersion = 6;
|
||||
uint32_t MinorOSVersion = 0;
|
||||
bool DynamicBase = true;
|
||||
bool AllowBind = true;
|
||||
bool NxCompat = true;
|
||||
bool AllowIsolation = true;
|
||||
bool TerminalServerAware = true;
|
||||
bool LargeAddressAware = false;
|
||||
bool HighEntropyVA = false;
|
||||
|
||||
// This is for debugging.
|
||||
bool DebugPdb = false;
|
||||
bool DumpPdb = false;
|
||||
};
|
||||
|
||||
extern Configuration *Config;
|
||||
|
||||
void writeImportLibrary();
|
||||
void parseModuleDefs(MemoryBufferRef MB);
|
||||
|
||||
} // namespace coff
|
||||
} // namespace lld
|
||||
|
||||
// writes the output to dll_path with .dll replaced with .lib
|
||||
void ZigLLDDefToLib(Buf *def_contents, Buf *dll_path) {
|
||||
lld::coff::Config = new lld::coff::Configuration;
|
||||
auto mem_buf = MemoryBuffer::getMemBuffer(buf_ptr(def_contents));
|
||||
MemoryBufferRef mbref(*mem_buf);
|
||||
lld::coff::parseModuleDefs(mbref);
|
||||
lld::coff::Config->OutputFile = buf_ptr(dll_path);
|
||||
lld::coff::writeImportLibrary();
|
||||
}
|
||||
|
@ -359,5 +359,6 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su
|
||||
ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type,
|
||||
ZigLLVM_ObjectFormatType *oformat);
|
||||
|
||||
void ZigLLDDefToLib(Buf *def_contents, Buf *dll_path);
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub extern fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int;
|
||||
pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int;
|
||||
fn extern "c" __error() -> &c_int;
|
||||
|
||||
extern fn __error() -> &c_int;
|
||||
pub const _errno = __error;
|
||||
|
@ -9,7 +9,6 @@ pub use switch(builtin.os) {
|
||||
else => empty_import,
|
||||
};
|
||||
|
||||
pub extern fn abort() -> noreturn;
|
||||
|
||||
pub extern "c" fn abort() -> noreturn;
|
||||
|
||||
const empty_import = @import("../empty.zig");
|
||||
|
@ -1,4 +1,3 @@
|
||||
pub extern fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int;
|
||||
|
||||
extern fn __errno_location() -> &c_int;
|
||||
pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int;
|
||||
extern "c" fn __errno_location() -> &c_int;
|
||||
pub const _errno = __errno_location;
|
||||
|
@ -1 +1 @@
|
||||
pub extern fn _errno() -> &c_int;
|
||||
pub extern "c" fn _errno() -> &c_int;
|
||||
|
@ -16,7 +16,9 @@ pub fn assert(ok: bool) {
|
||||
|
||||
var panicking = false;
|
||||
/// This is the default panic implementation.
|
||||
pub coldcc fn panic(comptime format: []const u8, args: ...) -> noreturn {
|
||||
pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
|
||||
// TODO an intrinsic that labels this as unlikely to be reached
|
||||
|
||||
// TODO
|
||||
// if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
|
||||
if (panicking) {
|
||||
|
@ -22,7 +22,6 @@ pub const net = @import("net.zig");
|
||||
pub const os = @import("os/index.zig");
|
||||
pub const rand = @import("rand.zig");
|
||||
pub const sort = @import("sort.zig");
|
||||
pub const target = @import("target.zig");
|
||||
|
||||
test "std" {
|
||||
// run tests from these
|
||||
@ -50,5 +49,4 @@ test "std" {
|
||||
_ = @import("os/index.zig");
|
||||
_ = @import("rand.zig");
|
||||
_ = @import("sort.zig");
|
||||
_ = @import("target.zig");
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ const debug = @import("../debug.zig");
|
||||
const assert = debug.assert;
|
||||
|
||||
const errno = @import("errno.zig");
|
||||
const linking_libc = @import("../target.zig").linking_libc;
|
||||
const c = @import("../c/index.zig");
|
||||
|
||||
const mem = @import("../mem.zig");
|
||||
@ -60,14 +59,14 @@ pub fn getRandomBytes(buf: []u8) -> %void {
|
||||
while (true) {
|
||||
const err = switch (builtin.os) {
|
||||
Os.linux => {
|
||||
if (linking_libc) {
|
||||
if (builtin.link_libc) {
|
||||
if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 0
|
||||
} else {
|
||||
posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0))
|
||||
}
|
||||
},
|
||||
Os.darwin, Os.macosx, Os.ios => {
|
||||
if (linking_libc) {
|
||||
if (builtin.link_libc) {
|
||||
if (posix.getrandom(buf.ptr, buf.len) == -1) *c._errno() else 0
|
||||
} else {
|
||||
posix.getErrno(posix.getrandom(buf.ptr, buf.len))
|
||||
@ -103,7 +102,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
|
||||
/// If linking against libc, this calls the abort() libc function. Otherwise
|
||||
/// it uses the zig standard library implementation.
|
||||
pub coldcc fn abort() -> noreturn {
|
||||
if (linking_libc) {
|
||||
if (builtin.link_libc) {
|
||||
c.abort();
|
||||
}
|
||||
switch (builtin.os) {
|
||||
|
@ -1,39 +1,50 @@
|
||||
pub const ERROR = @import("error.zig");
|
||||
|
||||
pub extern fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR,
|
||||
pub extern "kernel32" stdcallcc fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR,
|
||||
pszProvider: LPCTSTR, dwProvType: DWORD, dwFlags: DWORD) -> bool;
|
||||
|
||||
pub extern fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool;
|
||||
pub extern "kernel32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool;
|
||||
|
||||
pub extern fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool;
|
||||
pub extern "kernel32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool;
|
||||
|
||||
pub extern fn ExitProcess(exit_code: UINT) -> noreturn;
|
||||
pub extern "kernel32" fn ExitProcess(exit_code: UINT) -> noreturn;
|
||||
|
||||
pub extern fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;
|
||||
pub extern "kernel32" stdcallcc fn GetCommandLine() -> LPTSTR;
|
||||
|
||||
pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;
|
||||
|
||||
/// Retrieves the calling thread's last-error code value. The last-error code is maintained on a per-thread basis.
|
||||
/// Multiple threads do not overwrite each other's last-error code.
|
||||
pub extern fn GetLastError() -> DWORD;
|
||||
pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD;
|
||||
|
||||
/// Retrieves file information for the specified file.
|
||||
pub extern fn GetFileInformationByHandleEx(in_hFile: HANDLE, in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
|
||||
out_lpFileInformation: &c_void, in_dwBufferSize: DWORD) -> bool;
|
||||
pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE,
|
||||
in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, out_lpFileInformation: &c_void,
|
||||
in_dwBufferSize: DWORD) -> bool;
|
||||
|
||||
/// Retrieves a handle to the specified standard device (standard input, standard output, or standard error).
|
||||
pub extern fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;
|
||||
pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;
|
||||
|
||||
/// Reads data from the specified file or input/output (I/O) device. Reads occur at the position specified by the file pointer if supported by the device.
|
||||
/// This function is designed for both synchronous and asynchronous operations. For a similar function designed solely for asynchronous operation, see ReadFileEx.
|
||||
pub extern fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID, in_nNumberOfBytesToRead: DWORD,
|
||||
out_lpNumberOfBytesRead: &DWORD, in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
|
||||
pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID,
|
||||
in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
|
||||
in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
|
||||
|
||||
/// Writes data to the specified file or input/output (I/O) device.
|
||||
/// This function is designed for both synchronous and asynchronous operation. For a similar function designed solely for asynchronous operation, see WriteFileEx.
|
||||
pub extern fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &const c_void, in_nNumberOfBytesToWrite: DWORD,
|
||||
out_lpNumberOfBytesWritten: ?&DWORD, in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
|
||||
pub extern "kernel32" stdcallcc fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &const c_void,
|
||||
in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD,
|
||||
in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
|
||||
|
||||
pub const PROV_RSA_FULL = 1;
|
||||
|
||||
pub const UNICODE = false;
|
||||
pub const LPTSTR = if (unicode) LPWSTR else LPSTR;
|
||||
pub const LPWSTR = &WCHAR;
|
||||
pub const LPSTR = &CHAR;
|
||||
pub const CHAR = u8;
|
||||
|
||||
|
||||
pub const BOOL = bool;
|
||||
pub const BYTE = u8;
|
||||
@ -45,12 +56,13 @@ pub const LPCTSTR = &const TCHAR;
|
||||
pub const LPDWORD = &DWORD;
|
||||
pub const LPVOID = &c_void;
|
||||
pub const PVOID = &c_void;
|
||||
pub const TCHAR = u8; // TODO something about unicode WCHAR vs char
|
||||
pub const TCHAR = if (UNICODE) WCHAR else u8;
|
||||
pub const UINT = c_uint;
|
||||
pub const ULONG_PTR = usize;
|
||||
pub const WCHAR = u16;
|
||||
pub const LPCVOID = &const c_void;
|
||||
|
||||
|
||||
/// The standard input device. Initially, this is the console input buffer, CONIN$.
|
||||
pub const STD_INPUT_HANDLE = @maxValue(DWORD) - 10 + 1;
|
||||
|
||||
|
@ -5,19 +5,23 @@ const root = @import("@root");
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const want_main_symbol = std.target.linking_libc;
|
||||
const want_main_symbol = builtin.link_libc;
|
||||
const want_start_symbol = !want_main_symbol;
|
||||
|
||||
const posix_exit = std.os.posix.exit;
|
||||
|
||||
var argc_ptr: &usize = undefined;
|
||||
|
||||
const is_windows = builtin.os == builtin.Os.windows;
|
||||
|
||||
export nakedcc fn _start() -> noreturn {
|
||||
if (!want_start_symbol) {
|
||||
@setGlobalLinkage(_start, builtin.GlobalLinkage.Internal);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
if (is_windows) {
|
||||
windowsCallMainAndExit()
|
||||
}
|
||||
|
||||
switch (builtin.arch) {
|
||||
builtin.Arch.x86_64 => {
|
||||
argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));
|
||||
@ -27,23 +31,21 @@ export nakedcc fn _start() -> noreturn {
|
||||
},
|
||||
else => @compileError("unsupported arch"),
|
||||
}
|
||||
callMainAndExit()
|
||||
posixCallMainAndExit()
|
||||
}
|
||||
|
||||
fn callMainAndExit() -> noreturn {
|
||||
fn windowsCallMainAndExit() -> noreturn {
|
||||
std.debug.user_main_fn = root.main;
|
||||
root.main() %% std.os.windows.ExitProcess(1);
|
||||
std.os.windows.ExitProcess(0);
|
||||
}
|
||||
|
||||
fn posixCallMainAndExit() -> noreturn {
|
||||
const argc = *argc_ptr;
|
||||
const argv = @ptrCast(&&u8, &argc_ptr[1]);
|
||||
const envp = @ptrCast(&?&u8, &argv[argc + 1]);
|
||||
callMain(argc, argv, envp) %% exit(true);
|
||||
exit(false);
|
||||
}
|
||||
|
||||
fn exit(failure: bool) -> noreturn {
|
||||
if (builtin.os == builtin.Os.windows) {
|
||||
std.os.windows.ExitProcess(c_uint(failure));
|
||||
} else {
|
||||
posix_exit(i32(failure));
|
||||
}
|
||||
callMain(argc, argv, envp) %% std.os.posix.exit(1);
|
||||
std.os.posix.exit(0);
|
||||
}
|
||||
|
||||
fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
|
||||
|
@ -1,16 +0,0 @@
|
||||
const mem = @import("mem.zig");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub const linking_libc = linkingLibrary("c");
|
||||
|
||||
pub fn linkingLibrary(lib_name: []const u8) -> bool {
|
||||
// TODO shouldn't need this if
|
||||
if (builtin.link_libs.len != 0) {
|
||||
for (builtin.link_libs) |link_lib| {
|
||||
if (mem.eql(u8, link_lib, lib_name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
@ -409,18 +409,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
".tmp_source.zig:2:1: error: redefinition of 'a'",
|
||||
".tmp_source.zig:1:1: note: previous definition is here");
|
||||
|
||||
cases.add("byvalue struct parameter in exported function",
|
||||
\\const A = struct { x : i32, };
|
||||
\\export fn f(a : A) {}
|
||||
, ".tmp_source.zig:2:13: error: byvalue types not yet supported on extern function parameters");
|
||||
|
||||
cases.add("byvalue struct return value in exported function",
|
||||
\\const A = struct { x: i32, };
|
||||
\\export fn f() -> A {
|
||||
\\ A {.x = 1234 }
|
||||
\\}
|
||||
, ".tmp_source.zig:2:18: error: byvalue types not yet supported on extern function return values");
|
||||
|
||||
cases.add("duplicate field in struct value expression",
|
||||
\\const A = struct {
|
||||
\\ x : i32,
|
||||
@ -1070,7 +1058,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\export fn foo(comptime x: i32, y: i32) -> i32{
|
||||
\\ x + y
|
||||
\\}
|
||||
, ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function");
|
||||
, ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
|
||||
|
||||
cases.add("extern function with comptime parameter",
|
||||
\\extern fn foo(comptime x: i32, y: i32) -> i32;
|
||||
@ -1078,7 +1066,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\ foo(1, 2)
|
||||
\\}
|
||||
\\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
|
||||
, ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function");
|
||||
, ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
|
||||
|
||||
cases.add("convert fixed size array to slice with invalid size",
|
||||
\\export fn f() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user