Merge pull request #116 from birth-software/implement-c-compiling-in-builder
Implement first C ABI test
This commit is contained in:
commit
953e0b7013
@ -87,6 +87,7 @@ pub fn compileBuildExecutable(context: *const Context, arguments: [][*:0]u8) !vo
|
|||||||
.generate_debug_information = true,
|
.generate_debug_information = true,
|
||||||
.name = "build",
|
.name = "build",
|
||||||
.is_test = false,
|
.is_test = false,
|
||||||
|
.c_source_files = &.{},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,13 +103,18 @@ pub fn compileBuildExecutable(context: *const Context, arguments: [][*:0]u8) !vo
|
|||||||
else => false,
|
else => false,
|
||||||
};
|
};
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// std.debug.print("The following command terminated with failure ({s}): {s}\n", .{ @tagName(result.term), argv });
|
try write(.panic, "The following command terminated with failure: (");
|
||||||
// if (result.stdout.len > 0) {
|
try write(.panic, @tagName(result.term));
|
||||||
// std.debug.print("STDOUT:\n{s}\n", .{result.stdout});
|
try write(.panic, "):\n");
|
||||||
// }
|
for (argv) |arg| {
|
||||||
// if (result.stderr.len > 0) {
|
try write(.panic, arg);
|
||||||
// std.debug.print("STDOUT:\n{s}\n", .{result.stderr});
|
try write(.panic, ", ");
|
||||||
// }
|
}
|
||||||
|
try write(.panic, "\n");
|
||||||
|
try write(.panic, result.stdout);
|
||||||
|
try write(.panic, "\n");
|
||||||
|
try write(.panic, result.stderr);
|
||||||
|
try write(.panic, "\n");
|
||||||
std.os.abort();
|
std.os.abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2181,6 +2187,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
|
|||||||
var maybe_only_parse: ?bool = null;
|
var maybe_only_parse: ?bool = null;
|
||||||
var link_libc = false;
|
var link_libc = false;
|
||||||
var maybe_executable_name: ?[]const u8 = null;
|
var maybe_executable_name: ?[]const u8 = null;
|
||||||
|
var c_source_files = UnpinnedArray([*:0]u8){};
|
||||||
const generate_debug_information = true;
|
const generate_debug_information = true;
|
||||||
|
|
||||||
if (arguments.len == 0) return error.InvalidInput;
|
if (arguments.len == 0) return error.InvalidInput;
|
||||||
@ -2287,6 +2294,17 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
|
|||||||
} else {
|
} else {
|
||||||
reportUnterminatedArgumentError(current_argument);
|
reportUnterminatedArgumentError(current_argument);
|
||||||
}
|
}
|
||||||
|
} else if (byte_equal(current_argument, "-c_source_files")) {
|
||||||
|
if (i + 1 != arguments.len) {
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
try c_source_files.ensure_capacity(context.my_allocator, @intCast(arguments.len - i));
|
||||||
|
while (i < arguments.len) : (i += 1) {
|
||||||
|
c_source_files.append_with_capacity(arguments[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reportUnterminatedArgumentError(current_argument);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
@panic(current_argument);
|
@panic(current_argument);
|
||||||
// std.debug.panic("Unrecognized argument: {s}", .{current_argument});
|
// std.debug.panic("Unrecognized argument: {s}", .{current_argument});
|
||||||
@ -2328,6 +2346,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
|
|||||||
.generate_debug_information = generate_debug_information,
|
.generate_debug_information = generate_debug_information,
|
||||||
.name = executable_name,
|
.name = executable_name,
|
||||||
.is_test = options.is_test,
|
.is_test = options.is_test,
|
||||||
|
.c_source_files = c_source_files.slice(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -9886,7 +9905,7 @@ pub const Builder = struct {
|
|||||||
break :blk switch (result.value) {
|
break :blk switch (result.value) {
|
||||||
.@"comptime" => |ct| switch (ct) {
|
.@"comptime" => |ct| switch (ct) {
|
||||||
.global => |global| switch (global.initial_value) {
|
.global => |global| switch (global.initial_value) {
|
||||||
.function_definition => .{
|
.function_definition, .function_declaration => .{
|
||||||
.value = .{
|
.value = .{
|
||||||
.@"comptime" = .{
|
.@"comptime" = .{
|
||||||
.global = global,
|
.global = global,
|
||||||
@ -12163,6 +12182,7 @@ pub const Unit = struct {
|
|||||||
main_package: ?*Package = null,
|
main_package: ?*Package = null,
|
||||||
all_errors: Type.Index = .null,
|
all_errors: Type.Index = .null,
|
||||||
descriptor: Descriptor,
|
descriptor: Descriptor,
|
||||||
|
object_files: UnpinnedArray([*:0]const u8) = .{},
|
||||||
discard_identifiers: usize = 0,
|
discard_identifiers: usize = 0,
|
||||||
anon_i: usize = 0,
|
anon_i: usize = 0,
|
||||||
anon_arr: usize = 0,
|
anon_arr: usize = 0,
|
||||||
@ -12885,6 +12905,20 @@ pub const Unit = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!unit.descriptor.only_parse) {
|
if (!unit.descriptor.only_parse) {
|
||||||
|
try unit.object_files.ensure_capacity(context.my_allocator, @intCast(unit.descriptor.c_source_files.len));
|
||||||
|
for (unit.descriptor.c_source_files) |c_source_file| {
|
||||||
|
const c_src = span(c_source_file);
|
||||||
|
const dot_index = data_structures.last(c_src, '.') orelse unreachable;
|
||||||
|
const path_without_extension = c_src[0..dot_index];
|
||||||
|
const basename = std.fs.path.basename(path_without_extension);
|
||||||
|
const basename_z = try std.mem.joinZ(context.allocator, "/", &.{"nat", basename});
|
||||||
|
var c_flag = "-c".*;
|
||||||
|
var o_flag = "-o".*;
|
||||||
|
var arguments = [_][*:0]u8{&c_flag, c_source_file, &o_flag, basename_z};
|
||||||
|
try compileCSourceFile(context, &arguments);
|
||||||
|
unit.object_files.append_with_capacity(basename_z);
|
||||||
|
}
|
||||||
|
|
||||||
try unit.analyze(context);
|
try unit.analyze(context);
|
||||||
|
|
||||||
try llvm.codegen(unit, context);
|
try llvm.codegen(unit, context);
|
||||||
@ -12938,6 +12972,7 @@ pub const Descriptor = struct {
|
|||||||
link_libc: bool,
|
link_libc: bool,
|
||||||
is_test: bool,
|
is_test: bool,
|
||||||
generate_debug_information: bool,
|
generate_debug_information: bool,
|
||||||
|
c_source_files: []const [*:0]u8,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3062,6 +3062,11 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
|||||||
|
|
||||||
try arguments.append(context.my_allocator, object_file_path.ptr);
|
try arguments.append(context.my_allocator, object_file_path.ptr);
|
||||||
|
|
||||||
|
try arguments.append_slice(context.my_allocator, unit.object_files.slice());
|
||||||
|
// for (unit.object_files.slice()) |object_file| {
|
||||||
|
// _ = object_file; // autofix
|
||||||
|
// }
|
||||||
|
|
||||||
switch (unit.descriptor.os) {
|
switch (unit.descriptor.os) {
|
||||||
.macos => {
|
.macos => {
|
||||||
try arguments.append(context.my_allocator, "-dynamic");
|
try arguments.append(context.my_allocator, "-dynamic");
|
||||||
@ -3126,13 +3131,14 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!linking_result) {
|
if (!linking_result) {
|
||||||
|
try write(.panic, "\n");
|
||||||
for (arguments.slice()) |argument| {
|
for (arguments.slice()) |argument| {
|
||||||
const arg = data_structures.span(argument);
|
const arg = data_structures.span(argument);
|
||||||
try write(.llvm, arg);
|
try write(.panic, arg);
|
||||||
try write(.llvm, " ");
|
try write(.panic, " ");
|
||||||
}
|
}
|
||||||
try write(.llvm, "\n");
|
try write(.panic, "\n");
|
||||||
|
|
||||||
@panic("Above linker invokation failed");
|
@panic(stderr_ptr[0..stderr_len]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -723,3 +723,16 @@ pub fn span(ptr: [*:0]const u8) [:0]const u8 {
|
|||||||
}
|
}
|
||||||
return ptr[0..len :0];
|
return ptr[0..len :0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn last(bytes: []const u8, byte: u8) ?usize {
|
||||||
|
var i = bytes.len;
|
||||||
|
while (i > 0) {
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (bytes[i] == byte) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@ -29,10 +29,19 @@ pub export fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]
|
|||||||
if (entry_point(arguments)) |_| {
|
if (entry_point(arguments)) |_| {
|
||||||
return 0;
|
return 0;
|
||||||
} else |err| {
|
} else |err| {
|
||||||
const error_name: []const u8 = @errorName(err);
|
const print_stack_trace = @import("configuration").print_stack_trace;
|
||||||
Compilation.write(.panic, "Error: ") catch {};
|
switch (print_stack_trace) {
|
||||||
Compilation.write(.panic, error_name) catch {};
|
true => if (@errorReturnTrace()) |trace| {
|
||||||
Compilation.write(.panic, "\n") catch {};
|
std.debug.dumpStackTrace(trace.*);
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
const error_name: []const u8 = @errorName(err);
|
||||||
|
Compilation.write(.panic, "Error: ") catch {};
|
||||||
|
Compilation.write(.panic, error_name) catch {};
|
||||||
|
Compilation.write(.panic, "\n") catch {};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ const Executable = struct{
|
|||||||
main_source_path: [:0]const u8,
|
main_source_path: [:0]const u8,
|
||||||
link_libc: bool = false,
|
link_libc: bool = false,
|
||||||
name: [:0]const u8,
|
name: [:0]const u8,
|
||||||
c_source_files: []const []const u8 = .{}.&,
|
c_source_files: []const [:0]const u8 = .{}.&,
|
||||||
|
|
||||||
const compile = fn(executable: Executable) *!void {
|
const compile = fn(executable: Executable) *!void {
|
||||||
const argument_count = std.start.argument_count;
|
const argument_count = std.start.argument_count;
|
||||||
@ -35,8 +35,15 @@ const Executable = struct{
|
|||||||
} else {
|
} else {
|
||||||
link_libc_arg = "false";
|
link_libc_arg = "false";
|
||||||
}
|
}
|
||||||
const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe", "-main_source_file", executable.main_source_path.ptr, "-link_libc", link_libc_arg, "-name", executable.name.ptr };
|
|
||||||
try std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
|
if (executable.c_source_files.len > 0) {
|
||||||
|
assert(executable.c_source_files.len == 1);
|
||||||
|
const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe", "-main_source_file", executable.main_source_path.ptr, "-link_libc", link_libc_arg, "-name", executable.name.ptr, "-c_source_files", executable.c_source_files[0].ptr };
|
||||||
|
try std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
|
||||||
|
} else {
|
||||||
|
const argv = [_:null] ?[&:0]const u8{ compiler_path, "exe", "-main_source_file", executable.main_source_path.ptr, "-link_libc", link_libc_arg, "-name", executable.name.ptr };
|
||||||
|
try std.os.execute(path = compiler_path, argv = argv.&, env = std.start.environment_values);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const raw_status = try std.os.waitpid(pid, flags = 0);
|
const raw_status = try std.os.waitpid(pid, flags = 0);
|
||||||
if (std.os.ifexited(status = raw_status)) {
|
if (std.os.ifexited(status = raw_status)) {
|
||||||
|
@ -2,7 +2,7 @@ const Error = error{
|
|||||||
unexpected_result,
|
unexpected_result,
|
||||||
};
|
};
|
||||||
|
|
||||||
const expect(ok: bool) Error!void {
|
const expect = fn (ok: bool) Error!void {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return Error.unexpected_result;
|
return Error.unexpected_result;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const std = #import("std");
|
const std = #import("std");
|
||||||
const build = std.build;
|
const Executable = std.build.Executable;
|
||||||
|
|
||||||
const main = fn() *!void {
|
const main = fn() *!void {
|
||||||
const executable = Executable{
|
const executable = Executable{
|
||||||
@ -9,7 +9,8 @@ const main = fn() *!void {
|
|||||||
.abi = .gnu,
|
.abi = .gnu,
|
||||||
},
|
},
|
||||||
.main_source_path = "main.nat",
|
.main_source_path = "main.nat",
|
||||||
.name = "first",
|
.name = "c-abi",
|
||||||
|
.c_source_files = .{ "foo.c" }.&,
|
||||||
};
|
};
|
||||||
|
|
||||||
try executable.compile();
|
try executable.compile();
|
5
test/build/c-abi/foo.c
Normal file
5
test/build/c-abi/foo.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
typedef unsigned u32;
|
||||||
|
u32 foo(u32 arg)
|
||||||
|
{
|
||||||
|
return arg;
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
const std = #import("std");
|
const std = #import("std");
|
||||||
const expect = std.test.expect;
|
const expect = std.testing.expect;
|
||||||
const foo :: extern = fn(arg: u32) u32;
|
const foo :: extern = fn(arg: u32) u32;
|
||||||
const main = fn () *!void {
|
const main = fn () *!void {
|
||||||
const arg = 0xabcdef;
|
const arg = 0xabcdef;
|
Loading…
x
Reference in New Issue
Block a user