mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
Add TargetDetails abstraction
This commit is contained in:
parent
79a2747de4
commit
c61856ebcf
@ -1199,8 +1199,7 @@ pub const LibExeObjStep = struct {
|
||||
|
||||
subsystem: ?builtin.SubSystem = null,
|
||||
|
||||
cpu: ?[]const u8 = null,
|
||||
features: ?[]const u8 = null,
|
||||
target_details: ?std.target.TargetDetails = null,
|
||||
|
||||
const LinkObject = union(enum) {
|
||||
StaticPath: []const u8,
|
||||
@ -1387,21 +1386,8 @@ pub const LibExeObjStep = struct {
|
||||
self.computeOutFileNames();
|
||||
}
|
||||
|
||||
pub fn setCpu(self: *LibExeObjStep, cpu: *const std.target.Cpu) void {
|
||||
self.cpu = cpu.name;
|
||||
}
|
||||
|
||||
pub fn setFeatures(self: *LibExeObjStep, features: []*const std.target.Feature) void {
|
||||
var features_str_buffer = std.Buffer.init(self.builder.allocator, "") catch unreachable;
|
||||
defer features_str_buffer.deinit();
|
||||
|
||||
for (features) |feature| {
|
||||
features_str_buffer.append("+") catch unreachable;
|
||||
features_str_buffer.append(feature.name) catch unreachable;
|
||||
features_str_buffer.append(",") catch unreachable;
|
||||
}
|
||||
|
||||
self.features = features_str_buffer.toOwnedSlice();
|
||||
pub fn setTargetDetails(self: *LibExeObjStep, target_details: std.target.TargetDetails) void {
|
||||
self.target_details = target_details;
|
||||
}
|
||||
|
||||
pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void {
|
||||
@ -1994,14 +1980,20 @@ pub const LibExeObjStep = struct {
|
||||
},
|
||||
}
|
||||
|
||||
if (self.cpu) |cpu| {
|
||||
try zig_args.append("--cpu");
|
||||
try zig_args.append(cpu);
|
||||
}
|
||||
|
||||
if (self.features) |features| {
|
||||
try zig_args.append("--features");
|
||||
try zig_args.append(features);
|
||||
if (self.target_details) |td| {
|
||||
switch (td) {
|
||||
.cpu => |cpu| {
|
||||
try zig_args.append("--cpu");
|
||||
try zig_args.append(cpu.name);
|
||||
},
|
||||
.features => |features| {
|
||||
try zig_args.append("--features");
|
||||
for (features) |feature| {
|
||||
try zig_args.append(feature.name);
|
||||
try zig_args.append(",");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (self.target_glibc) |ver| {
|
||||
|
||||
@ -860,6 +860,7 @@ pub const x86 = @import("target/x86.zig");
|
||||
|
||||
pub const Feature = struct {
|
||||
name: []const u8,
|
||||
llvm_name: []const u8,
|
||||
description: []const u8,
|
||||
|
||||
dependencies: []*const Feature,
|
||||
@ -872,6 +873,11 @@ pub const Cpu = struct {
|
||||
dependencies: []*const Feature,
|
||||
};
|
||||
|
||||
pub const TargetDetails = union(enum) {
|
||||
cpu: *const Cpu,
|
||||
features: []*const Feature,
|
||||
};
|
||||
|
||||
pub fn getFeaturesForArch(arch: @TagType(Target.Arch)) []*const Feature {
|
||||
return switch (arch) {
|
||||
.arm, .armeb, .thumb, .thumbeb => arm.features,
|
||||
|
||||
@ -530,13 +530,13 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_list_features_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_subfeatures: bool) void {
|
||||
printFeaturesForArch(arch_name_ptr[0..arch_name_len], show_subfeatures) catch |err| {
|
||||
export fn stage2_list_features_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_dependencies: bool) void {
|
||||
printFeaturesForArch(arch_name_ptr[0..arch_name_len], show_dependencies) catch |err| {
|
||||
std.debug.warn("Failed to list features: {}\n", .{ @errorName(err) });
|
||||
};
|
||||
}
|
||||
|
||||
fn printFeaturesForArch(arch_name: []const u8, show_subfeatures: bool) !void {
|
||||
fn printFeaturesForArch(arch_name: []const u8, show_dependencies: bool) !void {
|
||||
const stdout_stream = &std.io.getStdOut().outStream().stream;
|
||||
|
||||
const arch = Target.parseArchTag(arch_name) catch {
|
||||
@ -565,22 +565,22 @@ fn printFeaturesForArch(arch_name: []const u8, show_subfeatures: bool) !void {
|
||||
|
||||
try stdout_stream.print(" - {}\n", .{ feature.description });
|
||||
|
||||
if (show_subfeatures and feature.subfeatures.len > 0) {
|
||||
for (feature.subfeatures) |subfeature| {
|
||||
try stdout_stream.print(" {}\n", .{ subfeature.name });
|
||||
if (show_dependencies and feature.dependencies.len > 0) {
|
||||
for (feature.dependencies) |dependency| {
|
||||
try stdout_stream.print(" {}\n", .{ dependency.name });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_list_cpus_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_subfeatures: bool) void {
|
||||
printCpusForArch(arch_name_ptr[0..arch_name_len], show_subfeatures) catch |err| {
|
||||
export fn stage2_list_cpus_for_arch(arch_name_ptr: [*]const u8, arch_name_len: usize, show_dependencies: bool) void {
|
||||
printCpusForArch(arch_name_ptr[0..arch_name_len], show_dependencies) catch |err| {
|
||||
std.debug.warn("Failed to list features: {}\n", .{ @errorName(err) });
|
||||
};
|
||||
}
|
||||
|
||||
fn printCpusForArch(arch_name: []const u8, show_subfeatures: bool) !void {
|
||||
fn printCpusForArch(arch_name: []const u8, show_dependencies: bool) !void {
|
||||
const stdout_stream = &std.io.getStdOut().outStream().stream;
|
||||
|
||||
const arch = Target.parseArchTag(arch_name) catch {
|
||||
@ -609,99 +609,158 @@ fn printCpusForArch(arch_name: []const u8, show_subfeatures: bool) !void {
|
||||
|
||||
try stdout_stream.write("\n");
|
||||
|
||||
if (show_subfeatures and cpu.subfeatures.len > 0) {
|
||||
for (cpu.subfeatures) |subfeature| {
|
||||
try stdout_stream.print(" {}\n", .{ subfeature.name });
|
||||
if (show_dependencies and cpu.dependencies.len > 0) {
|
||||
for (cpu.dependencies) |dependency| {
|
||||
try stdout_stream.print(" {}\n", .{ dependency.name });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// use target_arch_name(ZigLLVM_ArchType) to get name from main.cpp 'target'.
|
||||
// ABI warning
|
||||
export fn stage2_validate_cpu_and_features(
|
||||
arch_name: [*:0]const u8,
|
||||
cpu: ?[*:0]const u8,
|
||||
features: ?[*:0]const u8,
|
||||
) bool {
|
||||
const arch = Target.parseArchTag(std.mem.toSliceConst(u8, arch_name)) catch {
|
||||
std.debug.warn("Failed to parse arch '{}'\nInvoke 'zig targets' for a list of valid architectures\n", .{ arch_name });
|
||||
return false;
|
||||
};
|
||||
|
||||
const res = validateCpuAndFeatures(
|
||||
arch,
|
||||
if (cpu) |def_cpu| std.mem.toSliceConst(u8, def_cpu) else "",
|
||||
if (features) |def_features| std.mem.toSliceConst(u8, def_features) else "");
|
||||
|
||||
switch (res) {
|
||||
.Ok => return true,
|
||||
.InvalidCpu => |invalid_cpu| {
|
||||
std.debug.warn("Invalid CPU '{}'\n", .{ invalid_cpu });
|
||||
return false;
|
||||
},
|
||||
.InvalidFeaturesString => {
|
||||
std.debug.warn("Invalid features string\n", .{});
|
||||
std.debug.warn("Must have format \"+yes_feature,-no_feature\"\n", .{});
|
||||
return false;
|
||||
},
|
||||
.InvalidFeature => |invalid_feature| {
|
||||
std.debug.warn("Invalid feature '{}'\n", .{ invalid_feature });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ValidateCpuAndFeaturesResult = union(enum) {
|
||||
Ok,
|
||||
InvalidCpu: []const u8,
|
||||
InvalidFeaturesString,
|
||||
InvalidFeature: []const u8,
|
||||
const Stage2TargetDetails = struct {
|
||||
allocator: *std.mem.Allocator,
|
||||
target_details: std.target.TargetDetails,
|
||||
|
||||
llvm_cpu_str: [:0]const u8,
|
||||
llvm_features_str: [:0]const u8,
|
||||
};
|
||||
|
||||
fn validateCpuAndFeatures(arch: @TagType(std.Target.Arch), cpu: []const u8, features: []const u8) ValidateCpuAndFeaturesResult {
|
||||
// ABI warning
|
||||
export fn stage2_target_details_parse_cpu(arch_str: ?[*:0]const u8, cpu_str: ?[*:0]const u8) ?*Stage2TargetDetails {
|
||||
if (cpu_str == null) return null;
|
||||
if (arch_str == null) return null;
|
||||
|
||||
const known_cpus = std.target.getCpusForArch(arch);
|
||||
const known_features = std.target.getFeaturesForArch(arch);
|
||||
const arch = Target.parseArchTag(std.mem.toSliceConst(u8, arch_str.?)) catch {
|
||||
return null;
|
||||
};
|
||||
return parseCpu(arch, std.mem.toSliceConst(u8, cpu_str.?)) catch |err| {
|
||||
switch (err) {
|
||||
error.OutOfMemory => @panic("out of memory"),
|
||||
else => return null,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_target_details_parse_features(arch_str: ?[*:0]const u8, features_str: ?[*:0]const u8) ?*Stage2TargetDetails {
|
||||
if (features_str == null) return null;
|
||||
if (arch_str == null) return null;
|
||||
|
||||
if (cpu.len > 0) {
|
||||
var found_cpu = false;
|
||||
for (known_cpus) |known_cpu| {
|
||||
if (std.mem.eql(u8, cpu, known_cpu.name)) {
|
||||
found_cpu = true;
|
||||
const arch = Target.parseArchTag(std.mem.toSliceConst(u8, arch_str.?)) catch return null;
|
||||
return parseFeatures(arch, std.mem.toSliceConst(u8, features_str.?)) catch |err| {
|
||||
switch (err) {
|
||||
error.OutOfMemory => @panic("out of memory"),
|
||||
else => return null,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn parseCpu(arch: @TagType(std.Target.Arch), str: []const u8) !*Stage2TargetDetails {
|
||||
const cpus = std.target.getCpusForArch(arch);
|
||||
|
||||
for (cpus) |cpu| {
|
||||
if (std.mem.eql(u8, str, cpu.name)) {
|
||||
const allocator = std.heap.c_allocator;
|
||||
|
||||
const ptr = try allocator.create(Stage2TargetDetails);
|
||||
ptr.* = .{
|
||||
.allocator = allocator,
|
||||
.target_details = .{
|
||||
.cpu = cpu,
|
||||
},
|
||||
.llvm_cpu_str = cpu.name,
|
||||
.llvm_features_str = "",
|
||||
};
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return error.InvalidCpu;
|
||||
}
|
||||
|
||||
fn parseFeatures(arch: @TagType(std.Target.Arch), str: []const u8) !*Stage2TargetDetails {
|
||||
const allocator = std.heap.c_allocator;
|
||||
|
||||
const known_features = std.target.getFeaturesForArch(arch);
|
||||
|
||||
var features = std.ArrayList(*const std.target.Feature).init(allocator);
|
||||
defer features.deinit();
|
||||
|
||||
var start: usize = 0;
|
||||
while (start < str.len) {
|
||||
const next_comma_pos = std.mem.indexOfScalar(u8, str[start..], ',') orelse str.len - start;
|
||||
const feature_str = std.mem.trim(u8, str[start..start+next_comma_pos], " ");
|
||||
|
||||
start += next_comma_pos + 1;
|
||||
|
||||
if (feature_str.len == 0) continue;
|
||||
|
||||
var feature: ?*const std.target.Feature = null;
|
||||
for (known_features) |known_feature| {
|
||||
if (std.mem.eql(u8, feature_str, known_feature.name)) {
|
||||
feature = known_feature;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_cpu) {
|
||||
return .{ .InvalidCpu = cpu };
|
||||
if (feature) |f| {
|
||||
features.append(f) catch @panic("out of memory");
|
||||
} else {
|
||||
return error.InvalidFeature;
|
||||
}
|
||||
}
|
||||
|
||||
const features_slice = features.toOwnedSlice();
|
||||
|
||||
if (features.len > 0) {
|
||||
var start: usize = 0;
|
||||
while (start < features.len) {
|
||||
const next_comma_pos = std.mem.indexOfScalar(u8, features[start..], ',') orelse features.len - start;
|
||||
var feature = features[start..start+next_comma_pos];
|
||||
var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
|
||||
defer llvm_features_buffer.deinit();
|
||||
|
||||
if (feature.len < 2) return .{ .InvalidFeaturesString = {} };
|
||||
|
||||
if (feature[0] != '+' and feature[0] != '-') return .{ .InvalidFeaturesString = {} };
|
||||
feature = feature[1..];
|
||||
|
||||
var found_feature = false;
|
||||
for (known_features) |known_feature| {
|
||||
if (std.mem.eql(u8, feature, known_feature.name)) {
|
||||
found_feature = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_feature) return .{ .InvalidFeature = feature };
|
||||
|
||||
start += next_comma_pos + 1;
|
||||
}
|
||||
for (features_slice) |feature| {
|
||||
try llvm_features_buffer.append("+");
|
||||
try llvm_features_buffer.append(feature.llvm_name);
|
||||
try llvm_features_buffer.append(",");
|
||||
}
|
||||
|
||||
return .{ .Ok = {} };
|
||||
const ptr = try allocator.create(Stage2TargetDetails);
|
||||
ptr.* = Stage2TargetDetails{
|
||||
.allocator = allocator,
|
||||
.target_details = std.target.TargetDetails{
|
||||
.features = features_slice,
|
||||
},
|
||||
.llvm_cpu_str = "",
|
||||
.llvm_features_str = llvm_features_buffer.toOwnedSlice(),
|
||||
};
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_target_details_get_cache_str(target_details: ?*const Stage2TargetDetails) [*:0]const u8 {
|
||||
if (target_details) |td| {
|
||||
return @as([*:0]const u8, switch (td.target_details) {
|
||||
.cpu => td.llvm_cpu_str,
|
||||
.features => td.llvm_features_str,
|
||||
});
|
||||
}
|
||||
|
||||
return @as([*:0]const u8, "");
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_target_details_get_llvm_cpu(target_details: ?*const Stage2TargetDetails) [*:0]const u8 {
|
||||
if (target_details) |td| {
|
||||
return @as([*:0]const u8, td.llvm_cpu_str);
|
||||
}
|
||||
|
||||
return @as([*:0]const u8, "");
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_target_details_get_llvm_features(target_details: ?*const Stage2TargetDetails) [*:0]const u8 {
|
||||
if (target_details) |td| {
|
||||
return @as([*:0]const u8, td.llvm_features_str);
|
||||
}
|
||||
|
||||
return @as([*:0]const u8, "");
|
||||
}
|
||||
|
||||
@ -2216,8 +2216,7 @@ struct CodeGen {
|
||||
const char **clang_argv;
|
||||
size_t clang_argv_len;
|
||||
|
||||
const char *llvm_cpu;
|
||||
const char *llvm_features;
|
||||
Stage2TargetDetails *target_details;
|
||||
};
|
||||
|
||||
struct ZigVar {
|
||||
|
||||
@ -8655,8 +8655,10 @@ static Error define_builtin_compile_vars(CodeGen *g) {
|
||||
cache_bool(&cache_hash, g->valgrind_support);
|
||||
cache_bool(&cache_hash, g->link_eh_frame_hdr);
|
||||
cache_int(&cache_hash, detect_subsystem(g));
|
||||
if (g->llvm_cpu) cache_str(&cache_hash, g->llvm_cpu);
|
||||
if (g->llvm_features) cache_str(&cache_hash, g->llvm_features);
|
||||
|
||||
if (g->target_details) {
|
||||
cache_str(&cache_hash, stage2_target_details_get_cache_str(g->target_details));
|
||||
}
|
||||
|
||||
Buf digest = BUF_INIT;
|
||||
buf_resize(&digest, 0);
|
||||
@ -8802,15 +8804,12 @@ static void init(CodeGen *g) {
|
||||
target_specific_features = "";
|
||||
}
|
||||
|
||||
// Override CPU and features if non-null.
|
||||
if (g->llvm_cpu != nullptr) {
|
||||
target_specific_cpu_args = g->llvm_cpu;
|
||||
// Override CPU and features if defined by user.
|
||||
if (g->target_details) {
|
||||
target_specific_cpu_args = stage2_target_details_get_llvm_cpu(g->target_details);
|
||||
target_specific_features = stage2_target_details_get_llvm_features(g->target_details);
|
||||
}
|
||||
|
||||
if (g->llvm_features != nullptr) {
|
||||
target_specific_features = g->llvm_features;
|
||||
}
|
||||
|
||||
g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str),
|
||||
target_specific_cpu_args, target_specific_features, opt_level, reloc_mode,
|
||||
LLVMCodeModelDefault, g->function_sections);
|
||||
@ -10390,8 +10389,10 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
}
|
||||
cache_buf_opt(ch, g->dynamic_linker_path);
|
||||
cache_buf_opt(ch, g->version_script_path);
|
||||
if (g->llvm_cpu) cache_str(ch, g->llvm_cpu);
|
||||
if (g->llvm_features) cache_str(ch, g->llvm_features);
|
||||
|
||||
if (g->target_details) {
|
||||
cache_str(ch, stage2_target_details_get_cache_str(g->target_details));
|
||||
}
|
||||
|
||||
// gen_c_objects appends objects to g->link_objects which we want to include in the hash
|
||||
gen_c_objects(g);
|
||||
|
||||
25
src/main.cpp
25
src/main.cpp
@ -535,8 +535,8 @@ int main(int argc, char **argv) {
|
||||
WantStackCheck want_stack_check = WantStackCheckAuto;
|
||||
WantCSanitize want_sanitize_c = WantCSanitizeAuto;
|
||||
bool function_sections = false;
|
||||
const char *cpu = "";
|
||||
const char *features = "";
|
||||
const char *cpu = nullptr;
|
||||
const char *features = nullptr;
|
||||
|
||||
const char *targets_list_features_arch = nullptr;
|
||||
const char *targets_list_cpus_arch = nullptr;
|
||||
@ -1278,12 +1278,25 @@ int main(int argc, char **argv) {
|
||||
codegen_add_rpath(g, rpath_list.at(i));
|
||||
}
|
||||
|
||||
if (!stage2_validate_cpu_and_features(target_arch_name(target.arch), cpu, features)) {
|
||||
return 1;
|
||||
Stage2TargetDetails *target_details = nullptr;
|
||||
if (cpu && features) {
|
||||
fprintf(stderr, "--cpu and --features options not allowed together\n");
|
||||
return main_exit(root_progress_node, EXIT_FAILURE);
|
||||
} else if (cpu) {
|
||||
target_details = stage2_target_details_parse_cpu(target_arch_name(target.arch), cpu);
|
||||
if (!target_details) {
|
||||
fprintf(stderr, "invalid --cpu value\n");
|
||||
return main_exit(root_progress_node, EXIT_FAILURE);
|
||||
}
|
||||
} else if (features) {
|
||||
target_details = stage2_target_details_parse_features(target_arch_name(target.arch), features);
|
||||
if (!target_details) {
|
||||
fprintf(stderr, "invalid --features value\n");
|
||||
return main_exit(root_progress_node, EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
g->llvm_cpu = cpu;
|
||||
g->llvm_features = features;
|
||||
g->target_details = target_details;
|
||||
|
||||
codegen_set_rdynamic(g, rdynamic);
|
||||
if (mmacosx_version_min && mios_version_min) {
|
||||
|
||||
@ -91,4 +91,18 @@ void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_coun
|
||||
|
||||
void stage2_list_features_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {}
|
||||
void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures) {}
|
||||
bool stage2_validate_cpu_and_features(const char *arch_name, const char *cpu, const char *features) { return true; }
|
||||
Stage2TargetDetails *stage2_target_details_parse_cpu(const char *arch, const char *str) {
|
||||
return nullptr;
|
||||
}
|
||||
Stage2TargetDetails *stage2_target_details_parse_features(const char *arch, const char *str) {
|
||||
return nullptr;
|
||||
}
|
||||
const char *stage2_target_details_get_cache_str(const Stage2TargetDetails *target_details) {
|
||||
return "";
|
||||
}
|
||||
const char *stage2_target_details_get_llvm_cpu(const Stage2TargetDetails *target_details) {
|
||||
return "";
|
||||
}
|
||||
const char *stage2_target_details_get_llvm_features(const Stage2TargetDetails *target_details) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -181,6 +181,21 @@ ZIG_EXTERN_C void stage2_list_features_for_arch(const char *arch_name_ptr, size_
|
||||
ZIG_EXTERN_C void stage2_list_cpus_for_arch(const char *arch_name_ptr, size_t arch_name_len, bool show_subfeatures);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C bool stage2_validate_cpu_and_features(const char *arch_name, const char *cpu, const char *features);
|
||||
struct Stage2TargetDetails;
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C Stage2TargetDetails *stage2_target_details_parse_cpu(const char *arch, const char *str);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C Stage2TargetDetails *stage2_target_details_parse_features(const char *arch, const char *str);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C const char *stage2_target_details_get_cache_str(const Stage2TargetDetails *target_details);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C const char *stage2_target_details_get_llvm_cpu(const Stage2TargetDetails *target_details);
|
||||
|
||||
// ABI warning
|
||||
ZIG_EXTERN_C const char *stage2_target_details_get_llvm_features(const Stage2TargetDetails *target_details);
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user