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,
|
||||
.name = "build",
|
||||
.is_test = false,
|
||||
.c_source_files = &.{},
|
||||
},
|
||||
};
|
||||
|
||||
@ -102,13 +103,18 @@ pub fn compileBuildExecutable(context: *const Context, arguments: [][*:0]u8) !vo
|
||||
else => false,
|
||||
};
|
||||
if (!success) {
|
||||
// std.debug.print("The following command terminated with failure ({s}): {s}\n", .{ @tagName(result.term), argv });
|
||||
// if (result.stdout.len > 0) {
|
||||
// std.debug.print("STDOUT:\n{s}\n", .{result.stdout});
|
||||
// }
|
||||
// if (result.stderr.len > 0) {
|
||||
// std.debug.print("STDOUT:\n{s}\n", .{result.stderr});
|
||||
// }
|
||||
try write(.panic, "The following command terminated with failure: (");
|
||||
try write(.panic, @tagName(result.term));
|
||||
try write(.panic, "):\n");
|
||||
for (argv) |arg| {
|
||||
try write(.panic, arg);
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -2181,6 +2187,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
|
||||
var maybe_only_parse: ?bool = null;
|
||||
var link_libc = false;
|
||||
var maybe_executable_name: ?[]const u8 = null;
|
||||
var c_source_files = UnpinnedArray([*:0]u8){};
|
||||
const generate_debug_information = true;
|
||||
|
||||
if (arguments.len == 0) return error.InvalidInput;
|
||||
@ -2287,6 +2294,17 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
|
||||
} else {
|
||||
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 {
|
||||
@panic(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,
|
||||
.name = executable_name,
|
||||
.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) {
|
||||
.@"comptime" => |ct| switch (ct) {
|
||||
.global => |global| switch (global.initial_value) {
|
||||
.function_definition => .{
|
||||
.function_definition, .function_declaration => .{
|
||||
.value = .{
|
||||
.@"comptime" = .{
|
||||
.global = global,
|
||||
@ -12163,6 +12182,7 @@ pub const Unit = struct {
|
||||
main_package: ?*Package = null,
|
||||
all_errors: Type.Index = .null,
|
||||
descriptor: Descriptor,
|
||||
object_files: UnpinnedArray([*:0]const u8) = .{},
|
||||
discard_identifiers: usize = 0,
|
||||
anon_i: usize = 0,
|
||||
anon_arr: usize = 0,
|
||||
@ -12885,6 +12905,20 @@ pub const Unit = struct {
|
||||
}
|
||||
|
||||
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 llvm.codegen(unit, context);
|
||||
@ -12938,6 +12972,7 @@ pub const Descriptor = struct {
|
||||
link_libc: bool,
|
||||
is_test: bool,
|
||||
generate_debug_information: bool,
|
||||
c_source_files: []const [*:0]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_slice(context.my_allocator, unit.object_files.slice());
|
||||
// for (unit.object_files.slice()) |object_file| {
|
||||
// _ = object_file; // autofix
|
||||
// }
|
||||
|
||||
switch (unit.descriptor.os) {
|
||||
.macos => {
|
||||
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) {
|
||||
try write(.panic, "\n");
|
||||
for (arguments.slice()) |argument| {
|
||||
const arg = data_structures.span(argument);
|
||||
try write(.llvm, arg);
|
||||
try write(.llvm, " ");
|
||||
try write(.panic, arg);
|
||||
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];
|
||||
}
|
||||
|
||||
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)) |_| {
|
||||
return 0;
|
||||
} else |err| {
|
||||
const print_stack_trace = @import("configuration").print_stack_trace;
|
||||
switch (print_stack_trace) {
|
||||
true => if (@errorReturnTrace()) |trace| {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ const Executable = struct{
|
||||
main_source_path: [:0]const u8,
|
||||
link_libc: bool = false,
|
||||
name: [:0]const u8,
|
||||
c_source_files: []const []const u8 = .{}.&,
|
||||
c_source_files: []const [:0]const u8 = .{}.&,
|
||||
|
||||
const compile = fn(executable: Executable) *!void {
|
||||
const argument_count = std.start.argument_count;
|
||||
@ -35,8 +35,15 @@ const Executable = struct{
|
||||
} else {
|
||||
link_libc_arg = "false";
|
||||
}
|
||||
|
||||
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 {
|
||||
const raw_status = try std.os.waitpid(pid, flags = 0);
|
||||
if (std.os.ifexited(status = raw_status)) {
|
||||
|
@ -2,7 +2,7 @@ const Error = error{
|
||||
unexpected_result,
|
||||
};
|
||||
|
||||
const expect(ok: bool) Error!void {
|
||||
const expect = fn (ok: bool) Error!void {
|
||||
if (!ok) {
|
||||
return Error.unexpected_result;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = #import("std");
|
||||
const build = std.build;
|
||||
const Executable = std.build.Executable;
|
||||
|
||||
const main = fn() *!void {
|
||||
const executable = Executable{
|
||||
@ -9,7 +9,8 @@ const main = fn() *!void {
|
||||
.abi = .gnu,
|
||||
},
|
||||
.main_source_path = "main.nat",
|
||||
.name = "first",
|
||||
.name = "c-abi",
|
||||
.c_source_files = .{ "foo.c" }.&,
|
||||
};
|
||||
|
||||
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 expect = std.test.expect;
|
||||
const expect = std.testing.expect;
|
||||
const foo :: extern = fn(arg: u32) u32;
|
||||
const main = fn () *!void {
|
||||
const arg = 0xabcdef;
|
Loading…
x
Reference in New Issue
Block a user