Skip to content

Commit

Permalink
Merge pull request #631 from ehaas/gnuc-version
Browse files Browse the repository at this point in the history
Compilation: set __GNUC__ and related macros
  • Loading branch information
Vexu authored Feb 24, 2024
2 parents 6a683c5 + 69272dc commit bebda7c
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 25 deletions.
32 changes: 13 additions & 19 deletions src/aro/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ pub const SystemDefinesMode = enum {
fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
const ptr_width = comp.target.ptrBitWidth();

if (comp.langopts.gnuc_version > 0) {
try w.print("#define __GNUC__ {d}\n", .{comp.langopts.gnuc_version / 10_000});
try w.print("#define __GNUC_MINOR__ {d}\n", .{comp.langopts.gnuc_version / 100 % 100});
try w.print("#define __GNUC_PATCHLEVEL__ {d}\n", .{comp.langopts.gnuc_version % 100});
}

// os macros
switch (comp.target.os.tag) {
.linux => try w.writeAll(
Expand Down Expand Up @@ -1051,9 +1057,8 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness {
return comp.langopts.char_signedness_override orelse comp.target.charSignedness();
}

pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {
var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);
const allocator = stack_fallback.get();
/// Add built-in aro headers directory to system include paths
pub fn addBuiltinIncludeDir(comp: *Compilation, aro_dir: []const u8) !void {
var search_path = aro_dir;
while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {
var base_dir = std.fs.cwd().openDir(dirname, .{}) catch continue;
Expand All @@ -1065,23 +1070,12 @@ pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {
try comp.system_include_dirs.append(comp.gpa, path);
break;
} else return error.AroIncludeNotFound;
}

if (comp.target.os.tag == .linux) {
const triple_str = try comp.target.linuxTriple(allocator);
defer allocator.free(triple_str);

const multiarch_path = try std.fs.path.join(allocator, &.{ "/usr/include", triple_str });
defer allocator.free(multiarch_path);

if (!std.meta.isError(std.fs.accessAbsolute(multiarch_path, .{}))) {
const duped = try comp.gpa.dupe(u8, multiarch_path);
errdefer comp.gpa.free(duped);
try comp.system_include_dirs.append(comp.gpa, duped);
}
}
const usr_include = try comp.gpa.dupe(u8, "/usr/include");
errdefer comp.gpa.free(usr_include);
try comp.system_include_dirs.append(comp.gpa, usr_include);
pub fn addSystemIncludeDir(comp: *Compilation, path: []const u8) !void {
const duped = try comp.gpa.dupe(u8, path);
errdefer comp.gpa.free(duped);
try comp.system_include_dirs.append(comp.gpa, duped);
}

pub fn getSource(comp: *const Compilation, id: Source.Id) Source {
Expand Down
30 changes: 27 additions & 3 deletions src/aro/Driver.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const Preprocessor = @import("Preprocessor.zig");
const Source = @import("Source.zig");
const Toolchain = @import("Toolchain.zig");
const target_util = @import("target.zig");
const GCCVersion = @import("Driver/GCCVersion.zig");

pub const Linker = enum {
ld,
Expand Down Expand Up @@ -43,6 +44,9 @@ verbose_pp: bool = false,
verbose_ir: bool = false,
verbose_linker_args: bool = false,
color: ?bool = null,
nobuiltininc: bool = false,
nostdinc: bool = false,
nostdlibinc: bool = false,

/// Full path to the aro executable
aro_name: []const u8 = "",
Expand Down Expand Up @@ -95,6 +99,7 @@ pub const usage =
\\ -fcolor-diagnostics Enable colors in diagnostics
\\ -fno-color-diagnostics Disable colors in diagnostics
\\ -fdeclspec Enable support for __declspec attributes
\\ -fgnuc-version=<value> Controls value of __GNUC__ and related macros. Set to 0 or empty to disable them.
\\ -fno-declspec Disable support for __declspec attributes
\\ -ffp-eval-method=[source|double|extended]
\\ Evaluation method to use for floating-point arithmetic
Expand Down Expand Up @@ -127,6 +132,10 @@ pub const usage =
\\ -isystem Add directory to SYSTEM include search path
\\ --emulate=[clang|gcc|msvc]
\\ Select which C compiler to emulate (default clang)
\\ -nobuiltininc Do not search the compiler's builtin directory for include files
\\ -nostdinc, --no-standard-includes
\\ Do not search the standard system directories or compiler builtin directories for include files.
\\ -nostdlibinc Do not search the standard system directories for include files, but do search compiler builtin include directories
\\ -o <file> Write output to <file>
\\ -P, --no-line-commands Disable linemarker output in -E mode
\\ -pedantic Warn on language extensions
Expand Down Expand Up @@ -180,6 +189,7 @@ pub fn parseArgs(
var i: usize = 1;
var comment_arg: []const u8 = "";
var hosted: ?bool = null;
var gnuc_version: []const u8 = "4.2.1"; // default value set by clang
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-") and arg.len > 1) {
Expand Down Expand Up @@ -303,6 +313,10 @@ pub fn parseArgs(
d.only_syntax = true;
} else if (mem.startsWith(u8, arg, "-fno-syntax-only")) {
d.only_syntax = false;
} else if (mem.eql(u8, arg, "-fgnuc-version=")) {
gnuc_version = "0";
} else if (option(arg, "-fgnuc-version=")) |version| {
gnuc_version = version;
} else if (mem.startsWith(u8, arg, "-isystem")) {
var path = arg["-isystem".len..];
if (path.len == 0) {
Expand Down Expand Up @@ -421,6 +435,12 @@ pub fn parseArgs(
d.nodefaultlibs = true;
} else if (mem.eql(u8, arg, "-nolibc")) {
d.nolibc = true;
} else if (mem.eql(u8, arg, "-nobuiltininc")) {
d.nobuiltininc = true;
} else if (mem.eql(u8, arg, "-nostdinc") or mem.eql(u8, arg, "--no-standard-includes")) {
d.nostdinc = true;
} else if (mem.eql(u8, arg, "-nostdlibinc")) {
d.nostdlibinc = true;
} else if (mem.eql(u8, arg, "-nostdlib")) {
d.nostdlib = true;
} else if (mem.eql(u8, arg, "-nostartfiles")) {
Expand Down Expand Up @@ -459,6 +479,11 @@ pub fn parseArgs(
d.comp.target.os.tag = .freestanding;
}
}
const version = GCCVersion.parse(gnuc_version);
if (version.major == -1) {
return d.fatal("invalid value '{0s}' in '-fgnuc-version={0s}'", .{gnuc_version});
}
d.comp.langopts.gnuc_version = version.toUnsigned();
return false;
}

Expand Down Expand Up @@ -557,7 +582,8 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_
try d.comp.addDiagnostic(.{ .tag = .cli_unused_link_object, .extra = .{ .str = obj } }, &.{});
};

d.comp.defineSystemIncludes(d.aro_name) catch |er| switch (er) {
try tc.discover();
tc.defineSystemIncludes() catch |er| switch (er) {
error.OutOfMemory => return error.OutOfMemory,
error.AroIncludeNotFound => return d.fatal("unable to find Aro builtin headers", .{}),
};
Expand Down Expand Up @@ -762,8 +788,6 @@ fn dumpLinkerArgs(items: []const []const u8) !void {
/// The entry point of the Aro compiler.
/// **MAY call `exit` if `fast_exit` is set.**
pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void {
try tc.discover();

var argv = std.ArrayList([]const u8).init(d.comp.gpa);
defer argv.deinit();

Expand Down
10 changes: 10 additions & 0 deletions src/aro/Driver/GCCVersion.zig
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,16 @@ pub fn order(a: GCCVersion, b: GCCVersion) Order {
return .eq;
}

/// Used for determining __GNUC__ macro values
/// This matches clang's logic for overflowing values
pub fn toUnsigned(self: GCCVersion) u32 {
var result: u32 = 0;
if (self.major > 0) result = @as(u32, @intCast(self.major)) *% 10_000;
if (self.minor > 0) result +%= @as(u32, @intCast(self.minor)) *% 100;
if (self.patch > 0) result +%= @as(u32, @intCast(self.patch));
return result;
}

test parse {
const versions = [10]GCCVersion{
parse("5"),
Expand Down
5 changes: 5 additions & 0 deletions src/aro/LangOpts.zig
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ preserve_comments: bool = false,
/// Preserve comments in macros when preprocessing
preserve_comments_in_macros: bool = false,

/// Used ONLY for generating __GNUC__ and related macros. Does not control the presence/absence of any features
/// Encoded as major * 10,000 + minor * 100 + patch
/// e.g. 4.2.1 == 40201
gnuc_version: u32 = 0,

pub fn setStandard(self: *LangOpts, name: []const u8) error{InvalidStandard}!void {
self.standard = Standard.NameMap.get(name) orelse return error.InvalidStandard;
}
Expand Down
19 changes: 19 additions & 0 deletions src/aro/Toolchain.zig
Original file line number Diff line number Diff line change
Expand Up @@ -487,3 +487,22 @@ pub fn addRuntimeLibs(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !v
try argv.append("-ldl");
}
}

pub fn defineSystemIncludes(tc: *Toolchain) !void {
return switch (tc.inner) {
.uninitialized => unreachable,
.linux => |*linux| linux.defineSystemIncludes(tc),
.unknown => {
if (tc.driver.nostdinc) return;

const comp = tc.driver.comp;
if (!tc.driver.nobuiltininc) {
try comp.addBuiltinIncludeDir(tc.driver.aro_name);
}

if (!tc.driver.nostdlibinc) {
try comp.addSystemIncludeDir("/usr/include");
}
},
};
}
44 changes: 44 additions & 0 deletions src/aro/toolchains/Linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,50 @@ fn getOSLibDir(target: std.Target) []const u8 {
return "lib64";
}

pub fn defineSystemIncludes(self: *const Linux, tc: *const Toolchain) !void {
if (tc.driver.nostdinc) return;

const comp = tc.driver.comp;
const target = tc.getTarget();

// musl prefers /usr/include before builtin includes, so musl targets will add builtins
// at the end of this function (unless disabled with nostdlibinc)
if (!tc.driver.nobuiltininc and (!target.isMusl() or tc.driver.nostdlibinc)) {
try comp.addBuiltinIncludeDir(tc.driver.aro_name);
}

if (tc.driver.nostdlibinc) return;

const sysroot = tc.getSysroot();
const local_include = try std.fmt.allocPrint(comp.gpa, "{s}{s}", .{ sysroot, "/usr/local/include" });
defer comp.gpa.free(local_include);
try comp.addSystemIncludeDir(local_include);

if (self.gcc_detector.is_valid) {
const gcc_include_path = try std.fs.path.join(comp.gpa, &.{ self.gcc_detector.parent_lib_path, "..", self.gcc_detector.gcc_triple, "include" });
defer comp.gpa.free(gcc_include_path);
try comp.addSystemIncludeDir(gcc_include_path);
}

if (getMultiarchTriple(target)) |triple| {
const joined = try std.fs.path.join(comp.gpa, &.{ sysroot, "usr", "include", triple });
defer comp.gpa.free(joined);
if (tc.filesystem.exists(joined)) {
try comp.addSystemIncludeDir(joined);
}
}

if (target.os.tag == .rtems) return;

try comp.addSystemIncludeDir("/include");
try comp.addSystemIncludeDir("/usr/include");

std.debug.assert(!tc.driver.nostdlibinc);
if (!tc.driver.nobuiltininc and target.isMusl()) {
try comp.addBuiltinIncludeDir(tc.driver.aro_name);
}
}

test Linux {
if (@import("builtin").os.tag == .windows) return error.SkipZigTest;

Expand Down
3 changes: 3 additions & 0 deletions test/cases/gnuc version default.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
_Static_assert(__GNUC__ == 4, "");
_Static_assert(__GNUC_MINOR__ == 2, "");
_Static_assert(__GNUC_PATCHLEVEL__ == 1, "");
5 changes: 5 additions & 0 deletions test/cases/gnuc version empty.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//aro-args -fgnuc-version=

#if defined(__GNUC__) || defined(__GNUC_MINOR__) || defined(__GNUC_PATCHLEVEL__)
#error "__GNUC__ macros should not be defined"
#endif
5 changes: 5 additions & 0 deletions test/cases/gnuc version override.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//aro-args -fgnuc-version=5.3.42

_Static_assert(__GNUC__ == 5, "");
_Static_assert(__GNUC_MINOR__ == 3, "");
_Static_assert(__GNUC_PATCHLEVEL__ == 42, "");
2 changes: 1 addition & 1 deletion test/record_runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ fn singleRun(alloc: std.mem.Allocator, test_dir: []const u8, test_case: TestCase
defer comp.deinit();

try comp.addDefaultPragmaHandlers();
try comp.defineSystemIncludes(test_dir);
try comp.addBuiltinIncludeDir(test_dir);

const target = setTarget(&comp, test_case.target) catch |err| switch (err) {
error.UnknownCpuModel => unreachable,
Expand Down
5 changes: 3 additions & 2 deletions test/runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ fn addCommandLineArgs(comp: *aro.Compilation, file: aro.Source, macro_buf: anyty
var only_preprocess = false;
var line_markers: aro.Preprocessor.Linemarkers = .none;
var system_defines: aro.Compilation.SystemDefinesMode = .include_system_defines;
comp.langopts.gnuc_version = 40201; // Set to clang default value since we do not call parseArgs if there are no args
if (std.mem.startsWith(u8, file.buf, "//aro-args")) {
var test_args = std.ArrayList([]const u8).init(comp.gpa);
defer test_args.deinit();
Expand Down Expand Up @@ -57,7 +58,7 @@ fn testOne(allocator: std.mem.Allocator, path: []const u8, test_dir: []const u8)
defer comp.deinit();

try comp.addDefaultPragmaHandlers();
try comp.defineSystemIncludes(test_dir);
try comp.addBuiltinIncludeDir(test_dir);

const file = try comp.addSourceFromPath(path);
var macro_buf = std.ArrayList(u8).init(comp.gpa);
Expand Down Expand Up @@ -172,7 +173,7 @@ pub fn main() !void {
try initial_comp.include_dirs.append(gpa, cases_next_include_dir);

try initial_comp.addDefaultPragmaHandlers();
try initial_comp.defineSystemIncludes(test_dir);
try initial_comp.addBuiltinIncludeDir(test_dir);

// apparently we can't use setAstCwd without libc on windows yet
const win = @import("builtin").os.tag == .windows;
Expand Down

0 comments on commit bebda7c

Please sign in to comment.