mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
more C header interoperability
This commit is contained in:
parent
96d4d0d674
commit
a398afa7cc
5 changed files with 117 additions and 59 deletions
|
|
@ -42,9 +42,12 @@ make
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
* variable declarations and assignment expressions
|
* unreachable <--> noreturn attribute
|
||||||
* Type checking
|
* unused label error
|
||||||
* loops
|
* loops
|
||||||
|
* structs
|
||||||
|
* tagged enums
|
||||||
|
* calling external variadic functions and exporting variadic functions
|
||||||
* inline assembly and syscalls
|
* inline assembly and syscalls
|
||||||
* conditional compilation and ability to check target platform and architecture
|
* conditional compilation and ability to check target platform and architecture
|
||||||
* main function with command line arguments
|
* main function with command line arguments
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,7 @@ export library "mathtest";
|
||||||
export fn add(a: i32, b: i32) -> i32 {
|
export fn add(a: i32, b: i32) -> i32 {
|
||||||
a + b
|
a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn hang() -> unreachable {
|
||||||
|
entry: goto entry;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -951,6 +951,9 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
|
||||||
} else if (type_entry == g->builtin_types.entry_i32) {
|
} else if (type_entry == g->builtin_types.entry_i32) {
|
||||||
g->c_stdint_used = true;
|
g->c_stdint_used = true;
|
||||||
return buf_create_from_str("int32_t");
|
return buf_create_from_str("int32_t");
|
||||||
|
} else if (type_entry == g->builtin_types.entry_unreachable) {
|
||||||
|
g->c_unreachable_used = true;
|
||||||
|
return g->c_unreachable_macro;
|
||||||
} else {
|
} else {
|
||||||
zig_panic("TODO to_c_type");
|
zig_panic("TODO to_c_type");
|
||||||
}
|
}
|
||||||
|
|
@ -968,6 +971,9 @@ static void generate_h_file(CodeGen *g) {
|
||||||
Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name));
|
Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name));
|
||||||
buf_upcase(extern_c_macro);
|
buf_upcase(extern_c_macro);
|
||||||
|
|
||||||
|
g->c_unreachable_macro = buf_sprintf("%s_UNREACHABLE", buf_ptr(g->root_out_name));
|
||||||
|
buf_upcase(g->c_unreachable_macro);
|
||||||
|
|
||||||
Buf h_buf = BUF_INIT;
|
Buf h_buf = BUF_INIT;
|
||||||
buf_resize(&h_buf, 0);
|
buf_resize(&h_buf, 0);
|
||||||
for (int fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) {
|
for (int fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) {
|
||||||
|
|
@ -979,9 +985,11 @@ static void generate_h_file(CodeGen *g) {
|
||||||
if (fn_proto->visib_mod != FnProtoVisibModExport)
|
if (fn_proto->visib_mod != FnProtoVisibModExport)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Buf *return_type_c = to_c_type(g, fn_proto->return_type);
|
||||||
|
|
||||||
buf_appendf(&h_buf, "%s %s %s(",
|
buf_appendf(&h_buf, "%s %s %s(",
|
||||||
buf_ptr(export_macro),
|
buf_ptr(export_macro),
|
||||||
buf_ptr(to_c_type(g, fn_proto->return_type)),
|
buf_ptr(return_type_c),
|
||||||
buf_ptr(&fn_proto->name));
|
buf_ptr(&fn_proto->name));
|
||||||
|
|
||||||
if (fn_proto->params.length) {
|
if (fn_proto->params.length) {
|
||||||
|
|
@ -994,10 +1002,13 @@ static void generate_h_file(CodeGen *g) {
|
||||||
if (param_i < fn_proto->params.length - 1)
|
if (param_i < fn_proto->params.length - 1)
|
||||||
buf_appendf(&h_buf, ", ");
|
buf_appendf(&h_buf, ", ");
|
||||||
}
|
}
|
||||||
buf_appendf(&h_buf, ");\n");
|
buf_appendf(&h_buf, ")");
|
||||||
} else {
|
} else {
|
||||||
buf_appendf(&h_buf, "void);\n");
|
buf_appendf(&h_buf, "void)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf_appendf(&h_buf, ";\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Buf *ifdef_dance_name = buf_sprintf("%s_%s_H",
|
Buf *ifdef_dance_name = buf_sprintf("%s_%s_H",
|
||||||
|
|
@ -1009,6 +1020,8 @@ static void generate_h_file(CodeGen *g) {
|
||||||
|
|
||||||
if (g->c_stdint_used)
|
if (g->c_stdint_used)
|
||||||
fprintf(out_h, "#include <stdint.h>\n");
|
fprintf(out_h, "#include <stdint.h>\n");
|
||||||
|
if (g->c_unreachable_used)
|
||||||
|
fprintf(out_h, "#define %s __attribute__((__noreturn__)) void\n", buf_ptr(g->c_unreachable_macro));
|
||||||
|
|
||||||
fprintf(out_h, "\n");
|
fprintf(out_h, "\n");
|
||||||
|
|
||||||
|
|
|
||||||
144
src/parseh.cpp
144
src/parseh.cpp
|
|
@ -22,6 +22,8 @@ struct ParseH {
|
||||||
Fn *cur_fn;
|
Fn *cur_fn;
|
||||||
int arg_index;
|
int arg_index;
|
||||||
int cur_indent;
|
int cur_indent;
|
||||||
|
CXSourceRange range;
|
||||||
|
CXSourceLocation location;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int indent_size = 4;
|
static const int indent_size = 4;
|
||||||
|
|
@ -60,11 +62,20 @@ start_over:
|
||||||
return c_name;
|
return c_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Buf *to_zig_type(CXType raw_type) {
|
static void print_location(ParseH *p) {
|
||||||
|
CXFile file;
|
||||||
|
unsigned line, column, offset;
|
||||||
|
clang_getFileLocation(p->location, &file, &line, &column, &offset);
|
||||||
|
CXString file_name = clang_getFileName(file);
|
||||||
|
|
||||||
|
fprintf(stderr, "%s line %u, column %u\n", clang_getCString(file_name), line, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Buf *to_zig_type(ParseH *p, CXType raw_type) {
|
||||||
if (raw_type.kind == CXType_Unexposed) {
|
if (raw_type.kind == CXType_Unexposed) {
|
||||||
CXType canonical = clang_getCanonicalType(raw_type);
|
CXType canonical = clang_getCanonicalType(raw_type);
|
||||||
if (canonical.kind != CXType_Unexposed)
|
if (canonical.kind != CXType_Unexposed)
|
||||||
return to_zig_type(canonical);
|
return to_zig_type(p, canonical);
|
||||||
else
|
else
|
||||||
zig_panic("clang C api insufficient");
|
zig_panic("clang C api insufficient");
|
||||||
}
|
}
|
||||||
|
|
@ -83,11 +94,14 @@ static Buf *to_zig_type(CXType raw_type) {
|
||||||
case CXType_UChar:
|
case CXType_UChar:
|
||||||
return buf_create_from_str("u8");
|
return buf_create_from_str("u8");
|
||||||
case CXType_WChar:
|
case CXType_WChar:
|
||||||
zig_panic("TODO");
|
print_location(p);
|
||||||
|
zig_panic("TODO wchar");
|
||||||
case CXType_Char16:
|
case CXType_Char16:
|
||||||
zig_panic("TODO");
|
print_location(p);
|
||||||
|
zig_panic("TODO char16");
|
||||||
case CXType_Char32:
|
case CXType_Char32:
|
||||||
zig_panic("TODO");
|
print_location(p);
|
||||||
|
zig_panic("TODO char32");
|
||||||
case CXType_UShort:
|
case CXType_UShort:
|
||||||
return buf_create_from_str("c_ushort");
|
return buf_create_from_str("c_ushort");
|
||||||
case CXType_UInt:
|
case CXType_UInt:
|
||||||
|
|
@ -97,7 +111,8 @@ static Buf *to_zig_type(CXType raw_type) {
|
||||||
case CXType_ULongLong:
|
case CXType_ULongLong:
|
||||||
return buf_create_from_str("c_ulonglong");
|
return buf_create_from_str("c_ulonglong");
|
||||||
case CXType_UInt128:
|
case CXType_UInt128:
|
||||||
zig_panic("TODO");
|
print_location(p);
|
||||||
|
zig_panic("TODO uint128");
|
||||||
case CXType_Short:
|
case CXType_Short:
|
||||||
return buf_create_from_str("c_short");
|
return buf_create_from_str("c_short");
|
||||||
case CXType_Int:
|
case CXType_Int:
|
||||||
|
|
@ -107,43 +122,34 @@ static Buf *to_zig_type(CXType raw_type) {
|
||||||
case CXType_LongLong:
|
case CXType_LongLong:
|
||||||
return buf_create_from_str("c_longlong");
|
return buf_create_from_str("c_longlong");
|
||||||
case CXType_Int128:
|
case CXType_Int128:
|
||||||
zig_panic("TODO");
|
print_location(p);
|
||||||
|
zig_panic("TODO int128");
|
||||||
case CXType_Float:
|
case CXType_Float:
|
||||||
return buf_create_from_str("f32");
|
return buf_create_from_str("f32");
|
||||||
case CXType_Double:
|
case CXType_Double:
|
||||||
return buf_create_from_str("f64");
|
return buf_create_from_str("f64");
|
||||||
case CXType_LongDouble:
|
case CXType_LongDouble:
|
||||||
return buf_create_from_str("f128");
|
return buf_create_from_str("f128");
|
||||||
case CXType_NullPtr:
|
case CXType_IncompleteArray:
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_Overload:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_Dependent:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_ObjCId:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_ObjCClass:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_ObjCSel:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_Complex:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_Pointer:
|
|
||||||
{
|
{
|
||||||
CXType pointee_type = clang_getPointeeType(raw_type);
|
CXType pointee_type = clang_getArrayElementType(raw_type);
|
||||||
Buf *pointee_buf = to_zig_type(pointee_type);
|
Buf *pointee_buf = to_zig_type(p, pointee_type);
|
||||||
|
if (clang_isConstQualifiedType(pointee_type)) {
|
||||||
|
return buf_sprintf("*const %s", buf_ptr(pointee_buf));
|
||||||
|
} else {
|
||||||
|
return buf_sprintf("*mut %s", buf_ptr(pointee_buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case CXType_Pointer:
|
||||||
|
{
|
||||||
|
CXType pointee_type = clang_getPointeeType(raw_type);
|
||||||
|
Buf *pointee_buf = to_zig_type(p, pointee_type);
|
||||||
if (clang_isConstQualifiedType(pointee_type)) {
|
if (clang_isConstQualifiedType(pointee_type)) {
|
||||||
return buf_sprintf("*const %s", buf_ptr(pointee_buf));
|
return buf_sprintf("*const %s", buf_ptr(pointee_buf));
|
||||||
} else {
|
} else {
|
||||||
return buf_sprintf("*mut %s", buf_ptr(pointee_buf));
|
return buf_sprintf("*mut %s", buf_ptr(pointee_buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case CXType_BlockPointer:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_LValueReference:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_RValueReference:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_Record:
|
case CXType_Record:
|
||||||
{
|
{
|
||||||
const char *name = prefixes_stripped(raw_type);
|
const char *name = prefixes_stripped(raw_type);
|
||||||
|
|
@ -176,28 +182,44 @@ static Buf *to_zig_type(CXType raw_type) {
|
||||||
} else {
|
} else {
|
||||||
CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
|
CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
|
||||||
CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
|
CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
|
||||||
return to_zig_type(underlying_type);
|
return to_zig_type(p, underlying_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case CXType_ObjCInterface:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_ObjCObjectPointer:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_FunctionNoProto:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_FunctionProto:
|
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_ConstantArray:
|
case CXType_ConstantArray:
|
||||||
zig_panic("TODO");
|
{
|
||||||
|
CXType child_type = clang_getArrayElementType(raw_type);
|
||||||
|
Buf *zig_child_type = to_zig_type(p, child_type);
|
||||||
|
long size = (long)clang_getArraySize(raw_type);
|
||||||
|
return buf_sprintf("[%s; %ld]", buf_ptr(zig_child_type), size);
|
||||||
|
}
|
||||||
|
case CXType_FunctionProto:
|
||||||
|
fprintf(stderr, "warning: TODO function proto\n");
|
||||||
|
print_location(p);
|
||||||
|
return buf_create_from_str("*const u8");
|
||||||
|
case CXType_FunctionNoProto:
|
||||||
|
print_location(p);
|
||||||
|
zig_panic("TODO function no proto");
|
||||||
|
case CXType_BlockPointer:
|
||||||
|
print_location(p);
|
||||||
|
zig_panic("TODO block pointer");
|
||||||
case CXType_Vector:
|
case CXType_Vector:
|
||||||
zig_panic("TODO");
|
print_location(p);
|
||||||
case CXType_IncompleteArray:
|
zig_panic("TODO vector");
|
||||||
zig_panic("TODO");
|
case CXType_LValueReference:
|
||||||
|
case CXType_RValueReference:
|
||||||
case CXType_VariableArray:
|
case CXType_VariableArray:
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_DependentSizedArray:
|
case CXType_DependentSizedArray:
|
||||||
zig_panic("TODO");
|
|
||||||
case CXType_MemberPointer:
|
case CXType_MemberPointer:
|
||||||
|
case CXType_ObjCInterface:
|
||||||
|
case CXType_ObjCObjectPointer:
|
||||||
|
case CXType_NullPtr:
|
||||||
|
case CXType_Overload:
|
||||||
|
case CXType_Dependent:
|
||||||
|
case CXType_ObjCId:
|
||||||
|
case CXType_ObjCClass:
|
||||||
|
case CXType_ObjCSel:
|
||||||
|
case CXType_Complex:
|
||||||
|
print_location(p);
|
||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,6 +260,9 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl
|
||||||
enum CXCursorKind kind = clang_getCursorKind(cursor);
|
enum CXCursorKind kind = clang_getCursorKind(cursor);
|
||||||
CXString name = clang_getCursorSpelling(cursor);
|
CXString name = clang_getCursorSpelling(cursor);
|
||||||
|
|
||||||
|
p->range = clang_getCursorExtent(cursor);
|
||||||
|
p->location = clang_getRangeStart(p->range);
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case CXCursor_FunctionDecl:
|
case CXCursor_FunctionDecl:
|
||||||
{
|
{
|
||||||
|
|
@ -245,27 +270,37 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl
|
||||||
if (!is_storage_class_export(storage_class))
|
if (!is_storage_class_export(storage_class))
|
||||||
return CXChildVisit_Continue;
|
return CXChildVisit_Continue;
|
||||||
|
|
||||||
|
CXType fn_type = clang_getCursorType(cursor);
|
||||||
|
if (clang_isFunctionTypeVariadic(fn_type)) {
|
||||||
|
print_location(p);
|
||||||
|
fprintf(stderr, "warning: skipping variadic function, not yet supported\n");
|
||||||
|
return CXChildVisit_Continue;
|
||||||
|
}
|
||||||
|
if (clang_getFunctionTypeCallingConv(fn_type) != CXCallingConv_C) {
|
||||||
|
print_location(p);
|
||||||
|
fprintf(stderr, "warning: skipping non c calling convention function, not yet supported\n");
|
||||||
|
return CXChildVisit_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
end_fn(p);
|
end_fn(p);
|
||||||
begin_fn(p);
|
begin_fn(p);
|
||||||
|
|
||||||
CXType fn_type = clang_getCursorType(cursor);
|
|
||||||
if (clang_isFunctionTypeVariadic(fn_type)) {
|
|
||||||
zig_panic("TODO support variadic function");
|
|
||||||
}
|
|
||||||
if (clang_getFunctionTypeCallingConv(fn_type) != CXCallingConv_C) {
|
|
||||||
zig_panic("TODO support non c calling convention");
|
|
||||||
}
|
|
||||||
CXType return_type = clang_getResultType(fn_type);
|
CXType return_type = clang_getResultType(fn_type);
|
||||||
p->cur_fn->return_type = to_zig_type(return_type);
|
p->cur_fn->return_type = to_zig_type(p, return_type);
|
||||||
|
|
||||||
buf_init_from_str(&p->cur_fn->name, clang_getCString(name));
|
buf_init_from_str(&p->cur_fn->name, clang_getCString(name));
|
||||||
|
|
||||||
|
if (buf_eql_str(&p->cur_fn->name, "exit")) {
|
||||||
|
print_location(p);
|
||||||
|
zig_panic("Found it");
|
||||||
|
}
|
||||||
|
|
||||||
p->cur_fn->arg_count = clang_getNumArgTypes(fn_type);
|
p->cur_fn->arg_count = clang_getNumArgTypes(fn_type);
|
||||||
p->cur_fn->args = allocate<Arg>(p->cur_fn->arg_count);
|
p->cur_fn->args = allocate<Arg>(p->cur_fn->arg_count);
|
||||||
|
|
||||||
for (int i = 0; i < p->cur_fn->arg_count; i += 1) {
|
for (int i = 0; i < p->cur_fn->arg_count; i += 1) {
|
||||||
CXType param_type = clang_getArgType(fn_type, i);
|
CXType param_type = clang_getArgType(fn_type, i);
|
||||||
p->cur_fn->args[i].type = to_zig_type(param_type);
|
p->cur_fn->args[i].type = to_zig_type(p, param_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
p->arg_index = 0;
|
p->arg_index = 0;
|
||||||
|
|
@ -283,6 +318,7 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl
|
||||||
case CXCursor_UnexposedAttr:
|
case CXCursor_UnexposedAttr:
|
||||||
case CXCursor_CompoundStmt:
|
case CXCursor_CompoundStmt:
|
||||||
case CXCursor_FieldDecl:
|
case CXCursor_FieldDecl:
|
||||||
|
case CXCursor_TypedefDecl:
|
||||||
return CXChildVisit_Continue;
|
return CXChildVisit_Continue;
|
||||||
default:
|
default:
|
||||||
return CXChildVisit_Recurse;
|
return CXChildVisit_Recurse;
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,8 @@ struct CodeGen {
|
||||||
FnTableEntry *cur_fn;
|
FnTableEntry *cur_fn;
|
||||||
LLVMBasicBlockRef cur_basic_block;
|
LLVMBasicBlockRef cur_basic_block;
|
||||||
bool c_stdint_used;
|
bool c_stdint_used;
|
||||||
|
bool c_unreachable_used;
|
||||||
|
Buf *c_unreachable_macro;
|
||||||
AstNode *root_export_decl;
|
AstNode *root_export_decl;
|
||||||
int version_major;
|
int version_major;
|
||||||
int version_minor;
|
int version_minor;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue