mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-23 14:14:59 -07:00
build_dll; Require an entry point procedure main
This commit is contained in:
@@ -49,7 +49,8 @@ rem pushd %build_dir%
|
||||
cl %compiler_settings% "src\main.c" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run code/demo.odin
|
||||
rem odin run code/demo.odin
|
||||
rem && odin build_dll code/example.odin ^
|
||||
rem && odin run code/demo.odin
|
||||
|
||||
|
||||
:do_not_compile_exe
|
||||
|
||||
+24
-1
@@ -1,6 +1,29 @@
|
||||
#import "win32.odin"
|
||||
#import "fmt.odin"
|
||||
|
||||
|
||||
main :: proc() {
|
||||
get_proc :: proc(lib: win32.HMODULE, name: string) -> proc() {
|
||||
buf: [4096]byte
|
||||
copy(buf[:], name as []byte)
|
||||
|
||||
proc_handle := win32.GetProcAddress(lib, ^buf[0])
|
||||
return proc_handle as proc()
|
||||
}
|
||||
|
||||
lib := win32.LoadLibraryA(("example.dll\x00" as string).data)
|
||||
if lib == nil {
|
||||
fmt.println("Could not load library")
|
||||
return
|
||||
}
|
||||
defer win32.FreeLibrary(lib)
|
||||
|
||||
proc_handle := get_proc(lib, "some_thing")
|
||||
if proc_handle == nil {
|
||||
fmt.println("Could not load 'some_thing'")
|
||||
return
|
||||
}
|
||||
|
||||
some_thing := (proc_handle as proc())
|
||||
some_thing()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#shared_global_scope
|
||||
|
||||
/*
|
||||
#import "fmt.odin"
|
||||
|
||||
__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" {
|
||||
@@ -154,3 +155,4 @@ __u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
|
||||
q.all = (q.all << 1) | (carry as u128)
|
||||
return q.all, r.all
|
||||
}
|
||||
*/
|
||||
|
||||
+5
-4
@@ -123,6 +123,7 @@ bprint_i64 :: proc(buffer: ^[]byte, value: i64) {
|
||||
bprint_u64(buffer, i as u64)
|
||||
}
|
||||
|
||||
/*
|
||||
bprint_u128 :: proc(buffer: ^[]byte, value: u128) {
|
||||
a := value transmute [2]u64
|
||||
if a[1] != 0 {
|
||||
@@ -138,7 +139,7 @@ bprint_i128 :: proc(buffer: ^[]byte, value: i128) {
|
||||
}
|
||||
bprint_u128(buffer, i as u128)
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
|
||||
@@ -353,8 +354,8 @@ bprint_any :: proc(buf: ^[]byte, arg: any) {
|
||||
case u32: bprint_u64(buf, i as u64)
|
||||
case i64: bprint_i64(buf, i)
|
||||
case u64: bprint_u64(buf, i)
|
||||
case i128: bprint_i128(buf, i)
|
||||
case u128: bprint_u128(buf, i)
|
||||
// case i128: bprint_i128(buf, i)
|
||||
// case u128: bprint_u128(buf, i)
|
||||
|
||||
case int: bprint_i64(buf, i as i64)
|
||||
case uint: bprint_u64(buf, i as u64)
|
||||
@@ -484,7 +485,7 @@ bprint_any :: proc(buf: ^[]byte, arg: any) {
|
||||
bprint_string(buf, "(raw_union)")
|
||||
case Procedure:
|
||||
bprint_type(buf, arg.type_info)
|
||||
bprint_string(buf, " @ 0x")
|
||||
bprint_string(buf, " @ ")
|
||||
bprint_pointer(buf, (arg.data as ^rawptr)^)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
#import "fmt.odin"
|
||||
#import "os.odin"
|
||||
|
||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #export "__mem_set" {
|
||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
||||
llvm_memset_64bit(data, value as byte, len, 1, false)
|
||||
return data
|
||||
@@ -11,14 +11,14 @@ zero :: proc(data: rawptr, len: int) -> rawptr {
|
||||
return set(data, 0, len)
|
||||
}
|
||||
|
||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #export "__mem_copy" {
|
||||
// NOTE(bill): This _must_ implemented like C's memmove
|
||||
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
||||
llvm_memmove_64bit(dst, src, len, 1, false)
|
||||
return dst
|
||||
}
|
||||
|
||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
|
||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #export "__mem_copy_non_overlapping" {
|
||||
// NOTE(bill): This _must_ implemented like C's memcpy
|
||||
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
|
||||
llvm_memcpy_64bit(dst, src, len, 1, false)
|
||||
@@ -26,7 +26,7 @@ copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "_
|
||||
}
|
||||
|
||||
|
||||
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
||||
compare :: proc(dst, src: rawptr, n: int) -> int #export "__mem_compare" {
|
||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||
a := slice_ptr(dst as ^byte, n)
|
||||
b := slice_ptr(src as ^byte, n)
|
||||
|
||||
@@ -65,12 +65,13 @@ last_write_time :: proc(f: ^File) -> File_Time {
|
||||
last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
last_write_time: win32.FILETIME
|
||||
data: win32.WIN32_FILE_ATTRIBUTE_DATA
|
||||
|
||||
buf: [1024]byte
|
||||
path := buf[:0]
|
||||
fmt.bprint(^path, name, "\x00")
|
||||
|
||||
if win32.GetFileAttributesExA(path.data, win32.GetFileExInfoStandard, ^data) != 0 {
|
||||
assert(buf.count > name.count)
|
||||
|
||||
copy(buf[:], name as []byte)
|
||||
|
||||
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
||||
last_write_time = data.last_write_time
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ typedef struct BuildContext {
|
||||
i64 max_align;
|
||||
String llc_flags;
|
||||
String link_flags;
|
||||
bool is_dll;
|
||||
} BuildContext;
|
||||
|
||||
// TODO(bill): OS dependent versions for the BuildContext
|
||||
|
||||
+42
-8
@@ -292,9 +292,17 @@ bool decl_info_has_init(DeclInfo *d) {
|
||||
return true;
|
||||
}
|
||||
if (d->proc_decl != NULL) {
|
||||
ast_node(pd, ProcDecl, d->proc_decl);
|
||||
if (pd->body != NULL) {
|
||||
return true;
|
||||
switch (d->proc_decl->kind) {
|
||||
case_ast_node(pd, ProcDecl, d->proc_decl);
|
||||
if (pd->body != NULL) {
|
||||
return true;
|
||||
}
|
||||
case_end;
|
||||
case_ast_node(pd, ProcLit, d->proc_decl);
|
||||
if (pd->body != NULL) {
|
||||
return true;
|
||||
}
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -949,12 +957,15 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) {
|
||||
MapEntity map = {0}; // Key: Entity *
|
||||
map_entity_init(&map, heap_allocator());
|
||||
|
||||
for_array(i, info->entities.entries) {
|
||||
MapDeclInfoEntry *entry = &info->entities.entries.e[i];
|
||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
||||
for_array(i, info->definitions.entries) {
|
||||
Entity *e = info->definitions.entries.e[i].value;
|
||||
if (e->scope->is_global) {
|
||||
// NOTE(bill): Require runtime stuff
|
||||
add_dependency_to_map(&map, info, e);
|
||||
} else if (e->kind == Entity_Procedure) {
|
||||
if ((e->Procedure.tags & ProcTag_export) != 0) {
|
||||
add_dependency_to_map(&map, info, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1189,7 +1200,7 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
|
||||
case_ast_node(pd, ProcDecl, decl);
|
||||
ast_node(n, Ident, pd->name);
|
||||
Token token = *n;
|
||||
Entity *e = make_entity_procedure(c->allocator, parent_scope, token, NULL);
|
||||
Entity *e = make_entity_procedure(c->allocator, parent_scope, token, NULL, pd->tags);
|
||||
e->identifier = pd->name;
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->proc_decl = decl;
|
||||
@@ -1386,7 +1397,6 @@ void check_parsed_files(Checker *c) {
|
||||
|
||||
check_import_entities(c, &file_scopes);
|
||||
|
||||
map_scope_destroy(&file_scopes);
|
||||
|
||||
check_all_global_entities(c);
|
||||
init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)`
|
||||
@@ -1473,6 +1483,30 @@ void check_parsed_files(Checker *c) {
|
||||
i64 align = type_align_of(c->sizes, c->allocator, e->type);
|
||||
}
|
||||
}
|
||||
|
||||
for_array(i, file_scopes.entries) {
|
||||
Scope *s = file_scopes.entries.e[i].value;
|
||||
if (s->is_init) {
|
||||
Entity *e = current_scope_lookup_entity(s, str_lit("main"));
|
||||
if (e == NULL) {
|
||||
Token token = {0};
|
||||
if (s->file->tokens.count > 0) {
|
||||
token = s->file->tokens.e[0];
|
||||
} else {
|
||||
token.pos.file = s->file->tokenizer.fullpath;
|
||||
token.pos.line = 1;
|
||||
token.pos.column = 1;
|
||||
}
|
||||
|
||||
error(token, "Undefined entry point procedure `main`");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
map_scope_destroy(&file_scopes);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+19
-11
@@ -139,8 +139,9 @@ void check_var_decl_node(Checker *c, AstNode *node) {
|
||||
Type *init_type = NULL;
|
||||
if (vd->type) {
|
||||
init_type = check_type_extra(c, vd->type, NULL);
|
||||
if (init_type == NULL)
|
||||
if (init_type == NULL) {
|
||||
init_type = t_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
@@ -180,7 +181,9 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
|
||||
if (operand->mode != Addressing_Constant) {
|
||||
// TODO(bill): better error
|
||||
error_node(operand->expr, "`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
|
||||
gbString str = expr_to_string(operand->expr);
|
||||
error_node(operand->expr, "`%s` is not a constant", str);
|
||||
gb_string_free(str);
|
||||
if (e->type == NULL) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
@@ -306,7 +309,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
check_procedure_type(c, proc_type, pd->type);
|
||||
|
||||
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
||||
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
||||
bool is_export = (pd->tags & ProcTag_export) != 0;
|
||||
bool is_inline = (pd->tags & ProcTag_inline) != 0;
|
||||
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
||||
|
||||
@@ -315,10 +318,9 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
if (proc_type != NULL) {
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
if (pt->param_count != 0 ||
|
||||
pt->result_count) {
|
||||
pt->result_count != 0) {
|
||||
gbString str = type_to_string(proc_type);
|
||||
error(e->token,
|
||||
"Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
@@ -328,8 +330,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||
}
|
||||
|
||||
if (is_foreign && is_link_name) {
|
||||
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
|
||||
if (is_foreign && is_export) {
|
||||
error_node(pd->type, "You cannot apply both `foreign` and `export_name` to a procedure");
|
||||
}
|
||||
|
||||
if (pd->body != NULL) {
|
||||
@@ -350,6 +352,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
if (proc_decl->foreign_name.len > 0) {
|
||||
name = proc_decl->foreign_name;
|
||||
}
|
||||
|
||||
e->Procedure.is_foreign = true;
|
||||
e->Procedure.foreign_name = name;
|
||||
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_entity_get(fp, key);
|
||||
if (found) {
|
||||
@@ -366,10 +372,12 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
} else {
|
||||
map_entity_set(fp, key, e);
|
||||
}
|
||||
} else if (is_link_name) {
|
||||
} else if (is_export) {
|
||||
MapEntity *fp = &c->info.foreign_procs;
|
||||
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
|
||||
String name = proc_decl->link_name;
|
||||
String name = proc_decl->export_name;
|
||||
|
||||
e->Procedure.export_name = name;
|
||||
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_entity_get(fp, key);
|
||||
@@ -377,7 +385,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
error_node(d->proc_decl,
|
||||
"Non unique #link_name for procedure `%.*s`\n"
|
||||
"Non unique #export name for procedure `%.*s`\n"
|
||||
"\tother at %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
} else {
|
||||
|
||||
@@ -59,7 +59,12 @@ struct Entity {
|
||||
i32 field_src_index;
|
||||
} Variable;
|
||||
i32 TypeName;
|
||||
i32 Procedure;
|
||||
struct {
|
||||
bool is_foreign;
|
||||
String foreign_name;
|
||||
String export_name;
|
||||
u64 tags;
|
||||
} Procedure;
|
||||
struct {
|
||||
BuiltinProcId id;
|
||||
} Builtin;
|
||||
@@ -138,8 +143,9 @@ Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *signature_type) {
|
||||
Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *signature_type, u64 tags) {
|
||||
Entity *entity = alloc_entity(a, Entity_Procedure, scope, token, signature_type);
|
||||
entity->Procedure.tags = tags;
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -22,8 +22,9 @@ gb_inline Type *check_type(Checker *c, AstNode *expression) {
|
||||
|
||||
|
||||
typedef struct DelayedEntity {
|
||||
Entity *entity;
|
||||
DeclInfo *decl;
|
||||
AstNode * ident;
|
||||
Entity * entity;
|
||||
DeclInfo * decl;
|
||||
} DelayedEntity;
|
||||
|
||||
typedef struct DelayedOtherFields {
|
||||
@@ -104,7 +105,7 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
|
||||
|
||||
add_entity_and_decl_info(c, name, e, d);
|
||||
|
||||
DelayedEntity delay = {e, d};
|
||||
DelayedEntity delay = {name, e, d};
|
||||
array_add(delayed_entities, delay);
|
||||
}
|
||||
|
||||
@@ -181,7 +182,7 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
|
||||
|
||||
add_entity_and_decl_info(c, td->name, e, d);
|
||||
|
||||
DelayedEntity delay = {e, d};
|
||||
DelayedEntity delay = {td->name, e, d};
|
||||
array_add(delayed_entities, delay);
|
||||
|
||||
|
||||
@@ -231,6 +232,7 @@ void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size, Delay
|
||||
for_array(i, delayed_entities) {
|
||||
DelayedEntity delayed = delayed_entities.e[i];
|
||||
if (delayed.entity->kind == Entity_Constant) {
|
||||
add_entity_and_decl_info(c, delayed.ident, delayed.entity, delayed.decl);
|
||||
check_entity_decl(c, delayed.entity, delayed.decl, NULL);
|
||||
}
|
||||
}
|
||||
@@ -1480,7 +1482,7 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa
|
||||
case Basic_i16:
|
||||
case Basic_i32:
|
||||
case Basic_i64:
|
||||
case Basic_i128:
|
||||
// case Basic_i128:
|
||||
case Basic_int:
|
||||
return gb_is_between(i, -imax, imax-1);
|
||||
|
||||
@@ -1488,7 +1490,7 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa
|
||||
case Basic_u16:
|
||||
case Basic_u32:
|
||||
case Basic_u64:
|
||||
case Basic_u128:
|
||||
// case Basic_u128:
|
||||
case Basic_uint:
|
||||
return !(u < 0 || u > umax);
|
||||
|
||||
|
||||
+1
-1
@@ -1095,7 +1095,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
#if 1
|
||||
// NOTE(bill): This must be handled here so it has access to the parent scope stuff
|
||||
// e.g. using
|
||||
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL);
|
||||
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL, pd->tags);
|
||||
e->identifier = pd->name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
|
||||
+6
-6
@@ -11,8 +11,8 @@ typedef enum BasicKind {
|
||||
Basic_u32,
|
||||
Basic_i64,
|
||||
Basic_u64,
|
||||
Basic_i128,
|
||||
Basic_u128,
|
||||
// Basic_i128,
|
||||
// Basic_u128,
|
||||
// Basic_f16,
|
||||
Basic_f32,
|
||||
Basic_f64,
|
||||
@@ -205,8 +205,8 @@ gb_global Type basic_types[] = {
|
||||
{Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, 4, STR_LIT("u32")}},
|
||||
{Type_Basic, {Basic_i64, BasicFlag_Integer, 8, STR_LIT("i64")}},
|
||||
{Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, 8, STR_LIT("u64")}},
|
||||
{Type_Basic, {Basic_i128, BasicFlag_Integer, 16, STR_LIT("i128")}},
|
||||
{Type_Basic, {Basic_u128, BasicFlag_Integer | BasicFlag_Unsigned, 16, STR_LIT("u128")}},
|
||||
// {Type_Basic, {Basic_i128, BasicFlag_Integer, 16, STR_LIT("i128")}},
|
||||
// {Type_Basic, {Basic_u128, BasicFlag_Integer | BasicFlag_Unsigned, 16, STR_LIT("u128")}},
|
||||
// {Type_Basic, {Basic_f16, BasicFlag_Float, 2, STR_LIT("f16")}},
|
||||
{Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}},
|
||||
{Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}},
|
||||
@@ -239,8 +239,8 @@ gb_global Type *t_i32 = &basic_types[Basic_i32];
|
||||
gb_global Type *t_u32 = &basic_types[Basic_u32];
|
||||
gb_global Type *t_i64 = &basic_types[Basic_i64];
|
||||
gb_global Type *t_u64 = &basic_types[Basic_u64];
|
||||
gb_global Type *t_i128 = &basic_types[Basic_i128];
|
||||
gb_global Type *t_u128 = &basic_types[Basic_u128];
|
||||
// gb_global Type *t_i128 = &basic_types[Basic_i128];
|
||||
// gb_global Type *t_u128 = &basic_types[Basic_u128];
|
||||
// gb_global Type *t_f16 = &basic_types[Basic_f16];
|
||||
gb_global Type *t_f32 = &basic_types[Basic_f32];
|
||||
gb_global Type *t_f64 = &basic_types[Basic_f64];
|
||||
|
||||
+39
-14
@@ -16,7 +16,7 @@ extern "C" {
|
||||
// #include "vm.c"
|
||||
|
||||
// NOTE(bill): `name` is used in debugging and profiling modes
|
||||
i32 win32_exec_command_line_app(char *name, char *fmt, ...) {
|
||||
i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
char cmd_line[4096] = {0};
|
||||
@@ -29,8 +29,8 @@ i32 win32_exec_command_line_app(char *name, char *fmt, ...) {
|
||||
start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||
start_info.wShowWindow = SW_SHOW;
|
||||
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||
start_info.hStdOutput = is_silent ? NULL : GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
start_info.hStdError = is_silent ? NULL : GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
va_start(va, fmt);
|
||||
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
|
||||
@@ -80,11 +80,11 @@ int main(int argc, char **argv) {
|
||||
Timings timings = {0};
|
||||
timings_init(&timings, str_lit("Total Time"), 128);
|
||||
// defer (timings_destroy(&timings));
|
||||
|
||||
#if 1
|
||||
init_string_buffer_memory();
|
||||
init_global_error_collector();
|
||||
|
||||
#if 1
|
||||
|
||||
BuildContext build_context = {0};
|
||||
init_build_context(&build_context);
|
||||
|
||||
@@ -94,9 +94,24 @@ int main(int argc, char **argv) {
|
||||
bool run_output = false;
|
||||
String arg1 = make_string_c(argv[1]);
|
||||
if (str_eq(arg1, str_lit("run"))) {
|
||||
run_output = true;
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_filename = argv[2];
|
||||
run_output = true;
|
||||
} else if (str_eq(arg1, str_lit("build_dll"))) {
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_filename = argv[2];
|
||||
build_context.is_dll = true;
|
||||
} else if (str_eq(arg1, str_lit("build"))) {
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_filename = argv[2];
|
||||
} else if (str_eq(arg1, str_lit("version"))) {
|
||||
gb_printf("%s version %.*s", argv[0], LIT(build_context.ODIN_VERSION));
|
||||
@@ -136,7 +151,7 @@ int main(int argc, char **argv) {
|
||||
#if 1
|
||||
|
||||
ssaGen ssa = {0};
|
||||
if (!ssa_gen_init(&ssa, &checker)) {
|
||||
if (!ssa_gen_init(&ssa, &checker, &build_context)) {
|
||||
return 1;
|
||||
}
|
||||
// defer (ssa_gen_destroy(&ssa));
|
||||
@@ -164,7 +179,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
i32 exit_code = 0;
|
||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||
exit_code = win32_exec_command_line_app("llvm-opt",
|
||||
exit_code = win32_exec_command_line_app("llvm-opt", false,
|
||||
"%.*sbin/opt %s -o %.*s.bc "
|
||||
"-mem2reg "
|
||||
"-memcpyopt "
|
||||
@@ -182,7 +197,7 @@ int main(int argc, char **argv) {
|
||||
#if 1
|
||||
timings_start_section(&timings, str_lit("llvm-llc"));
|
||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||
exit_code = win32_exec_command_line_app("llvm-llc",
|
||||
exit_code = win32_exec_command_line_app("llvm-llc", false,
|
||||
"%.*sbin/llc %.*s.bc -filetype=obj -O%d "
|
||||
"%.*s "
|
||||
// "-debug-pass=Arguments "
|
||||
@@ -207,14 +222,24 @@ int main(int argc, char **argv) {
|
||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||
}
|
||||
|
||||
exit_code = win32_exec_command_line_app("msvc-link",
|
||||
"link %.*s.obj -OUT:%.*s.exe %s "
|
||||
char *output_ext = "exe";
|
||||
char *link_settings = "";
|
||||
if (build_context.is_dll) {
|
||||
output_ext = "dll";
|
||||
link_settings = "/DLL";
|
||||
}
|
||||
|
||||
exit_code = win32_exec_command_line_app("msvc-link", true,
|
||||
"link %.*s.obj -OUT:%.*s.%s %s "
|
||||
"/defaultlib:libcmt "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:console "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"",
|
||||
LIT(output), LIT(output),
|
||||
lib_str, LIT(build_context.link_flags));
|
||||
LIT(output), LIT(output), output_ext,
|
||||
lib_str, LIT(build_context.link_flags),
|
||||
link_settings
|
||||
);
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
}
|
||||
@@ -222,7 +247,7 @@ int main(int argc, char **argv) {
|
||||
// timings_print_all(&timings);
|
||||
|
||||
if (run_output) {
|
||||
win32_exec_command_line_app("odin run", "%.*s.exe", cast(int)base_name_len, output_name);
|
||||
win32_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+31
-30
@@ -65,15 +65,15 @@ typedef enum ProcTag {
|
||||
ProcTag_no_bounds_check = GB_BIT(1),
|
||||
|
||||
ProcTag_foreign = GB_BIT(10),
|
||||
ProcTag_link_name = GB_BIT(11),
|
||||
ProcTag_export = GB_BIT(11),
|
||||
ProcTag_inline = GB_BIT(12),
|
||||
ProcTag_no_inline = GB_BIT(13),
|
||||
ProcTag_dll_import = GB_BIT(14),
|
||||
ProcTag_dll_export = GB_BIT(15),
|
||||
|
||||
ProcTag_stdcall = GB_BIT(16),
|
||||
ProcTag_fastcall = GB_BIT(17),
|
||||
// ProcTag_cdecl = GB_BIT(18),
|
||||
ProcTag_stdcall = GB_BIT(20),
|
||||
ProcTag_fastcall = GB_BIT(21),
|
||||
// ProcTag_cdecl = GB_BIT(22),
|
||||
} ProcTag;
|
||||
|
||||
typedef enum VarDeclTag {
|
||||
@@ -106,7 +106,7 @@ AstNodeArray make_ast_node_array(AstFile *f) {
|
||||
AstNode *body; \
|
||||
u64 tags; \
|
||||
String foreign_name; \
|
||||
String link_name; \
|
||||
String export_name; \
|
||||
}) \
|
||||
AST_NODE_KIND(CompoundLit, "compound literal", struct { \
|
||||
AstNode *type; \
|
||||
@@ -246,7 +246,7 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
||||
AstNode *body; \
|
||||
u64 tags; \
|
||||
String foreign_name; \
|
||||
String link_name; \
|
||||
String export_name; \
|
||||
AstNode *note; \
|
||||
}) \
|
||||
AST_NODE_KIND(TypeDecl, "type declaration", struct { \
|
||||
@@ -686,13 +686,13 @@ AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) {
|
||||
}
|
||||
|
||||
|
||||
AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String foreign_name, String link_name) {
|
||||
AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String foreign_name, String export_name) {
|
||||
AstNode *result = make_node(f, AstNode_ProcLit);
|
||||
result->ProcLit.type = type;
|
||||
result->ProcLit.body = body;
|
||||
result->ProcLit.tags = tags;
|
||||
result->ProcLit.foreign_name = foreign_name;
|
||||
result->ProcLit.link_name = link_name;
|
||||
result->ProcLit.export_name = export_name;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -926,14 +926,14 @@ AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArr
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) {
|
||||
AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String export_name) {
|
||||
AstNode *result = make_node(f, AstNode_ProcDecl);
|
||||
result->ProcDecl.name = name;
|
||||
result->ProcDecl.type = proc_type;
|
||||
result->ProcDecl.body = body;
|
||||
result->ProcDecl.tags = tags;
|
||||
result->ProcDecl.foreign_name = foreign_name;
|
||||
result->ProcDecl.link_name = link_name;
|
||||
result->ProcDecl.export_name = export_name;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1364,10 +1364,10 @@ bool is_foreign_name_valid(String name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name) {
|
||||
void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *export_name) {
|
||||
// TODO(bill): Add this to procedure literals too
|
||||
GB_ASSERT(foreign_name != NULL);
|
||||
GB_ASSERT(link_name != NULL);
|
||||
GB_ASSERT(export_name != NULL);
|
||||
|
||||
while (f->curr_token.kind == Token_Hash) {
|
||||
AstNode *tag_expr = parse_tag_expr(f, NULL);
|
||||
@@ -1390,13 +1390,13 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
|
||||
|
||||
next_token(f);
|
||||
}
|
||||
} else if (str_eq(tag_name, str_lit("link_name"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_link_name, tag_name);
|
||||
} else if (str_eq(tag_name, str_lit("export"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_export, tag_name);
|
||||
if (f->curr_token.kind == Token_String) {
|
||||
*link_name = f->curr_token.string;
|
||||
*export_name = f->curr_token.string;
|
||||
// TODO(bill): Check if valid string
|
||||
if (!is_foreign_name_valid(*link_name)) {
|
||||
syntax_error_node(tag_expr, "Invalid alternative link procedure name `%.*s`", LIT(*link_name));
|
||||
if (!is_foreign_name_valid(*export_name)) {
|
||||
syntax_error_node(tag_expr, "Invalid alternative link procedure name `%.*s`", LIT(*export_name));
|
||||
}
|
||||
|
||||
next_token(f);
|
||||
@@ -1420,8 +1420,8 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
|
||||
#undef ELSE_IF_ADD_TAG
|
||||
}
|
||||
|
||||
if ((*tags & ProcTag_foreign) && (*tags & ProcTag_link_name)) {
|
||||
syntax_error(f->curr_token, "You cannot apply both #foreign and #link_name to a procedure");
|
||||
if ((*tags & ProcTag_foreign) && (*tags & ProcTag_export)) {
|
||||
syntax_error(f->curr_token, "You cannot apply both #foreign and #export to a procedure");
|
||||
}
|
||||
|
||||
if ((*tags & ProcTag_inline) && (*tags & ProcTag_no_inline)) {
|
||||
@@ -1534,23 +1534,24 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
u64 tags = 0;
|
||||
String foreign_name = {0};
|
||||
String link_name = {0};
|
||||
parse_proc_tags(f, &tags, &foreign_name, &link_name);
|
||||
String export_name = {0};
|
||||
parse_proc_tags(f, &tags, &foreign_name, &export_name);
|
||||
if (tags & ProcTag_foreign) {
|
||||
syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals");
|
||||
}
|
||||
if (tags & ProcTag_link_name) {
|
||||
syntax_error(f->curr_token, "#link_name cannot be applied to procedure literals");
|
||||
if (tags & ProcTag_export) {
|
||||
syntax_error(f->curr_token, "#export cannot be applied to procedure literals");
|
||||
}
|
||||
|
||||
if (f->curr_token.kind == Token_OpenBrace) {
|
||||
AstNode *body;
|
||||
|
||||
f->expr_level++;
|
||||
body = parse_body(f);
|
||||
f->expr_level--;
|
||||
if ((tags & ProcTag_foreign) != 0) {
|
||||
syntax_error(f->curr_token, "A procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
|
||||
type = make_proc_lit(f, type, body, tags, foreign_name, link_name);
|
||||
body = parse_body(f);
|
||||
type = make_proc_lit(f, type, body, tags, foreign_name, export_name);
|
||||
} else if (type != NULL && type->kind == AstNode_ProcType) {
|
||||
type->ProcType.tags = tags;
|
||||
}
|
||||
@@ -2425,9 +2426,9 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) {
|
||||
AstNode *body = NULL;
|
||||
u64 tags = 0;
|
||||
String foreign_name = {0};
|
||||
String link_name = {0};
|
||||
String export_name = {0};
|
||||
|
||||
parse_proc_tags(f, &tags, &foreign_name, &link_name);
|
||||
parse_proc_tags(f, &tags, &foreign_name, &export_name);
|
||||
|
||||
AstNode *curr_proc = f->curr_proc;
|
||||
f->curr_proc = proc_type;
|
||||
@@ -2442,7 +2443,7 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) {
|
||||
}
|
||||
|
||||
f->curr_proc = curr_proc;
|
||||
return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
|
||||
return make_proc_decl(f, name, proc_type, body, tags, foreign_name, export_name);
|
||||
}
|
||||
|
||||
AstNode *parse_if_stmt(AstFile *f) {
|
||||
|
||||
@@ -17,6 +17,7 @@ typedef Array(ssaValue *) ssaValueArray;
|
||||
|
||||
typedef struct ssaModule {
|
||||
CheckerInfo * info;
|
||||
BuildContext *build_context;
|
||||
BaseTypeSizes sizes;
|
||||
gbArena arena;
|
||||
gbArena tmp_arena;
|
||||
@@ -3188,11 +3189,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
ssa_emit_store(proc, ssa_emit_struct_ep(proc, slice, 2), len);
|
||||
}
|
||||
|
||||
if (args[0]->kind == ssaValue_Constant) {
|
||||
ssaValueConstant *c = &args[0]->Constant;
|
||||
gb_printf_err("%s %d\n", type_to_string(c->type), c->value.kind);
|
||||
}
|
||||
|
||||
arg_count = type->param_count;
|
||||
args[arg_count-1] = ssa_emit_load(proc, slice);
|
||||
}
|
||||
@@ -3934,8 +3930,8 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
|
||||
// parent.name-guid
|
||||
String original_name = pd->name->Ident.string;
|
||||
String pd_name = original_name;
|
||||
if (pd->link_name.len > 0) {
|
||||
pd_name = pd->link_name;
|
||||
if (pd->export_name.len > 0) {
|
||||
pd_name = pd->export_name;
|
||||
}
|
||||
|
||||
isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
|
||||
@@ -4676,7 +4672,7 @@ void ssa_module_add_value(ssaModule *m, Entity *e, ssaValue *v) {
|
||||
map_ssa_value_set(&m->values, hash_pointer(e), v);
|
||||
}
|
||||
|
||||
void ssa_init_module(ssaModule *m, Checker *c) {
|
||||
void ssa_init_module(ssaModule *m, Checker *c, BuildContext *build_context) {
|
||||
// TODO(bill): Determine a decent size for the arena
|
||||
isize token_count = c->parser->total_token_count;
|
||||
isize arena_size = 4 * token_count * gb_size_of(ssaValue);
|
||||
@@ -4686,6 +4682,7 @@ void ssa_init_module(ssaModule *m, Checker *c) {
|
||||
m->tmp_allocator = gb_arena_allocator(&m->tmp_arena);
|
||||
m->info = &c->info;
|
||||
m->sizes = c->sizes;
|
||||
m->build_context = build_context;
|
||||
|
||||
map_ssa_value_init(&m->values, heap_allocator());
|
||||
map_ssa_value_init(&m->members, heap_allocator());
|
||||
@@ -4769,7 +4766,7 @@ void ssa_destroy_module(ssaModule *m) {
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
bool ssa_gen_init(ssaGen *s, Checker *c) {
|
||||
bool ssa_gen_init(ssaGen *s, Checker *c, BuildContext *build_context) {
|
||||
if (global_error_collector.count != 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -4779,7 +4776,7 @@ bool ssa_gen_init(ssaGen *s, Checker *c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ssa_init_module(&s->module, c);
|
||||
ssa_init_module(&s->module, c, build_context);
|
||||
s->module.generate_debug_info = false;
|
||||
|
||||
// TODO(bill): generate appropriate output name
|
||||
@@ -4870,6 +4867,7 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
} else if (e->kind == Entity_Procedure) {
|
||||
if (e->scope->is_init && str_eq(name, str_lit("main"))) {
|
||||
entry_point = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4944,13 +4942,13 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
|
||||
String original_name = name;
|
||||
AstNode *body = pd->body;
|
||||
if (pd->tags & ProcTag_foreign) {
|
||||
name = pd->name->Ident.string;
|
||||
if (e->Procedure.is_foreign) {
|
||||
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||
}
|
||||
if (pd->foreign_name.len > 0) {
|
||||
name = pd->foreign_name;
|
||||
} else if (pd->link_name.len > 0) {
|
||||
name = pd->link_name;
|
||||
} else if (pd->export_name.len > 0) {
|
||||
name = pd->export_name;
|
||||
}
|
||||
|
||||
ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
|
||||
@@ -4968,8 +4966,9 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
for_array(i, m->members.entries) {
|
||||
MapSsaValueEntry *entry = &m->members.entries.e[i];
|
||||
ssaValue *v = entry->value;
|
||||
if (v->kind == ssaValue_Proc)
|
||||
if (v->kind == ssaValue_Proc) {
|
||||
ssa_build_proc(v, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ssaDebugInfo *compile_unit = m->debug_info.entries.e[0].value;
|
||||
@@ -5011,7 +5010,7 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
ssaValue *p = ssa_make_value_procedure(a, m, NULL, proc_type, NULL, body, name);
|
||||
Token token = {0};
|
||||
token.string = name;
|
||||
Entity *e = make_entity_procedure(a, NULL, token, proc_type);
|
||||
Entity *e = make_entity_procedure(a, NULL, token, proc_type, 0);
|
||||
|
||||
map_ssa_value_set(&m->values, hash_pointer(e), p);
|
||||
map_ssa_value_set(&m->members, hash_string(name), p);
|
||||
@@ -5103,8 +5102,8 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
case Basic_u32:
|
||||
case Basic_i64:
|
||||
case Basic_u64:
|
||||
case Basic_i128:
|
||||
case Basic_u128:
|
||||
// case Basic_i128:
|
||||
// case Basic_u128:
|
||||
case Basic_int:
|
||||
case Basic_uint: {
|
||||
tag = ssa_add_local_generated(proc, t_type_info_integer);
|
||||
|
||||
+42
-7
@@ -154,8 +154,8 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
|
||||
case Basic_u32: ssa_fprintf(f, "i32"); break;
|
||||
case Basic_i64: ssa_fprintf(f, "i64"); break;
|
||||
case Basic_u64: ssa_fprintf(f, "i64"); break;
|
||||
case Basic_i128: ssa_fprintf(f, "i128"); break;
|
||||
case Basic_u128: ssa_fprintf(f, "i128"); break;
|
||||
// case Basic_i128: ssa_fprintf(f, "i128"); break;
|
||||
// case Basic_u128: ssa_fprintf(f, "i128"); break;
|
||||
// case Basic_f16: ssa_fprintf(f, "half"); break;
|
||||
case Basic_f32: ssa_fprintf(f, "float"); break;
|
||||
case Basic_f64: ssa_fprintf(f, "double"); break;
|
||||
@@ -623,7 +623,7 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type
|
||||
ssa_print_encoded_local(f, value->Param.entity->token.string);
|
||||
break;
|
||||
case ssaValue_Proc:
|
||||
ssa_print_encoded_global(f, value->Proc.name, (value->Proc.tags & (ProcTag_foreign|ProcTag_link_name)) != 0);
|
||||
ssa_print_encoded_global(f, value->Proc.name, (value->Proc.tags & (ProcTag_foreign|ProcTag_export)) != 0);
|
||||
break;
|
||||
case ssaValue_Instr:
|
||||
ssa_fprintf(f, "%%%d", value->index);
|
||||
@@ -1226,11 +1226,14 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
|
||||
if (proc->tags & ProcTag_dll_import) {
|
||||
ssa_fprintf(f, "dllimport ");
|
||||
}
|
||||
if (proc->tags & ProcTag_dll_export) {
|
||||
} else {
|
||||
ssa_fprintf(f, "\n");
|
||||
ssa_fprintf(f, "define ");
|
||||
if (proc->tags & ProcTag_export) {
|
||||
ssa_fprintf(f, "dllexport ");
|
||||
} else if (proc->tags & ProcTag_dll_export) {
|
||||
ssa_fprintf(f, "dllexport ");
|
||||
}
|
||||
} else {
|
||||
ssa_fprintf(f, "\ndefine ");
|
||||
}
|
||||
|
||||
if (proc->tags & ProcTag_stdcall) {
|
||||
@@ -1248,7 +1251,7 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
|
||||
}
|
||||
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_encoded_global(f, proc->name, (proc->tags & (ProcTag_foreign|ProcTag_link_name)) != 0);
|
||||
ssa_print_encoded_global(f, proc->name, (proc->tags & (ProcTag_foreign|ProcTag_export)) != 0);
|
||||
ssa_fprintf(f, "(");
|
||||
|
||||
if (proc_type->param_count > 0) {
|
||||
@@ -1357,12 +1360,21 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
|
||||
|
||||
ssa_fprintf(f, "\n");
|
||||
|
||||
bool dll_main_found = false;
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapSsaValueEntry *entry = &m->members.entries.e[member_index];
|
||||
ssaValue *v = entry->value;
|
||||
if (v->kind != ssaValue_Proc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
if (str_eq(v->Proc.name, str_lit("DllMain"))) {
|
||||
dll_main_found = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (v->Proc.body == NULL) {
|
||||
ssa_print_proc(f, m, &v->Proc);
|
||||
}
|
||||
@@ -1374,11 +1386,34 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
|
||||
if (v->kind != ssaValue_Proc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
if (str_eq(v->Proc.name, str_lit("DllMain"))) {
|
||||
dll_main_found = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (v->Proc.body != NULL) {
|
||||
ssa_print_proc(f, m, &v->Proc);
|
||||
}
|
||||
}
|
||||
|
||||
if (m->build_context->is_dll) {
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
#error Setup dll initialization on linux if appropriate
|
||||
#else
|
||||
if (!dll_main_found) {
|
||||
ssa_fprintf(f,
|
||||
"define i32 @DllMain(%%..rawptr %%inst, i32 %%reason, %%..rawptr %%reserved) {\n"
|
||||
"entry:\n"
|
||||
" call void @main()\n"
|
||||
" ret i32 1\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapSsaValueEntry *entry = &m->members.entries.e[member_index];
|
||||
|
||||
Reference in New Issue
Block a user