zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

preprocess.zig (5102B) - Raw


      1 const std = @import("std");
      2 const builtin = @import("builtin");
      3 const Allocator = std.mem.Allocator;
      4 const cli = @import("cli.zig");
      5 const aro = @import("aro");
      6 
      7 const PreprocessError = error{ ArgError, GeneratedSourceError, PreprocessError, StreamTooLong, OutOfMemory };
      8 
      9 pub fn preprocess(
     10     comp: *aro.Compilation,
     11     writer: anytype,
     12     /// Expects argv[0] to be the command name
     13     argv: []const []const u8,
     14     maybe_dependencies_list: ?*std.array_list.Managed([]const u8),
     15 ) PreprocessError!void {
     16     try comp.addDefaultPragmaHandlers();
     17 
     18     var driver: aro.Driver = .{ .comp = comp, .aro_name = "arocc" };
     19     defer driver.deinit();
     20 
     21     var macro_buf = std.array_list.Managed(u8).init(comp.gpa);
     22     defer macro_buf.deinit();
     23 
     24     _ = driver.parseArgs(std.io.null_writer, macro_buf.writer(), argv) catch |err| switch (err) {
     25         error.FatalError => return error.ArgError,
     26         error.OutOfMemory => |e| return e,
     27     };
     28 
     29     if (hasAnyErrors(comp)) return error.ArgError;
     30 
     31     // .include_system_defines gives us things like _WIN32
     32     const builtin_macros = comp.generateBuiltinMacros(.include_system_defines) catch |err| switch (err) {
     33         error.FatalError => return error.GeneratedSourceError,
     34         else => |e| return e,
     35     };
     36     const user_macros = comp.addSourceFromBuffer("<command line>", macro_buf.items) catch |err| switch (err) {
     37         error.FatalError => return error.GeneratedSourceError,
     38         else => |e| return e,
     39     };
     40     const source = driver.inputs.items[0];
     41 
     42     if (hasAnyErrors(comp)) return error.GeneratedSourceError;
     43 
     44     comp.generated_buf.items.len = 0;
     45     var pp = try aro.Preprocessor.initDefault(comp);
     46     defer pp.deinit();
     47 
     48     if (comp.langopts.ms_extensions) {
     49         comp.ms_cwd_source_id = source.id;
     50     }
     51 
     52     pp.preserve_whitespace = true;
     53     pp.linemarkers = .line_directives;
     54 
     55     pp.preprocessSources(&.{ source, builtin_macros, user_macros }) catch |err| switch (err) {
     56         error.FatalError => return error.PreprocessError,
     57         else => |e| return e,
     58     };
     59 
     60     if (hasAnyErrors(comp)) return error.PreprocessError;
     61 
     62     try pp.prettyPrintTokens(writer, .result_only);
     63 
     64     if (maybe_dependencies_list) |dependencies_list| {
     65         for (comp.sources.values()) |comp_source| {
     66             if (comp_source.id == builtin_macros.id or comp_source.id == user_macros.id) continue;
     67             if (comp_source.id == .unused or comp_source.id == .generated) continue;
     68             const duped_path = try dependencies_list.allocator.dupe(u8, comp_source.path);
     69             errdefer dependencies_list.allocator.free(duped_path);
     70             try dependencies_list.append(duped_path);
     71         }
     72     }
     73 }
     74 
     75 fn hasAnyErrors(comp: *aro.Compilation) bool {
     76     // In theory we could just check Diagnostics.errors != 0, but that only
     77     // gets set during rendering of the error messages, see:
     78     // https://github.com/Vexu/arocc/issues/603
     79     for (comp.diagnostics.list.items) |msg| {
     80         switch (msg.kind) {
     81             .@"fatal error", .@"error" => return true,
     82             else => {},
     83         }
     84     }
     85     return false;
     86 }
     87 
     88 /// `arena` is used for temporary -D argument strings and the INCLUDE environment variable.
     89 /// The arena should be kept alive at least as long as `argv`.
     90 pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8), options: cli.Options, system_include_paths: []const []const u8) !void {
     91     try argv.appendSlice(&.{
     92         "-E",
     93         "--comments",
     94         "-fuse-line-directives",
     95         "--target=x86_64-windows-msvc",
     96         "--emulate=msvc",
     97         "-nostdinc",
     98         "-DRC_INVOKED",
     99         "-D_WIN32", // undocumented, but defined by default
    100     });
    101     for (options.extra_include_paths.items) |extra_include_path| {
    102         try argv.append("-I");
    103         try argv.append(extra_include_path);
    104     }
    105 
    106     for (system_include_paths) |include_path| {
    107         try argv.append("-isystem");
    108         try argv.append(include_path);
    109     }
    110 
    111     if (!options.ignore_include_env_var) {
    112         const INCLUDE = std.process.getEnvVarOwned(arena, "INCLUDE") catch "";
    113 
    114         // The only precedence here is llvm-rc which also uses the platform-specific
    115         // delimiter. There's no precedence set by `rc.exe` since it's Windows-only.
    116         const delimiter = switch (builtin.os.tag) {
    117             .windows => ';',
    118             else => ':',
    119         };
    120         var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
    121         while (it.next()) |include_path| {
    122             try argv.append("-isystem");
    123             try argv.append(include_path);
    124         }
    125     }
    126 
    127     var symbol_it = options.symbols.iterator();
    128     while (symbol_it.next()) |entry| {
    129         switch (entry.value_ptr.*) {
    130             .define => |value| {
    131                 try argv.append("-D");
    132                 const define_arg = try std.fmt.allocPrint(arena, "{s}={s}", .{ entry.key_ptr.*, value });
    133                 try argv.append(define_arg);
    134             },
    135             .undefine => {
    136                 try argv.append("-U");
    137                 try argv.append(entry.key_ptr.*);
    138             },
    139         }
    140     }
    141 }