mirror of
https://github.com/ziglang/zig.git
synced 2025-01-21 17:31:12 +00:00
zig run/cc: recognize "-x language"
This commit adds support for "-x language" for a couple of hand-picked supported languages. There is no reason the list of supported languages to not grow (e.g. add "c-header"), but I'd like to keep it small at the start. Alternative 1 ------------- I first tried to add a new type "Language", and then add that to the `CSourceFile`. But oh boy what a change it turns out to be. So I am keeping myself tied to FileExt and see what you folks think. Alternative 2 ------------- I tried adding `Language: ?[]const u8` to `CSourceFile`. However, the language/ext, whatever we want to call it, still needs to be interpreted in the main loop: one kind of handling for source files, other kind of handling for everything else. Test case --------- *standalone.c* #include <iostream> int main() { std::cout << "elho\n"; } Compile and run: $ ./zig run -x c++ -lc++ standalone.c elho $ ./zig c++ -x c++ standalone.c -o standalone && ./standalone elho Fixes #10915
This commit is contained in:
parent
d813cef42a
commit
6b3f59c3a7
@ -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.
|
/// For passing to a C compiler.
|
||||||
pub const CSourceFile = struct {
|
pub const CSourceFile = struct {
|
||||||
src_path: []const u8,
|
src_path: []const u8,
|
||||||
extra_flags: []const []const u8 = &.{},
|
extra_flags: []const []const u8 = &.{},
|
||||||
/// Same as extra_flags except they are not added to the Cache hash.
|
/// Same as extra_flags except they are not added to the Cache hash.
|
||||||
cache_exempt_flags: []const []const u8 = &.{},
|
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) {
|
const Job = union(enum) {
|
||||||
@ -2612,6 +2630,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
|
|||||||
|
|
||||||
for (comp.c_object_table.keys()) |key| {
|
for (comp.c_object_table.keys()) |key| {
|
||||||
_ = try man.addFile(key.src.src_path, null);
|
_ = try man.addFile(key.src.src_path, null);
|
||||||
|
man.hash.addOptional(key.src.ext);
|
||||||
man.hash.addListOfBytes(key.src.extra_flags);
|
man.hash.addListOfBytes(key.src.extra_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3926,14 +3945,23 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
|
|||||||
break :e o_ext;
|
break :e o_ext;
|
||||||
};
|
};
|
||||||
const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext });
|
const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext });
|
||||||
|
const ext = c_object.src.ext orelse classifyFileExt(c_object.src.src_path);
|
||||||
|
|
||||||
try argv.appendSlice(&[_][]const u8{
|
try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
|
||||||
self_exe_path,
|
// if "ext" is explicit, add "-x <lang>". Otherwise let clang do its thing.
|
||||||
"clang",
|
if (c_object.src.ext != null) {
|
||||||
c_object.src.src_path,
|
try argv.appendSlice(&[_][]const u8{ "-x", switch (ext) {
|
||||||
});
|
.assembly => "assembler",
|
||||||
|
.assembly_with_cpp => "assembler-with-cpp",
|
||||||
const ext = classifyFileExt(c_object.src.src_path);
|
.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
|
// 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
|
// this compilation is to perform a single zig cc operation. This means
|
||||||
@ -4395,7 +4423,7 @@ pub fn addCCArgs(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig => {},
|
.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
|
// 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
|
// compiler frontend does. Therefore we must hard-code the -m flags for
|
||||||
// all CPU features here.
|
// all CPU features here.
|
||||||
@ -4535,6 +4563,7 @@ pub const FileExt = enum {
|
|||||||
ll,
|
ll,
|
||||||
bc,
|
bc,
|
||||||
assembly,
|
assembly,
|
||||||
|
assembly_with_cpp,
|
||||||
shared_library,
|
shared_library,
|
||||||
object,
|
object,
|
||||||
static_library,
|
static_library,
|
||||||
@ -4549,6 +4578,7 @@ pub const FileExt = enum {
|
|||||||
.ll,
|
.ll,
|
||||||
.bc,
|
.bc,
|
||||||
.assembly,
|
.assembly,
|
||||||
|
.assembly_with_cpp,
|
||||||
.shared_library,
|
.shared_library,
|
||||||
.object,
|
.object,
|
||||||
.static_library,
|
.static_library,
|
||||||
@ -4588,10 +4618,6 @@ pub fn hasObjCppExt(filename: []const u8) bool {
|
|||||||
return mem.endsWith(u8, filename, ".mm");
|
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 {
|
pub fn hasSharedLibraryExt(filename: []const u8) bool {
|
||||||
if (mem.endsWith(u8, filename, ".so") or
|
if (mem.endsWith(u8, filename, ".so") or
|
||||||
mem.endsWith(u8, filename, ".dll") or
|
mem.endsWith(u8, filename, ".dll") or
|
||||||
@ -4632,8 +4658,10 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
|
|||||||
return .ll;
|
return .ll;
|
||||||
} else if (mem.endsWith(u8, filename, ".bc")) {
|
} else if (mem.endsWith(u8, filename, ".bc")) {
|
||||||
return .bc;
|
return .bc;
|
||||||
} else if (hasAsmExt(filename)) {
|
} else if (mem.endsWith(u8, filename, ".s")) {
|
||||||
return .assembly;
|
return .assembly;
|
||||||
|
} else if (mem.endsWith(u8, filename, ".S")) {
|
||||||
|
return .assembly_with_cpp;
|
||||||
} else if (mem.endsWith(u8, filename, ".h")) {
|
} else if (mem.endsWith(u8, filename, ".h")) {
|
||||||
return .h;
|
return .h;
|
||||||
} else if (mem.endsWith(u8, filename, ".zig")) {
|
} else if (mem.endsWith(u8, filename, ".zig")) {
|
||||||
|
@ -7171,6 +7171,13 @@ joinpd1("d"),
|
|||||||
.psl = true,
|
.psl = true,
|
||||||
},
|
},
|
||||||
jspd1("u"),
|
jspd1("u"),
|
||||||
jspd1("x"),
|
.{
|
||||||
|
.name = "x",
|
||||||
|
.syntax = .joined_or_separate,
|
||||||
|
.zig_equivalent = .x,
|
||||||
|
.pd1 = true,
|
||||||
|
.pd2 = false,
|
||||||
|
.psl = false,
|
||||||
|
},
|
||||||
joinpd1("y"),
|
joinpd1("y"),
|
||||||
};};
|
};};
|
||||||
|
@ -48,7 +48,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
|
|||||||
try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "include" }),
|
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.
|
else => unreachable, // You can see the entire list of files just above.
|
||||||
}
|
}
|
||||||
try cflags.append("-I");
|
try cflags.append("-I");
|
||||||
|
81
src/main.zig
81
src/main.zig
@ -391,6 +391,7 @@ const usage_build_generic =
|
|||||||
\\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses
|
\\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses
|
||||||
\\ small|kernel|
|
\\ small|kernel|
|
||||||
\\ medium|large]
|
\\ medium|large]
|
||||||
|
\\ -x language Treat subsequent input files as having type <language>
|
||||||
\\ -mred-zone Force-enable the "red-zone"
|
\\ -mred-zone Force-enable the "red-zone"
|
||||||
\\ -mno-red-zone Force-disable the "red-zone"
|
\\ -mno-red-zone Force-disable the "red-zone"
|
||||||
\\ -fomit-frame-pointer Omit the stack frame pointer
|
\\ -fomit-frame-pointer Omit the stack frame pointer
|
||||||
@ -913,6 +914,7 @@ fn buildOutputType(
|
|||||||
var cssan = ClangSearchSanitizer.init(gpa, &clang_argv);
|
var cssan = ClangSearchSanitizer.init(gpa, &clang_argv);
|
||||||
defer cssan.map.deinit();
|
defer cssan.map.deinit();
|
||||||
|
|
||||||
|
var file_ext: ?Compilation.FileExt = null;
|
||||||
args_loop: while (args_iter.next()) |arg| {
|
args_loop: while (args_iter.next()) |arg| {
|
||||||
if (mem.startsWith(u8, arg, "@")) {
|
if (mem.startsWith(u8, arg, "@")) {
|
||||||
// This is a "compiler response file". We must parse the file and treat its
|
// This is a "compiler response file". We must parse the file and treat its
|
||||||
@ -1401,6 +1403,15 @@ fn buildOutputType(
|
|||||||
try clang_argv.append(arg);
|
try clang_argv.append(arg);
|
||||||
} else if (mem.startsWith(u8, arg, "-I")) {
|
} else if (mem.startsWith(u8, arg, "-I")) {
|
||||||
try cssan.addIncludePath(.I, arg, arg[2..], true);
|
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=")) {
|
} else if (mem.startsWith(u8, arg, "-mexec-model=")) {
|
||||||
wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, arg["-mexec-model=".len..]) orelse {
|
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..]});
|
fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{arg["-mexec-model=".len..]});
|
||||||
@ -1408,22 +1419,21 @@ fn buildOutputType(
|
|||||||
} else {
|
} else {
|
||||||
fatal("unrecognized parameter: '{s}'", .{arg});
|
fatal("unrecognized parameter: '{s}'", .{arg});
|
||||||
}
|
}
|
||||||
} else switch (Compilation.classifyFileExt(arg)) {
|
} else switch (file_ext orelse
|
||||||
.object, .static_library, .shared_library => {
|
Compilation.classifyFileExt(arg)) {
|
||||||
try link_objects.append(.{ .path = arg });
|
.object, .static_library, .shared_library => try link_objects.append(.{ .path = arg }),
|
||||||
},
|
.assembly, .assembly_with_cpp, .c, .cpp, .h, .ll, .bc, .m, .mm, .cu => {
|
||||||
.assembly, .c, .cpp, .h, .ll, .bc, .m, .mm, .cu => {
|
|
||||||
try c_source_files.append(.{
|
try c_source_files.append(.{
|
||||||
.src_path = arg,
|
.src_path = arg,
|
||||||
.extra_flags = try arena.dupe([]const u8, extra_cflags.items),
|
.extra_flags = try arena.dupe([]const u8, extra_cflags.items),
|
||||||
|
// duped when parsing the args.
|
||||||
|
.ext = file_ext,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.zig => {
|
.zig => {
|
||||||
if (root_src_file) |other| {
|
if (root_src_file) |other| {
|
||||||
fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
|
fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
|
||||||
} else {
|
} else root_src_file = arg;
|
||||||
root_src_file = arg;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.def, .unknown => {
|
.def, .unknown => {
|
||||||
fatal("unrecognized file extension of parameter '{s}'", .{arg});
|
fatal("unrecognized file extension of parameter '{s}'", .{arg});
|
||||||
@ -1464,6 +1474,7 @@ fn buildOutputType(
|
|||||||
var needed = false;
|
var needed = false;
|
||||||
var must_link = false;
|
var must_link = false;
|
||||||
var force_static_libs = false;
|
var force_static_libs = false;
|
||||||
|
var file_ext: ?Compilation.FileExt = null;
|
||||||
while (it.has_next) {
|
while (it.has_next) {
|
||||||
it.next() catch |err| {
|
it.next() catch |err| {
|
||||||
fatal("unable to parse command line parameters: {s}", .{@errorName(err)});
|
fatal("unable to parse command line parameters: {s}", .{@errorName(err)});
|
||||||
@ -1484,32 +1495,39 @@ fn buildOutputType(
|
|||||||
.asm_only => c_out_mode = .assembly, // -S
|
.asm_only => c_out_mode = .assembly, // -S
|
||||||
.preprocess_only => c_out_mode = .preprocessor, // -E
|
.preprocess_only => c_out_mode = .preprocessor, // -E
|
||||||
.emit_llvm => emit_llvm = true,
|
.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 => {
|
.other => {
|
||||||
try clang_argv.appendSlice(it.other_args);
|
try clang_argv.appendSlice(it.other_args);
|
||||||
},
|
},
|
||||||
.positional => {
|
.positional => switch (file_ext orelse
|
||||||
const file_ext = Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0));
|
Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) {
|
||||||
switch (file_ext) {
|
.assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .m, .mm, .cu => {
|
||||||
.assembly, .c, .cpp, .ll, .bc, .h, .m, .mm, .cu => {
|
try c_source_files.append(.{
|
||||||
try c_source_files.append(.{ .src_path = it.only_arg });
|
.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,
|
.unknown, .shared_library, .object, .static_library => try link_objects.append(.{
|
||||||
.must_link = must_link,
|
.path = it.only_arg,
|
||||||
});
|
.must_link = must_link,
|
||||||
},
|
}),
|
||||||
.def => {
|
.def => {
|
||||||
linker_module_definition_file = it.only_arg;
|
linker_module_definition_file = it.only_arg;
|
||||||
},
|
},
|
||||||
.zig => {
|
.zig => {
|
||||||
if (root_src_file) |other| {
|
if (root_src_file) |other| {
|
||||||
fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
|
fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
|
||||||
} else {
|
} else root_src_file = it.only_arg;
|
||||||
root_src_file = it.only_arg;
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.l => {
|
.l => {
|
||||||
// -l
|
// -l
|
||||||
@ -4860,6 +4878,7 @@ pub const ClangArgIterator = struct {
|
|||||||
o,
|
o,
|
||||||
c,
|
c,
|
||||||
m,
|
m,
|
||||||
|
x,
|
||||||
other,
|
other,
|
||||||
positional,
|
positional,
|
||||||
l,
|
l,
|
||||||
|
@ -500,6 +500,10 @@ const known_options = [_]KnownOpt{
|
|||||||
.name = "undefined",
|
.name = "undefined",
|
||||||
.ident = "undefined",
|
.ident = "undefined",
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
.name = "x",
|
||||||
|
.ident = "x",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const blacklisted_options = [_][]const u8{};
|
const blacklisted_options = [_][]const u8{};
|
||||||
|
Loading…
Reference in New Issue
Block a user