@@ -6304,6 +6304,30 @@ pub fn addCCArgs(
6304
6304
) ! void {
6305
6305
const target = & mod .resolved_target .result ;
6306
6306
6307
+ var user_isystem_paths : std .ArrayList ([]const u8 ) = .init (arena );
6308
+ var other_cc_argv : std .ArrayList ([]const u8 ) = .init (arena );
6309
+
6310
+ var isystem_path_next = false ;
6311
+ for ([_ ][]const []const u8 { comp .global_cc_argv , mod .cc_argv }) | cc_argv | {
6312
+ for (cc_argv ) | arg | {
6313
+ if (isystem_path_next ) {
6314
+ try user_isystem_paths .append (arg );
6315
+ isystem_path_next = false ;
6316
+ continue ;
6317
+ }
6318
+ if (mem .eql (u8 , arg , "-isystem" )) {
6319
+ isystem_path_next = true ;
6320
+ continue ;
6321
+ }
6322
+ try other_cc_argv .append (arg );
6323
+ }
6324
+ }
6325
+
6326
+ for (user_isystem_paths .items ) | path | {
6327
+ try argv .append ("-isystem" );
6328
+ try argv .append (path );
6329
+ }
6330
+
6307
6331
// As of Clang 16.x, it will by default read extra flags from /etc/clang.
6308
6332
// I'm sure the person who implemented this means well, but they have a lot
6309
6333
// to learn about abstractions and where the appropriate boundaries between
@@ -6798,8 +6822,145 @@ pub fn addCCArgs(
6798
6822
else = > {},
6799
6823
}
6800
6824
6801
- try argv .appendSlice (comp .global_cc_argv );
6802
- try argv .appendSlice (mod .cc_argv );
6825
+ try argv .appendSlice (other_cc_argv .items );
6826
+ }
6827
+
6828
+ test "addCCArgs() puts user provided `-isystem` paths before native paths" {
6829
+ const expected_isys_path_order : []const []const u8 = &.{ "/user_provided/isystem/dir/" , "/module/isystem/dir/" , "/native/isystem/dir/" };
6830
+ var expected_isys_path_queue : std .fifo .LinearFifo ([]const u8 , .{ .Static = expected_isys_path_order .len }) = .init ();
6831
+ try expected_isys_path_queue .write (expected_isys_path_order );
6832
+ var alloc : std .heap .DebugAllocator (.{}) = .init ;
6833
+ var arena = std .heap .ArenaAllocator .init (alloc .allocator ());
6834
+
6835
+ const resolved_target : Package.Module.ResolvedTarget = .{
6836
+ .is_native_os = true ,
6837
+ .is_explicit_dynamic_linker = false ,
6838
+ .is_native_abi = true ,
6839
+ .result = .{
6840
+ .abi = .musl ,
6841
+ .cpu = .{
6842
+ .arch = .x86_64 ,
6843
+ .features = .empty ,
6844
+ .model = Target .Cpu .Model .baseline (.x86_64 , .{
6845
+ .tag = .linux ,
6846
+ .version_range = .{ .none = {} },
6847
+ }),
6848
+ },
6849
+ .os = .{
6850
+ .tag = .linux ,
6851
+ .version_range = .default (.x86_64 , .linux , .musl ),
6852
+ },
6853
+ .ofmt = .c ,
6854
+ },
6855
+ };
6856
+ const conf = try Compilation .Config .resolve (.{
6857
+ .emit_bin = true ,
6858
+ .have_zcu = false ,
6859
+ .is_test = true ,
6860
+ .output_mode = .Exe ,
6861
+ .resolved_target = resolved_target ,
6862
+ });
6863
+
6864
+ const cwd = try std .fs .cwd ().realpathAlloc (arena .allocator (), "." );
6865
+ const global_cache = try introspect .resolveGlobalCacheDir (arena .allocator ());
6866
+ const global_cache_handle = try std .fs .openDirAbsolute (global_cache , .{ .access_sub_paths = true });
6867
+ const local_cache = (try introspect .resolveSuitableLocalCacheDir (arena .allocator (), cwd )).? ;
6868
+ const local_cache_handle = try std .fs .openDirAbsolute (local_cache , .{ .access_sub_paths = true });
6869
+ var thread_pool : std.Thread.Pool = undefined ;
6870
+ try thread_pool .init (.{ .allocator = arena .allocator () });
6871
+
6872
+ const mod = try Package .Module .create (arena .allocator (), .{
6873
+ .paths = .{
6874
+ .root = .{
6875
+ .root = .none ,
6876
+ .sub_path = cwd ,
6877
+ },
6878
+ .root_src_path = "src" ,
6879
+ },
6880
+ .cc_argv = &.{ "-isystem" , "/module/isystem/dir/" },
6881
+ .fully_qualified_name = "mod" ,
6882
+ .parent = null ,
6883
+ .global = conf ,
6884
+ .inherited = .{ .resolved_target = resolved_target },
6885
+ });
6886
+
6887
+ const compilation = try Compilation .create (
6888
+ alloc .allocator (),
6889
+ arena .allocator (),
6890
+ .{
6891
+ .dirs = .{
6892
+ .cwd = cwd ,
6893
+ .global_cache = .{ .path = global_cache , .handle = global_cache_handle },
6894
+ .local_cache = .{ .path = local_cache , .handle = local_cache_handle },
6895
+ .zig_lib = try introspect .findZigLibDir (arena .allocator ()),
6896
+ },
6897
+ .cache_mode = .whole ,
6898
+ .config = conf ,
6899
+ .thread_pool = & thread_pool ,
6900
+ .root_mod = mod ,
6901
+ .root_name = "mod" ,
6902
+ .emit_bin = .yes_cache ,
6903
+ .native_system_include_paths = &.{"/native/isystem/dir/" },
6904
+ .global_cc_argv = &.{ "-isystem" , "/user_provided/isystem/dir/" },
6905
+ },
6906
+ );
6907
+
6908
+ var argv : std .ArrayList ([]const u8 ) = .init (arena .allocator ());
6909
+
6910
+ try compilation .addCCArgs (arena .allocator (), & argv , .c , null , mod );
6911
+
6912
+ var isys_paths_result : std .ArrayList ([]const u8 ) = .init (arena .allocator ());
6913
+
6914
+ const isys_paths_in_order = check_path_order : {
6915
+ var isystem_path_up_next = false ;
6916
+ for (argv .items ) | arg | {
6917
+ if (mem .eql (u8 , arg , "-isystem" )) {
6918
+ isystem_path_up_next = true ;
6919
+ continue ;
6920
+ }
6921
+ if (isystem_path_up_next ) {
6922
+ try isys_paths_result .append (arg );
6923
+ if (mem .eql (u8 , arg , expected_isys_path_queue .peekItem (0 ))) {
6924
+ expected_isys_path_queue .discard (1 );
6925
+ if (expected_isys_path_queue .readableLength () == 0 ) {
6926
+ break :check_path_order true ;
6927
+ }
6928
+ }
6929
+ }
6930
+ isystem_path_up_next = false ;
6931
+ }
6932
+ break :check_path_order false ;
6933
+ };
6934
+
6935
+ std .testing .expect (isys_paths_in_order ) catch | e | {
6936
+ var result_str : std .ArrayList (u8 ) = .init (arena .allocator ());
6937
+ var result_writer = result_str .writer ();
6938
+ var expect_str : std .ArrayList (u8 ) = .init (arena .allocator ());
6939
+ var expect_writer = expect_str .writer ();
6940
+
6941
+ for (isys_paths_result .items , 0.. ) | path , index | {
6942
+ _ = try result_writer .write (path );
6943
+ if (index < isys_paths_result .items .len - 1 )
6944
+ _ = try result_writer .write (", " );
6945
+ }
6946
+ for (expected_isys_path_order , 0.. ) | path , index | {
6947
+ _ = try expect_writer .write (path );
6948
+ if (index < expected_isys_path_order .len - 1 )
6949
+ _ = try expect_writer .write (", " );
6950
+ }
6951
+ std .log .err (
6952
+ \\Expected isystem paths were not found in the correct order.
6953
+ \\
6954
+ \\Expected:
6955
+ \\ [{s}]
6956
+ \\
6957
+ \\Result:
6958
+ \\ [{s}]
6959
+ \\
6960
+ \\Note: Expected and Result do not need to match 1:1, all items in expected just need to be found in result in the same order.
6961
+ , .{ expect_str .items , result_str .items });
6962
+ return e ;
6963
+ };
6803
6964
}
6804
6965
6805
6966
fn failCObj (
0 commit comments