Skip to content

Commit 59eff92

Browse files
committed
std.Build: add an option to CSourceFile to override the language detection.
It is normally based on the file extension, but it can be ambiguous. Notably, ".h" is often used for c headers or c++ headers. Or some .s (instead of .S) assembly files still need the c preprocessor. (ziglang#20655)
1 parent dcdd80b commit 59eff92

File tree

4 files changed

+128
-12
lines changed

4 files changed

+128
-12
lines changed

lib/std/Build/Module.zig

+82-7
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,36 @@ pub const RPath = union(enum) {
4646
special: []const u8,
4747
};
4848

49+
// subset of Compilation.FileExt
50+
pub const AsmSourceLang = enum {
51+
assembly,
52+
assembly_with_cpp,
53+
54+
pub fn getLangName(lang: @This()) []const u8 {
55+
return switch (lang) {
56+
.assembly => "assembler",
57+
.assembly_with_cpp => "assembler-with-cpp",
58+
};
59+
}
60+
};
61+
62+
pub const AsmSourceFile = struct {
63+
file: LazyPath,
64+
lang: ?AsmSourceLang = null,
65+
66+
pub fn dupe(file: AsmSourceFile, b: *std.Build) AsmSourceFile {
67+
return .{
68+
.file = file.file.dupe(b),
69+
.lang = file.lang,
70+
};
71+
}
72+
};
73+
4974
pub const LinkObject = union(enum) {
5075
static_path: LazyPath,
5176
other_step: *Step.Compile,
5277
system_lib: SystemLib,
53-
assembly_file: LazyPath,
78+
assembly_file: *AsmSourceFile,
5479
c_source_file: *CSourceFile,
5580
c_source_files: *CSourceFiles,
5681
win32_resource_file: *RcSourceFile,
@@ -78,21 +103,67 @@ pub const SystemLib = struct {
78103
pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
79104
};
80105

106+
/// Supported languages for "zig clang -x <lang>".
107+
// subset of Compilation.FileExt
108+
pub const CSourceLang = enum {
109+
/// "c"
110+
c,
111+
/// "c-header"
112+
h,
113+
/// "c++"
114+
cpp,
115+
/// "c++-header"
116+
hpp,
117+
/// "objective-c"
118+
m,
119+
/// "objective-c-header"
120+
hm,
121+
/// "objective-c++"
122+
mm,
123+
/// "objective-c++-header"
124+
hmm,
125+
/// "assembler"
126+
assembly,
127+
/// "assembler-with-cpp"
128+
assembly_with_cpp,
129+
/// "cuda"
130+
cu,
131+
132+
pub fn getLangName(lang: @This()) []const u8 {
133+
return switch (lang) {
134+
.assembly => "assembler",
135+
.assembly_with_cpp => "assembler-with-cpp",
136+
.c => "c",
137+
.cpp => "c++",
138+
.h => "c-header",
139+
.hpp => "c++-header",
140+
.hm => "objective-c-header",
141+
.hmm => "objective-c++-header",
142+
.cu => "cuda",
143+
.m => "objective-c",
144+
.mm => "objective-c++",
145+
};
146+
}
147+
};
148+
81149
pub const CSourceFiles = struct {
82150
root: LazyPath,
83151
/// `files` is relative to `root`, which is
84152
/// the build root by default
85153
files: []const []const u8,
154+
lang: ?CSourceLang = null,
86155
flags: []const []const u8,
87156
};
88157

89158
pub const CSourceFile = struct {
90159
file: LazyPath,
160+
lang: ?CSourceLang = null,
91161
flags: []const []const u8 = &.{},
92162

93163
pub fn dupe(file: CSourceFile, b: *std.Build) CSourceFile {
94164
return .{
95165
.file = file.file.dupe(b),
166+
.lang = file.lang,
96167
.flags = b.dupeStrings(file.flags),
97168
};
98169
}
@@ -286,9 +357,8 @@ fn addShallowDependencies(m: *Module, dependee: *Module) void {
286357
addLazyPathDependenciesOnly(m, compile.getEmittedIncludeTree());
287358
},
288359

289-
.static_path,
290-
.assembly_file,
291-
=> |lp| addLazyPathDependencies(m, dependee, lp),
360+
.static_path => |lp| addLazyPathDependencies(m, dependee, lp),
361+
.assembly_file => |x| addLazyPathDependencies(m, dependee, x.file),
292362

293363
.c_source_file => |x| addLazyPathDependencies(m, dependee, x.file),
294364
.win32_resource_file => |x| addLazyPathDependencies(m, dependee, x.file),
@@ -485,6 +555,7 @@ pub const AddCSourceFilesOptions = struct {
485555
/// package that owns the `Compile` step.
486556
root: ?LazyPath = null,
487557
files: []const []const u8,
558+
lang: ?CSourceLang = null,
488559
flags: []const []const u8 = &.{},
489560
};
490561

@@ -506,6 +577,7 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
506577
c_source_files.* = .{
507578
.root = options.root orelse b.path(""),
508579
.files = b.dupeStrings(options.files),
580+
.lang = options.lang,
509581
.flags = b.dupeStrings(options.flags),
510582
};
511583
m.link_objects.append(allocator, .{ .c_source_files = c_source_files }) catch @panic("OOM");
@@ -541,10 +613,13 @@ pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void {
541613
}
542614
}
543615

544-
pub fn addAssemblyFile(m: *Module, source: LazyPath) void {
616+
pub fn addAssemblyFile(m: *Module, source: AsmSourceFile) void {
545617
const b = m.owner;
546-
m.link_objects.append(b.allocator, .{ .assembly_file = source.dupe(b) }) catch @panic("OOM");
547-
addLazyPathDependenciesOnly(m, source);
618+
const allocator = b.allocator;
619+
const source_file = allocator.create(AsmSourceFile) catch @panic("OOM");
620+
source_file.* = source.dupe(b);
621+
m.link_objects.append(b.allocator, .{ .assembly_file = source_file }) catch @panic("OOM");
622+
addLazyPathDependenciesOnly(m, source.file);
548623
}
549624

550625
pub fn addObjectFile(m: *Module, object: LazyPath) void {

lib/std/Build/Step/Compile.zig

+43-2
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
885885
return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);
886886
}
887887

888-
pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {
888+
pub fn addAssemblyFile(compile: *Compile, source: Module.AsmSourceFile) void {
889889
compile.root_module.addAssemblyFile(source);
890890
}
891891

@@ -1068,6 +1068,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
10681068

10691069
var prev_has_cflags = false;
10701070
var prev_has_rcflags = false;
1071+
var prev_has_xflag = false;
10711072
var prev_search_strategy: Module.SystemLib.SearchStrategy = .paths_first;
10721073
var prev_preferred_link_mode: std.builtin.LinkMode = .dynamic;
10731074
// Track the number of positional arguments so that a nice error can be
@@ -1106,6 +1107,12 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
11061107

11071108
// Inherit dependencies on system libraries and static libraries.
11081109
for (dep.module.link_objects.items) |link_object| {
1110+
if (prev_has_xflag and link_object != .c_source_file and link_object != .c_source_files and link_object != .assembly_file) {
1111+
try zig_args.append("-x");
1112+
try zig_args.append("none");
1113+
prev_has_xflag = false;
1114+
}
1115+
11091116
switch (link_object) {
11101117
.static_path => |static_path| {
11111118
if (my_responsibility) {
@@ -1236,7 +1243,19 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
12361243
try zig_args.append("--");
12371244
prev_has_cflags = false;
12381245
}
1239-
try zig_args.append(asm_file.getPath2(dep.module.owner, step));
1246+
1247+
if (asm_file.lang) |lang| {
1248+
assert(lang == .assembly or lang == .assembly_with_cpp);
1249+
try zig_args.append("-x");
1250+
try zig_args.append(lang.getLangName());
1251+
prev_has_xflag = true;
1252+
} else if (prev_has_xflag) {
1253+
try zig_args.append("-x");
1254+
try zig_args.append("none");
1255+
prev_has_xflag = false;
1256+
}
1257+
1258+
try zig_args.append(asm_file.file.getPath2(dep.module.owner, step));
12401259
total_linker_objects += 1;
12411260
},
12421261

@@ -1257,6 +1276,17 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
12571276
try zig_args.append("--");
12581277
prev_has_cflags = true;
12591278
}
1279+
1280+
if (c_source_file.lang) |lang| {
1281+
try zig_args.append("-x");
1282+
try zig_args.append(lang.getLangName());
1283+
prev_has_xflag = true;
1284+
} else if (prev_has_xflag) {
1285+
try zig_args.append("-x");
1286+
try zig_args.append("none");
1287+
prev_has_xflag = false;
1288+
}
1289+
12601290
try zig_args.append(c_source_file.file.getPath2(dep.module.owner, step));
12611291
total_linker_objects += 1;
12621292
},
@@ -1279,6 +1309,16 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
12791309
prev_has_cflags = true;
12801310
}
12811311

1312+
if (c_source_files.lang) |lang| {
1313+
try zig_args.append("-x");
1314+
try zig_args.append(lang.getLangName());
1315+
prev_has_xflag = true;
1316+
} else if (prev_has_xflag) {
1317+
try zig_args.append("-x");
1318+
try zig_args.append("none");
1319+
prev_has_xflag = false;
1320+
}
1321+
12821322
const root_path = c_source_files.root.getPath2(dep.module.owner, step);
12831323
for (c_source_files.files) |file| {
12841324
try zig_args.append(b.pathJoin(&.{ root_path, file }));
@@ -1308,6 +1348,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
13081348
try zig_args.append("--");
13091349
prev_has_rcflags = true;
13101350
}
1351+
13111352
try zig_args.append(rc_source_file.file.getPath2(dep.module.owner, step));
13121353
total_linker_objects += 1;
13131354
},

test/link/link.zig

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ fn addCompileStep(
119119
});
120120
}
121121
if (overlay.asm_source_bytes) |bytes| {
122-
compile_step.addAssemblyFile(b.addWriteFiles().add("a.s", bytes));
122+
compile_step.addAssemblyFile(.{ .file = b.addWriteFiles().add("a.s", bytes) });
123123
}
124124
return compile_step;
125125
}
@@ -147,7 +147,7 @@ pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {
147147
const b = comp.step.owner;
148148
const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");
149149
const file = WriteFile.create(b).add("a.s", actual_bytes);
150-
comp.addAssemblyFile(file);
150+
comp.addAssemblyFile(.{ .file = file });
151151
}
152152

153153
pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void {

test/src/CompareOutput.zig

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void {
101101
.target = b.graph.host,
102102
.optimize = .Debug,
103103
});
104-
exe.addAssemblyFile(first_file);
104+
exe.addAssemblyFile(.{ .file = first_file });
105105

106106
const run = b.addRunArtifact(exe);
107107
run.setName(annotated_case_name);

0 commit comments

Comments
 (0)