Skip to content

zig run/cc: recognize "-x language" #13544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,30 @@ pub const CRTFile = struct {
}
};

// supported languages for "zig clang -x <lang>".
// Loosely based on llvm-project/clang/include/clang/Driver/Types.def
pub const LangToExt = std.ComptimeStringMap(FileExt, .{
.{ "c", .c },
.{ "c-header", .h },
.{ "c++", .cpp },
.{ "c++-header", .h },
.{ "objective-c", .m },
.{ "objective-c-header", .h },
.{ "objective-c++", .mm },
.{ "objective-c++-header", .h },
.{ "assembler", .assembly },
.{ "assembler-with-cpp", .assembly_with_cpp },
.{ "cuda", .cu },
});

/// For passing to a C compiler.
pub const CSourceFile = struct {
src_path: []const u8,
extra_flags: []const []const u8 = &.{},
/// Same as extra_flags except they are not added to the Cache hash.
cache_exempt_flags: []const []const u8 = &.{},
// this field is non-null iff language was explicitly set with "-x lang".
ext: ?FileExt = null,
};

const Job = union(enum) {
Expand Down Expand Up @@ -2612,6 +2630,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes

for (comp.c_object_table.keys()) |key| {
_ = try man.addFile(key.src.src_path, null);
man.hash.addOptional(key.src.ext);
man.hash.addListOfBytes(key.src.extra_flags);
}

Expand Down Expand Up @@ -3926,14 +3945,23 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
break :e o_ext;
};
const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext });

try argv.appendSlice(&[_][]const u8{
self_exe_path,
"clang",
c_object.src.src_path,
});

const ext = classifyFileExt(c_object.src.src_path);
const ext = c_object.src.ext orelse classifyFileExt(c_object.src.src_path);

try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
// if "ext" is explicit, add "-x <lang>". Otherwise let clang do its thing.
if (c_object.src.ext != null) {
try argv.appendSlice(&[_][]const u8{ "-x", switch (ext) {
.assembly => "assembler",
.assembly_with_cpp => "assembler-with-cpp",
.c => "c",
.cpp => "c++",
.cu => "cuda",
.m => "objective-c",
.mm => "objective-c++",
else => fatal("language '{s}' is unsupported in this context", .{@tagName(ext)}),
} });
}
try argv.append(c_object.src.src_path);

