mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
start moving zig cc to stage2
* build.zig: repair the ability to link against llvm, clang, and lld
* move the zig cc arg parsing logic to stage2
- the preprocessor flag is still TODO
- the clang arg iterator code is improved to use slices instead of
raw pointers because it no longer has to deal with an extern
struct.
* clean up error printing with a `fatal` function and use log API
for messages rather than std.debug.print
* add support for more CLI options to stage2 & update usage text
- hooking up most of these new options is TODO
* clean up the way libc and libc++ are detected via command line
options. target information is used to determine if any of the libc
candidate names are chosen.
* add native library directory detection
* implement the ability to invoke clang from stage2
* introduce a build_options.have_llvm so we can comptime branch
on whether LLVM is linked in or not.
This commit is contained in:
parent
749417a1f3
commit
503ba7b27c
91
build.zig
91
build.zig
@ -9,6 +9,7 @@ const ArrayList = std.ArrayList;
|
||||
const io = std.io;
|
||||
const fs = std.fs;
|
||||
const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const zig_version = std.builtin.Version{ .major = 0, .minor = 6, .patch = 0 };
|
||||
|
||||
@ -57,11 +58,13 @@ pub fn build(b: *Builder) !void {
|
||||
|
||||
if (!only_install_lib_files) {
|
||||
var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
|
||||
exe.install();
|
||||
exe.setBuildMode(mode);
|
||||
exe.setTarget(target);
|
||||
test_step.dependOn(&exe.step);
|
||||
b.default_step.dependOn(&exe.step);
|
||||
|
||||
exe.addBuildOption(bool, "have_llvm", enable_llvm);
|
||||
if (enable_llvm) {
|
||||
const config_h_text = if (config_h_path_option) |config_h_path|
|
||||
try std.fs.cwd().readFileAlloc(b.allocator, toNativePathSep(b, config_h_path), max_config_h_bytes)
|
||||
@ -73,11 +76,8 @@ pub fn build(b: *Builder) !void {
|
||||
|
||||
try configureStage2(b, exe, ctx);
|
||||
}
|
||||
if (!only_install_lib_files) {
|
||||
exe.install();
|
||||
}
|
||||
const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
|
||||
const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;
|
||||
const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm;
|
||||
if (link_libc) {
|
||||
exe.linkLibC();
|
||||
test_stage2.linkLibC();
|
||||
@ -323,17 +323,13 @@ fn configureStage2(b: *Builder, exe: anytype, ctx: Context) !void {
|
||||
exe.addIncludeDir("src");
|
||||
exe.addIncludeDir(ctx.cmake_binary_dir);
|
||||
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
|
||||
if (ctx.lld_include_dir.len != 0) {
|
||||
exe.addIncludeDir(ctx.lld_include_dir);
|
||||
assert(ctx.lld_include_dir.len != 0);
|
||||
exe.addIncludeDir(ctx.lld_include_dir);
|
||||
{
|
||||
var it = mem.tokenize(ctx.lld_libraries, ";");
|
||||
while (it.next()) |lib| {
|
||||
exe.addObjectFile(lib);
|
||||
}
|
||||
} else {
|
||||
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_wasm");
|
||||
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_elf");
|
||||
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_coff");
|
||||
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_lib");
|
||||
}
|
||||
{
|
||||
var it = mem.tokenize(ctx.clang_libraries, ";");
|
||||
@ -343,42 +339,51 @@ fn configureStage2(b: *Builder, exe: anytype, ctx: Context) !void {
|
||||
}
|
||||
dependOnLib(b, exe, ctx.llvm);
|
||||
|
||||
if (exe.target.getOsTag() == .linux) {
|
||||
// First we try to static link against gcc libstdc++. If that doesn't work,
|
||||
// we fall back to -lc++ and cross our fingers.
|
||||
addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) {
|
||||
error.RequiredLibraryNotFound => {
|
||||
exe.linkSystemLibrary("c++");
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
// Boy, it sure would be nice to simply linkSystemLibrary("c++") and rely on zig's
|
||||
// ability to provide libc++ right? Well thanks to C++ not having a stable ABI this
|
||||
// will cause linker errors. It would work in the situation when `zig cc` is used to
|
||||
// build LLVM, Clang, and LLD, however when depending on them as system libraries, system
|
||||
// libc++ must be used.
|
||||
const cross_compile = false; // TODO
|
||||
if (cross_compile) {
|
||||
// In this case we assume that zig cc was used to build the LLVM, Clang, LLD dependencies.
|
||||
exe.linkSystemLibrary("c++");
|
||||
} else {
|
||||
if (exe.target.getOsTag() == .linux) {
|
||||
// First we try to static link against gcc libstdc++. If that doesn't work,
|
||||
// we fall back to -lc++ and cross our fingers.
|
||||
addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) {
|
||||
error.RequiredLibraryNotFound => {
|
||||
exe.linkSystemLibrary("c++");
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
exe.linkSystemLibrary("pthread");
|
||||
} else if (exe.target.isFreeBSD()) {
|
||||
try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
|
||||
exe.linkSystemLibrary("pthread");
|
||||
} else if (exe.target.isDarwin()) {
|
||||
if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
|
||||
// Compiler is GCC.
|
||||
try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);
|
||||
exe.linkSystemLibrary("pthread");
|
||||
// TODO LLD cannot perform this link.
|
||||
// See https://github.com/ziglang/zig/issues/1535
|
||||
exe.enableSystemLinkerHack();
|
||||
} else |err| switch (err) {
|
||||
error.RequiredLibraryNotFound => {
|
||||
// System compiler, not gcc.
|
||||
exe.linkSystemLibrary("c++");
|
||||
},
|
||||
else => |e| return e,
|
||||
} else if (exe.target.isFreeBSD()) {
|
||||
try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
|
||||
exe.linkSystemLibrary("pthread");
|
||||
} else if (exe.target.isDarwin()) {
|
||||
if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
|
||||
// Compiler is GCC.
|
||||
try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);
|
||||
exe.linkSystemLibrary("pthread");
|
||||
// TODO LLD cannot perform this link.
|
||||
// See https://github.com/ziglang/zig/issues/1535
|
||||
exe.enableSystemLinkerHack();
|
||||
} else |err| switch (err) {
|
||||
error.RequiredLibraryNotFound => {
|
||||
// System compiler, not gcc.
|
||||
exe.linkSystemLibrary("c++");
|
||||
},
|
||||
else => |e| return e,
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.dia_guids_lib.len != 0) {
|
||||
exe.addObjectFile(ctx.dia_guids_lib);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.dia_guids_lib.len != 0) {
|
||||
exe.addObjectFile(ctx.dia_guids_lib);
|
||||
}
|
||||
|
||||
exe.linkSystemLibrary("c");
|
||||
}
|
||||
|
||||
fn addCxxKnownPath(
|
||||
|
||||
@ -7,9 +7,7 @@ pub const CliArg = struct {
|
||||
name: []const u8,
|
||||
syntax: Syntax,
|
||||
|
||||
/// TODO we're going to want to change this when we start shipping self-hosted because this causes
|
||||
/// all the functions in stage2.zig to get exported.
|
||||
zig_equivalent: @import("stage2.zig").ClangArgIterator.ZigEquivalent,
|
||||
zig_equivalent: @import("main.zig").ClangArgIterator.ZigEquivalent,
|
||||
|
||||
/// Prefixed by "-"
|
||||
pd1: bool = false,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -414,6 +414,23 @@ export fn stage2_env(argc: c_int, argv: [*]const [*:0]const u8) c_int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn stage2_cc(argc: c_int, argv: [*]const [*:0]const u8, is_cpp: bool) c_int {
|
||||
const allocator = std.heap.c_allocator;
|
||||
|
||||
var args_list = argvToArrayList(allocator, argc, argv) catch |err| {
|
||||
std.debug.print("unable to parse arguments: {}\n", .{@errorName(err)});
|
||||
return -1;
|
||||
};
|
||||
defer args_list.deinit();
|
||||
|
||||
self_hosted_main.buildOutputType(allocator, allocator, args_list.items, if (is_cpp) .cpp else .cc) catch |err| {
|
||||
std.debug.print("zig cc failure: {}\n", .{@errorName(err)});
|
||||
return -1;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_cmd_targets(
|
||||
zig_triple: ?[*:0]const u8,
|
||||
@ -1038,267 +1055,4 @@ fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void {
|
||||
ptr.* = new_slice.ptr;
|
||||
}
|
||||
|
||||
const clang_args = @import("clang_options.zig").list;
|
||||
|
||||
// ABI warning
|
||||
pub const ClangArgIterator = extern struct {
|
||||
has_next: bool,
|
||||
zig_equivalent: ZigEquivalent,
|
||||
only_arg: [*:0]const u8,
|
||||
second_arg: [*:0]const u8,
|
||||
other_args_ptr: [*]const [*:0]const u8,
|
||||
other_args_len: usize,
|
||||
argv_ptr: [*]const [*:0]const u8,
|
||||
argv_len: usize,
|
||||
next_index: usize,
|
||||
root_args: ?*Args,
|
||||
|
||||
// ABI warning
|
||||
pub const ZigEquivalent = extern enum {
|
||||
target,
|
||||
o,
|
||||
c,
|
||||
other,
|
||||
positional,
|
||||
l,
|
||||
ignore,
|
||||
driver_punt,
|
||||
pic,
|
||||
no_pic,
|
||||
nostdlib,
|
||||
nostdlib_cpp,
|
||||
shared,
|
||||
rdynamic,
|
||||
wl,
|
||||
pp_or_asm,
|
||||
optimize,
|
||||
debug,
|
||||
sanitize,
|
||||
linker_script,
|
||||
verbose_cmds,
|
||||
for_linker,
|
||||
linker_input_z,
|
||||
lib_dir,
|
||||
mcpu,
|
||||
dep_file,
|
||||
framework_dir,
|
||||
framework,
|
||||
nostdlibinc,
|
||||
};
|
||||
|
||||
const Args = struct {
|
||||
next_index: usize,
|
||||
argv_ptr: [*]const [*:0]const u8,
|
||||
argv_len: usize,
|
||||
};
|
||||
|
||||
pub fn init(argv: []const [*:0]const u8) ClangArgIterator {
|
||||
return .{
|
||||
.next_index = 2, // `zig cc foo` this points to `foo`
|
||||
.has_next = argv.len > 2,
|
||||
.zig_equivalent = undefined,
|
||||
.only_arg = undefined,
|
||||
.second_arg = undefined,
|
||||
.other_args_ptr = undefined,
|
||||
.other_args_len = undefined,
|
||||
.argv_ptr = argv.ptr,
|
||||
.argv_len = argv.len,
|
||||
.root_args = null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(self: *ClangArgIterator) !void {
|
||||
assert(self.has_next);
|
||||
assert(self.next_index < self.argv_len);
|
||||
// In this state we know that the parameter we are looking at is a root parameter
|
||||
// rather than an argument to a parameter.
|
||||
self.other_args_ptr = self.argv_ptr + self.next_index;
|
||||
self.other_args_len = 1; // We adjust this value below when necessary.
|
||||
var arg = mem.span(self.argv_ptr[self.next_index]);
|
||||
self.incrementArgIndex();
|
||||
|
||||
if (mem.startsWith(u8, arg, "@")) {
|
||||
if (self.root_args != null) return error.NestedResponseFile;
|
||||
|
||||
// This is a "compiler response file". We must parse the file and treat its
|
||||
// contents as command line parameters.
|
||||
const allocator = std.heap.c_allocator;
|
||||
const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
|
||||
const resp_file_path = arg[1..];
|
||||
const resp_contents = fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes) catch |err| {
|
||||
std.debug.warn("unable to read response file '{}': {}\n", .{ resp_file_path, @errorName(err) });
|
||||
process.exit(1);
|
||||
};
|
||||
defer allocator.free(resp_contents);
|
||||
// TODO is there a specification for this file format? Let's find it and make this parsing more robust
|
||||
// at the very least I'm guessing this needs to handle quotes and `#` comments.
|
||||
var it = mem.tokenize(resp_contents, " \t\r\n");
|
||||
var resp_arg_list = std.ArrayList([*:0]const u8).init(allocator);
|
||||
defer resp_arg_list.deinit();
|
||||
{
|
||||
errdefer {
|
||||
for (resp_arg_list.span()) |item| {
|
||||
allocator.free(mem.span(item));
|
||||
}
|
||||
}
|
||||
while (it.next()) |token| {
|
||||
const dupe_token = try mem.dupeZ(allocator, u8, token);
|
||||
errdefer allocator.free(dupe_token);
|
||||
try resp_arg_list.append(dupe_token);
|
||||
}
|
||||
const args = try allocator.create(Args);
|
||||
errdefer allocator.destroy(args);
|
||||
args.* = .{
|
||||
.next_index = self.next_index,
|
||||
.argv_ptr = self.argv_ptr,
|
||||
.argv_len = self.argv_len,
|
||||
};
|
||||
self.root_args = args;
|
||||
}
|
||||
const resp_arg_slice = resp_arg_list.toOwnedSlice();
|
||||
self.next_index = 0;
|
||||
self.argv_ptr = resp_arg_slice.ptr;
|
||||
self.argv_len = resp_arg_slice.len;
|
||||
|
||||
if (resp_arg_slice.len == 0) {
|
||||
self.resolveRespFileArgs();
|
||||
return;
|
||||
}
|
||||
|
||||
self.has_next = true;
|
||||
self.other_args_ptr = self.argv_ptr + self.next_index;
|
||||
self.other_args_len = 1; // We adjust this value below when necessary.
|
||||
arg = mem.span(self.argv_ptr[self.next_index]);
|
||||
self.incrementArgIndex();
|
||||
}
|
||||
if (!mem.startsWith(u8, arg, "-")) {
|
||||
self.zig_equivalent = .positional;
|
||||
self.only_arg = arg.ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) {
|
||||
.flag => {
|
||||
const prefix_len = clang_arg.matchEql(arg);
|
||||
if (prefix_len > 0) {
|
||||
self.zig_equivalent = clang_arg.zig_equivalent;
|
||||
self.only_arg = arg.ptr + prefix_len;
|
||||
|
||||
break :find_clang_arg;
|
||||
}
|
||||
},
|
||||
.joined, .comma_joined => {
|
||||
// joined example: --target=foo
|
||||
// comma_joined example: -Wl,-soname,libsoundio.so.2
|
||||
const prefix_len = clang_arg.matchStartsWith(arg);
|
||||
if (prefix_len != 0) {
|
||||
self.zig_equivalent = clang_arg.zig_equivalent;
|
||||
self.only_arg = arg.ptr + prefix_len; // This will skip over the "--target=" part.
|
||||
|
||||
break :find_clang_arg;
|
||||
}
|
||||
},
|
||||
.joined_or_separate => {
|
||||
// Examples: `-lfoo`, `-l foo`
|
||||
const prefix_len = clang_arg.matchStartsWith(arg);
|
||||
if (prefix_len == arg.len) {
|
||||
if (self.next_index >= self.argv_len) {
|
||||
std.debug.warn("Expected parameter after '{}'\n", .{arg});
|
||||
process.exit(1);
|
||||
}
|
||||
self.only_arg = self.argv_ptr[self.next_index];
|
||||
self.incrementArgIndex();
|
||||
self.other_args_len += 1;
|
||||
self.zig_equivalent = clang_arg.zig_equivalent;
|
||||
|
||||
break :find_clang_arg;
|
||||
} else if (prefix_len != 0) {
|
||||
self.zig_equivalent = clang_arg.zig_equivalent;
|
||||
self.only_arg = arg.ptr + prefix_len;
|
||||
|
||||
break :find_clang_arg;
|
||||
}
|
||||
},
|
||||
.joined_and_separate => {
|
||||
// Example: `-Xopenmp-target=riscv64-linux-unknown foo`
|
||||
const prefix_len = clang_arg.matchStartsWith(arg);
|
||||
if (prefix_len != 0) {
|
||||
self.only_arg = arg.ptr + prefix_len;
|
||||
if (self.next_index >= self.argv_len) {
|
||||
std.debug.warn("Expected parameter after '{}'\n", .{arg});
|
||||
process.exit(1);
|
||||
}
|
||||
self.second_arg = self.argv_ptr[self.next_index];
|
||||
self.incrementArgIndex();
|
||||
self.other_args_len += 1;
|
||||
self.zig_equivalent = clang_arg.zig_equivalent;
|
||||
break :find_clang_arg;
|
||||
}
|
||||
},
|
||||
.separate => if (clang_arg.matchEql(arg) > 0) {
|
||||
if (self.next_index >= self.argv_len) {
|
||||
std.debug.warn("Expected parameter after '{}'\n", .{arg});
|
||||
process.exit(1);
|
||||
}
|
||||
self.only_arg = self.argv_ptr[self.next_index];
|
||||
self.incrementArgIndex();
|
||||
self.other_args_len += 1;
|
||||
self.zig_equivalent = clang_arg.zig_equivalent;
|
||||
break :find_clang_arg;
|
||||
},
|
||||
.remaining_args_joined => {
|
||||
const prefix_len = clang_arg.matchStartsWith(arg);
|
||||
if (prefix_len != 0) {
|
||||
@panic("TODO");
|
||||
}
|
||||
},
|
||||
.multi_arg => if (clang_arg.matchEql(arg) > 0) {
|
||||
@panic("TODO");
|
||||
},
|
||||
}
|
||||
else {
|
||||
std.debug.warn("Unknown Clang option: '{}'\n", .{arg});
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn incrementArgIndex(self: *ClangArgIterator) void {
|
||||
self.next_index += 1;
|
||||
self.resolveRespFileArgs();
|
||||
}
|
||||
|
||||
fn resolveRespFileArgs(self: *ClangArgIterator) void {
|
||||
const allocator = std.heap.c_allocator;
|
||||
if (self.next_index >= self.argv_len) {
|
||||
if (self.root_args) |root_args| {
|
||||
self.next_index = root_args.next_index;
|
||||
self.argv_ptr = root_args.argv_ptr;
|
||||
self.argv_len = root_args.argv_len;
|
||||
|
||||
allocator.destroy(root_args);
|
||||
self.root_args = null;
|
||||
}
|
||||
if (self.next_index >= self.argv_len) {
|
||||
self.has_next = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export fn stage2_clang_arg_iterator(
|
||||
result: *ClangArgIterator,
|
||||
argc: usize,
|
||||
argv: [*]const [*:0]const u8,
|
||||
) void {
|
||||
result.* = ClangArgIterator.init(argv[0..argc]);
|
||||
}
|
||||
|
||||
export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {
|
||||
it.next() catch |err| switch (err) {
|
||||
error.NestedResponseFile => return .NestedResponseFile,
|
||||
error.OutOfMemory => return .OutOfMemory,
|
||||
};
|
||||
return .None;
|
||||
}
|
||||
|
||||
export const stage2_is_zig0 = false;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
pub const have_llvm = true;
|
||||
pub const version: []const u8 = "@ZIG_VERSION@";
|
||||
pub const log_scopes: []const []const u8 = &[_][]const u8{};
|
||||
pub const zir_dumps: []const []const u8 = &[_][]const u8{};
|
||||
pub const enable_tracy = false;
|
||||
|
||||
412
src/main.cpp
412
src/main.cpp
@ -404,7 +404,6 @@ static int main0(int argc, char **argv) {
|
||||
ZigList<const char *> framework_dirs = {0};
|
||||
ZigList<const char *> frameworks = {0};
|
||||
bool have_libc = false;
|
||||
bool have_libcpp = false;
|
||||
const char *target_string = nullptr;
|
||||
bool rdynamic = false;
|
||||
const char *linker_script = nullptr;
|
||||
@ -446,18 +445,8 @@ static int main0(int argc, char **argv) {
|
||||
bool function_sections = false;
|
||||
const char *mcpu = nullptr;
|
||||
CodeModel code_model = CodeModelDefault;
|
||||
const char *override_soname = nullptr;
|
||||
bool only_pp_or_asm = false;
|
||||
bool ensure_libc_on_non_freestanding = false;
|
||||
bool ensure_libcpp_on_non_freestanding = false;
|
||||
bool disable_c_depfile = false;
|
||||
bool want_native_include_dirs = false;
|
||||
Buf *linker_optimization = nullptr;
|
||||
OptionalBool linker_gc_sections = OptionalBoolNull;
|
||||
OptionalBool linker_allow_shlib_undefined = OptionalBoolNull;
|
||||
OptionalBool linker_bind_global_refs_locally = OptionalBoolNull;
|
||||
bool linker_z_nodelete = false;
|
||||
bool linker_z_defs = false;
|
||||
size_t stack_size_override = 0;
|
||||
|
||||
ZigList<const char *> llvm_argv = {0};
|
||||
@ -585,355 +574,10 @@ static int main0(int argc, char **argv) {
|
||||
return stage2_fmt(argc, argv);
|
||||
} else if (argc >= 2 && strcmp(argv[1], "env") == 0) {
|
||||
return stage2_env(argc, argv);
|
||||
} else if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || strcmp(argv[1], "c++") == 0)) {
|
||||
emit_h = false;
|
||||
strip = true;
|
||||
ensure_libc_on_non_freestanding = true;
|
||||
ensure_libcpp_on_non_freestanding = (strcmp(argv[1], "c++") == 0);
|
||||
want_native_include_dirs = true;
|
||||
|
||||
bool c_arg = false;
|
||||
Stage2ClangArgIterator it;
|
||||
stage2_clang_arg_iterator(&it, argc, argv);
|
||||
bool is_shared_lib = false;
|
||||
ZigList<Buf *> linker_args = {};
|
||||
while (it.has_next) {
|
||||
if ((err = stage2_clang_arg_next(&it))) {
|
||||
fprintf(stderr, "unable to parse command line parameters: %s\n", err_str(err));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
switch (it.kind) {
|
||||
case Stage2ClangArgTarget: // example: -target riscv64-linux-unknown
|
||||
target_string = it.only_arg;
|
||||
break;
|
||||
case Stage2ClangArgO: // -o
|
||||
emit_bin_override_path = it.only_arg;
|
||||
enable_cache = CacheOptOn;
|
||||
break;
|
||||
case Stage2ClangArgC: // -c
|
||||
c_arg = true;
|
||||
break;
|
||||
case Stage2ClangArgOther:
|
||||
for (size_t i = 0; i < it.other_args_len; i += 1) {
|
||||
clang_argv.append(it.other_args_ptr[i]);
|
||||
}
|
||||
break;
|
||||
case Stage2ClangArgPositional: {
|
||||
FileExt file_ext = classify_file_ext(it.only_arg, strlen(it.only_arg));
|
||||
switch (file_ext) {
|
||||
case FileExtAsm:
|
||||
case FileExtC:
|
||||
case FileExtCpp:
|
||||
case FileExtLLVMIr:
|
||||
case FileExtLLVMBitCode:
|
||||
case FileExtHeader: {
|
||||
CFile *c_file = heap::c_allocator.create<CFile>();
|
||||
c_file->source_path = it.only_arg;
|
||||
c_source_files.append(c_file);
|
||||
break;
|
||||
}
|
||||
case FileExtUnknown:
|
||||
objects.append(it.only_arg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Stage2ClangArgL: // -l
|
||||
if (strcmp(it.only_arg, "c") == 0) {
|
||||
have_libc = true;
|
||||
link_libs.append("c");
|
||||
} else if (strcmp(it.only_arg, "c++") == 0 ||
|
||||
strcmp(it.only_arg, "stdc++") == 0)
|
||||
{
|
||||
have_libcpp = true;
|
||||
link_libs.append("c++");
|
||||
} else {
|
||||
link_libs.append(it.only_arg);
|
||||
}
|
||||
break;
|
||||
case Stage2ClangArgIgnore:
|
||||
break;
|
||||
case Stage2ClangArgDriverPunt:
|
||||
// Never mind what we're doing, just pass the args directly. For example --help.
|
||||
return ZigClang_main(argc, argv);
|
||||
case Stage2ClangArgPIC:
|
||||
want_pic = WantPICEnabled;
|
||||
break;
|
||||
case Stage2ClangArgNoPIC:
|
||||
want_pic = WantPICDisabled;
|
||||
break;
|
||||
case Stage2ClangArgNoStdLib:
|
||||
ensure_libc_on_non_freestanding = false;
|
||||
break;
|
||||
case Stage2ClangArgNoStdLibCpp:
|
||||
ensure_libcpp_on_non_freestanding = false;
|
||||
break;
|
||||
case Stage2ClangArgShared:
|
||||
is_dynamic = true;
|
||||
is_shared_lib = true;
|
||||
break;
|
||||
case Stage2ClangArgRDynamic:
|
||||
rdynamic = true;
|
||||
break;
|
||||
case Stage2ClangArgWL: {
|
||||
const char *arg = it.only_arg;
|
||||
for (;;) {
|
||||
size_t pos = 0;
|
||||
while (arg[pos] != ',' && arg[pos] != 0) pos += 1;
|
||||
linker_args.append(buf_create_from_mem(arg, pos));
|
||||
if (arg[pos] == 0) break;
|
||||
arg += pos + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Stage2ClangArgPreprocessOrAsm:
|
||||
// this handles both -E and -S
|
||||
only_pp_or_asm = true;
|
||||
for (size_t i = 0; i < it.other_args_len; i += 1) {
|
||||
clang_argv.append(it.other_args_ptr[i]);
|
||||
}
|
||||
break;
|
||||
case Stage2ClangArgOptimize:
|
||||
// alright what release mode do they want?
|
||||
if (strcmp(it.only_arg, "Os") == 0) {
|
||||
build_mode = BuildModeSmallRelease;
|
||||
} else if (strcmp(it.only_arg, "O2") == 0 ||
|
||||
strcmp(it.only_arg, "O3") == 0 ||
|
||||
strcmp(it.only_arg, "O4") == 0)
|
||||
{
|
||||
build_mode = BuildModeFastRelease;
|
||||
} else if (strcmp(it.only_arg, "Og") == 0 ||
|
||||
strcmp(it.only_arg, "O0") == 0)
|
||||
{
|
||||
build_mode = BuildModeDebug;
|
||||
} else {
|
||||
for (size_t i = 0; i < it.other_args_len; i += 1) {
|
||||
clang_argv.append(it.other_args_ptr[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Stage2ClangArgDebug:
|
||||
strip = false;
|
||||
if (strcmp(it.only_arg, "-g") == 0) {
|
||||
// we handled with strip = false above
|
||||
} else {
|
||||
for (size_t i = 0; i < it.other_args_len; i += 1) {
|
||||
clang_argv.append(it.other_args_ptr[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Stage2ClangArgSanitize:
|
||||
if (strcmp(it.only_arg, "undefined") == 0) {
|
||||
want_sanitize_c = WantCSanitizeEnabled;
|
||||
} else {
|
||||
for (size_t i = 0; i < it.other_args_len; i += 1) {
|
||||
clang_argv.append(it.other_args_ptr[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Stage2ClangArgLinkerScript:
|
||||
linker_script = it.only_arg;
|
||||
break;
|
||||
case Stage2ClangArgVerboseCmds:
|
||||
verbose_cc = true;
|
||||
verbose_link = true;
|
||||
break;
|
||||
case Stage2ClangArgForLinker:
|
||||
linker_args.append(buf_create_from_str(it.only_arg));
|
||||
break;
|
||||
case Stage2ClangArgLinkerInputZ:
|
||||
linker_args.append(buf_create_from_str("-z"));
|
||||
linker_args.append(buf_create_from_str(it.only_arg));
|
||||
break;
|
||||
case Stage2ClangArgLibDir:
|
||||
lib_dirs.append(it.only_arg);
|
||||
break;
|
||||
case Stage2ClangArgMCpu:
|
||||
mcpu = it.only_arg;
|
||||
break;
|
||||
case Stage2ClangArgDepFile:
|
||||
disable_c_depfile = true;
|
||||
for (size_t i = 0; i < it.other_args_len; i += 1) {
|
||||
clang_argv.append(it.other_args_ptr[i]);
|
||||
}
|
||||
break;
|
||||
case Stage2ClangArgFrameworkDir:
|
||||
framework_dirs.append(it.only_arg);
|
||||
break;
|
||||
case Stage2ClangArgFramework:
|
||||
frameworks.append(it.only_arg);
|
||||
break;
|
||||
case Stage2ClangArgNoStdLibInc:
|
||||
want_native_include_dirs = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Parse linker args
|
||||
for (size_t i = 0; i < linker_args.length; i += 1) {
|
||||
Buf *arg = linker_args.at(i);
|
||||
if (buf_eql_str(arg, "-soname")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
Buf *soname_buf = linker_args.at(i);
|
||||
override_soname = buf_ptr(soname_buf);
|
||||
// use it as --name
|
||||
// example: libsoundio.so.2
|
||||
size_t prefix = 0;
|
||||
if (buf_starts_with_str(soname_buf, "lib")) {
|
||||
prefix = 3;
|
||||
}
|
||||
size_t end = buf_len(soname_buf);
|
||||
if (buf_ends_with_str(soname_buf, ".so")) {
|
||||
end -= 3;
|
||||
} else {
|
||||
bool found_digit = false;
|
||||
while (end > 0 && isdigit(buf_ptr(soname_buf)[end - 1])) {
|
||||
found_digit = true;
|
||||
end -= 1;
|
||||
}
|
||||
if (found_digit && end > 0 && buf_ptr(soname_buf)[end - 1] == '.') {
|
||||
end -= 1;
|
||||
} else {
|
||||
end = buf_len(soname_buf);
|
||||
}
|
||||
if (buf_ends_with_str(buf_slice(soname_buf, prefix, end), ".so")) {
|
||||
end -= 3;
|
||||
}
|
||||
}
|
||||
out_name = buf_ptr(buf_slice(soname_buf, prefix, end));
|
||||
} else if (buf_eql_str(arg, "-rpath")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
Buf *rpath = linker_args.at(i);
|
||||
rpath_list.append(buf_ptr(rpath));
|
||||
} else if (buf_eql_str(arg, "-I") ||
|
||||
buf_eql_str(arg, "--dynamic-linker") ||
|
||||
buf_eql_str(arg, "-dynamic-linker"))
|
||||
{
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
dynamic_linker = buf_ptr(linker_args.at(i));
|
||||
} else if (buf_eql_str(arg, "-E") ||
|
||||
buf_eql_str(arg, "--export-dynamic") ||
|
||||
buf_eql_str(arg, "-export-dynamic"))
|
||||
{
|
||||
rdynamic = true;
|
||||
} else if (buf_eql_str(arg, "--version-script")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
version_script = linker_args.at(i);
|
||||
} else if (buf_starts_with_str(arg, "-O")) {
|
||||
linker_optimization = arg;
|
||||
} else if (buf_eql_str(arg, "--gc-sections")) {
|
||||
linker_gc_sections = OptionalBoolTrue;
|
||||
} else if (buf_eql_str(arg, "--no-gc-sections")) {
|
||||
linker_gc_sections = OptionalBoolFalse;
|
||||
} else if (buf_eql_str(arg, "--allow-shlib-undefined") ||
|
||||
buf_eql_str(arg, "-allow-shlib-undefined"))
|
||||
{
|
||||
linker_allow_shlib_undefined = OptionalBoolTrue;
|
||||
} else if (buf_eql_str(arg, "--no-allow-shlib-undefined") ||
|
||||
buf_eql_str(arg, "-no-allow-shlib-undefined"))
|
||||
{
|
||||
linker_allow_shlib_undefined = OptionalBoolFalse;
|
||||
} else if (buf_eql_str(arg, "-Bsymbolic")) {
|
||||
linker_bind_global_refs_locally = OptionalBoolTrue;
|
||||
} else if (buf_eql_str(arg, "-z")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
Buf *z_arg = linker_args.at(i);
|
||||
if (buf_eql_str(z_arg, "nodelete")) {
|
||||
linker_z_nodelete = true;
|
||||
} else if (buf_eql_str(z_arg, "defs")) {
|
||||
linker_z_defs = true;
|
||||
} else {
|
||||
fprintf(stderr, "warning: unsupported linker arg: -z %s\n", buf_ptr(z_arg));
|
||||
}
|
||||
} else if (buf_eql_str(arg, "--major-image-version")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ver_major = atoi(buf_ptr(linker_args.at(i)));
|
||||
} else if (buf_eql_str(arg, "--minor-image-version")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ver_minor = atoi(buf_ptr(linker_args.at(i)));
|
||||
} else if (buf_eql_str(arg, "--stack")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.length) {
|
||||
fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
stack_size_override = atoi(buf_ptr(linker_args.at(i)));
|
||||
} else {
|
||||
fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg));
|
||||
}
|
||||
}
|
||||
|
||||
if (want_sanitize_c == WantCSanitizeEnabled && build_mode == BuildModeFastRelease) {
|
||||
build_mode = BuildModeSafeRelease;
|
||||
}
|
||||
|
||||
if (only_pp_or_asm) {
|
||||
cmd = CmdBuild;
|
||||
out_type = OutTypeObj;
|
||||
emit_bin = false;
|
||||
// Transfer "objects" into c_source_files
|
||||
for (size_t i = 0; i < objects.length; i += 1) {
|
||||
CFile *c_file = heap::c_allocator.create<CFile>();
|
||||
c_file->source_path = objects.at(i);
|
||||
c_source_files.append(c_file);
|
||||
}
|
||||
for (size_t i = 0; i < c_source_files.length; i += 1) {
|
||||
Buf *src_path;
|
||||
if (emit_bin_override_path != nullptr) {
|
||||
src_path = buf_create_from_str(emit_bin_override_path);
|
||||
} else {
|
||||
src_path = buf_create_from_str(c_source_files.at(i)->source_path);
|
||||
}
|
||||
Buf basename = BUF_INIT;
|
||||
os_path_split(src_path, nullptr, &basename);
|
||||
c_source_files.at(i)->preprocessor_only_basename = buf_ptr(&basename);
|
||||
}
|
||||
} else if (!c_arg) {
|
||||
cmd = CmdBuild;
|
||||
if (is_shared_lib) {
|
||||
out_type = OutTypeLib;
|
||||
} else {
|
||||
out_type = OutTypeExe;
|
||||
}
|
||||
if (emit_bin_override_path == nullptr) {
|
||||
emit_bin_override_path = "a.out";
|
||||
enable_cache = CacheOptOn;
|
||||
}
|
||||
} else {
|
||||
cmd = CmdBuild;
|
||||
out_type = OutTypeObj;
|
||||
}
|
||||
if (c_source_files.length == 0 && objects.length == 0) {
|
||||
// For example `zig cc` and no args should print the "no input files" message.
|
||||
return ZigClang_main(argc, argv);
|
||||
}
|
||||
} else if (argc >= 2 && strcmp(argv[1], "cc") == 0) {
|
||||
return stage2_cc(argc, argv, false);
|
||||
} else if (argc >= 2 && strcmp(argv[1], "c++") == 0) {
|
||||
return stage2_cc(argc, argv, true);
|
||||
} else for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
|
||||
@ -1038,7 +682,6 @@ static int main0(int argc, char **argv) {
|
||||
have_libc = true;
|
||||
link_libs.append("c");
|
||||
} else if (strcmp(l, "c++") == 0 || strcmp(l, "stdc++") == 0) {
|
||||
have_libcpp = true;
|
||||
link_libs.append("c++");
|
||||
} else {
|
||||
link_libs.append(l);
|
||||
@ -1185,7 +828,6 @@ static int main0(int argc, char **argv) {
|
||||
have_libc = true;
|
||||
link_libs.append("c");
|
||||
} else if (strcmp(argv[i], "c++") == 0 || strcmp(argv[i], "stdc++") == 0) {
|
||||
have_libcpp = true;
|
||||
link_libs.append("c++");
|
||||
} else {
|
||||
link_libs.append(argv[i]);
|
||||
@ -1351,15 +993,6 @@ static int main0(int argc, char **argv) {
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
|
||||
if (!have_libc && ensure_libc_on_non_freestanding && target.os != OsFreestanding) {
|
||||
have_libc = true;
|
||||
link_libs.append("c");
|
||||
}
|
||||
if (!have_libcpp && ensure_libcpp_on_non_freestanding && target.os != OsFreestanding) {
|
||||
have_libcpp = true;
|
||||
link_libs.append("c++");
|
||||
}
|
||||
|
||||
Buf zig_triple_buf = BUF_INIT;
|
||||
target_triple_zig(&zig_triple_buf, &target);
|
||||
|
||||
@ -1616,20 +1249,10 @@ static int main0(int argc, char **argv) {
|
||||
g->system_linker_hack = system_linker_hack;
|
||||
g->function_sections = function_sections;
|
||||
g->code_model = code_model;
|
||||
g->disable_c_depfile = disable_c_depfile;
|
||||
|
||||
g->linker_optimization = linker_optimization;
|
||||
g->linker_gc_sections = linker_gc_sections;
|
||||
g->linker_allow_shlib_undefined = linker_allow_shlib_undefined;
|
||||
g->linker_bind_global_refs_locally = linker_bind_global_refs_locally;
|
||||
g->linker_z_nodelete = linker_z_nodelete;
|
||||
g->linker_z_defs = linker_z_defs;
|
||||
g->stack_size_override = stack_size_override;
|
||||
|
||||
if (override_soname) {
|
||||
g->override_soname = buf_create_from_str(override_soname);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < lib_dirs.length; i += 1) {
|
||||
codegen_add_lib_dir(g, lib_dirs.at(i));
|
||||
}
|
||||
@ -1713,37 +1336,12 @@ static int main0(int argc, char **argv) {
|
||||
buf_replace(g->output_dir, '/', '\\');
|
||||
#endif
|
||||
Buf *dest_path = buf_create_from_str(emit_bin_override_path);
|
||||
Buf *source_path;
|
||||
if (only_pp_or_asm) {
|
||||
source_path = buf_alloc();
|
||||
Buf *pp_only_basename = buf_create_from_str(
|
||||
c_source_files.at(0)->preprocessor_only_basename);
|
||||
os_path_join(g->output_dir, pp_only_basename, source_path);
|
||||
|
||||
} else {
|
||||
source_path = &g->bin_file_output_path;
|
||||
}
|
||||
Buf *source_path = &g->bin_file_output_path;
|
||||
if ((err = os_update_file(source_path, dest_path))) {
|
||||
fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(source_path),
|
||||
buf_ptr(dest_path), err_str(err));
|
||||
return main_exit(root_progress_node, EXIT_FAILURE);
|
||||
}
|
||||
} else if (only_pp_or_asm) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
buf_replace(g->c_artifact_dir, '/', '\\');
|
||||
#endif
|
||||
// dump the preprocessed output to stdout
|
||||
for (size_t i = 0; i < c_source_files.length; i += 1) {
|
||||
Buf *source_path = buf_alloc();
|
||||
Buf *pp_only_basename = buf_create_from_str(
|
||||
c_source_files.at(i)->preprocessor_only_basename);
|
||||
os_path_join(g->c_artifact_dir, pp_only_basename, source_path);
|
||||
if ((err = os_dump_file(source_path, stdout))) {
|
||||
fprintf(stderr, "unable to read %s: %s\n", buf_ptr(source_path),
|
||||
err_str(err));
|
||||
return main_exit(root_progress_node, EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
} else if (g->enable_cache) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
buf_replace(&g->bin_file_output_path, '/', '\\');
|
||||
|
||||
@ -32,6 +32,11 @@ int stage2_env(int argc, char** argv) {
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
|
||||
int stage2_cc(int argc, char** argv, bool is_cpp) {
|
||||
const char *msg = "stage0 called stage2_cc";
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
|
||||
void stage2_attach_segfault_handler(void) { }
|
||||
|
||||
void stage2_panic(const char *ptr, size_t len) {
|
||||
@ -316,16 +321,4 @@ enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) {
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it,
|
||||
size_t argc, char **argv)
|
||||
{
|
||||
const char *msg = "stage0 called stage2_clang_arg_iterator";
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
|
||||
enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it) {
|
||||
const char *msg = "stage0 called stage2_clang_arg_next";
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
|
||||
const bool stage2_is_zig0 = true;
|
||||
|
||||
57
src/stage2.h
57
src/stage2.h
@ -144,6 +144,9 @@ ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C int stage2_env(int argc, char **argv);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C int stage2_cc(int argc, char **argv, bool is_cpp);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C void stage2_attach_segfault_handler(void);
|
||||
|
||||
@ -328,60 +331,6 @@ struct Stage2NativePaths {
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths);
|
||||
|
||||
// ABI warning
|
||||
enum Stage2ClangArg {
|
||||
Stage2ClangArgTarget,
|
||||
Stage2ClangArgO,
|
||||
Stage2ClangArgC,
|
||||
Stage2ClangArgOther,
|
||||
Stage2ClangArgPositional,
|
||||
Stage2ClangArgL,
|
||||
Stage2ClangArgIgnore,
|
||||
Stage2ClangArgDriverPunt,
|
||||
Stage2ClangArgPIC,
|
||||
Stage2ClangArgNoPIC,
|
||||
Stage2ClangArgNoStdLib,
|
||||
Stage2ClangArgNoStdLibCpp,
|
||||
Stage2ClangArgShared,
|
||||
Stage2ClangArgRDynamic,
|
||||
Stage2ClangArgWL,
|
||||
Stage2ClangArgPreprocessOrAsm,
|
||||
Stage2ClangArgOptimize,
|
||||
Stage2ClangArgDebug,
|
||||
Stage2ClangArgSanitize,
|
||||
Stage2ClangArgLinkerScript,
|
||||
Stage2ClangArgVerboseCmds,
|
||||
Stage2ClangArgForLinker,
|
||||
Stage2ClangArgLinkerInputZ,
|
||||
Stage2ClangArgLibDir,
|
||||
Stage2ClangArgMCpu,
|
||||
Stage2ClangArgDepFile,
|
||||
Stage2ClangArgFrameworkDir,
|
||||
Stage2ClangArgFramework,
|
||||
Stage2ClangArgNoStdLibInc,
|
||||
};
|
||||
|
||||
// ABI warning
|
||||
struct Stage2ClangArgIterator {
|
||||
bool has_next;
|
||||
enum Stage2ClangArg kind;
|
||||
const char *only_arg;
|
||||
const char *second_arg;
|
||||
const char **other_args_ptr;
|
||||
size_t other_args_len;
|
||||
const char **argv_ptr;
|
||||
size_t argv_len;
|
||||
size_t next_index;
|
||||
size_t root_args;
|
||||
};
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it,
|
||||
size_t argc, char **argv);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C const bool stage2_is_zig0;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user