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