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:
Andrew Kelley 2020-09-03 20:23:00 -07:00
parent 749417a1f3
commit 503ba7b27c
8 changed files with 938 additions and 867 deletions

View File

@ -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(

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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, '/', '\\');

View File

@ -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;

View File

@ -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;