Skip to content

Commit

Permalink
Compilation: set __GNUC__ and related macros
Browse files Browse the repository at this point in the history
This allows us to pretend to be GCC 4.2.1, just like clang
  • Loading branch information
ehaas committed Feb 23, 2024
1 parent c990ebe commit d1f5878
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 0 deletions.
6 changes: 6 additions & 0 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
12 changes: 12 additions & 0 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 @@ -95,6 +96,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 @@ -180,6 +182,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 +306,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 @@ -459,6 +466,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
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
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, "");
1 change: 1 addition & 0 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

0 comments on commit d1f5878

Please sign in to comment.