@@ -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
+ const isystem_flag = "-isystem" ;
6319
+ if (mem .eql (u8 , arg , isystem_flag )) {
6320
+ isystem_path_next = true ;
6321
+ continue ;
6322
+ }
6323
+ if (mem .startsWith (u8 , arg , isystem_flag )) {
6324
+ try user_isystem_paths .append (arg [isystem_flag .len .. ]);
6325
+ continue ;
6326
+ }
6327
+ try other_cc_argv .append (arg );
6328
+ }
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
@@ -6518,6 +6542,12 @@ pub fn addCCArgs(
6518
6542
}
6519
6543
}
6520
6544
6545
+ // User provided isystem paths come first in clang.
6546
+ for (user_isystem_paths .items ) | path | {
6547
+ try argv .append ("-isystem" );
6548
+ try argv .append (path );
6549
+ }
6550
+
6521
6551
if (comp .config .link_libcpp ) {
6522
6552
try argv .append ("-isystem" );
6523
6553
try argv .append (try fs .path .join (arena , &[_ ][]const u8 {
@@ -6798,8 +6828,145 @@ pub fn addCCArgs(
6798
6828
else = > {},
6799
6829
}
6800
6830
6801
- try argv .appendSlice (comp .global_cc_argv );
6802
- try argv .appendSlice (mod .cc_argv );
6831
+ try argv .appendSlice (other_cc_argv .items );
6832
+ }
6833
+
6834
+ test "addCCArgs() puts user provided `-isystem` paths before native paths" {
6835
+ const expected_isys_path_order : []const []const u8 = &.{ "/user_provided/isystem/dir/" , "/module/isystem/dir1/" , "/module/isystem/dir2/" , "/native/isystem/dir/" };
6836
+ var expected_isys_path_queue : std .fifo .LinearFifo ([]const u8 , .{ .Static = expected_isys_path_order .len }) = .init ();
6837
+ try expected_isys_path_queue .write (expected_isys_path_order );
6838
+ var alloc : std .heap .DebugAllocator (.{}) = .init ;
6839
+ var arena = std .heap .ArenaAllocator .init (alloc .allocator ());
6840
+
6841
+ const resolved_target : Package.Module.ResolvedTarget = .{
6842
+ .is_native_os = true ,
6843
+ .is_explicit_dynamic_linker = false ,
6844
+ .is_native_abi = true ,
6845
+ .result = .{
6846
+ .abi = .musl ,
6847
+ .cpu = .{
6848
+ .arch = .x86_64 ,
6849
+ .features = .empty ,
6850
+ .model = Target .Cpu .Model .baseline (.x86_64 , .{
6851
+ .tag = .linux ,
6852
+ .version_range = .{ .none = {} },
6853
+ }),
6854
+ },
6855
+ .os = .{
6856
+ .tag = .linux ,
6857
+ .version_range = .default (.x86_64 , .linux , .musl ),
6858
+ },
6859
+ .ofmt = .c ,
6860
+ },
6861
+ };
6862
+ const conf = try Compilation .Config .resolve (.{
6863
+ .emit_bin = true ,
6864
+ .have_zcu = false ,
6865
+ .is_test = true ,
6866
+ .output_mode = .Exe ,
6867
+ .resolved_target = resolved_target ,
6868
+ });
6869
+
6870
+ const cwd = try std .fs .cwd ().realpathAlloc (arena .allocator (), "." );
6871
+ const global_cache = try introspect .resolveGlobalCacheDir (arena .allocator ());
6872
+ const global_cache_handle = try std .fs .openDirAbsolute (global_cache , .{ .access_sub_paths = true });
6873
+ const local_cache = (try introspect .resolveSuitableLocalCacheDir (arena .allocator (), cwd )).? ;
6874
+ const local_cache_handle = try std .fs .openDirAbsolute (local_cache , .{ .access_sub_paths = true });
6875
+ var thread_pool : std.Thread.Pool = undefined ;
6876
+ try thread_pool .init (.{ .allocator = arena .allocator () });
6877
+
6878
+ const mod = try Package .Module .create (arena .allocator (), .{
6879
+ .paths = .{
6880
+ .root = .{
6881
+ .root = .none ,
6882
+ .sub_path = cwd ,
6883
+ },
6884
+ .root_src_path = "src" ,
6885
+ },
6886
+ .cc_argv = &.{ "-isystem" , "/module/isystem/dir1/" , "-isystem/module/isystem/dir2/" },
6887
+ .fully_qualified_name = "mod" ,
6888
+ .parent = null ,
6889
+ .global = conf ,
6890
+ .inherited = .{ .resolved_target = resolved_target },
6891
+ });
6892
+
6893
+ const compilation = try Compilation .create (
6894
+ alloc .allocator (),
6895
+ arena .allocator (),
6896
+ .{
6897
+ .dirs = .{
6898
+ .cwd = cwd ,
6899
+ .global_cache = .{ .path = global_cache , .handle = global_cache_handle },
6900
+ .local_cache = .{ .path = local_cache , .handle = local_cache_handle },
6901
+ .zig_lib = try introspect .findZigLibDir (arena .allocator ()),
6902
+ },
6903
+ .cache_mode = .whole ,
6904
+ .config = conf ,
6905
+ .thread_pool = & thread_pool ,
6906
+ .root_mod = mod ,
6907
+ .root_name = "mod" ,
6908
+ .emit_bin = .yes_cache ,
6909
+ .native_system_include_paths = &.{"/native/isystem/dir/" },
6910
+ .global_cc_argv = &.{ "-isystem" , "/user_provided/isystem/dir/" },
6911
+ },
6912
+ );
6913
+
6914
+ var argv : std .ArrayList ([]const u8 ) = .init (arena .allocator ());
6915
+
6916
+ try compilation .addCCArgs (arena .allocator (), & argv , .c , null , mod );
6917
+
6918
+ var isys_paths_result : std .ArrayList ([]const u8 ) = .init (arena .allocator ());
6919
+
6920
+ const isys_paths_in_order = check_path_order : {
6921
+ var isystem_path_up_next = false ;
6922
+ for (argv .items ) | arg | {
6923
+ if (mem .eql (u8 , arg , "-isystem" )) {
6924
+ isystem_path_up_next = true ;
6925
+ continue ;
6926
+ }
6927
+ if (isystem_path_up_next ) {
6928
+ try isys_paths_result .append (arg );
6929
+ if (mem .eql (u8 , arg , expected_isys_path_queue .peekItem (0 ))) {
6930
+ expected_isys_path_queue .discard (1 );
6931
+ if (expected_isys_path_queue .readableLength () == 0 ) {
6932
+ break :check_path_order true ;
6933
+ }
6934
+ }
6935
+ }
6936
+ isystem_path_up_next = false ;
6937
+ }
6938
+ break :check_path_order false ;
6939
+ };
6940
+
6941
+ std .testing .expect (isys_paths_in_order ) catch | e | {
6942
+ var result_str : std .ArrayList (u8 ) = .init (arena .allocator ());
6943
+ var result_writer = result_str .writer ();
6944
+ var expect_str : std .ArrayList (u8 ) = .init (arena .allocator ());
6945
+ var expect_writer = expect_str .writer ();
6946
+
6947
+ for (isys_paths_result .items , 0.. ) | path , index | {
6948
+ _ = try result_writer .write (path );
6949
+ if (index < isys_paths_result .items .len - 1 )
6950
+ _ = try result_writer .write (", " );
6951
+ }
6952
+ for (expected_isys_path_order , 0.. ) | path , index | {
6953
+ _ = try expect_writer .write (path );
6954
+ if (index < expected_isys_path_order .len - 1 )
6955
+ _ = try expect_writer .write (", " );
6956
+ }
6957
+ std .log .err (
6958
+ \\Expected isystem paths were not found in the correct order.
6959
+ \\
6960
+ \\Expected:
6961
+ \\ [{s}]
6962
+ \\
6963
+ \\Result:
6964
+ \\ [{s}]
6965
+ \\
6966
+ \\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.
6967
+ , .{ expect_str .items , result_str .items });
6968
+ return e ;
6969
+ };
6803
6970
}
6804
6971
6805
6972
fn failCObj (
0 commit comments