| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| | 2 | const assert = std.debug.assert; |
| 2 | const io = std.io; | 3 | const io = std.io; |
| 3 | const fs = std.fs; | 4 | const fs = std.fs; |
| 4 | const mem = std.mem; | 5 | const mem = std.mem; |
| ... | @@ -11,6 +12,13 @@ const link = @import("link.zig"); | ... | @@ -11,6 +12,13 @@ const link = @import("link.zig"); |
| 11 | const Package = @import("Package.zig"); | 12 | const Package = @import("Package.zig"); |
| 12 | const zir = @import("zir.zig"); | 13 | const zir = @import("zir.zig"); |
| 13 | const build_options = @import("build_options"); | 14 | const build_options = @import("build_options"); |
| | 15 | const warn = std.log.warn; |
| | 16 | const info = std.log.info; |
| | 17 | |
| | 18 | fn fatal(comptime format: []const u8, args: anytype) noreturn { |
| | 19 | std.log.emerg(format, args); |
| | 20 | process.exit(1); |
| | 21 | } |
| 14 | | 22 | |
| 15 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB | 23 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB |
| 16 | | 24 | |
| ... | @@ -28,9 +36,11 @@ const usage = | ... | @@ -28,9 +36,11 @@ const usage = |
| 28 | \\ build-exe [source] Create executable from source or object files | 36 | \\ build-exe [source] Create executable from source or object files |
| 29 | \\ build-lib [source] Create library from source or object files | 37 | \\ build-lib [source] Create library from source or object files |
| 30 | \\ build-obj [source] Create object from source or assembly | 38 | \\ 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 format | 42 | \\ fmt [source] Parse file and render in canonical zig format |
| 32 | \\ targets List available compilation targets | 43 | \\ targets List available compilation targets |
| 33 | \\ env Print lib path, std path, compiler id and version | | |
| 34 | \\ version Print version number and exit | 44 | \\ version Print version number and exit |
| 35 | \\ zen Print zen of zig and exit | 45 | \\ 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 off | 165 | \\ ReleaseFast Optimizations on, safety off |
| 148 | \\ ReleaseSafe Optimizations on, safety on | 166 | \\ ReleaseSafe Optimizations on, safety on |
| 149 | \\ ReleaseSmall Optimize for small binary, safety off | 167 | \\ 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 linked | 170 | \\ --dynamic Force output to be dynamically linked |
| 151 | \\ --strip Exclude debug symbols | 171 | \\ --strip Exclude debug symbols |
| 152 | \\ -ofmt=[mode] Override target object format | 172 | \\ -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 relocatables | 178 | \\ macho (planned) macOS relocatables |
| 159 | \\ hex (planned) Intel IHEX | 179 | \\ hex (planned) Intel IHEX |
| 160 | \\ raw (planned) Dump machine code directly | 180 | \\ 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 library | 187 | \\ -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 semver | 191 | \\ --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 diagnostics | 196 | \\ -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 | }; |
| 183 | | 211 | |
| 184 | fn buildOutputType( | 212 | pub 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; |
| 211 | | 267 | |
| 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(); |
| 214 | | 270 | |
| 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") or | 465 | } else if (mem.endsWith(u8, arg, ".o") or |
| 352 | mem.endsWith(u8, arg, ".obj") or | 466 | mem.endsWith(u8, arg, ".obj") or |
| 353 | mem.endsWith(u8, arg, ".a") or | 467 | 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") or | 472 | 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") or | 473 | } else if (mem.endsWith(u8, arg, ".so") or |
| 364 | mem.endsWith(u8, arg, ".dylib") or | 474 | 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 | } |
| 381 | | 764 | |
| 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 | }; |
| 392 | | 774 | |
| 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 | }; |
| 431 | | 808 | |
| 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 implementing | 811 | // 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 | } |
| 439 | | 867 | |
| 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 | }; |
| 444 | | 871 | |
| 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 | }; |
| 468 | | 894 | |
| 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( |
| 515 | | 940 | |
| 516 | try updateModule(gpa, &module, zir_out_path); | 941 | try updateModule(gpa, &module, zir_out_path); |
| 517 | | 942 | |
| | 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 | } |
| 567 | | 997 | |
| 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 { |
| 662 | | 1089 | |
| 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 | } |
| 668 | | 1094 | |
| 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); |
| 673 | | 1099 | |
| 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(); |
| 679 | | 1104 | |
| ... | @@ -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 | } |
| 696 | | 1121 | |
| 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 | } |
| 701 | | 1125 | |
| 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); |
| 719 | | 1142 | |
| ... | @@ -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( |
| 858 | | 1282 | |
| 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 | |
| | 1354 | const FileExt = enum { |
| | 1355 | c, |
| | 1356 | cpp, |
| | 1357 | h, |
| | 1358 | ll, |
| | 1359 | bc, |
| | 1360 | assembly, |
| | 1361 | unknown, |
| | 1362 | }; |
| | 1363 | |
| | 1364 | fn hasCExt(filename: []const u8) bool { |
| | 1365 | return mem.endsWith(u8, filename, ".c"); |
| | 1366 | } |
| | 1367 | |
| | 1368 | fn 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 | |
| | 1375 | fn hasAsmExt(filename: []const u8) bool { |
| | 1376 | return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S"); |
| | 1377 | } |
| | 1378 | |
| | 1379 | fn 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 | |
| | 1398 | extern "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 |
| | 1401 | fn 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 | |
| | 1412 | const clang_args = @import("clang_options.zig").list; |
| | 1413 | |
| | 1414 | pub 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 | |
| | 1645 | fn 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 | |
| | 1653 | fn 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 | |
| | 1693 | fn 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 | } |