// When all these flags are true, it means that the entire purpose of
// this compilation is to perform a single zig cc operation. This means
Expand Down Expand Up @@ -4395,7 +4423,7 @@ pub fn addCCArgs(
}
},
.shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig => {},
.assembly => {
.assembly, .assembly_with_cpp => {
// The Clang assembler does not accept the list of CPU features like the
// compiler frontend does. Therefore we must hard-code the -m flags for
// all CPU features here.
Expand Down Expand Up @@ -4535,6 +4563,7 @@ pub const FileExt = enum {
ll,
bc,
assembly,
assembly_with_cpp,
shared_library,
object,
static_library,
Expand All @@ -4549,6 +4578,7 @@ pub const FileExt = enum {
.ll,
.bc,
.assembly,
.assembly_with_cpp,
.shared_library,
.object,
.static_library,
Expand Down Expand Up @@ -4588,10 +4618,6 @@ pub fn hasObjCppExt(filename: []const u8) bool {
return mem.endsWith(u8, filename, ".mm");
}

pub fn hasAsmExt(filename: []const u8) bool {
return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
}

pub fn hasSharedLibraryExt(filename: []const u8) bool {
if (mem.endsWith(u8, filename, ".so") or
mem.endsWith(u8, filename, ".dll") or
Expand Down Expand Up @@ -4632,8 +4658,10 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
return .ll;
} else if (mem.endsWith(u8, filename, ".bc")) {
return .bc;
} else if (hasAsmExt(filename)) {
} else if (mem.endsWith(u8, filename, ".s")) {
return .assembly;
} else if (mem.endsWith(u8, filename, ".S")) {
return .assembly_with_cpp;
} else if (mem.endsWith(u8, filename, ".h")) {
return .h;
} else if (mem.endsWith(u8, filename, ".zig")) {
Expand Down
9 changes: 8 additions & 1 deletion src/clang_options_data.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7171,6 +7171,13 @@ joinpd1("d"),
.psl = true,
},
jspd1("u"),
jspd1("x"),
.{
.name = "x",
.syntax = .joined_or_separate,
.zig_equivalent = .x,
.pd1 = true,
.pd2 = false,
.psl = false,
},
joinpd1("y"),
};};
2 changes: 1 addition & 1 deletion src/libunwind.zig
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "include" }),
});
},
.assembly => {},
.assembly_with_cpp => {},
else => unreachable, // You can see the entire list of files just above.
}
try cflags.append("-I");
Expand Down
81 changes: 50 additions & 31 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ const usage_build_generic =
\\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses
\\ small|kernel|
\\ medium|large]
\\ -x language Treat subsequent input files as having type <language>
\\ -mred-zone Force-enable the "red-zone"
\\ -mno-red-zone Force-disable the "red-zone"
\\ -fomit-frame-pointer Omit the stack frame pointer
Expand Down Expand Up @@ -913,6 +914,7 @@ fn buildOutputType(
var cssan = ClangSearchSanitizer.init(gpa, &clang_argv);
defer cssan.map.deinit();

var file_ext: ?Compilation.FileExt = null;
args_loop: while (args_iter.next()) |arg| {
if (mem.startsWith(u8, arg, "@")) {
// This is a "compiler response file". We must parse the file and treat its
Expand Down Expand Up @@ -1401,29 +1403,37 @@ fn buildOutputType(
try clang_argv.append(arg);
} else if (mem.startsWith(u8, arg, "-I")) {
try cssan.addIncludePath(.I, arg, arg[2..], true);
} else if (mem.eql(u8, arg, "-x")) {
const lang = args_iter.nextOrFatal();
if (mem.eql(u8, lang, "none")) {
file_ext = null;
} else if (Compilation.LangToExt.get(lang)) |got_ext| {
file_ext = got_ext;
} else {
fatal("language not recognized: '{s}'", .{lang});
}
} else if (mem.startsWith(u8, arg, "-mexec-model=")) {
wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, arg["-mexec-model=".len..]) orelse {
fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{arg["-mexec-model=".len..]});
};
} else {
fatal("unrecognized parameter: '{s}'", .{arg});
}
} else switch (Compilation.classifyFileExt(arg)) {
.object, .static_library, .shared_library => {
try link_objects.append(.{ .path = arg });
},
.assembly, .c, .cpp, .h, .ll, .bc, .m, .mm, .cu => {
} else switch (file_ext orelse
Compilation.classifyFileExt(arg)) {
.object, .static_library, .shared_library => try link_objects.append(.{ .path = arg }),
.assembly, .assembly_with_cpp, .c, .cpp, .h, .ll, .bc, .m, .mm, .cu => {
try c_source_files.append(.{
.src_path = arg,
.extra_flags = try arena.dupe([]const u8, extra_cflags.items),
// duped when parsing the args.
.ext = file_ext,
});
},
.zig => {
if (root_src_file) |other| {
fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
} else {
root_src_file = arg;
}
} else root_src_file = arg;
},
.def, .unknown => {
fatal("unrecognized file extension of parameter '{s}'", .{arg});
Expand Down Expand Up @@ -1464,6 +1474,7 @@ fn buildOutputType(
var needed = false;
var must_link = false;
var force_static_libs = false;
var file_ext: ?Compilation.FileExt = null;
while (it.has_next) {
it.next() catch |err| {
fatal("unable to parse command line parameters: {s}", .{@errorName(err)});
Expand All @@ -1484,32 +1495,39 @@ fn buildOutputType(
.asm_only => c_out_mode = .assembly, // -S
.preprocess_only => c_out_mode = .preprocessor, // -E
.emit_llvm => emit_llvm = true,
.x => {
const lang = mem.sliceTo(it.only_arg, 0);
if (mem.eql(u8, lang, "none")) {
file_ext = null;
} else if (Compilation.LangToExt.get(lang)) |got_ext| {
file_ext = got_ext;
} else {
fatal("language not recognized: '{s}'", .{lang});
}
},
.other => {
try clang_argv.appendSlice(it.other_args);
},
.positional => {
const file_ext = Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0));
switch (file_ext) {
.assembly, .c, .cpp, .ll, .bc, .h, .m, .mm, .cu => {
try c_source_files.append(.{ .src_path = it.only_arg });
},
.unknown, .shared_library, .object, .static_library => {
try link_objects.append(.{
.path = it.only_arg,
.must_link = must_link,
});
},
.def => {
linker_module_definition_file = it.only_arg;
},
.zig => {
if (root_src_file) |other| {
fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
} else {
root_src_file = it.only_arg;
}
},
}
.positional => switch (file_ext orelse
Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) {
.assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .m, .mm, .cu => {
try c_source_files.append(.{
.src_path = it.only_arg,
.ext = file_ext, // duped while parsing the args.
});
},
.unknown, .shared_library, .object, .static_library => try link_objects.append(.{
.path = it.only_arg,
.must_link = must_link,
}),
.def => {
linker_module_definition_file = it.only_arg;
},
.zig => {
if (root_src_file) |other| {
fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
} else root_src_file = it.only_arg;
},
},
.l => {
// -l
Expand Down Expand Up @@ -4860,6 +4878,7 @@ pub const ClangArgIterator = struct {
o,
c,
m,
x,
other,
positional,
l,
Expand Down
4 changes: 4 additions & 0 deletions tools/update_clang_options.zig
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,10 @@ const known_options = [_]KnownOpt{
.name = "undefined",
.ident = "undefined",
},
.{
.name = "x",
.ident = "x",
},
};

const blacklisted_options = [_][]const u8{};
Expand Down