authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-03 20:23:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-09 09:28:05-07:00
log503ba7b27c6e8e248d271aec936623853cd8fcd1
tree005438102ec6ba09cb9368397b9ff180f44790ad
parent749417a1f3060f0695bbfe72d929f06b0be42535

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.

8 files changed, 937 insertions(+), 866 deletions(-)

build.zig+47-42
...@@ -9,6 +9,7 @@ const ArrayList = std.ArrayList;...@@ -9,6 +9,7 @@ const ArrayList = std.ArrayList;
9const io = std.io;9const io = std.io;
10const fs = std.fs;10const fs = std.fs;
11const InstallDirectoryOptions = std.build.InstallDirectoryOptions;11const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
12const assert = std.debug.assert;
1213
13const zig_version = std.builtin.Version{ .major = 0, .minor = 6, .patch = 0 };14const zig_version = std.builtin.Version{ .major = 0, .minor = 6, .patch = 0 };
1415
...@@ -57,11 +58,13 @@ pub fn build(b: *Builder) !void {...@@ -57,11 +58,13 @@ pub fn build(b: *Builder) !void {
5758
58 if (!only_install_lib_files) {59 if (!only_install_lib_files) {
59 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");60 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
61 exe.install();
60 exe.setBuildMode(mode);62 exe.setBuildMode(mode);
61 exe.setTarget(target);63 exe.setTarget(target);
62 test_step.dependOn(&exe.step);64 test_step.dependOn(&exe.step);
63 b.default_step.dependOn(&exe.step);65 b.default_step.dependOn(&exe.step);
6466
67 exe.addBuildOption(bool, "have_llvm", enable_llvm);
65 if (enable_llvm) {68 if (enable_llvm) {
66 const config_h_text = if (config_h_path_option) |config_h_path|69 const config_h_text = if (config_h_path_option) |config_h_path|
67 try std.fs.cwd().readFileAlloc(b.allocator, toNativePathSep(b, config_h_path), max_config_h_bytes)70 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 {...@@ -73,11 +76,8 @@ pub fn build(b: *Builder) !void {
7376
74 try configureStage2(b, exe, ctx);77 try configureStage2(b, exe, ctx);
75 }78 }
76 if (!only_install_lib_files) {
77 exe.install();
78 }
79 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");79 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
80 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;80 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm;
81 if (link_libc) {81 if (link_libc) {
82 exe.linkLibC();82 exe.linkLibC();
83 test_stage2.linkLibC();83 test_stage2.linkLibC();
...@@ -323,17 +323,13 @@ fn configureStage2(b: *Builder, exe: anytype, ctx: Context) !void {...@@ -323,17 +323,13 @@ fn configureStage2(b: *Builder, exe: anytype, ctx: Context) !void {
323 exe.addIncludeDir("src");323 exe.addIncludeDir("src");
324 exe.addIncludeDir(ctx.cmake_binary_dir);324 exe.addIncludeDir(ctx.cmake_binary_dir);
325 addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");325 addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
326 if (ctx.lld_include_dir.len != 0) {326 assert(ctx.lld_include_dir.len != 0);
327 exe.addIncludeDir(ctx.lld_include_dir);327 exe.addIncludeDir(ctx.lld_include_dir);
328 {
328 var it = mem.tokenize(ctx.lld_libraries, ";");329 var it = mem.tokenize(ctx.lld_libraries, ";");
329 while (it.next()) |lib| {330 while (it.next()) |lib| {
330 exe.addObjectFile(lib);331 exe.addObjectFile(lib);
331 }332 }
332 } else {
333 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_wasm");
334 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_elf");
335 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_coff");
336 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_lib");
337 }333 }
338 {334 {
339 var it = mem.tokenize(ctx.clang_libraries, ";");335 var it = mem.tokenize(ctx.clang_libraries, ";");
...@@ -343,42 +339,51 @@ fn configureStage2(b: *Builder, exe: anytype, ctx: Context) !void {...@@ -343,42 +339,51 @@ fn configureStage2(b: *Builder, exe: anytype, ctx: Context) !void {
343 }339 }
344 dependOnLib(b, exe, ctx.llvm);340 dependOnLib(b, exe, ctx.llvm);
345341
346 if (exe.target.getOsTag() == .linux) {342 // Boy, it sure would be nice to simply linkSystemLibrary("c++") and rely on zig's
347 // First we try to static link against gcc libstdc++. If that doesn't work,343 // ability to provide libc++ right? Well thanks to C++ not having a stable ABI this
348 // we fall back to -lc++ and cross our fingers.344 // will cause linker errors. It would work in the situation when `zig cc` is used to
349 addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) {345 // build LLVM, Clang, and LLD, however when depending on them as system libraries, system
350 error.RequiredLibraryNotFound => {346 // libc++ must be used.
351 exe.linkSystemLibrary("c++");347 const cross_compile = false; // TODO
352 },348 if (cross_compile) {
353 else => |e| return e,349 // In this case we assume that zig cc was used to build the LLVM, Clang, LLD dependencies.
354 };350 exe.linkSystemLibrary("c++");
351 } else {
352 if (exe.target.getOsTag() == .linux) {
353 // First we try to static link against gcc libstdc++. If that doesn't work,
354 // we fall back to -lc++ and cross our fingers.
355 addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) {
356 error.RequiredLibraryNotFound => {
357 exe.linkSystemLibrary("c++");
358 },
359 else => |e| return e,
360 };
355361
356 exe.linkSystemLibrary("pthread");
357 } else if (exe.target.isFreeBSD()) {
358 try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
359 exe.linkSystemLibrary("pthread");
360 } else if (exe.target.isDarwin()) {
361 if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
362 // Compiler is GCC.
363 try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);
364 exe.linkSystemLibrary("pthread");362 exe.linkSystemLibrary("pthread");
365 // TODO LLD cannot perform this link.363 } else if (exe.target.isFreeBSD()) {
366 // See https://github.com/ziglang/zig/issues/1535364 try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
367 exe.enableSystemLinkerHack();365 exe.linkSystemLibrary("pthread");
368 } else |err| switch (err) {366 } else if (exe.target.isDarwin()) {
369 error.RequiredLibraryNotFound => {367 if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
370 // System compiler, not gcc.368 // Compiler is GCC.
371 exe.linkSystemLibrary("c++");369 try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);
372 },370 exe.linkSystemLibrary("pthread");
373 else => |e| return e,371 // TODO LLD cannot perform this link.
372 // See https://github.com/ziglang/zig/issues/1535
373 exe.enableSystemLinkerHack();
374 } else |err| switch (err) {
375 error.RequiredLibraryNotFound => {
376 // System compiler, not gcc.
377 exe.linkSystemLibrary("c++");
378 },
379 else => |e| return e,
380 }
374 }381 }
375 }
376382
377 if (ctx.dia_guids_lib.len != 0) {383 if (ctx.dia_guids_lib.len != 0) {
378 exe.addObjectFile(ctx.dia_guids_lib);384 exe.addObjectFile(ctx.dia_guids_lib);
385 }
379 }386 }
380
381 exe.linkSystemLibrary("c");
382}387}
383388
384fn addCxxKnownPath(389fn addCxxKnownPath(
src-self-hosted/clang_options.zig+1-3
...@@ -7,9 +7,7 @@ pub const CliArg = struct {...@@ -7,9 +7,7 @@ pub const CliArg = struct {
7 name: []const u8,7 name: []const u8,
8 syntax: Syntax,8 syntax: Syntax,
99
10 /// TODO we're going to want to change this when we start shipping self-hosted because this causes10 zig_equivalent: @import("main.zig").ClangArgIterator.ZigEquivalent,
11 /// all the functions in stage2.zig to get exported.
12 zig_equivalent: @import("stage2.zig").ClangArgIterator.ZigEquivalent,
1311
14 /// Prefixed by "-"12 /// Prefixed by "-"
15 pd1: bool = false,13 pd1: bool = false,
src-self-hosted/main.zig+857-85
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const assert = std.debug.assert;
2const io = std.io;3const io = std.io;
3const fs = std.fs;4const fs = std.fs;
4const mem = std.mem;5const mem = std.mem;
...@@ -11,6 +12,13 @@ const link = @import("link.zig");...@@ -11,6 +12,13 @@ const link = @import("link.zig");
11const Package = @import("Package.zig");12const Package = @import("Package.zig");
12const zir = @import("zir.zig");13const zir = @import("zir.zig");
13const build_options = @import("build_options");14const build_options = @import("build_options");
15const warn = std.log.warn;
16const info = std.log.info;
17
18fn fatal(comptime format: []const u8, args: anytype) noreturn {
19 std.log.emerg(format, args);
20 process.exit(1);
21}
1422
15pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB23pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
1624
...@@ -28,9 +36,11 @@ const usage =...@@ -28,9 +36,11 @@ const usage =
28 \\ build-exe [source] Create executable from source or object files36 \\ build-exe [source] Create executable from source or object files
29 \\ build-lib [source] Create library from source or object files37 \\ build-lib [source] Create library from source or object files
30 \\ build-obj [source] Create object from source or assembly38 \\ build-obj [source] Create object from source or assembly
39 \\ cc Use Zig as a drop-in C compiler
40 \\ c++ Use Zig as a drop-in C++ compiler
41 \\ env Print lib path, std path, compiler id and version
31 \\ fmt [source] Parse file and render in canonical zig format42 \\ fmt [source] Parse file and render in canonical zig format
32 \\ targets List available compilation targets43 \\ targets List available compilation targets
33 \\ env Print lib path, std path, compiler id and version
34 \\ version Print version number and exit44 \\ version Print version number and exit
35 \\ zen Print zen of zig and exit45 \\ zen Print zen of zig and exit
36 \\46 \\
...@@ -84,11 +94,19 @@ pub fn main() !void {...@@ -84,11 +94,19 @@ pub fn main() !void {
84 const cmd = args[1];94 const cmd = args[1];
85 const cmd_args = args[2..];95 const cmd_args = args[2..];
86 if (mem.eql(u8, cmd, "build-exe")) {96 if (mem.eql(u8, cmd, "build-exe")) {
87 return buildOutputType(gpa, arena, cmd_args, .Exe);97 return buildOutputType(gpa, arena, args, .{ .build = .Exe });
88 } else if (mem.eql(u8, cmd, "build-lib")) {98 } else if (mem.eql(u8, cmd, "build-lib")) {
89 return buildOutputType(gpa, arena, cmd_args, .Lib);99 return buildOutputType(gpa, arena, args, .{ .build = .Lib });
90 } else if (mem.eql(u8, cmd, "build-obj")) {100 } else if (mem.eql(u8, cmd, "build-obj")) {
91 return buildOutputType(gpa, arena, cmd_args, .Obj);101 return buildOutputType(gpa, arena, args, .{ .build = .Obj });
102 } else if (mem.eql(u8, cmd, "cc")) {
103 return buildOutputType(gpa, arena, args, .cc);
104 } else if (mem.eql(u8, cmd, "c++")) {
105 return buildOutputType(gpa, arena, args, .cpp);
106 } else if (mem.eql(u8, cmd, "clang") or
107 mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
108 {
109 return punt_to_clang(arena, args);
92 } else if (mem.eql(u8, cmd, "fmt")) {110 } else if (mem.eql(u8, cmd, "fmt")) {
93 return cmdFmt(gpa, cmd_args);111 return cmdFmt(gpa, cmd_args);
94 } else if (mem.eql(u8, cmd, "targets")) {112 } else if (mem.eql(u8, cmd, "targets")) {
...@@ -147,6 +165,8 @@ const usage_build_generic =...@@ -147,6 +165,8 @@ const usage_build_generic =
147 \\ ReleaseFast Optimizations on, safety off165 \\ ReleaseFast Optimizations on, safety off
148 \\ ReleaseSafe Optimizations on, safety on166 \\ ReleaseSafe Optimizations on, safety on
149 \\ ReleaseSmall Optimize for small binary, safety off167 \\ ReleaseSmall Optimize for small binary, safety off
168 \\ -fPIC Force-enable Position Independent Code
169 \\ -fno-PIC Force-disable Position Independent Code
150 \\ --dynamic Force output to be dynamically linked170 \\ --dynamic Force output to be dynamically linked
151 \\ --strip Exclude debug symbols171 \\ --strip Exclude debug symbols
152 \\ -ofmt=[mode] Override target object format172 \\ -ofmt=[mode] Override target object format
...@@ -158,11 +178,19 @@ const usage_build_generic =...@@ -158,11 +178,19 @@ const usage_build_generic =
158 \\ macho (planned) macOS relocatables178 \\ macho (planned) macOS relocatables
159 \\ hex (planned) Intel IHEX179 \\ hex (planned) Intel IHEX
160 \\ raw (planned) Dump machine code directly180 \\ raw (planned) Dump machine code directly
181 \\ -dirafter [dir] Add directory to AFTER include search path
182 \\ -isystem [dir] Add directory to SYSTEM include search path
183 \\ -I[dir] Add directory to include search path
184 \\ -D[macro]=[value] Define C [macro] to [value] (1 if [value] omitted)
161 \\185 \\
162 \\Link Options:186 \\Link Options:
163 \\ -l[lib], --library [lib] Link against system library187 \\ -l[lib], --library [lib] Link against system library
188 \\ -L[d], --library-directory [d] Add a directory to the library search path
189 \\ -T[script] Use a custom linker script
164 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)190 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
165 \\ --version [ver] Dynamic library semver191 \\ --version [ver] Dynamic library semver
192 \\ -rdynamic Add all symbols to the dynamic symbol table
193 \\ -rpath [path] Add directory to the runtime library search path
166 \\194 \\
167 \\Debug Options (Zig Compiler Development):195 \\Debug Options (Zig Compiler Development):
168 \\ -ftime-report Print timing diagnostics196 \\ -ftime-report Print timing diagnostics
...@@ -181,11 +209,15 @@ const Emit = union(enum) {...@@ -181,11 +209,15 @@ const Emit = union(enum) {
181 yes: []const u8,209 yes: []const u8,
182};210};
183211
184fn buildOutputType(212pub fn buildOutputType(
185 gpa: *Allocator,213 gpa: *Allocator,
186 arena: *Allocator,214 arena: *Allocator,
187 args: []const []const u8,215 all_args: []const []const u8,
188 output_mode: std.builtin.OutputMode,216 arg_mode: union(enum) {
217 build: std.builtin.OutputMode,
218 cc,
219 cpp,
220 },
189) !void {221) !void {
190 var color: Color = .Auto;222 var color: Color = .Auto;
191 var build_mode: std.builtin.Mode = .Debug;223 var build_mode: std.builtin.Mode = .Debug;
...@@ -194,6 +226,7 @@ fn buildOutputType(...@@ -194,6 +226,7 @@ fn buildOutputType(
194 var root_src_file: ?[]const u8 = null;226 var root_src_file: ?[]const u8 = null;
195 var version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 };227 var version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 };
196 var strip = false;228 var strip = false;
229 var emit_h = true;
197 var watch = false;230 var watch = false;
198 var debug_tokenize = false;231 var debug_tokenize = false;
199 var debug_ast_tree = false;232 var debug_ast_tree = false;
...@@ -201,6 +234,7 @@ fn buildOutputType(...@@ -201,6 +234,7 @@ fn buildOutputType(
201 var debug_link = false;234 var debug_link = false;
202 var debug_ir = false;235 var debug_ir = false;
203 var debug_codegen = false;236 var debug_codegen = false;
237 var debug_cc = false;
204 var time_report = false;238 var time_report = false;
205 var emit_bin: Emit = .yes_default_path;239 var emit_bin: Emit = .yes_default_path;
206 var emit_zir: Emit = .no;240 var emit_zir: Emit = .no;
...@@ -208,11 +242,57 @@ fn buildOutputType(...@@ -208,11 +242,57 @@ fn buildOutputType(
208 var target_mcpu: ?[]const u8 = null;242 var target_mcpu: ?[]const u8 = null;
209 var target_dynamic_linker: ?[]const u8 = null;243 var target_dynamic_linker: ?[]const u8 = null;
210 var target_ofmt: ?[]const u8 = null;244 var target_ofmt: ?[]const u8 = null;
245 var output_mode: std.builtin.OutputMode = undefined;
246 var ensure_libc_on_non_freestanding = false;
247 var ensure_libcpp_on_non_freestanding = false;
248 var have_libc = false;
249 var have_libcpp = false;
250 var want_native_include_dirs = false;
251 var enable_cache: ?bool = null;
252 var want_pic: ?bool = null;
253 var want_sanitize_c: ?bool = null;
254 var rdynamic: bool = false;
255 var only_pp_or_asm = false;
256 var linker_script: ?[]const u8 = null;
257 var version_script: ?[]const u8 = null;
258 var disable_c_depfile = false;
259 var override_soname: ?[]const u8 = null;
260 var linker_optimization: ?[]const u8 = null;
261 var linker_gc_sections: ?bool = null;
262 var linker_allow_shlib_undefined: ?bool = null;
263 var linker_bind_global_refs_locally: ?bool = null;
264 var linker_z_nodelete = false;
265 var linker_z_defs = false;
266 var stack_size_override: u64 = 0;
211267
212 var system_libs = std.ArrayList([]const u8).init(gpa);268 var system_libs = std.ArrayList([]const u8).init(gpa);
213 defer system_libs.deinit();269 defer system_libs.deinit();
214270
215 {271 var clang_argv = std.ArrayList([]const u8).init(gpa);
272 defer clang_argv.deinit();
273
274 var lib_dirs = std.ArrayList([]const u8).init(gpa);
275 defer lib_dirs.deinit();
276
277 var rpath_list = std.ArrayList([]const u8).init(gpa);
278 defer rpath_list.deinit();
279
280 var c_source_files = std.ArrayList([]const u8).init(gpa);
281 defer c_source_files.deinit();
282
283 var link_objects = std.ArrayList([]const u8).init(gpa);
284 defer link_objects.deinit();
285
286 var framework_dirs = std.ArrayList([]const u8).init(gpa);
287 defer framework_dirs.deinit();
288
289 var frameworks = std.ArrayList([]const u8).init(gpa);
290 defer frameworks.deinit();
291
292 if (arg_mode == .build) {
293 output_mode = arg_mode.build;
294
295 const args = all_args[2..];
216 var i: usize = 0;296 var i: usize = 0;
217 while (i < args.len) : (i += 1) {297 while (i < args.len) : (i += 1) {
218 const arg = args[i];298 const arg = args[i];
...@@ -222,8 +302,7 @@ fn buildOutputType(...@@ -222,8 +302,7 @@ fn buildOutputType(
222 process.exit(0);302 process.exit(0);
223 } else if (mem.eql(u8, arg, "--color")) {303 } else if (mem.eql(u8, arg, "--color")) {
224 if (i + 1 >= args.len) {304 if (i + 1 >= args.len) {
225 std.debug.print("expected [auto|on|off] after --color\n", .{});305 fatal("expected [auto|on|off] after --color", .{});
226 process.exit(1);
227 }306 }
228 i += 1;307 i += 1;
229 const next_arg = args[i];308 const next_arg = args[i];
...@@ -234,13 +313,11 @@ fn buildOutputType(...@@ -234,13 +313,11 @@ fn buildOutputType(
234 } else if (mem.eql(u8, next_arg, "off")) {313 } else if (mem.eql(u8, next_arg, "off")) {
235 color = .Off;314 color = .Off;
236 } else {315 } else {
237 std.debug.print("expected [auto|on|off] after --color, found '{}'\n", .{next_arg});316 fatal("expected [auto|on|off] after --color, found '{}'", .{next_arg});
238 process.exit(1);
239 }317 }
240 } else if (mem.eql(u8, arg, "--mode")) {318 } else if (mem.eql(u8, arg, "--mode")) {
241 if (i + 1 >= args.len) {319 if (i + 1 >= args.len) {
242 std.debug.print("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n", .{});320 fatal("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode", .{});
243 process.exit(1);
244 }321 }
245 i += 1;322 i += 1;
246 const next_arg = args[i];323 const next_arg = args[i];
...@@ -253,44 +330,66 @@ fn buildOutputType(...@@ -253,44 +330,66 @@ fn buildOutputType(
253 } else if (mem.eql(u8, next_arg, "ReleaseSmall")) {330 } else if (mem.eql(u8, next_arg, "ReleaseSmall")) {
254 build_mode = .ReleaseSmall;331 build_mode = .ReleaseSmall;
255 } else {332 } else {
256 std.debug.print("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode, found '{}'\n", .{next_arg});333 fatal("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode, found '{}'", .{next_arg});
257 process.exit(1);
258 }334 }
335 } else if (mem.eql(u8, arg, "--stack")) {
336 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
337 i += 1;
338 stack_size_override = std.fmt.parseInt(u64, args[i], 10) catch |err| {
339 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
340 };
259 } else if (mem.eql(u8, arg, "--name")) {341 } else if (mem.eql(u8, arg, "--name")) {
260 if (i + 1 >= args.len) {342 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
261 std.debug.print("expected parameter after --name\n", .{});
262 process.exit(1);
263 }
264 i += 1;343 i += 1;
265 provided_name = args[i];344 provided_name = args[i];
266 } else if (mem.eql(u8, arg, "--library")) {345 } else if (mem.eql(u8, arg, "-rpath")) {
267 if (i + 1 >= args.len) {346 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
268 std.debug.print("expected parameter after --library\n", .{});347 i += 1;
269 process.exit(1);348 try rpath_list.append(args[i]);
270 }349 } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) {
350 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
351 i += 1;
352 try lib_dirs.append(args[i]);
353 } else if (mem.eql(u8, arg, "-T")) {
354 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
355 i += 1;
356 linker_script = args[i];
357 } else if (mem.eql(u8, arg, "--version-script")) {
358 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
359 i += 1;
360 version_script = args[i];
361 } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {
362 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
363 // We don't know whether this library is part of libc or libc++ until we resolve the target.
364 // So we simply append to the list for now.
271 i += 1;365 i += 1;
272 try system_libs.append(args[i]);366 try system_libs.append(args[i]);
367 } else if (mem.eql(u8, arg, "-D") or
368 mem.eql(u8, arg, "-isystem") or
369 mem.eql(u8, arg, "-I") or
370 mem.eql(u8, arg, "-dirafter"))
371 {
372 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
373 i += 1;
374 try clang_argv.append(arg);
375 try clang_argv.append(args[i]);
273 } else if (mem.eql(u8, arg, "--version")) {376 } else if (mem.eql(u8, arg, "--version")) {
274 if (i + 1 >= args.len) {377 if (i + 1 >= args.len) {
275 std.debug.print("expected parameter after --version\n", .{});378 fatal("expected parameter after --version", .{});
276 process.exit(1);
277 }379 }
278 i += 1;380 i += 1;
279 version = std.builtin.Version.parse(args[i]) catch |err| {381 version = std.builtin.Version.parse(args[i]) catch |err| {
280 std.debug.print("unable to parse --version '{}': {}\n", .{ args[i], @errorName(err) });382 fatal("unable to parse --version '{}': {}", .{ args[i], @errorName(err) });
281 process.exit(1);
282 };383 };
283 } else if (mem.eql(u8, arg, "-target")) {384 } else if (mem.eql(u8, arg, "-target")) {
284 if (i + 1 >= args.len) {385 if (i + 1 >= args.len) {
285 std.debug.print("expected parameter after -target\n", .{});386 fatal("expected parameter after -target", .{});
286 process.exit(1);
287 }387 }
288 i += 1;388 i += 1;
289 target_arch_os_abi = args[i];389 target_arch_os_abi = args[i];
290 } else if (mem.eql(u8, arg, "-mcpu")) {390 } else if (mem.eql(u8, arg, "-mcpu")) {
291 if (i + 1 >= args.len) {391 if (i + 1 >= args.len) {
292 std.debug.print("expected parameter after -mcpu\n", .{});392 fatal("expected parameter after -mcpu", .{});
293 process.exit(1);
294 }393 }
295 i += 1;394 i += 1;
296 target_mcpu = args[i];395 target_mcpu = args[i];
...@@ -300,8 +399,7 @@ fn buildOutputType(...@@ -300,8 +399,7 @@ fn buildOutputType(
300 target_mcpu = arg["-mcpu=".len..];399 target_mcpu = arg["-mcpu=".len..];
301 } else if (mem.eql(u8, arg, "--dynamic-linker")) {400 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
302 if (i + 1 >= args.len) {401 if (i + 1 >= args.len) {
303 std.debug.print("expected parameter after --dynamic-linker\n", .{});402 fatal("expected parameter after --dynamic-linker", .{});
304 process.exit(1);
305 }403 }
306 i += 1;404 i += 1;
307 target_dynamic_linker = args[i];405 target_dynamic_linker = args[i];
...@@ -309,6 +407,12 @@ fn buildOutputType(...@@ -309,6 +407,12 @@ fn buildOutputType(
309 watch = true;407 watch = true;
310 } else if (mem.eql(u8, arg, "-ftime-report")) {408 } else if (mem.eql(u8, arg, "-ftime-report")) {
311 time_report = true;409 time_report = true;
410 } else if (mem.eql(u8, arg, "-fPIC")) {
411 want_pic = true;
412 } else if (mem.eql(u8, arg, "-fno-PIC")) {
413 want_pic = false;
414 } else if (mem.eql(u8, arg, "-rdynamic")) {
415 rdynamic = true;
312 } else if (mem.eql(u8, arg, "-femit-bin")) {416 } else if (mem.eql(u8, arg, "-femit-bin")) {
313 emit_bin = .yes_default_path;417 emit_bin = .yes_default_path;
314 } else if (mem.startsWith(u8, arg, "-femit-bin=")) {418 } else if (mem.startsWith(u8, arg, "-femit-bin=")) {
...@@ -327,6 +431,8 @@ fn buildOutputType(...@@ -327,6 +431,8 @@ fn buildOutputType(
327 link_mode = .Static;431 link_mode = .Static;
328 } else if (mem.eql(u8, arg, "--strip")) {432 } else if (mem.eql(u8, arg, "--strip")) {
329 strip = true;433 strip = true;
434 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
435 linker_bind_global_refs_locally = true;
330 } else if (mem.eql(u8, arg, "--debug-tokenize")) {436 } else if (mem.eql(u8, arg, "--debug-tokenize")) {
331 debug_tokenize = true;437 debug_tokenize = true;
332 } else if (mem.eql(u8, arg, "--debug-ast-tree")) {438 } else if (mem.eql(u8, arg, "--debug-ast-tree")) {
...@@ -339,44 +445,321 @@ fn buildOutputType(...@@ -339,44 +445,321 @@ fn buildOutputType(
339 debug_ir = true;445 debug_ir = true;
340 } else if (mem.eql(u8, arg, "--debug-codegen")) {446 } else if (mem.eql(u8, arg, "--debug-codegen")) {
341 debug_codegen = true;447 debug_codegen = true;
448 } else if (mem.eql(u8, arg, "--debug-cc")) {
449 debug_cc = true;
450 } else if (mem.startsWith(u8, arg, "-T")) {
451 linker_script = arg[2..];
452 } else if (mem.startsWith(u8, arg, "-L")) {
453 try lib_dirs.append(arg[2..]);
342 } else if (mem.startsWith(u8, arg, "-l")) {454 } else if (mem.startsWith(u8, arg, "-l")) {
455 // We don't know whether this library is part of libc or libc++ until we resolve the target.
456 // So we simply append to the list for now.
343 try system_libs.append(arg[2..]);457 try system_libs.append(arg[2..]);
458 } else if (mem.startsWith(u8, arg, "-D") or
459 mem.startsWith(u8, arg, "-I"))
460 {
461 try clang_argv.append(arg);
344 } else {462 } else {
345 std.debug.print("unrecognized parameter: '{}'\n", .{arg});463 fatal("unrecognized parameter: '{}'", .{arg});
346 process.exit(1);
347 }464 }
348 } else if (mem.endsWith(u8, arg, ".s") or mem.endsWith(u8, arg, ".S")) {
349 std.debug.print("assembly files not supported yet\n", .{});
350 process.exit(1);
351 } else if (mem.endsWith(u8, arg, ".o") or465 } else if (mem.endsWith(u8, arg, ".o") or
352 mem.endsWith(u8, arg, ".obj") or466 mem.endsWith(u8, arg, ".obj") or
353 mem.endsWith(u8, arg, ".a") or467 mem.endsWith(u8, arg, ".a") or
354 mem.endsWith(u8, arg, ".lib"))468 mem.endsWith(u8, arg, ".lib"))
355 {469 {
356 std.debug.print("object files and static libraries not supported yet\n", .{});470 try link_objects.append(arg);
357 process.exit(1);471 } else if (hasAsmExt(arg) or hasCExt(arg) or hasCppExt(arg)) {
358 } else if (mem.endsWith(u8, arg, ".c") or472 try c_source_files.append(arg);
359 mem.endsWith(u8, arg, ".cpp"))
360 {
361 std.debug.print("compilation of C and C++ source code requires LLVM extensions which are not implemented yet\n", .{});
362 process.exit(1);
363 } else if (mem.endsWith(u8, arg, ".so") or473 } else if (mem.endsWith(u8, arg, ".so") or
364 mem.endsWith(u8, arg, ".dylib") or474 mem.endsWith(u8, arg, ".dylib") or
365 mem.endsWith(u8, arg, ".dll"))475 mem.endsWith(u8, arg, ".dll"))
366 {476 {
367 std.debug.print("linking against dynamic libraries not yet supported\n", .{});477 fatal("linking against dynamic libraries not yet supported", .{});
368 process.exit(1);
369 } else if (mem.endsWith(u8, arg, ".zig") or mem.endsWith(u8, arg, ".zir")) {478 } else if (mem.endsWith(u8, arg, ".zig") or mem.endsWith(u8, arg, ".zir")) {
370 if (root_src_file) |other| {479 if (root_src_file) |other| {
371 std.debug.print("found another zig file '{}' after root source file '{}'\n", .{ arg, other });480 fatal("found another zig file '{}' after root source file '{}'", .{ arg, other });
372 process.exit(1);
373 } else {481 } else {
374 root_src_file = arg;482 root_src_file = arg;
375 }483 }
376 } else {484 } else {
377 std.debug.print("unrecognized file extension of parameter '{}'\n", .{arg});485 fatal("unrecognized file extension of parameter '{}'", .{arg});
486 }
487 }
488 } else {
489 if (!build_options.have_llvm)
490 fatal("`zig cc` and `zig c++` unavailable: compiler not built with LLVM extensions enabled", .{});
491 emit_h = false;
492 strip = true;
493 ensure_libc_on_non_freestanding = true;
494 ensure_libcpp_on_non_freestanding = arg_mode == .cpp;
495 want_native_include_dirs = true;
496
497 var c_arg = false;
498 var is_shared_lib = false;
499 var linker_args = std.ArrayList([]const u8).init(arena);
500 var it = ClangArgIterator.init(arena, all_args);
501 while (it.has_next) {
502 it.next() catch |err| {
503 fatal("unable to parse command line parameters: {}", .{@errorName(err)});
504 };
505 switch (it.zig_equivalent) {
506 .target => target_arch_os_abi = it.only_arg, // example: -target riscv64-linux-unknown
507 .o => {
508 // -o
509 emit_bin = .{ .yes = it.only_arg };
510 enable_cache = true;
511 },
512 .c => c_arg = true, // -c
513 .other => {
514 try clang_argv.appendSlice(it.other_args);
515 },
516 .positional => {
517 const file_ext = classify_file_ext(mem.spanZ(it.only_arg));
518 switch (file_ext) {
519 .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg),
520 .unknown => try link_objects.append(it.only_arg),
521 }
522 },
523 .l => {
524 // -l
525 // We don't know whether this library is part of libc or libc++ until we resolve the target.
526 // So we simply append to the list for now.
527 try system_libs.append(it.only_arg);
528 },
529 .ignore => {},
530 .driver_punt => {
531 // Never mind what we're doing, just pass the args directly. For example --help.
532 return punt_to_clang(arena, all_args);
533 },
534 .pic => want_pic = true,
535 .no_pic => want_pic = false,
536 .nostdlib => ensure_libc_on_non_freestanding = false,
537 .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false,
538 .shared => {
539 link_mode = .Dynamic;
540 is_shared_lib = true;
541 },
542 .rdynamic => rdynamic = true,
543 .wl => {
544 var split_it = mem.split(it.only_arg, ",");
545 @breakpoint(); // TODO the first arg is empty string right? skip past that.
546 while (split_it.next()) |linker_arg| {
547 try linker_args.append(linker_arg);
548 }
549 },
550 .pp_or_asm => {
551 // This handles both -E and -S.
552 only_pp_or_asm = true;
553 try clang_argv.appendSlice(it.other_args);
554 },
555 .optimize => {
556 // Alright, what release mode do they want?
557 if (mem.eql(u8, it.only_arg, "Os")) {
558 build_mode = .ReleaseSmall;
559 } else if (mem.eql(u8, it.only_arg, "O2") or
560 mem.eql(u8, it.only_arg, "O3") or
561 mem.eql(u8, it.only_arg, "O4"))
562 {
563 build_mode = .ReleaseFast;
564 } else if (mem.eql(u8, it.only_arg, "Og") or
565 mem.eql(u8, it.only_arg, "O0"))
566 {
567 build_mode = .Debug;
568 } else {
569 try clang_argv.appendSlice(it.other_args);
570 }
571 },
572 .debug => {
573 strip = false;
574 if (mem.eql(u8, it.only_arg, "-g")) {
575 // We handled with strip = false above.
576 } else {
577 try clang_argv.appendSlice(it.other_args);
578 }
579 },
580 .sanitize => {
581 if (mem.eql(u8, it.only_arg, "undefined")) {
582 want_sanitize_c = true;
583 } else {
584 try clang_argv.appendSlice(it.other_args);
585 }
586 },
587 .linker_script => linker_script = it.only_arg,
588 .verbose_cmds => {
589 debug_cc = true;
590 debug_link = true;
591 },
592 .for_linker => try linker_args.append(it.only_arg),
593 .linker_input_z => {
594 try linker_args.append("-z");
595 try linker_args.append(it.only_arg);
596 },
597 .lib_dir => try lib_dirs.append(it.only_arg),
598 .mcpu => target_mcpu = it.only_arg,
599 .dep_file => {
600 disable_c_depfile = true;
601 try clang_argv.appendSlice(it.other_args);
602 },
603 .framework_dir => try framework_dirs.append(it.only_arg),
604 .framework => try frameworks.append(it.only_arg),
605 .nostdlibinc => want_native_include_dirs = false,
606 }
607 }
608 // Parse linker args.
609 var i: usize = 0;
610 while (i < linker_args.items.len) : (i += 1) {
611 const arg = linker_args.items[i];
612 if (mem.eql(u8, arg, "-soname")) {
613 i += 1;
614 if (i >= linker_args.items.len) {
615 fatal("expected linker arg after '{}'", .{arg});
616 }
617 const soname = linker_args.items[i];
618 override_soname = soname;
619 // Use it as --name.
620 // Example: libsoundio.so.2
621 var prefix: usize = 0;
622 if (mem.startsWith(u8, soname, "lib")) {
623 prefix = 3;
624 }
625 var end: usize = soname.len;
626 if (mem.endsWith(u8, soname, ".so")) {
627 end -= 3;
628 } else {
629 var found_digit = false;
630 while (end > 0 and std.ascii.isDigit(soname[end - 1])) {
631 found_digit = true;
632 end -= 1;
633 }
634 if (found_digit and end > 0 and soname[end - 1] == '.') {
635 end -= 1;
636 } else {
637 end = soname.len;
638 }
639 if (mem.endsWith(u8, soname[prefix..end], ".so")) {
640 end -= 3;
641 }
642 }
643 provided_name = soname[prefix..end];
644 } else if (mem.eql(u8, arg, "-rpath")) {
645 i += 1;
646 if (i >= linker_args.items.len) {
647 fatal("expected linker arg after '{}'", .{arg});
648 }
649 try rpath_list.append(linker_args.items[i]);
650 } else if (mem.eql(u8, arg, "-I") or
651 mem.eql(u8, arg, "--dynamic-linker") or
652 mem.eql(u8, arg, "-dynamic-linker"))
653 {
654 i += 1;
655 if (i >= linker_args.items.len) {
656 fatal("expected linker arg after '{}'", .{arg});
657 }
658 target_dynamic_linker = linker_args.items[i];
659 } else if (mem.eql(u8, arg, "-E") or
660 mem.eql(u8, arg, "--export-dynamic") or
661 mem.eql(u8, arg, "-export-dynamic"))
662 {
663 rdynamic = true;
664 } else if (mem.eql(u8, arg, "--version-script")) {
665 i += 1;
666 if (i >= linker_args.items.len) {
667 fatal("expected linker arg after '{}'", .{arg});
668 }
669 version_script = linker_args.items[i];
670 } else if (mem.startsWith(u8, arg, "-O")) {
671 linker_optimization = arg;
672 } else if (mem.eql(u8, arg, "--gc-sections")) {
673 linker_gc_sections = true;
674 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
675 linker_gc_sections = false;
676 } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or
677 mem.eql(u8, arg, "-allow-shlib-undefined"))
678 {
679 linker_allow_shlib_undefined = true;
680 } else if (mem.eql(u8, arg, "--no-allow-shlib-undefined") or
681 mem.eql(u8, arg, "-no-allow-shlib-undefined"))
682 {
683 linker_allow_shlib_undefined = false;
684 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
685 linker_bind_global_refs_locally = true;
686 } else if (mem.eql(u8, arg, "-z")) {
687 i += 1;
688 if (i >= linker_args.items.len) {
689 fatal("expected linker arg after '{}'", .{arg});
690 }
691 const z_arg = linker_args.items[i];
692 if (mem.eql(u8, z_arg, "nodelete")) {
693 linker_z_nodelete = true;
694 } else if (mem.eql(u8, z_arg, "defs")) {
695 linker_z_defs = true;
696 } else {
697 warn("unsupported linker arg: -z {}", .{z_arg});
698 }
699 } else if (mem.eql(u8, arg, "--major-image-version")) {
700 i += 1;
701 if (i >= linker_args.items.len) {
702 fatal("expected linker arg after '{}'", .{arg});
703 }
704 version.major = std.fmt.parseInt(u32, linker_args.items[i], 10) catch |err| {
705 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
706 };
707 } else if (mem.eql(u8, arg, "--minor-image-version")) {
708 i += 1;
709 if (i >= linker_args.items.len) {
710 fatal("expected linker arg after '{}'", .{arg});
711 }
712 version.minor = std.fmt.parseInt(u32, linker_args.items[i], 10) catch |err| {
713 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
714 };
715 } else if (mem.eql(u8, arg, "--stack")) {
716 i += 1;
717 if (i >= linker_args.items.len) {
718 fatal("expected linker arg after '{}'", .{arg});
719 }
720 stack_size_override = std.fmt.parseInt(u64, linker_args.items[i], 10) catch |err| {
721 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
722 };
723 } else {
724 warn("unsupported linker arg: {}", .{arg});
378 }725 }
379 }726 }
727
728 if (want_sanitize_c == true and build_mode == .ReleaseFast) {
729 build_mode = .ReleaseSafe;
730 }
731
732 if (only_pp_or_asm) {
733 output_mode = .Obj;
734 fatal("TODO implement using zig cc as a preprocessor", .{});
735 //// Transfer "link_objects" into c_source_files so that all those
736 //// args make it onto the command line.
737 //try c_source_files.appendSlice(link_objects.items);
738 //for (c_source_files.items) |c_source_file| {
739 // const src_path = switch (emit_bin) {
740 // .yes => |p| p,
741 // else => c_source_file.source_path,
742 // };
743 // const basename = std.fs.path.basename(src_path);
744 // c_source_file.preprocessor_only_basename = basename;
745 //}
746 //emit_bin = .no;
747 } else if (!c_arg) {
748 output_mode = if (is_shared_lib) .Lib else .Exe;
749 switch (emit_bin) {
750 .no, .yes_default_path => {
751 emit_bin = .{ .yes = "a.out" };
752 enable_cache = true;
753 },
754 .yes => {},
755 }
756 } else {
757 output_mode = .Obj;
758 }
759 if (c_source_files.items.len == 0 and link_objects.items.len == 0) {
760 // For example `zig cc` and no args should print the "no input files" message.
761 return punt_to_clang(arena, all_args);
762 }
380 }763 }
381764
382 const root_name = if (provided_name) |n| n else blk: {765 const root_name = if (provided_name) |n| n else blk: {
...@@ -385,16 +768,10 @@ fn buildOutputType(...@@ -385,16 +768,10 @@ fn buildOutputType(
385 var it = mem.split(basename, ".");768 var it = mem.split(basename, ".");
386 break :blk it.next() orelse basename;769 break :blk it.next() orelse basename;
387 } else {770 } else {
388 std.debug.print("--name [name] not provided and unable to infer\n", .{});771 fatal("--name [name] not provided and unable to infer", .{});
389 process.exit(1);
390 }772 }
391 };773 };
392774
393 if (system_libs.items.len != 0) {
394 std.debug.print("linking against system libraries not yet supported\n", .{});
395 process.exit(1);
396 }
397
398 var diags: std.zig.CrossTarget.ParseOptions.Diagnostics = .{};775 var diags: std.zig.CrossTarget.ParseOptions.Diagnostics = .{};
399 const cross_target = std.zig.CrossTarget.parse(.{776 const cross_target = std.zig.CrossTarget.parse(.{
400 .arch_os_abi = target_arch_os_abi,777 .arch_os_abi = target_arch_os_abi,
...@@ -429,17 +806,67 @@ fn buildOutputType(...@@ -429,17 +806,67 @@ fn buildOutputType(
429 else => |e| return e,806 else => |e| return e,
430 };807 };
431808
432 var target_info = try std.zig.system.NativeTargetInfo.detect(gpa, cross_target);809 const target_info = try std.zig.system.NativeTargetInfo.detect(gpa, cross_target);
433 if (target_info.cpu_detection_unimplemented) {810 if (target_info.cpu_detection_unimplemented) {
434 // TODO We want to just use detected_info.target but implementing811 // TODO We want to just use detected_info.target but implementing
435 // CPU model & feature detection is todo so here we rely on LLVM.812 // CPU model & feature detection is todo so here we rely on LLVM.
436 std.debug.print("CPU features detection is not yet available for this system without LLVM extensions\n", .{});813 fatal("CPU features detection is not yet available for this system without LLVM extensions", .{});
437 process.exit(1);814 }
815
816 if (target_info.target.os.tag != .freestanding) {
817 if (ensure_libc_on_non_freestanding)
818 have_libc = true;
819 if (ensure_libcpp_on_non_freestanding)
820 have_libcpp = true;
821 }
822
823 // Now that we have target info, we can find out if any of the system libraries
824 // are part of libc or libc++. We remove them from the list and communicate their
825 // existence via flags instead.
826 {
827 var i: usize = 0;
828 while (i < system_libs.items.len) {
829 const lib_name = system_libs.items[i];
830 if (is_libc_lib_name(target_info.target, lib_name)) {
831 have_libc = true;
832 _ = system_libs.orderedRemove(i);
833 continue;
834 }
835 if (is_libcpp_lib_name(target_info.target, lib_name)) {
836 have_libcpp = true;
837 _ = system_libs.orderedRemove(i);
838 continue;
839 }
840 i += 1;
841 }
842 }
843
844 if (cross_target.isNativeOs() and (system_libs.items.len != 0 or want_native_include_dirs)) {
845 const paths = std.zig.system.NativePaths.detect(arena) catch |err| {
846 fatal("unable to detect native system paths: {}", .{@errorName(err)});
847 };
848 for (paths.warnings.items) |warning| {
849 warn("{}", .{warning});
850 }
851 try clang_argv.ensureCapacity(clang_argv.items.len + paths.include_dirs.items.len * 2);
852 for (paths.include_dirs.items) |include_dir| {
853 clang_argv.appendAssumeCapacity("-isystem");
854 clang_argv.appendAssumeCapacity(include_dir);
855 }
856 for (paths.lib_dirs.items) |lib_dir| {
857 try lib_dirs.append(lib_dir);
858 }
859 for (paths.rpaths.items) |rpath| {
860 try rpath_list.append(rpath);
861 }
862 }
863
864 if (system_libs.items.len != 0) {
865 fatal("linking against system libraries not yet supported", .{});
438 }866 }
439867
440 const src_path = root_src_file orelse {868 const src_path = root_src_file orelse {
441 std.debug.print("expected at least one file argument", .{});869 fatal("expected at least one file argument", .{});
442 process.exit(1);
443 };870 };
444871
445 const object_format: ?std.Target.ObjectFormat = blk: {872 const object_format: ?std.Target.ObjectFormat = blk: {
...@@ -461,15 +888,13 @@ fn buildOutputType(...@@ -461,15 +888,13 @@ fn buildOutputType(
461 } else if (mem.eql(u8, ofmt, "raw")) {888 } else if (mem.eql(u8, ofmt, "raw")) {
462 break :blk .raw;889 break :blk .raw;
463 } else {890 } else {
464 std.debug.print("unsupported object format: {}", .{ofmt});891 fatal("unsupported object format: {}", .{ofmt});
465 process.exit(1);
466 }892 }
467 };893 };
468894
469 const bin_path = switch (emit_bin) {895 const bin_path = switch (emit_bin) {
470 .no => {896 .no => {
471 std.debug.print("-fno-emit-bin not supported yet", .{});897 fatal("-fno-emit-bin not supported yet", .{});
472 process.exit(1);
473 },898 },
474 .yes_default_path => if (object_format != null and object_format.? == .c)899 .yes_default_path => if (object_format != null and object_format.? == .c)
475 try std.fmt.allocPrint(arena, "{}.c", .{root_name})900 try std.fmt.allocPrint(arena, "{}.c", .{root_name})
...@@ -515,6 +940,11 @@ fn buildOutputType(...@@ -515,6 +940,11 @@ fn buildOutputType(
515940
516 try updateModule(gpa, &module, zir_out_path);941 try updateModule(gpa, &module, zir_out_path);
517942
943 if (build_options.have_llvm and only_pp_or_asm) {
944 // this may include dumping the output to stdout
945 fatal("TODO: implement `zig cc` when using it as a preprocessor", .{});
946 }
947
518 while (watch) {948 while (watch) {
519 try stderr.print("🦎 ", .{});949 try stderr.print("🦎 ", .{});
520 if (output_mode == .Exe) {950 if (output_mode == .Exe) {
...@@ -562,7 +992,7 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo...@@ -562,7 +992,7 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo
562 });992 });
563 }993 }
564 } else {994 } else {
565 std.log.scoped(.compiler).info("Update completed in {} ms\n", .{update_nanos / std.time.ns_per_ms});995 info("Update completed in {} ms", .{update_nanos / std.time.ns_per_ms});
566 }996 }
567997
568 if (zir_out_path) |zop| {998 if (zir_out_path) |zop| {
...@@ -631,8 +1061,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -631,8 +1061,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
631 process.exit(0);1061 process.exit(0);
632 } else if (mem.eql(u8, arg, "--color")) {1062 } else if (mem.eql(u8, arg, "--color")) {
633 if (i + 1 >= args.len) {1063 if (i + 1 >= args.len) {
634 std.debug.print("expected [auto|on|off] after --color\n", .{});1064 fatal("expected [auto|on|off] after --color", .{});
635 process.exit(1);
636 }1065 }
637 i += 1;1066 i += 1;
638 const next_arg = args[i];1067 const next_arg = args[i];
...@@ -643,16 +1072,14 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -643,16 +1072,14 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
643 } else if (mem.eql(u8, next_arg, "off")) {1072 } else if (mem.eql(u8, next_arg, "off")) {
644 color = .Off;1073 color = .Off;
645 } else {1074 } else {
646 std.debug.print("expected [auto|on|off] after --color, found '{}'\n", .{next_arg});1075 fatal("expected [auto|on|off] after --color, found '{}'", .{next_arg});
647 process.exit(1);
648 }1076 }
649 } else if (mem.eql(u8, arg, "--stdin")) {1077 } else if (mem.eql(u8, arg, "--stdin")) {
650 stdin_flag = true;1078 stdin_flag = true;
651 } else if (mem.eql(u8, arg, "--check")) {1079 } else if (mem.eql(u8, arg, "--check")) {
652 check_flag = true;1080 check_flag = true;
653 } else {1081 } else {
654 std.debug.print("unrecognized parameter: '{}'", .{arg});1082 fatal("unrecognized parameter: '{}'", .{arg});
655 process.exit(1);
656 }1083 }
657 } else {1084 } else {
658 try input_files.append(arg);1085 try input_files.append(arg);
...@@ -662,8 +1089,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -662,8 +1089,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
6621089
663 if (stdin_flag) {1090 if (stdin_flag) {
664 if (input_files.items.len != 0) {1091 if (input_files.items.len != 0) {
665 std.debug.print("cannot use --stdin with positional arguments\n", .{});1092 fatal("cannot use --stdin with positional arguments", .{});
666 process.exit(1);
667 }1093 }
6681094
669 const stdin = io.getStdIn().inStream();1095 const stdin = io.getStdIn().inStream();
...@@ -672,8 +1098,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -672,8 +1098,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
672 defer gpa.free(source_code);1098 defer gpa.free(source_code);
6731099
674 const tree = std.zig.parse(gpa, source_code) catch |err| {1100 const tree = std.zig.parse(gpa, source_code) catch |err| {
675 std.debug.print("error parsing stdin: {}\n", .{err});1101 fatal("error parsing stdin: {}", .{err});
676 process.exit(1);
677 };1102 };
678 defer tree.deinit();1103 defer tree.deinit();
6791104
...@@ -695,8 +1120,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -695,8 +1120,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
695 }1120 }
6961121
697 if (input_files.items.len == 0) {1122 if (input_files.items.len == 0) {
698 std.debug.print("expected at least one source file argument\n", .{});1123 fatal("expected at least one source file argument", .{});
699 process.exit(1);
700 }1124 }
7011125
702 var fmt = Fmt{1126 var fmt = Fmt{
...@@ -712,8 +1136,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {...@@ -712,8 +1136,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
712 for (input_files.span()) |file_path| {1136 for (input_files.span()) |file_path| {
713 // Get the real path here to avoid Windows failing on relative file paths with . or .. in them.1137 // Get the real path here to avoid Windows failing on relative file paths with . or .. in them.
714 const real_path = fs.realpathAlloc(gpa, file_path) catch |err| {1138 const real_path = fs.realpathAlloc(gpa, file_path) catch |err| {
715 std.debug.print("unable to open '{}': {}\n", .{ file_path, err });1139 fatal("unable to open '{}': {}", .{ file_path, err });
716 process.exit(1);
717 };1140 };
718 defer gpa.free(real_path);1141 defer gpa.free(real_path);
7191142
...@@ -752,7 +1175,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_...@@ -752,7 +1175,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_
752 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {1175 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
753 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),1176 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
754 else => {1177 else => {
755 std.debug.print("unable to format '{}': {}\n", .{ file_path, err });1178 warn("unable to format '{}': {}", .{ file_path, err });
756 fmt.any_error = true;1179 fmt.any_error = true;
757 return;1180 return;
758 },1181 },
...@@ -783,7 +1206,7 @@ fn fmtPathDir(...@@ -783,7 +1206,7 @@ fn fmtPathDir(
783 try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);1206 try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
784 } else {1207 } else {
785 fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {1208 fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
786 std.debug.print("unable to format '{}': {}\n", .{ full_path, err });1209 warn("unable to format '{}': {}", .{ full_path, err });
787 fmt.any_error = true;1210 fmt.any_error = true;
788 return;1211 return;
789 };1212 };
...@@ -841,6 +1264,7 @@ fn fmtPathFile(...@@ -841,6 +1264,7 @@ fn fmtPathFile(
841 if (check_mode) {1264 if (check_mode) {
842 const anything_changed = try std.zig.render(fmt.gpa, io.null_out_stream, tree);1265 const anything_changed = try std.zig.render(fmt.gpa, io.null_out_stream, tree);
843 if (anything_changed) {1266 if (anything_changed) {
1267 // TODO this should output to stdout instead of stderr.
844 std.debug.print("{}\n", .{file_path});1268 std.debug.print("{}\n", .{file_path});
845 fmt.any_error = true;1269 fmt.any_error = true;
846 }1270 }
...@@ -858,6 +1282,7 @@ fn fmtPathFile(...@@ -858,6 +1282,7 @@ fn fmtPathFile(
8581282
859 try af.file.writeAll(fmt.out_buffer.items);1283 try af.file.writeAll(fmt.out_buffer.items);
860 try af.finish();1284 try af.finish();
1285 // TODO this should output to stdout instead of stderr.
861 std.debug.print("{}\n", .{file_path});1286 std.debug.print("{}\n", .{file_path});
862 }1287 }
863}1288}
...@@ -925,3 +1350,350 @@ pub const info_zen =...@@ -925,3 +1350,350 @@ pub const info_zen =
925 \\1350 \\
926 \\1351 \\
927;1352;
1353
1354const FileExt = enum {
1355 c,
1356 cpp,
1357 h,
1358 ll,
1359 bc,
1360 assembly,
1361 unknown,
1362};
1363
1364fn hasCExt(filename: []const u8) bool {
1365 return mem.endsWith(u8, filename, ".c");
1366}
1367
1368fn hasCppExt(filename: []const u8) bool {
1369 return mem.endsWith(u8, filename, ".C") or
1370 mem.endsWith(u8, filename, ".cc") or
1371 mem.endsWith(u8, filename, ".cpp") or
1372 mem.endsWith(u8, filename, ".cxx");
1373}
1374
1375fn hasAsmExt(filename: []const u8) bool {
1376 return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
1377}
1378
1379fn classify_file_ext(filename: []const u8) FileExt {
1380 if (hasCExt(filename)) {
1381 return .c;
1382 } else if (hasCppExt(filename)) {
1383 return .cpp;
1384 } else if (mem.endsWith(u8, filename, ".ll")) {
1385 return .ll;
1386 } else if (mem.endsWith(u8, filename, ".bc")) {
1387 return .bc;
1388 } else if (hasAsmExt(filename)) {
1389 return .assembly;
1390 } else if (mem.endsWith(u8, filename, ".h")) {
1391 return .h;
1392 } else {
1393 // TODO look for .so, .so.X, .so.X.Y, .so.X.Y.Z
1394 return .unknown;
1395 }
1396}
1397
1398extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
1399
1400/// TODO make it so the return value can be !noreturn
1401fn punt_to_clang(arena: *Allocator, args: []const []const u8) error{OutOfMemory} {
1402 // Convert the args to the format Clang expects.
1403 const argv = try arena.alloc(?[*:0]u8, args.len + 1);
1404 for (args) |arg, i| {
1405 argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
1406 }
1407 argv[args.len] = null;
1408 const exit_code = ZigClang_main(@intCast(c_int, args.len), argv[0..args.len :null].ptr);
1409 process.exit(@bitCast(u8, @truncate(i8, exit_code)));
1410}
1411
1412const clang_args = @import("clang_options.zig").list;
1413
1414pub const ClangArgIterator = struct {
1415 has_next: bool,
1416 zig_equivalent: ZigEquivalent,
1417 only_arg: []const u8,
1418 second_arg: []const u8,
1419 other_args: []const []const u8,
1420 argv: []const []const u8,
1421 next_index: usize,
1422 root_args: ?*Args,
1423 allocator: *Allocator,
1424
1425 pub const ZigEquivalent = enum {
1426 target,
1427 o,
1428 c,
1429 other,
1430 positional,
1431 l,
1432 ignore,
1433 driver_punt,
1434 pic,
1435 no_pic,
1436 nostdlib,
1437 nostdlib_cpp,
1438 shared,
1439 rdynamic,
1440 wl,
1441 pp_or_asm,
1442 optimize,
1443 debug,
1444 sanitize,
1445 linker_script,
1446 verbose_cmds,
1447 for_linker,
1448 linker_input_z,
1449 lib_dir,
1450 mcpu,
1451 dep_file,
1452 framework_dir,
1453 framework,
1454 nostdlibinc,
1455 };
1456
1457 const Args = struct {
1458 next_index: usize,
1459 argv: []const []const u8,
1460 };
1461
1462 fn init(allocator: *Allocator, argv: []const []const u8) ClangArgIterator {
1463 return .{
1464 .next_index = 2, // `zig cc foo` this points to `foo`
1465 .has_next = argv.len > 2,
1466 .zig_equivalent = undefined,
1467 .only_arg = undefined,
1468 .second_arg = undefined,
1469 .other_args = undefined,
1470 .argv = argv,
1471 .root_args = null,
1472 .allocator = allocator,
1473 };
1474 }
1475
1476 fn next(self: *ClangArgIterator) !void {
1477 assert(self.has_next);
1478 assert(self.next_index < self.argv.len);
1479 // In this state we know that the parameter we are looking at is a root parameter
1480 // rather than an argument to a parameter.
1481 // We adjust the len below when necessary.
1482 self.other_args = (self.argv.ptr + self.next_index)[0..1];
1483 var arg = mem.span(self.argv[self.next_index]);
1484 self.incrementArgIndex();
1485
1486 if (mem.startsWith(u8, arg, "@")) {
1487 if (self.root_args != null) return error.NestedResponseFile;
1488
1489 // This is a "compiler response file". We must parse the file and treat its
1490 // contents as command line parameters.
1491 const allocator = self.allocator;
1492 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
1493 const resp_file_path = arg[1..];
1494 const resp_contents = fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes) catch |err| {
1495 fatal("unable to read response file '{}': {}", .{ resp_file_path, @errorName(err) });
1496 };
1497 defer allocator.free(resp_contents);
1498 // TODO is there a specification for this file format? Let's find it and make this parsing more robust
1499 // at the very least I'm guessing this needs to handle quotes and `#` comments.
1500 var it = mem.tokenize(resp_contents, " \t\r\n");
1501 var resp_arg_list = std.ArrayList([]const u8).init(allocator);
1502 defer resp_arg_list.deinit();
1503 {
1504 errdefer {
1505 for (resp_arg_list.span()) |item| {
1506 allocator.free(mem.span(item));
1507 }
1508 }
1509 while (it.next()) |token| {
1510 const dupe_token = try mem.dupeZ(allocator, u8, token);
1511 errdefer allocator.free(dupe_token);
1512 try resp_arg_list.append(dupe_token);
1513 }
1514 const args = try allocator.create(Args);
1515 errdefer allocator.destroy(args);
1516 args.* = .{
1517 .next_index = self.next_index,
1518 .argv = self.argv,
1519 };
1520 self.root_args = args;
1521 }
1522 const resp_arg_slice = resp_arg_list.toOwnedSlice();
1523 self.next_index = 0;
1524 self.argv = resp_arg_slice;
1525
1526 if (resp_arg_slice.len == 0) {
1527 self.resolveRespFileArgs();
1528 return;
1529 }
1530
1531 self.has_next = true;
1532 self.other_args = (self.argv.ptr + self.next_index)[0..1]; // We adjust len below when necessary.
1533 arg = mem.span(self.argv[self.next_index]);
1534 self.incrementArgIndex();
1535 }
1536 if (!mem.startsWith(u8, arg, "-")) {
1537 self.zig_equivalent = .positional;
1538 self.only_arg = arg;
1539 return;
1540 }
1541
1542 find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) {
1543 .flag => {
1544 const prefix_len = clang_arg.matchEql(arg);
1545 if (prefix_len > 0) {
1546 self.zig_equivalent = clang_arg.zig_equivalent;
1547 self.only_arg = arg[prefix_len..];
1548
1549 break :find_clang_arg;
1550 }
1551 },
1552 .joined, .comma_joined => {
1553 // joined example: --target=foo
1554 // comma_joined example: -Wl,-soname,libsoundio.so.2
1555 const prefix_len = clang_arg.matchStartsWith(arg);
1556 if (prefix_len != 0) {
1557 self.zig_equivalent = clang_arg.zig_equivalent;
1558 self.only_arg = arg[prefix_len..]; // This will skip over the "--target=" part.
1559
1560 break :find_clang_arg;
1561 }
1562 },
1563 .joined_or_separate => {
1564 // Examples: `-lfoo`, `-l foo`
1565 const prefix_len = clang_arg.matchStartsWith(arg);
1566 if (prefix_len == arg.len) {
1567 if (self.next_index >= self.argv.len) {
1568 fatal("Expected parameter after '{}'", .{arg});
1569 }
1570 self.only_arg = self.argv[self.next_index];
1571 self.incrementArgIndex();
1572 self.other_args.len += 1;
1573 self.zig_equivalent = clang_arg.zig_equivalent;
1574
1575 break :find_clang_arg;
1576 } else if (prefix_len != 0) {
1577 self.zig_equivalent = clang_arg.zig_equivalent;
1578 self.only_arg = arg[prefix_len..];
1579
1580 break :find_clang_arg;
1581 }
1582 },
1583 .joined_and_separate => {
1584 // Example: `-Xopenmp-target=riscv64-linux-unknown foo`
1585 const prefix_len = clang_arg.matchStartsWith(arg);
1586 if (prefix_len != 0) {
1587 self.only_arg = arg[prefix_len..];
1588 if (self.next_index >= self.argv.len) {
1589 fatal("Expected parameter after '{}'", .{arg});
1590 }
1591 self.second_arg = self.argv[self.next_index];
1592 self.incrementArgIndex();
1593 self.other_args.len += 1;
1594 self.zig_equivalent = clang_arg.zig_equivalent;
1595 break :find_clang_arg;
1596 }
1597 },
1598 .separate => if (clang_arg.matchEql(arg) > 0) {
1599 if (self.next_index >= self.argv.len) {
1600 fatal("Expected parameter after '{}'", .{arg});
1601 }
1602 self.only_arg = self.argv[self.next_index];
1603 self.incrementArgIndex();
1604 self.other_args.len += 1;
1605 self.zig_equivalent = clang_arg.zig_equivalent;
1606 break :find_clang_arg;
1607 },
1608 .remaining_args_joined => {
1609 const prefix_len = clang_arg.matchStartsWith(arg);
1610 if (prefix_len != 0) {
1611 @panic("TODO");
1612 }
1613 },
1614 .multi_arg => if (clang_arg.matchEql(arg) > 0) {
1615 @panic("TODO");
1616 },
1617 }
1618 else {
1619 fatal("Unknown Clang option: '{}'", .{arg});
1620 }
1621 }
1622
1623 fn incrementArgIndex(self: *ClangArgIterator) void {
1624 self.next_index += 1;
1625 self.resolveRespFileArgs();
1626 }
1627
1628 fn resolveRespFileArgs(self: *ClangArgIterator) void {
1629 const allocator = self.allocator;
1630 if (self.next_index >= self.argv.len) {
1631 if (self.root_args) |root_args| {
1632 self.next_index = root_args.next_index;
1633 self.argv = root_args.argv;
1634
1635 allocator.destroy(root_args);
1636 self.root_args = null;
1637 }
1638 if (self.next_index >= self.argv.len) {
1639 self.has_next = false;
1640 }
1641 }
1642 }
1643};
1644
1645fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
1646 if (ignore_case) {
1647 return std.ascii.eqlIgnoreCase(a, b);
1648 } else {
1649 return mem.eql(u8, a, b);
1650 }
1651}
1652
1653fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
1654 const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
1655
1656 if (eqlIgnoreCase(ignore_case, name, "c"))
1657 return true;
1658
1659 if (target.isMinGW()) {
1660 if (eqlIgnoreCase(ignore_case, name, "m"))
1661 return true;
1662
1663 return false;
1664 }
1665
1666 if (target.abi.isGnu() or target.abi.isMusl() or target.os.tag.isDarwin()) {
1667 if (eqlIgnoreCase(ignore_case, name, "m"))
1668 return true;
1669 if (eqlIgnoreCase(ignore_case, name, "rt"))
1670 return true;
1671 if (eqlIgnoreCase(ignore_case, name, "pthread"))
1672 return true;
1673 if (eqlIgnoreCase(ignore_case, name, "crypt"))
1674 return true;
1675 if (eqlIgnoreCase(ignore_case, name, "util"))
1676 return true;
1677 if (eqlIgnoreCase(ignore_case, name, "xnet"))
1678 return true;
1679 if (eqlIgnoreCase(ignore_case, name, "resolv"))
1680 return true;
1681 if (eqlIgnoreCase(ignore_case, name, "dl"))
1682 return true;
1683 if (eqlIgnoreCase(ignore_case, name, "util"))
1684 return true;
1685 }
1686
1687 if (target.os.tag.isDarwin() and eqlIgnoreCase(ignore_case, name, "System"))
1688 return true;
1689
1690 return false;
1691}
1692
1693fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool {
1694 const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
1695
1696 return eqlIgnoreCase(ignore_case, name, "c++") or
1697 eqlIgnoreCase(ignore_case, name, "stdc++") or
1698 eqlIgnoreCase(ignore_case, name, "c++abi");
1699}
src-self-hosted/stage2.zig+17-263
...@@ -414,6 +414,23 @@ export fn stage2_env(argc: c_int, argv: [*]const [*:0]const u8) c_int {...@@ -414,6 +414,23 @@ export fn stage2_env(argc: c_int, argv: [*]const [*:0]const u8) c_int {
414 return 0;414 return 0;
415}415}
416416
417export fn stage2_cc(argc: c_int, argv: [*]const [*:0]const u8, is_cpp: bool) c_int {
418 const allocator = std.heap.c_allocator;
419
420 var args_list = argvToArrayList(allocator, argc, argv) catch |err| {
421 std.debug.print("unable to parse arguments: {}\n", .{@errorName(err)});
422 return -1;
423 };
424 defer args_list.deinit();
425
426 self_hosted_main.buildOutputType(allocator, allocator, args_list.items, if (is_cpp) .cpp else .cc) catch |err| {
427 std.debug.print("zig cc failure: {}\n", .{@errorName(err)});
428 return -1;
429 };
430
431 return 0;
432}
433
417// ABI warning434// ABI warning
418export fn stage2_cmd_targets(435export fn stage2_cmd_targets(
419 zig_triple: ?[*:0]const u8,436 zig_triple: ?[*:0]const u8,
...@@ -1038,267 +1055,4 @@ fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void {...@@ -1038,267 +1055,4 @@ fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void {
1038 ptr.* = new_slice.ptr;1055 ptr.* = new_slice.ptr;
1039}1056}
10401057
1041const clang_args = @import("clang_options.zig").list;
1042
1043// ABI warning
1044pub const ClangArgIterator = extern struct {
1045 has_next: bool,
1046 zig_equivalent: ZigEquivalent,
1047 only_arg: [*:0]const u8,
1048 second_arg: [*:0]const u8,
1049 other_args_ptr: [*]const [*:0]const u8,
1050 other_args_len: usize,
1051 argv_ptr: [*]const [*:0]const u8,
1052 argv_len: usize,
1053 next_index: usize,
1054 root_args: ?*Args,
1055
1056 // ABI warning
1057 pub const ZigEquivalent = extern enum {
1058 target,
1059 o,
1060 c,
1061 other,
1062 positional,
1063 l,
1064 ignore,
1065 driver_punt,
1066 pic,
1067 no_pic,
1068 nostdlib,
1069 nostdlib_cpp,
1070 shared,
1071 rdynamic,
1072 wl,
1073 pp_or_asm,
1074 optimize,
1075 debug,
1076 sanitize,
1077 linker_script,
1078 verbose_cmds,
1079 for_linker,
1080 linker_input_z,
1081 lib_dir,
1082 mcpu,
1083 dep_file,
1084 framework_dir,
1085 framework,
1086 nostdlibinc,
1087 };
1088
1089 const Args = struct {
1090 next_index: usize,
1091 argv_ptr: [*]const [*:0]const u8,
1092 argv_len: usize,
1093 };
1094
1095 pub fn init(argv: []const [*:0]const u8) ClangArgIterator {
1096 return .{
1097 .next_index = 2, // `zig cc foo` this points to `foo`
1098 .has_next = argv.len > 2,
1099 .zig_equivalent = undefined,
1100 .only_arg = undefined,
1101 .second_arg = undefined,
1102 .other_args_ptr = undefined,
1103 .other_args_len = undefined,
1104 .argv_ptr = argv.ptr,
1105 .argv_len = argv.len,
1106 .root_args = null,
1107 };
1108 }
1109
1110 pub fn next(self: *ClangArgIterator) !void {
1111 assert(self.has_next);
1112 assert(self.next_index < self.argv_len);
1113 // In this state we know that the parameter we are looking at is a root parameter
1114 // rather than an argument to a parameter.
1115 self.other_args_ptr = self.argv_ptr + self.next_index;
1116 self.other_args_len = 1; // We adjust this value below when necessary.
1117 var arg = mem.span(self.argv_ptr[self.next_index]);
1118 self.incrementArgIndex();
1119
1120 if (mem.startsWith(u8, arg, "@")) {
1121 if (self.root_args != null) return error.NestedResponseFile;
1122
1123 // This is a "compiler response file". We must parse the file and treat its
1124 // contents as command line parameters.
1125 const allocator = std.heap.c_allocator;
1126 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
1127 const resp_file_path = arg[1..];
1128 const resp_contents = fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes) catch |err| {
1129 std.debug.warn("unable to read response file '{}': {}\n", .{ resp_file_path, @errorName(err) });
1130 process.exit(1);
1131 };
1132 defer allocator.free(resp_contents);
1133 // TODO is there a specification for this file format? Let's find it and make this parsing more robust
1134 // at the very least I'm guessing this needs to handle quotes and `#` comments.
1135 var it = mem.tokenize(resp_contents, " \t\r\n");
1136 var resp_arg_list = std.ArrayList([*:0]const u8).init(allocator);
1137 defer resp_arg_list.deinit();
1138 {
1139 errdefer {
1140 for (resp_arg_list.span()) |item| {
1141 allocator.free(mem.span(item));
1142 }
1143 }
1144 while (it.next()) |token| {
1145 const dupe_token = try mem.dupeZ(allocator, u8, token);
1146 errdefer allocator.free(dupe_token);
1147 try resp_arg_list.append(dupe_token);
1148 }
1149 const args = try allocator.create(Args);
1150 errdefer allocator.destroy(args);
1151 args.* = .{
1152 .next_index = self.next_index,
1153 .argv_ptr = self.argv_ptr,
1154 .argv_len = self.argv_len,
1155 };
1156 self.root_args = args;
1157 }
1158 const resp_arg_slice = resp_arg_list.toOwnedSlice();
1159 self.next_index = 0;
1160 self.argv_ptr = resp_arg_slice.ptr;
1161 self.argv_len = resp_arg_slice.len;
1162
1163 if (resp_arg_slice.len == 0) {
1164 self.resolveRespFileArgs();
1165 return;
1166 }
1167
1168 self.has_next = true;
1169 self.other_args_ptr = self.argv_ptr + self.next_index;
1170 self.other_args_len = 1; // We adjust this value below when necessary.
1171 arg = mem.span(self.argv_ptr[self.next_index]);
1172 self.incrementArgIndex();
1173 }
1174 if (!mem.startsWith(u8, arg, "-")) {
1175 self.zig_equivalent = .positional;
1176 self.only_arg = arg.ptr;
1177 return;
1178 }
1179
1180 find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) {
1181 .flag => {
1182 const prefix_len = clang_arg.matchEql(arg);
1183 if (prefix_len > 0) {
1184 self.zig_equivalent = clang_arg.zig_equivalent;
1185 self.only_arg = arg.ptr + prefix_len;
1186
1187 break :find_clang_arg;
1188 }
1189 },
1190 .joined, .comma_joined => {
1191 // joined example: --target=foo
1192 // comma_joined example: -Wl,-soname,libsoundio.so.2
1193 const prefix_len = clang_arg.matchStartsWith(arg);
1194 if (prefix_len != 0) {
1195 self.zig_equivalent = clang_arg.zig_equivalent;
1196 self.only_arg = arg.ptr + prefix_len; // This will skip over the "--target=" part.
1197
1198 break :find_clang_arg;
1199 }
1200 },
1201 .joined_or_separate => {
1202 // Examples: `-lfoo`, `-l foo`
1203 const prefix_len = clang_arg.matchStartsWith(arg);
1204 if (prefix_len == arg.len) {
1205 if (self.next_index >= self.argv_len) {
1206 std.debug.warn("Expected parameter after '{}'\n", .{arg});
1207 process.exit(1);
1208 }
1209 self.only_arg = self.argv_ptr[self.next_index];
1210 self.incrementArgIndex();
1211 self.other_args_len += 1;
1212 self.zig_equivalent = clang_arg.zig_equivalent;
1213
1214 break :find_clang_arg;
1215 } else if (prefix_len != 0) {
1216 self.zig_equivalent = clang_arg.zig_equivalent;
1217 self.only_arg = arg.ptr + prefix_len;
1218
1219 break :find_clang_arg;
1220 }
1221 },
1222 .joined_and_separate => {
1223 // Example: `-Xopenmp-target=riscv64-linux-unknown foo`
1224 const prefix_len = clang_arg.matchStartsWith(arg);
1225 if (prefix_len != 0) {
1226 self.only_arg = arg.ptr + prefix_len;
1227 if (self.next_index >= self.argv_len) {
1228 std.debug.warn("Expected parameter after '{}'\n", .{arg});
1229 process.exit(1);
1230 }
1231 self.second_arg = self.argv_ptr[self.next_index];
1232 self.incrementArgIndex();
1233 self.other_args_len += 1;
1234 self.zig_equivalent = clang_arg.zig_equivalent;
1235 break :find_clang_arg;
1236 }
1237 },
1238 .separate => if (clang_arg.matchEql(arg) > 0) {
1239 if (self.next_index >= self.argv_len) {
1240 std.debug.warn("Expected parameter after '{}'\n", .{arg});
1241 process.exit(1);
1242 }
1243 self.only_arg = self.argv_ptr[self.next_index];
1244 self.incrementArgIndex();
1245 self.other_args_len += 1;
1246 self.zig_equivalent = clang_arg.zig_equivalent;
1247 break :find_clang_arg;
1248 },
1249 .remaining_args_joined => {
1250 const prefix_len = clang_arg.matchStartsWith(arg);
1251 if (prefix_len != 0) {
1252 @panic("TODO");
1253 }
1254 },
1255 .multi_arg => if (clang_arg.matchEql(arg) > 0) {
1256 @panic("TODO");
1257 },
1258 }
1259 else {
1260 std.debug.warn("Unknown Clang option: '{}'\n", .{arg});
1261 process.exit(1);
1262 }
1263 }
1264
1265 fn incrementArgIndex(self: *ClangArgIterator) void {
1266 self.next_index += 1;
1267 self.resolveRespFileArgs();
1268 }
1269
1270 fn resolveRespFileArgs(self: *ClangArgIterator) void {
1271 const allocator = std.heap.c_allocator;
1272 if (self.next_index >= self.argv_len) {
1273 if (self.root_args) |root_args| {
1274 self.next_index = root_args.next_index;
1275 self.argv_ptr = root_args.argv_ptr;
1276 self.argv_len = root_args.argv_len;
1277
1278 allocator.destroy(root_args);
1279 self.root_args = null;
1280 }
1281 if (self.next_index >= self.argv_len) {
1282 self.has_next = false;
1283 }
1284 }
1285 }
1286};
1287
1288export fn stage2_clang_arg_iterator(
1289 result: *ClangArgIterator,
1290 argc: usize,
1291 argv: [*]const [*:0]const u8,
1292) void {
1293 result.* = ClangArgIterator.init(argv[0..argc]);
1294}
1295
1296export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {
1297 it.next() catch |err| switch (err) {
1298 error.NestedResponseFile => return .NestedResponseFile,
1299 error.OutOfMemory => return .OutOfMemory,
1300 };
1301 return .None;
1302}
1303
1304export const stage2_is_zig0 = false;1058export const stage2_is_zig0 = false;
src/config.zig.in+2
...@@ -1,3 +1,5 @@...@@ -1,3 +1,5 @@
1pub const have_llvm = true;
1pub const version: []const u8 = "@ZIG_VERSION@";2pub const version: []const u8 = "@ZIG_VERSION@";
2pub const log_scopes: []const []const u8 = &[_][]const u8{};3pub const log_scopes: []const []const u8 = &[_][]const u8{};
4pub const zir_dumps: []const []const u8 = &[_][]const u8{};
3pub const enable_tracy = false;5pub const enable_tracy = false;
src/main.cpp+5-407
...@@ -404,7 +404,6 @@ static int main0(int argc, char **argv) {...@@ -404,7 +404,6 @@ static int main0(int argc, char **argv) {
404 ZigList<const char *> framework_dirs = {0};404 ZigList<const char *> framework_dirs = {0};
405 ZigList<const char *> frameworks = {0};405 ZigList<const char *> frameworks = {0};
406 bool have_libc = false;406 bool have_libc = false;
407 bool have_libcpp = false;
408 const char *target_string = nullptr;407 const char *target_string = nullptr;
409 bool rdynamic = false;408 bool rdynamic = false;
410 const char *linker_script = nullptr;409 const char *linker_script = nullptr;
...@@ -446,18 +445,8 @@ static int main0(int argc, char **argv) {...@@ -446,18 +445,8 @@ static int main0(int argc, char **argv) {
446 bool function_sections = false;445 bool function_sections = false;
447 const char *mcpu = nullptr;446 const char *mcpu = nullptr;
448 CodeModel code_model = CodeModelDefault;447 CodeModel code_model = CodeModelDefault;
449 const char *override_soname = nullptr;
450 bool only_pp_or_asm = false;
451 bool ensure_libc_on_non_freestanding = false;
452 bool ensure_libcpp_on_non_freestanding = false;
453 bool disable_c_depfile = false;
454 bool want_native_include_dirs = false;448 bool want_native_include_dirs = false;
455 Buf *linker_optimization = nullptr;
456 OptionalBool linker_gc_sections = OptionalBoolNull;
457 OptionalBool linker_allow_shlib_undefined = OptionalBoolNull;
458 OptionalBool linker_bind_global_refs_locally = OptionalBoolNull;449 OptionalBool linker_bind_global_refs_locally = OptionalBoolNull;
459 bool linker_z_nodelete = false;
460 bool linker_z_defs = false;
461 size_t stack_size_override = 0;450 size_t stack_size_override = 0;
462451
463 ZigList<const char *> llvm_argv = {0};452 ZigList<const char *> llvm_argv = {0};
...@@ -585,355 +574,10 @@ static int main0(int argc, char **argv) {...@@ -585,355 +574,10 @@ static int main0(int argc, char **argv) {
585 return stage2_fmt(argc, argv);574 return stage2_fmt(argc, argv);
586 } else if (argc >= 2 && strcmp(argv[1], "env") == 0) {575 } else if (argc >= 2 && strcmp(argv[1], "env") == 0) {
587 return stage2_env(argc, argv);576 return stage2_env(argc, argv);
588 } else if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || strcmp(argv[1], "c++") == 0)) {577 } else if (argc >= 2 && strcmp(argv[1], "cc") == 0) {
589 emit_h = false;578 return stage2_cc(argc, argv, false);
590 strip = true;579 } else if (argc >= 2 && strcmp(argv[1], "c++") == 0) {
591 ensure_libc_on_non_freestanding = true;580 return stage2_cc(argc, argv, true);
592 ensure_libcpp_on_non_freestanding = (strcmp(argv[1], "c++") == 0);
593 want_native_include_dirs = true;
594
595 bool c_arg = false;
596 Stage2ClangArgIterator it;
597 stage2_clang_arg_iterator(&it, argc, argv);
598 bool is_shared_lib = false;
599 ZigList<Buf *> linker_args = {};
600 while (it.has_next) {
601 if ((err = stage2_clang_arg_next(&it))) {
602 fprintf(stderr, "unable to parse command line parameters: %s\n", err_str(err));
603 return EXIT_FAILURE;
604 }
605 switch (it.kind) {
606 case Stage2ClangArgTarget: // example: -target riscv64-linux-unknown
607 target_string = it.only_arg;
608 break;
609 case Stage2ClangArgO: // -o
610 emit_bin_override_path = it.only_arg;
611 enable_cache = CacheOptOn;
612 break;
613 case Stage2ClangArgC: // -c
614 c_arg = true;
615 break;
616 case Stage2ClangArgOther:
617 for (size_t i = 0; i < it.other_args_len; i += 1) {
618 clang_argv.append(it.other_args_ptr[i]);
619 }
620 break;
621 case Stage2ClangArgPositional: {
622 FileExt file_ext = classify_file_ext(it.only_arg, strlen(it.only_arg));
623 switch (file_ext) {
624 case FileExtAsm:
625 case FileExtC:
626 case FileExtCpp:
627 case FileExtLLVMIr:
628 case FileExtLLVMBitCode:
629 case FileExtHeader: {
630 CFile *c_file = heap::c_allocator.create<CFile>();
631 c_file->source_path = it.only_arg;
632 c_source_files.append(c_file);
633 break;
634 }
635 case FileExtUnknown:
636 objects.append(it.only_arg);
637 break;
638 }
639 break;
640 }
641 case Stage2ClangArgL: // -l
642 if (strcmp(it.only_arg, "c") == 0) {
643 have_libc = true;
644 link_libs.append("c");
645 } else if (strcmp(it.only_arg, "c++") == 0 ||
646 strcmp(it.only_arg, "stdc++") == 0)
647 {
648 have_libcpp = true;
649 link_libs.append("c++");
650 } else {
651 link_libs.append(it.only_arg);
652 }
653 break;
654 case Stage2ClangArgIgnore:
655 break;
656 case Stage2ClangArgDriverPunt:
657 // Never mind what we're doing, just pass the args directly. For example --help.
658 return ZigClang_main(argc, argv);
659 case Stage2ClangArgPIC:
660 want_pic = WantPICEnabled;
661 break;
662 case Stage2ClangArgNoPIC:
663 want_pic = WantPICDisabled;
664 break;
665 case Stage2ClangArgNoStdLib:
666 ensure_libc_on_non_freestanding = false;
667 break;
668 case Stage2ClangArgNoStdLibCpp:
669 ensure_libcpp_on_non_freestanding = false;
670 break;
671 case Stage2ClangArgShared:
672 is_dynamic = true;
673 is_shared_lib = true;
674 break;
675 case Stage2ClangArgRDynamic:
676 rdynamic = true;
677 break;
678 case Stage2ClangArgWL: {
679 const char *arg = it.only_arg;
680 for (;;) {
681 size_t pos = 0;
682 while (arg[pos] != ',' && arg[pos] != 0) pos += 1;
683 linker_args.append(buf_create_from_mem(arg, pos));
684 if (arg[pos] == 0) break;
685 arg += pos + 1;
686 }
687 break;
688 }
689 case Stage2ClangArgPreprocessOrAsm:
690 // this handles both -E and -S
691 only_pp_or_asm = true;
692 for (size_t i = 0; i < it.other_args_len; i += 1) {
693 clang_argv.append(it.other_args_ptr[i]);
694 }
695 break;
696 case Stage2ClangArgOptimize:
697 // alright what release mode do they want?
698 if (strcmp(it.only_arg, "Os") == 0) {
699 build_mode = BuildModeSmallRelease;
700 } else if (strcmp(it.only_arg, "O2") == 0 ||
701 strcmp(it.only_arg, "O3") == 0 ||
702 strcmp(it.only_arg, "O4") == 0)
703 {
704 build_mode = BuildModeFastRelease;
705 } else if (strcmp(it.only_arg, "Og") == 0 ||
706 strcmp(it.only_arg, "O0") == 0)
707 {
708 build_mode = BuildModeDebug;
709 } else {
710 for (size_t i = 0; i < it.other_args_len; i += 1) {
711 clang_argv.append(it.other_args_ptr[i]);
712 }
713 }
714 break;
715 case Stage2ClangArgDebug:
716 strip = false;
717 if (strcmp(it.only_arg, "-g") == 0) {
718 // we handled with strip = false above
719 } else {
720 for (size_t i = 0; i < it.other_args_len; i += 1) {
721 clang_argv.append(it.other_args_ptr[i]);
722 }
723 }
724 break;
725 case Stage2ClangArgSanitize:
726 if (strcmp(it.only_arg, "undefined") == 0) {
727 want_sanitize_c = WantCSanitizeEnabled;
728 } else {
729 for (size_t i = 0; i < it.other_args_len; i += 1) {
730 clang_argv.append(it.other_args_ptr[i]);
731 }
732 }
733 break;
734 case Stage2ClangArgLinkerScript:
735 linker_script = it.only_arg;
736 break;
737 case Stage2ClangArgVerboseCmds:
738 verbose_cc = true;
739 verbose_link = true;
740 break;
741 case Stage2ClangArgForLinker:
742 linker_args.append(buf_create_from_str(it.only_arg));
743 break;
744 case Stage2ClangArgLinkerInputZ:
745 linker_args.append(buf_create_from_str("-z"));
746 linker_args.append(buf_create_from_str(it.only_arg));
747 break;
748 case Stage2ClangArgLibDir:
749 lib_dirs.append(it.only_arg);
750 break;
751 case Stage2ClangArgMCpu:
752 mcpu = it.only_arg;
753 break;
754 case Stage2ClangArgDepFile:
755 disable_c_depfile = true;
756 for (size_t i = 0; i < it.other_args_len; i += 1) {
757 clang_argv.append(it.other_args_ptr[i]);
758 }
759 break;
760 case Stage2ClangArgFrameworkDir:
761 framework_dirs.append(it.only_arg);
762 break;
763 case Stage2ClangArgFramework:
764 frameworks.append(it.only_arg);
765 break;
766 case Stage2ClangArgNoStdLibInc:
767 want_native_include_dirs = false;
768 break;
769 }
770 }
771 // Parse linker args
772 for (size_t i = 0; i < linker_args.length; i += 1) {
773 Buf *arg = linker_args.at(i);
774 if (buf_eql_str(arg, "-soname")) {
775 i += 1;
776 if (i >= linker_args.length) {
777 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
778 return EXIT_FAILURE;
779 }
780 Buf *soname_buf = linker_args.at(i);
781 override_soname = buf_ptr(soname_buf);
782 // use it as --name
783 // example: libsoundio.so.2
784 size_t prefix = 0;
785 if (buf_starts_with_str(soname_buf, "lib")) {
786 prefix = 3;
787 }
788 size_t end = buf_len(soname_buf);
789 if (buf_ends_with_str(soname_buf, ".so")) {
790 end -= 3;
791 } else {
792 bool found_digit = false;
793 while (end > 0 && isdigit(buf_ptr(soname_buf)[end - 1])) {
794 found_digit = true;
795 end -= 1;
796 }
797 if (found_digit && end > 0 && buf_ptr(soname_buf)[end - 1] == '.') {
798 end -= 1;
799 } else {
800 end = buf_len(soname_buf);
801 }
802 if (buf_ends_with_str(buf_slice(soname_buf, prefix, end), ".so")) {
803 end -= 3;
804 }
805 }
806 out_name = buf_ptr(buf_slice(soname_buf, prefix, end));
807 } else if (buf_eql_str(arg, "-rpath")) {
808 i += 1;
809 if (i >= linker_args.length) {
810 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
811 return EXIT_FAILURE;
812 }
813 Buf *rpath = linker_args.at(i);
814 rpath_list.append(buf_ptr(rpath));
815 } else if (buf_eql_str(arg, "-I") ||
816 buf_eql_str(arg, "--dynamic-linker") ||
817 buf_eql_str(arg, "-dynamic-linker"))
818 {
819 i += 1;
820 if (i >= linker_args.length) {
821 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
822 return EXIT_FAILURE;
823 }
824 dynamic_linker = buf_ptr(linker_args.at(i));
825 } else if (buf_eql_str(arg, "-E") ||
826 buf_eql_str(arg, "--export-dynamic") ||
827 buf_eql_str(arg, "-export-dynamic"))
828 {
829 rdynamic = true;
830 } else if (buf_eql_str(arg, "--version-script")) {
831 i += 1;
832 if (i >= linker_args.length) {
833 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
834 return EXIT_FAILURE;
835 }
836 version_script = linker_args.at(i);
837 } else if (buf_starts_with_str(arg, "-O")) {
838 linker_optimization = arg;
839 } else if (buf_eql_str(arg, "--gc-sections")) {
840 linker_gc_sections = OptionalBoolTrue;
841 } else if (buf_eql_str(arg, "--no-gc-sections")) {
842 linker_gc_sections = OptionalBoolFalse;
843 } else if (buf_eql_str(arg, "--allow-shlib-undefined") ||
844 buf_eql_str(arg, "-allow-shlib-undefined"))
845 {
846 linker_allow_shlib_undefined = OptionalBoolTrue;
847 } else if (buf_eql_str(arg, "--no-allow-shlib-undefined") ||
848 buf_eql_str(arg, "-no-allow-shlib-undefined"))
849 {
850 linker_allow_shlib_undefined = OptionalBoolFalse;
851 } else if (buf_eql_str(arg, "-Bsymbolic")) {
852 linker_bind_global_refs_locally = OptionalBoolTrue;
853 } else if (buf_eql_str(arg, "-z")) {
854 i += 1;
855 if (i >= linker_args.length) {
856 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
857 return EXIT_FAILURE;
858 }
859 Buf *z_arg = linker_args.at(i);
860 if (buf_eql_str(z_arg, "nodelete")) {
861 linker_z_nodelete = true;
862 } else if (buf_eql_str(z_arg, "defs")) {
863 linker_z_defs = true;
864 } else {
865 fprintf(stderr, "warning: unsupported linker arg: -z %s\n", buf_ptr(z_arg));
866 }
867 } else if (buf_eql_str(arg, "--major-image-version")) {
868 i += 1;
869 if (i >= linker_args.length) {
870 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
871 return EXIT_FAILURE;
872 }
873 ver_major = atoi(buf_ptr(linker_args.at(i)));
874 } else if (buf_eql_str(arg, "--minor-image-version")) {
875 i += 1;
876 if (i >= linker_args.length) {
877 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
878 return EXIT_FAILURE;
879 }
880 ver_minor = atoi(buf_ptr(linker_args.at(i)));
881 } else if (buf_eql_str(arg, "--stack")) {
882 i += 1;
883 if (i >= linker_args.length) {
884 fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg));
885 return EXIT_FAILURE;
886 }
887 stack_size_override = atoi(buf_ptr(linker_args.at(i)));
888 } else {
889 fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg));
890 }
891 }
892
893 if (want_sanitize_c == WantCSanitizeEnabled && build_mode == BuildModeFastRelease) {
894 build_mode = BuildModeSafeRelease;
895 }
896
897 if (only_pp_or_asm) {
898 cmd = CmdBuild;
899 out_type = OutTypeObj;
900 emit_bin = false;
901 // Transfer "objects" into c_source_files
902 for (size_t i = 0; i < objects.length; i += 1) {
903 CFile *c_file = heap::c_allocator.create<CFile>();
904 c_file->source_path = objects.at(i);
905 c_source_files.append(c_file);
906 }
907 for (size_t i = 0; i < c_source_files.length; i += 1) {
908 Buf *src_path;
909 if (emit_bin_override_path != nullptr) {
910 src_path = buf_create_from_str(emit_bin_override_path);
911 } else {
912 src_path = buf_create_from_str(c_source_files.at(i)->source_path);
913 }
914 Buf basename = BUF_INIT;
915 os_path_split(src_path, nullptr, &basename);
916 c_source_files.at(i)->preprocessor_only_basename = buf_ptr(&basename);
917 }
918 } else if (!c_arg) {
919 cmd = CmdBuild;
920 if (is_shared_lib) {
921 out_type = OutTypeLib;
922 } else {
923 out_type = OutTypeExe;
924 }
925 if (emit_bin_override_path == nullptr) {
926 emit_bin_override_path = "a.out";
927 enable_cache = CacheOptOn;
928 }
929 } else {
930 cmd = CmdBuild;
931 out_type = OutTypeObj;
932 }
933 if (c_source_files.length == 0 && objects.length == 0) {
934 // For example `zig cc` and no args should print the "no input files" message.
935 return ZigClang_main(argc, argv);
936 }
937 } else for (int i = 1; i < argc; i += 1) {581 } else for (int i = 1; i < argc; i += 1) {
938 char *arg = argv[i];582 char *arg = argv[i];
939583
...@@ -1038,7 +682,6 @@ static int main0(int argc, char **argv) {...@@ -1038,7 +682,6 @@ static int main0(int argc, char **argv) {
1038 have_libc = true;682 have_libc = true;
1039 link_libs.append("c");683 link_libs.append("c");
1040 } else if (strcmp(l, "c++") == 0 || strcmp(l, "stdc++") == 0) {684 } else if (strcmp(l, "c++") == 0 || strcmp(l, "stdc++") == 0) {
1041 have_libcpp = true;
1042 link_libs.append("c++");685 link_libs.append("c++");
1043 } else {686 } else {
1044 link_libs.append(l);687 link_libs.append(l);
...@@ -1185,7 +828,6 @@ static int main0(int argc, char **argv) {...@@ -1185,7 +828,6 @@ static int main0(int argc, char **argv) {
1185 have_libc = true;828 have_libc = true;
1186 link_libs.append("c");829 link_libs.append("c");
1187 } else if (strcmp(argv[i], "c++") == 0 || strcmp(argv[i], "stdc++") == 0) {830 } else if (strcmp(argv[i], "c++") == 0 || strcmp(argv[i], "stdc++") == 0) {
1188 have_libcpp = true;
1189 link_libs.append("c++");831 link_libs.append("c++");
1190 } else {832 } else {
1191 link_libs.append(argv[i]);833 link_libs.append(argv[i]);
...@@ -1351,15 +993,6 @@ static int main0(int argc, char **argv) {...@@ -1351,15 +993,6 @@ static int main0(int argc, char **argv) {
1351 return print_error_usage(arg0);993 return print_error_usage(arg0);
1352 }994 }
1353995
1354 if (!have_libc && ensure_libc_on_non_freestanding && target.os != OsFreestanding) {
1355 have_libc = true;
1356 link_libs.append("c");
1357 }
1358 if (!have_libcpp && ensure_libcpp_on_non_freestanding && target.os != OsFreestanding) {
1359 have_libcpp = true;
1360 link_libs.append("c++");
1361 }
1362
1363 Buf zig_triple_buf = BUF_INIT;996 Buf zig_triple_buf = BUF_INIT;
1364 target_triple_zig(&zig_triple_buf, &target);997 target_triple_zig(&zig_triple_buf, &target);
1365998
...@@ -1616,20 +1249,10 @@ static int main0(int argc, char **argv) {...@@ -1616,20 +1249,10 @@ static int main0(int argc, char **argv) {
1616 g->system_linker_hack = system_linker_hack;1249 g->system_linker_hack = system_linker_hack;
1617 g->function_sections = function_sections;1250 g->function_sections = function_sections;
1618 g->code_model = code_model;1251 g->code_model = code_model;
1619 g->disable_c_depfile = disable_c_depfile;
16201252
1621 g->linker_optimization = linker_optimization;
1622 g->linker_gc_sections = linker_gc_sections;
1623 g->linker_allow_shlib_undefined = linker_allow_shlib_undefined;
1624 g->linker_bind_global_refs_locally = linker_bind_global_refs_locally;1253 g->linker_bind_global_refs_locally = linker_bind_global_refs_locally;
1625 g->linker_z_nodelete = linker_z_nodelete;
1626 g->linker_z_defs = linker_z_defs;
1627 g->stack_size_override = stack_size_override;1254 g->stack_size_override = stack_size_override;
16281255
1629 if (override_soname) {
1630 g->override_soname = buf_create_from_str(override_soname);
1631 }
1632
1633 for (size_t i = 0; i < lib_dirs.length; i += 1) {1256 for (size_t i = 0; i < lib_dirs.length; i += 1) {
1634 codegen_add_lib_dir(g, lib_dirs.at(i));1257 codegen_add_lib_dir(g, lib_dirs.at(i));
1635 }1258 }
...@@ -1713,37 +1336,12 @@ static int main0(int argc, char **argv) {...@@ -1713,37 +1336,12 @@ static int main0(int argc, char **argv) {
1713 buf_replace(g->output_dir, '/', '\\');1336 buf_replace(g->output_dir, '/', '\\');
1714#endif1337#endif
1715 Buf *dest_path = buf_create_from_str(emit_bin_override_path);1338 Buf *dest_path = buf_create_from_str(emit_bin_override_path);
1716 Buf *source_path;1339 Buf *source_path = &g->bin_file_output_path;
1717 if (only_pp_or_asm) {
1718 source_path = buf_alloc();
1719 Buf *pp_only_basename = buf_create_from_str(
1720 c_source_files.at(0)->preprocessor_only_basename);
1721 os_path_join(g->output_dir, pp_only_basename, source_path);
1722
1723 } else {
1724 source_path = &g->bin_file_output_path;
1725 }
1726 if ((err = os_update_file(source_path, dest_path))) {1340 if ((err = os_update_file(source_path, dest_path))) {
1727 fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(source_path),1341 fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(source_path),
1728 buf_ptr(dest_path), err_str(err));1342 buf_ptr(dest_path), err_str(err));
1729 return main_exit(root_progress_node, EXIT_FAILURE);1343 return main_exit(root_progress_node, EXIT_FAILURE);
1730 }1344 }
1731 } else if (only_pp_or_asm) {
1732#if defined(ZIG_OS_WINDOWS)
1733 buf_replace(g->c_artifact_dir, '/', '\\');
1734#endif
1735 // dump the preprocessed output to stdout
1736 for (size_t i = 0; i < c_source_files.length; i += 1) {
1737 Buf *source_path = buf_alloc();
1738 Buf *pp_only_basename = buf_create_from_str(
1739 c_source_files.at(i)->preprocessor_only_basename);
1740 os_path_join(g->c_artifact_dir, pp_only_basename, source_path);
1741 if ((err = os_dump_file(source_path, stdout))) {
1742 fprintf(stderr, "unable to read %s: %s\n", buf_ptr(source_path),
1743 err_str(err));
1744 return main_exit(root_progress_node, EXIT_FAILURE);
1745 }
1746 }
1747 } else if (g->enable_cache) {1345 } else if (g->enable_cache) {
1748#if defined(ZIG_OS_WINDOWS)1346#if defined(ZIG_OS_WINDOWS)
1749 buf_replace(&g->bin_file_output_path, '/', '\\');1347 buf_replace(&g->bin_file_output_path, '/', '\\');
src/stage2.cpp+5-12
...@@ -32,6 +32,11 @@ int stage2_env(int argc, char** argv) {...@@ -32,6 +32,11 @@ int stage2_env(int argc, char** argv) {
32 stage2_panic(msg, strlen(msg));32 stage2_panic(msg, strlen(msg));
33}33}
3434
35int stage2_cc(int argc, char** argv, bool is_cpp) {
36 const char *msg = "stage0 called stage2_cc";
37 stage2_panic(msg, strlen(msg));
38}
39
35void stage2_attach_segfault_handler(void) { }40void stage2_attach_segfault_handler(void) { }
3641
37void stage2_panic(const char *ptr, size_t len) {42void stage2_panic(const char *ptr, size_t len) {
...@@ -316,16 +321,4 @@ enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) {...@@ -316,16 +321,4 @@ enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) {
316 return ErrorNone;321 return ErrorNone;
317}322}
318323
319void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it,
320 size_t argc, char **argv)
321{
322 const char *msg = "stage0 called stage2_clang_arg_iterator";
323 stage2_panic(msg, strlen(msg));
324}
325
326enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it) {
327 const char *msg = "stage0 called stage2_clang_arg_next";
328 stage2_panic(msg, strlen(msg));
329}
330
331const bool stage2_is_zig0 = true;324const bool stage2_is_zig0 = true;
src/stage2.h+3-54
...@@ -144,6 +144,9 @@ ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);...@@ -144,6 +144,9 @@ ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len);
144// ABI warning144// ABI warning
145ZIG_EXTERN_C int stage2_env(int argc, char **argv);145ZIG_EXTERN_C int stage2_env(int argc, char **argv);
146146
147// ABI warning
148ZIG_EXTERN_C int stage2_cc(int argc, char **argv, bool is_cpp);
149
147// ABI warning150// ABI warning
148ZIG_EXTERN_C void stage2_attach_segfault_handler(void);151ZIG_EXTERN_C void stage2_attach_segfault_handler(void);
149152
...@@ -328,60 +331,6 @@ struct Stage2NativePaths {...@@ -328,60 +331,6 @@ struct Stage2NativePaths {
328// ABI warning331// ABI warning
329ZIG_EXTERN_C enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths);332ZIG_EXTERN_C enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths);
330333
331// ABI warning
332enum Stage2ClangArg {
333 Stage2ClangArgTarget,
334 Stage2ClangArgO,
335 Stage2ClangArgC,
336 Stage2ClangArgOther,
337 Stage2ClangArgPositional,
338 Stage2ClangArgL,
339 Stage2ClangArgIgnore,
340 Stage2ClangArgDriverPunt,
341 Stage2ClangArgPIC,
342 Stage2ClangArgNoPIC,
343 Stage2ClangArgNoStdLib,
344 Stage2ClangArgNoStdLibCpp,
345 Stage2ClangArgShared,
346 Stage2ClangArgRDynamic,
347 Stage2ClangArgWL,
348 Stage2ClangArgPreprocessOrAsm,
349 Stage2ClangArgOptimize,
350 Stage2ClangArgDebug,
351 Stage2ClangArgSanitize,
352 Stage2ClangArgLinkerScript,
353 Stage2ClangArgVerboseCmds,
354 Stage2ClangArgForLinker,
355 Stage2ClangArgLinkerInputZ,
356 Stage2ClangArgLibDir,
357 Stage2ClangArgMCpu,
358 Stage2ClangArgDepFile,
359 Stage2ClangArgFrameworkDir,
360 Stage2ClangArgFramework,
361 Stage2ClangArgNoStdLibInc,
362};
363
364// ABI warning
365struct Stage2ClangArgIterator {
366 bool has_next;
367 enum Stage2ClangArg kind;
368 const char *only_arg;
369 const char *second_arg;
370 const char **other_args_ptr;
371 size_t other_args_len;
372 const char **argv_ptr;
373 size_t argv_len;
374 size_t next_index;
375 size_t root_args;
376};
377
378// ABI warning
379ZIG_EXTERN_C void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it,
380 size_t argc, char **argv);
381
382// ABI warning
383ZIG_EXTERN_C enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it);
384
385// ABI warning334// ABI warning
386ZIG_EXTERN_C const bool stage2_is_zig0;335ZIG_EXTERN_C const bool stage2_is_zig0;
387336