authorgravatar for michael.dusan@gmail.comMichael Dusan <michael.dusan@gmail.com> 2022-09-19 19:11:10-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-12 13:50:25-04:00
log0b47e69b7c0aedbc142400305cda86ef58b41656
tree69ddb125e0d0cabc888045697f26da92b5c10f06
parentc23b3e6fd924725d21ecbbc85ef086d330dd4322

improve header searchlist handling in build, main

build.zig: - use "-I" instead of "-isystem" for `b.addSearchPrefix()` main.zig: - silently ignore superfluous search dirs - warn when a dir is added to multiple searchlists - consolidate "expected paramter after {s}" fatal error messages - rename command-line switch `-dirafter` → `-idirafter` closes #12888

2 files changed, 129 insertions(+), 135 deletions(-)

lib/std/build.zig+1-1
......@@ -3123,7 +3123,7 @@ pub const LibExeObjStep = struct {
31233123 try zig_args.append(builder.pathJoin(&.{
31243124 search_prefix, "lib",
31253125 }));
3126 try zig_args.append("-isystem");
3126 try zig_args.append("-I");
31273127 try zig_args.append(builder.pathJoin(&.{
31283128 search_prefix, "include",
31293129 }));
src/main.zig+128-134
......@@ -416,7 +416,7 @@ const usage_build_generic =
416416 \\ plan9 Plan 9 from Bell Labs object format
417417 \\ hex (planned feature) Intel IHEX
418418 \\ raw (planned feature) Dump machine code directly
419 \\ -dirafter [dir] Add directory to AFTER include search path
419 \\ -idirafter [dir] Add directory to AFTER include search path
420420 \\ -isystem [dir] Add directory to SYSTEM include search path
421421 \\ -I[dir] Add directory to include search path
422422 \\ -D[macro]=[value] Define C [macro] to [value] (1 if [value] omitted)
......@@ -845,11 +845,22 @@ fn buildOutputType(
845845 defer it.i += 1;
846846 return it.args[it.i];
847847 }
848 fn nextOrFatal(it: *@This()) []const u8 {
849 if (it.i >= it.args.len) {
850 if (it.resp_file) |*resp| if (resp.next()) |sentinel| return std.mem.span(sentinel);
851 fatal("expected parameter after {s}", .{it.args[it.i - 1]});
852 }
853 defer it.i += 1;
854 return it.args[it.i];
855 }
848856 };
849857 var args_iter = Iterator{
850858 .args = all_args[2..],
851859 };
852860
861 var cssan = ClangSearchSanitizer.init(gpa, &clang_argv);
862 defer cssan.map.deinit();
863
853864 args_loop: while (args_iter.next()) |arg| {
854865 if (mem.startsWith(u8, arg, "@")) {
855866 // This is a "compiler response file". We must parse the file and treat its
......@@ -895,9 +906,7 @@ fn buildOutputType(
895906 cur_pkg = cur_pkg.parent orelse
896907 fatal("encountered --pkg-end with no matching --pkg-begin", .{});
897908 } else if (mem.eql(u8, arg, "--main-pkg-path")) {
898 main_pkg_path = args_iter.next() orelse {
899 fatal("expected parameter after {s}", .{arg});
900 };
909 main_pkg_path = args_iter.nextOrFatal();
901910 } else if (mem.eql(u8, arg, "-cflags")) {
902911 extra_cflags.shrinkRetainingCapacity(0);
903912 while (true) {
......@@ -915,67 +924,37 @@ fn buildOutputType(
915924 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
916925 };
917926 } else if (mem.eql(u8, arg, "--subsystem")) {
918 const next_arg = args_iter.next() orelse {
919 fatal("expected parameter after {s}", .{arg});
920 };
921 subsystem = try parseSubSystem(next_arg);
927 subsystem = try parseSubSystem(args_iter.nextOrFatal());
922928 } else if (mem.eql(u8, arg, "-O")) {
923 optimize_mode_string = args_iter.next() orelse {
924 fatal("expected parameter after {s}", .{arg});
925 };
929 optimize_mode_string = args_iter.nextOrFatal();
926930 } else if (mem.eql(u8, arg, "--entry")) {
927 entry = args_iter.next() orelse {
928 fatal("expected parameter after {s}", .{arg});
929 };
931 entry = args_iter.nextOrFatal();
930932 } else if (mem.eql(u8, arg, "--stack")) {
931 const next_arg = args_iter.next() orelse {
932 fatal("expected parameter after {s}", .{arg});
933 };
933 const next_arg = args_iter.nextOrFatal();
934934 stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
935935 fatal("unable to parse stack size '{s}': {s}", .{ next_arg, @errorName(err) });
936936 };
937937 } else if (mem.eql(u8, arg, "--image-base")) {
938 const next_arg = args_iter.next() orelse {
939 fatal("expected parameter after {s}", .{arg});
940 };
938 const next_arg = args_iter.nextOrFatal();
941939 image_base_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
942940 fatal("unable to parse image base override '{s}': {s}", .{ next_arg, @errorName(err) });
943941 };
944942 } else if (mem.eql(u8, arg, "--name")) {
945 provided_name = args_iter.next() orelse {
946 fatal("expected parameter after {s}", .{arg});
947 };
943 provided_name = args_iter.nextOrFatal();
948944 } else if (mem.eql(u8, arg, "-rpath")) {
949 try rpath_list.append(args_iter.next() orelse {
950 fatal("expected parameter after {s}", .{arg});
951 });
945 try rpath_list.append(args_iter.nextOrFatal());
952946 } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) {
953 try lib_dirs.append(args_iter.next() orelse {
954 fatal("expected parameter after {s}", .{arg});
955 });
947 try lib_dirs.append(args_iter.nextOrFatal());
956948 } else if (mem.eql(u8, arg, "-F")) {
957 try framework_dirs.append(args_iter.next() orelse {
958 fatal("expected parameter after {s}", .{arg});
959 });
949 try framework_dirs.append(args_iter.nextOrFatal());
960950 } else if (mem.eql(u8, arg, "-framework")) {
961 const path = args_iter.next() orelse {
962 fatal("expected parameter after {s}", .{arg});
963 };
964 try frameworks.put(gpa, path, .{});
951 try frameworks.put(gpa, args_iter.nextOrFatal(), .{});
965952 } else if (mem.eql(u8, arg, "-weak_framework")) {
966 const path = args_iter.next() orelse {
967 fatal("expected parameter after {s}", .{arg});
968 };
969 try frameworks.put(gpa, path, .{ .weak = true });
953 try frameworks.put(gpa, args_iter.nextOrFatal(), .{ .weak = true });
970954 } else if (mem.eql(u8, arg, "-needed_framework")) {
971 const path = args_iter.next() orelse {
972 fatal("expected parameter after {s}", .{arg});
973 };
974 try frameworks.put(gpa, path, .{ .needed = true });
955 try frameworks.put(gpa, args_iter.nextOrFatal(), .{ .needed = true });
975956 } else if (mem.eql(u8, arg, "-install_name")) {
976 install_name = args_iter.next() orelse {
977 fatal("expected parameter after {s}", .{arg});
978 };
957 install_name = args_iter.nextOrFatal();
979958 } else if (mem.startsWith(u8, arg, "--compress-debug-sections=")) {
980959 const param = arg["--compress-debug-sections=".len..];
981960 linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, param) orelse {
......@@ -984,9 +963,7 @@ fn buildOutputType(
984963 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
985964 linker_compress_debug_sections = link.CompressDebugSections.zlib;
986965 } else if (mem.eql(u8, arg, "-pagezero_size")) {
987 const next_arg = args_iter.next() orelse {
988 fatal("expected parameter after {s}", .{arg});
989 };
966 const next_arg = args_iter.nextOrFatal();
990967 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
991968 fatal("unable to parse pagezero size'{s}': {s}", .{ next_arg, @errorName(err) });
992969 };
......@@ -995,9 +972,7 @@ fn buildOutputType(
995972 } else if (mem.eql(u8, arg, "-search_dylibs_first")) {
996973 search_strategy = .dylibs_first;
997974 } else if (mem.eql(u8, arg, "-headerpad")) {
998 const next_arg = args_iter.next() orelse {
999 fatal("expected parameter after {s}", .{arg});
1000 };
975 const next_arg = args_iter.nextOrFatal();
1001976 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
1002977 fatal("unable to parse headerpat size '{s}': {s}", .{ next_arg, @errorName(err) });
1003978 };
......@@ -1008,65 +983,44 @@ fn buildOutputType(
1008983 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
1009984 dead_strip_dylibs = true;
1010985 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
1011 linker_script = args_iter.next() orelse {
1012 fatal("expected parameter after {s}", .{arg});
1013 };
986 linker_script = args_iter.nextOrFatal();
1014987 } else if (mem.eql(u8, arg, "--version-script")) {
1015 version_script = args_iter.next() orelse {
1016 fatal("expected parameter after {s}", .{arg});
1017 };
988 version_script = args_iter.nextOrFatal();
1018989 } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {
1019 const next_arg = args_iter.next() orelse {
1020 fatal("expected parameter after {s}", .{arg});
1021 };
1022990 // We don't know whether this library is part of libc or libc++ until
1023991 // we resolve the target, so we simply append to the list for now.
1024 try system_libs.put(next_arg, .{});
992 try system_libs.put(args_iter.nextOrFatal(), .{});
1025993 } else if (mem.eql(u8, arg, "--needed-library") or
1026994 mem.eql(u8, arg, "-needed-l") or
1027995 mem.eql(u8, arg, "-needed_library"))
1028996 {
1029 const next_arg = args_iter.next() orelse {
1030 fatal("expected parameter after {s}", .{arg});
1031 };
997 const next_arg = args_iter.nextOrFatal();
1032998 try system_libs.put(next_arg, .{ .needed = true });
1033999 } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {
1034 const next_arg = args_iter.next() orelse {
1035 fatal("expected parameter after {s}", .{arg});
1036 };
1037 try system_libs.put(next_arg, .{ .weak = true });
1038 } else if (mem.eql(u8, arg, "-D") or
1039 mem.eql(u8, arg, "-isystem") or
1040 mem.eql(u8, arg, "-I") or
1041 mem.eql(u8, arg, "-dirafter") or
1042 mem.eql(u8, arg, "-iwithsysroot") or
1043 mem.eql(u8, arg, "-iframework") or
1044 mem.eql(u8, arg, "-iframeworkwithsysroot"))
1045 {
1000 try system_libs.put(args_iter.nextOrFatal(), .{ .weak = true });
1001 } else if (mem.eql(u8, arg, "-D")) {
10461002 try clang_argv.append(arg);
1047 try clang_argv.append(args_iter.next() orelse {
1048 fatal("expected parameter after {s}", .{arg});
1049 });
1003 try clang_argv.append(args_iter.nextOrFatal());
1004 } else if (mem.eql(u8, arg, "-I")) {
1005 try cssan.addIncludePath(.I, arg, args_iter.nextOrFatal(), false);
1006 } else if (mem.eql(u8, arg, "-isystem") or mem.eql(u8, arg, "-iwithsysroot")) {
1007 try cssan.addIncludePath(.isystem, arg, args_iter.nextOrFatal(), false);
1008 } else if (mem.eql(u8, arg, "-idirafter")) {
1009 try cssan.addIncludePath(.idirafter, arg, args_iter.nextOrFatal(), false);
1010 } else if (mem.eql(u8, arg, "-iframework") or mem.eql(u8, arg, "-iframeworkwithsysroot")) {
1011 try cssan.addIncludePath(.iframework, arg, args_iter.nextOrFatal(), false);
10501012 } else if (mem.eql(u8, arg, "--version")) {
1051 const next_arg = args_iter.next() orelse {
1052 fatal("expected parameter after {s}", .{arg});
1053 };
1013 const next_arg = args_iter.nextOrFatal();
10541014 version = std.builtin.Version.parse(next_arg) catch |err| {
10551015 fatal("unable to parse --version '{s}': {s}", .{ next_arg, @errorName(err) });
10561016 };
10571017 have_version = true;
10581018 } else if (mem.eql(u8, arg, "-target")) {
1059 target_arch_os_abi = args_iter.next() orelse {
1060 fatal("expected parameter after {s}", .{arg});
1061 };
1019 target_arch_os_abi = args_iter.nextOrFatal();
10621020 } else if (mem.eql(u8, arg, "-mcpu")) {
1063 target_mcpu = args_iter.next() orelse {
1064 fatal("expected parameter after {s}", .{arg});
1065 };
1021 target_mcpu = args_iter.nextOrFatal();
10661022 } else if (mem.eql(u8, arg, "-mcmodel")) {
1067 machine_code_model = parseCodeModel(args_iter.next() orelse {
1068 fatal("expected parameter after {s}", .{arg});
1069 });
1023 machine_code_model = parseCodeModel(args_iter.nextOrFatal());
10701024 } else if (mem.startsWith(u8, arg, "-ofmt=")) {
10711025 target_ofmt = arg["-ofmt=".len..];
10721026 } else if (mem.startsWith(u8, arg, "-mcpu=")) {
......@@ -1076,51 +1030,29 @@ fn buildOutputType(
10761030 } else if (mem.startsWith(u8, arg, "-O")) {
10771031 optimize_mode_string = arg["-O".len..];
10781032 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
1079 target_dynamic_linker = args_iter.next() orelse {
1080 fatal("expected parameter after {s}", .{arg});
1081 };
1033 target_dynamic_linker = args_iter.nextOrFatal();
10821034 } else if (mem.eql(u8, arg, "--sysroot")) {
1083 sysroot = args_iter.next() orelse {
1084 fatal("expected parameter after {s}", .{arg});
1085 };
10861035 try clang_argv.append("-isysroot");
1087 try clang_argv.append(sysroot.?);
1036 try clang_argv.append(args_iter.nextOrFatal());
10881037 } else if (mem.eql(u8, arg, "--libc")) {
1089 libc_paths_file = args_iter.next() orelse {
1090 fatal("expected parameter after {s}", .{arg});
1091 };
1038 libc_paths_file = args_iter.nextOrFatal();
10921039 } else if (mem.eql(u8, arg, "--test-filter")) {
1093 test_filter = args_iter.next() orelse {
1094 fatal("expected parameter after {s}", .{arg});
1095 };
1040 test_filter = args_iter.nextOrFatal();
10961041 } else if (mem.eql(u8, arg, "--test-name-prefix")) {
1097 test_name_prefix = args_iter.next() orelse {
1098 fatal("expected parameter after {s}", .{arg});
1099 };
1042 test_name_prefix = args_iter.nextOrFatal();
11001043 } else if (mem.eql(u8, arg, "--test-cmd")) {
1101 try test_exec_args.append(args_iter.next() orelse {
1102 fatal("expected parameter after {s}", .{arg});
1103 });
1044 try test_exec_args.append(args_iter.nextOrFatal());
11041045 } else if (mem.eql(u8, arg, "--cache-dir")) {
1105 override_local_cache_dir = args_iter.next() orelse {
1106 fatal("expected parameter after {s}", .{arg});
1107 };
1046 override_local_cache_dir = args_iter.nextOrFatal();
11081047 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
1109 override_global_cache_dir = args_iter.next() orelse {
1110 fatal("expected parameter after {s}", .{arg});
1111 };
1048 override_global_cache_dir = args_iter.nextOrFatal();
11121049 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
1113 override_lib_dir = args_iter.next() orelse {
1114 fatal("expected parameter after {s}", .{arg});
1115 };
1050 override_lib_dir = args_iter.nextOrFatal();
11161051 } else if (mem.eql(u8, arg, "--debug-log")) {
1117 const next_arg = args_iter.next() orelse {
1118 fatal("expected parameter after {s}", .{arg});
1119 };
11201052 if (!build_options.enable_logging) {
11211053 std.log.warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
11221054 } else {
1123 try log_scopes.append(gpa, next_arg);
1055 try log_scopes.append(gpa, args_iter.nextOrFatal());
11241056 }
11251057 } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {
11261058 if (!build_options.enable_link_snapshots) {
......@@ -1129,9 +1061,7 @@ fn buildOutputType(
11291061 enable_link_snapshots = true;
11301062 }
11311063 } else if (mem.eql(u8, arg, "--entitlements")) {
1132 entitlements = args_iter.next() orelse {
1133 fatal("expected parameter after {s}", .{arg});
1134 };
1064 entitlements = args_iter.nextOrFatal();
11351065 } else if (mem.eql(u8, arg, "-fcompiler-rt")) {
11361066 want_compiler_rt = true;
11371067 } else if (mem.eql(u8, arg, "-fno-compiler-rt")) {
......@@ -1322,9 +1252,7 @@ fn buildOutputType(
13221252 } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {
13231253 linker_allow_shlib_undefined = false;
13241254 } else if (mem.eql(u8, arg, "-z")) {
1325 const z_arg = args_iter.next() orelse {
1326 fatal("expected parameter after {s}", .{arg});
1327 };
1255 const z_arg = args_iter.nextOrFatal();
13281256 if (mem.eql(u8, z_arg, "nodelete")) {
13291257 linker_z_nodelete = true;
13301258 } else if (mem.eql(u8, z_arg, "notext")) {
......@@ -1394,10 +1322,10 @@ fn buildOutputType(
13941322 try system_libs.put(arg["-needed-l".len..], .{ .needed = true });
13951323 } else if (mem.startsWith(u8, arg, "-weak-l")) {
13961324 try system_libs.put(arg["-weak-l".len..], .{ .weak = true });
1397 } else if (mem.startsWith(u8, arg, "-D") or
1398 mem.startsWith(u8, arg, "-I"))
1399 {
1325 } else if (mem.startsWith(u8, arg, "-D")) {
14001326 try clang_argv.append(arg);
1327 } else if (mem.startsWith(u8, arg, "-I")) {
1328 try cssan.addIncludePath(.I, arg, arg[2..], true);
14011329 } else if (mem.startsWith(u8, arg, "-mexec-model=")) {
14021330 wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, arg["-mexec-model=".len..]) orelse {
14031331 fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{arg["-mexec-model=".len..]});
......@@ -5497,3 +5425,69 @@ fn parseSubSystem(next_arg: []const u8) !std.Target.SubSystem {
54975425 });
54985426 }
54995427}
5428
5429/// Model a header searchlist as a group.
5430/// Silently ignore superfluous search dirs.
5431/// Warn when a dir is added to multiple searchlists.
5432const ClangSearchSanitizer = struct {
5433 argv: *std.ArrayList([]const u8),
5434 map: std.StringHashMap(Membership),
5435
5436 fn init(gpa: Allocator, argv: *std.ArrayList([]const u8)) @This() {
5437 return .{
5438 .argv = argv,
5439 .map = std.StringHashMap(Membership).init(gpa),
5440 };
5441 }
5442
5443 fn addIncludePath(self: *@This(), group: Group, arg: []const u8, dir: []const u8, joined: bool) !void {
5444 const gopr = try self.map.getOrPut(dir);
5445 const m = gopr.value_ptr;
5446 if (!gopr.found_existing) {
5447 // init empty membership
5448 m.* = .{};
5449 }
5450 const wtxt = "add '{s}' to header searchlist '-{s}' conflicts with '-{s}'";
5451 switch (group) {
5452 .I => {
5453 if (m.I) return;
5454 m.I = true;
5455 if (m.isystem) std.log.warn(wtxt, .{ dir, "I", "isystem" });
5456 if (m.idirafter) std.log.warn(wtxt, .{ dir, "I", "idirafter" });
5457 if (m.iframework) std.log.warn(wtxt, .{ dir, "I", "iframework" });
5458 },
5459 .isystem => {
5460 if (m.isystem) return;
5461 m.isystem = true;
5462 if (m.I) std.log.warn(wtxt, .{ dir, "isystem", "I" });
5463 if (m.idirafter) std.log.warn(wtxt, .{ dir, "isystem", "idirafter" });
5464 if (m.iframework) std.log.warn(wtxt, .{ dir, "isystem", "iframework" });
5465 },
5466 .idirafter => {
5467 if (m.idirafter) return;
5468 m.idirafter = true;
5469 if (m.I) std.log.warn(wtxt, .{ dir, "idirafter", "I" });
5470 if (m.isystem) std.log.warn(wtxt, .{ dir, "idirafter", "isystem" });
5471 if (m.iframework) std.log.warn(wtxt, .{ dir, "idirafter", "iframework" });
5472 },
5473 .iframework => {
5474 if (m.iframework) return;
5475 m.iframework = true;
5476 if (m.I) std.log.warn(wtxt, .{ dir, "iframework", "I" });
5477 if (m.isystem) std.log.warn(wtxt, .{ dir, "iframework", "isystem" });
5478 if (m.idirafter) std.log.warn(wtxt, .{ dir, "iframework", "idirafter" });
5479 },
5480 }
5481 try self.argv.append(arg);
5482 if (!joined) try self.argv.append(dir);
5483 }
5484
5485 const Group = enum { I, isystem, idirafter, iframework };
5486
5487 const Membership = packed struct {
5488 I: bool = false,
5489 isystem: bool = false,
5490 idirafter: bool = false,
5491 iframework: bool = false,
5492 };
5493};