stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
// This is Zig code that is used by both stage1 and stage2.
|
|
|
|
// The prototypes in src/userland.h must match these definitions.
|
2019-04-21 14:24:58 -07:00
|
|
|
|
2019-05-26 10:17:34 -07:00
|
|
|
const std = @import("std");
|
|
|
|
const io = std.io;
|
|
|
|
const mem = std.mem;
|
|
|
|
const fs = std.fs;
|
|
|
|
const process = std.process;
|
|
|
|
const Allocator = mem.Allocator;
|
|
|
|
const ArrayList = std.ArrayList;
|
2020-04-01 09:44:45 -07:00
|
|
|
const ArrayListSentineled = std.ArrayListSentineled;
|
2019-12-17 06:45:30 -08:00
|
|
|
const Target = std.Target;
|
2020-02-25 22:18:23 -08:00
|
|
|
const CrossTarget = std.zig.CrossTarget;
|
2019-05-26 10:17:34 -07:00
|
|
|
const self_hosted_main = @import("main.zig");
|
2019-05-30 09:07:55 -07:00
|
|
|
const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
|
2020-01-21 09:14:43 -08:00
|
|
|
const assert = std.debug.assert;
|
2020-02-16 10:25:30 -08:00
|
|
|
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
2019-05-26 10:17:34 -07:00
|
|
|
|
|
|
|
var stderr_file: fs.File = undefined;
|
2020-03-10 12:27:45 -07:00
|
|
|
var stderr: fs.File.OutStream = undefined;
|
|
|
|
var stdout: fs.File.OutStream = undefined;
|
stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
|
2019-05-27 16:47:10 -07:00
|
|
|
comptime {
|
2019-05-30 09:07:55 -07:00
|
|
|
_ = @import("dep_tokenizer.zig");
|
2019-05-27 16:47:10 -07:00
|
|
|
}
|
|
|
|
|
2019-04-21 16:37:39 -07:00
|
|
|
// ABI warning
|
stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
|
2019-04-21 16:37:39 -07:00
|
|
|
const info_zen = @import("main.zig").info_zen;
|
2019-11-19 17:29:08 -08:00
|
|
|
ptr.* = info_zen;
|
stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
len.* = info_zen.len;
|
|
|
|
}
|
2019-04-17 12:58:20 -07:00
|
|
|
|
2019-04-21 16:37:39 -07:00
|
|
|
// ABI warning
|
2019-04-17 12:58:20 -07:00
|
|
|
export fn stage2_panic(ptr: [*]const u8, len: usize) void {
|
|
|
|
@panic(ptr[0..len]);
|
|
|
|
}
|
2019-04-21 14:24:58 -07:00
|
|
|
|
2019-04-21 16:37:39 -07:00
|
|
|
// ABI warning
|
2019-04-21 14:24:58 -07:00
|
|
|
const Error = extern enum {
|
|
|
|
None,
|
|
|
|
OutOfMemory,
|
|
|
|
InvalidFormat,
|
|
|
|
SemanticAnalyzeFail,
|
|
|
|
AccessDenied,
|
|
|
|
Interrupted,
|
|
|
|
SystemResources,
|
|
|
|
FileNotFound,
|
|
|
|
FileSystem,
|
|
|
|
FileTooBig,
|
|
|
|
DivByZero,
|
|
|
|
Overflow,
|
|
|
|
PathAlreadyExists,
|
|
|
|
Unexpected,
|
|
|
|
ExactDivRemainder,
|
|
|
|
NegativeDenominator,
|
|
|
|
ShiftedOutOneBits,
|
|
|
|
CCompileErrors,
|
|
|
|
EndOfFile,
|
|
|
|
IsDir,
|
|
|
|
NotDir,
|
|
|
|
UnsupportedOperatingSystem,
|
|
|
|
SharingViolation,
|
|
|
|
PipeBusy,
|
|
|
|
PrimitiveTypeNotFound,
|
|
|
|
CacheUnavailable,
|
|
|
|
PathTooLong,
|
|
|
|
CCompilerCannotFindFile,
|
2020-01-20 21:34:54 -08:00
|
|
|
NoCCompilerInstalled,
|
2019-04-21 14:24:58 -07:00
|
|
|
ReadingDepFile,
|
|
|
|
InvalidDepFile,
|
|
|
|
MissingArchitecture,
|
|
|
|
MissingOperatingSystem,
|
|
|
|
UnknownArchitecture,
|
|
|
|
UnknownOperatingSystem,
|
|
|
|
UnknownABI,
|
|
|
|
InvalidFilename,
|
|
|
|
DiskQuota,
|
|
|
|
DiskSpace,
|
|
|
|
UnexpectedWriteFailure,
|
|
|
|
UnexpectedSeekFailure,
|
|
|
|
UnexpectedFileTruncationFailure,
|
|
|
|
Unimplemented,
|
|
|
|
OperationAborted,
|
|
|
|
BrokenPipe,
|
|
|
|
NoSpaceLeft,
|
2020-01-18 23:40:35 -08:00
|
|
|
NotLazy,
|
|
|
|
IsAsync,
|
|
|
|
ImportOutsidePkgPath,
|
2020-02-25 22:18:23 -08:00
|
|
|
UnknownCpuModel,
|
2020-01-19 22:42:31 -08:00
|
|
|
UnknownCpuFeature,
|
|
|
|
InvalidCpuFeatures,
|
|
|
|
InvalidLlvmCpuFeaturesFormat,
|
2020-01-20 21:34:54 -08:00
|
|
|
UnknownApplicationBinaryInterface,
|
2020-02-15 02:14:31 -08:00
|
|
|
ASTUnitFailure,
|
2020-02-16 10:25:30 -08:00
|
|
|
BadPathName,
|
|
|
|
SymLinkLoop,
|
|
|
|
ProcessFdQuotaExceeded,
|
|
|
|
SystemFdQuotaExceeded,
|
|
|
|
NoDevice,
|
|
|
|
DeviceBusy,
|
|
|
|
UnableToSpawnCCompiler,
|
|
|
|
CCompilerExitCode,
|
|
|
|
CCompilerCrashed,
|
|
|
|
CCompilerCannotFindHeaders,
|
|
|
|
LibCRuntimeNotFound,
|
|
|
|
LibCStdLibHeaderNotFound,
|
|
|
|
LibCKernel32LibNotFound,
|
|
|
|
UnsupportedArchitecture,
|
2020-02-16 16:58:27 -08:00
|
|
|
WindowsSdkNotFound,
|
2020-02-17 12:23:59 -08:00
|
|
|
UnknownDynamicLinkerPath,
|
2020-02-17 12:46:53 -08:00
|
|
|
TargetHasNoDynamicLinker,
|
2020-02-24 22:52:27 -08:00
|
|
|
InvalidAbiVersion,
|
|
|
|
InvalidOperatingSystemVersion,
|
2020-03-21 07:12:28 -07:00
|
|
|
UnknownClangOption,
|
2020-03-27 19:24:40 -07:00
|
|
|
NestedResponseFile,
|
2020-04-04 09:26:57 -07:00
|
|
|
ZigIsTheCCompiler,
|
2020-03-23 20:39:10 -07:00
|
|
|
FileBusy,
|
|
|
|
Locked,
|
2019-04-21 14:24:58 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
const FILE = std.c.FILE;
|
|
|
|
const ast = std.zig.ast;
|
2019-04-21 16:37:39 -07:00
|
|
|
const translate_c = @import("translate_c.zig");
|
2019-04-21 14:24:58 -07:00
|
|
|
|
|
|
|
/// Args should have a null terminating last arg.
|
|
|
|
export fn stage2_translate_c(
|
|
|
|
out_ast: **ast.Tree,
|
2019-04-21 16:37:39 -07:00
|
|
|
out_errors_ptr: *[*]translate_c.ClangErrMsg,
|
|
|
|
out_errors_len: *usize,
|
2019-04-21 14:24:58 -07:00
|
|
|
args_begin: [*]?[*]const u8,
|
|
|
|
args_end: [*]?[*]const u8,
|
2019-12-15 23:55:37 -08:00
|
|
|
resources_path: [*:0]const u8,
|
2019-04-21 14:24:58 -07:00
|
|
|
) Error {
|
2020-03-16 18:41:46 -07:00
|
|
|
var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
|
2019-12-12 04:26:24 -08:00
|
|
|
out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
|
2019-05-14 16:23:31 -07:00
|
|
|
error.SemanticAnalyzeFail => {
|
2019-04-21 16:46:34 -07:00
|
|
|
out_errors_ptr.* = errors.ptr;
|
|
|
|
out_errors_len.* = errors.len;
|
2020-02-16 10:25:30 -08:00
|
|
|
return .CCompileErrors;
|
2019-04-21 16:46:34 -07:00
|
|
|
},
|
2020-02-16 10:25:30 -08:00
|
|
|
error.ASTUnitFailure => return .ASTUnitFailure,
|
|
|
|
error.OutOfMemory => return .OutOfMemory,
|
2019-04-21 14:24:58 -07:00
|
|
|
};
|
2020-02-16 10:25:30 -08:00
|
|
|
return .None;
|
2019-04-21 14:24:58 -07:00
|
|
|
}
|
|
|
|
|
2019-04-21 16:37:39 -07:00
|
|
|
export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void {
|
|
|
|
translate_c.freeErrors(errors_ptr[0..errors_len]);
|
|
|
|
}
|
|
|
|
|
2019-04-21 14:24:58 -07:00
|
|
|
export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
|
2020-03-10 12:27:45 -07:00
|
|
|
const c_out_stream = std.io.cOutStream(output_file);
|
2019-04-21 14:24:58 -07:00
|
|
|
_ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
|
2019-10-29 19:59:30 -07:00
|
|
|
error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
|
2020-02-16 10:25:30 -08:00
|
|
|
error.SystemResources => return .SystemResources,
|
|
|
|
error.OperationAborted => return .OperationAborted,
|
|
|
|
error.BrokenPipe => return .BrokenPipe,
|
|
|
|
error.DiskQuota => return .DiskQuota,
|
|
|
|
error.FileTooBig => return .FileTooBig,
|
|
|
|
error.NoSpaceLeft => return .NoSpaceLeft,
|
|
|
|
error.AccessDenied => return .AccessDenied,
|
|
|
|
error.OutOfMemory => return .OutOfMemory,
|
|
|
|
error.Unexpected => return .Unexpected,
|
|
|
|
error.InputOutput => return .FileSystem,
|
2019-04-21 14:24:58 -07:00
|
|
|
};
|
2020-02-16 10:25:30 -08:00
|
|
|
return .None;
|
2019-04-21 14:24:58 -07:00
|
|
|
}
|
2019-04-26 17:41:37 -07:00
|
|
|
|
2019-11-24 18:12:01 -08:00
|
|
|
export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int {
|
2019-04-26 17:41:37 -07:00
|
|
|
if (std.debug.runtime_safety) {
|
|
|
|
fmtMain(argc, argv) catch unreachable;
|
|
|
|
} else {
|
|
|
|
fmtMain(argc, argv) catch |e| {
|
2019-12-08 20:46:50 -08:00
|
|
|
std.debug.warn("{}\n", .{@errorName(e)});
|
2019-04-26 17:41:37 -07:00
|
|
|
return -1;
|
2019-04-26 17:58:43 -07:00
|
|
|
};
|
2019-04-26 17:41:37 -07:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-24 18:12:01 -08:00
|
|
|
fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
|
2019-04-26 17:41:37 -07:00
|
|
|
const allocator = std.heap.c_allocator;
|
|
|
|
var args_list = std.ArrayList([]const u8).init(allocator);
|
|
|
|
const argc_usize = @intCast(usize, argc);
|
|
|
|
var arg_i: usize = 0;
|
|
|
|
while (arg_i < argc_usize) : (arg_i += 1) {
|
2020-03-30 11:23:22 -07:00
|
|
|
try args_list.append(mem.spanZ(argv[arg_i]));
|
2019-04-26 17:41:37 -07:00
|
|
|
}
|
|
|
|
|
2020-03-30 11:23:22 -07:00
|
|
|
const args = args_list.span()[2..];
|
2019-12-10 23:08:33 -08:00
|
|
|
|
2020-05-15 12:20:42 -07:00
|
|
|
return self_hosted_main.cmdFmt(allocator, args);
|
2019-04-26 17:41:37 -07:00
|
|
|
}
|
2019-05-30 09:07:55 -07:00
|
|
|
|
|
|
|
export fn stage2_DepTokenizer_init(input: [*]const u8, len: usize) stage2_DepTokenizer {
|
|
|
|
const t = std.heap.c_allocator.create(DepTokenizer) catch @panic("failed to create .d tokenizer");
|
|
|
|
t.* = DepTokenizer.init(std.heap.c_allocator, input[0..len]);
|
|
|
|
return stage2_DepTokenizer{
|
|
|
|
.handle = t,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void {
|
|
|
|
self.handle.deinit();
|
|
|
|
}
|
|
|
|
|
|
|
|
export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextResult {
|
|
|
|
const otoken = self.handle.next() catch {
|
2020-04-01 09:44:45 -07:00
|
|
|
const textz = std.ArrayListSentineled(u8, 0).init(&self.handle.arena.allocator, self.handle.error_text) catch @panic("failed to create .d tokenizer error text");
|
2019-05-30 09:07:55 -07:00
|
|
|
return stage2_DepNextResult{
|
|
|
|
.type_id = .error_,
|
2020-03-30 11:23:22 -07:00
|
|
|
.textz = textz.span().ptr,
|
2019-05-30 09:07:55 -07:00
|
|
|
};
|
|
|
|
};
|
|
|
|
const token = otoken orelse {
|
|
|
|
return stage2_DepNextResult{
|
|
|
|
.type_id = .null_,
|
|
|
|
.textz = undefined,
|
|
|
|
};
|
|
|
|
};
|
2020-04-01 09:44:45 -07:00
|
|
|
const textz = std.ArrayListSentineled(u8, 0).init(&self.handle.arena.allocator, token.bytes) catch @panic("failed to create .d tokenizer token text");
|
2019-05-30 09:07:55 -07:00
|
|
|
return stage2_DepNextResult{
|
|
|
|
.type_id = switch (token.id) {
|
2019-11-06 22:31:00 -08:00
|
|
|
.target => .target,
|
|
|
|
.prereq => .prereq,
|
2019-05-30 09:07:55 -07:00
|
|
|
},
|
2020-03-30 11:23:22 -07:00
|
|
|
.textz = textz.span().ptr,
|
2019-05-30 09:07:55 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-09-21 14:29:55 -07:00
|
|
|
const stage2_DepTokenizer = extern struct {
|
2019-05-30 09:07:55 -07:00
|
|
|
handle: *DepTokenizer,
|
|
|
|
};
|
|
|
|
|
2019-09-21 14:29:55 -07:00
|
|
|
const stage2_DepNextResult = extern struct {
|
2019-05-30 09:07:55 -07:00
|
|
|
type_id: TypeId,
|
|
|
|
|
|
|
|
// when type_id == error --> error text
|
|
|
|
// when type_id == null --> undefined
|
|
|
|
// when type_id == target --> target pathname
|
|
|
|
// when type_id == prereq --> prereq pathname
|
|
|
|
textz: [*]const u8,
|
|
|
|
|
2019-09-21 14:29:55 -07:00
|
|
|
const TypeId = extern enum {
|
2019-05-30 09:07:55 -07:00
|
|
|
error_,
|
|
|
|
null_,
|
|
|
|
target,
|
|
|
|
prereq,
|
|
|
|
};
|
|
|
|
};
|
2019-07-02 10:38:33 -07:00
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_attach_segfault_handler() void {
|
|
|
|
if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) {
|
|
|
|
std.debug.attachSegfaultHandler();
|
|
|
|
}
|
|
|
|
}
|
2019-10-17 17:20:22 -07:00
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_progress_create() *std.Progress {
|
|
|
|
const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory");
|
|
|
|
ptr.* = std.Progress{};
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_progress_destroy(progress: *std.Progress) void {
|
|
|
|
std.heap.c_allocator.destroy(progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ABI warning
|
2019-10-17 18:46:41 -07:00
|
|
|
export fn stage2_progress_start_root(
|
|
|
|
progress: *std.Progress,
|
|
|
|
name_ptr: [*]const u8,
|
|
|
|
name_len: usize,
|
|
|
|
estimated_total_items: usize,
|
|
|
|
) *std.Progress.Node {
|
2019-10-17 17:20:22 -07:00
|
|
|
return progress.start(
|
|
|
|
name_ptr[0..name_len],
|
|
|
|
if (estimated_total_items == 0) null else estimated_total_items,
|
|
|
|
) catch @panic("timer unsupported");
|
|
|
|
}
|
|
|
|
|
2019-10-17 18:46:41 -07:00
|
|
|
// ABI warning
|
|
|
|
export fn stage2_progress_disable_tty(progress: *std.Progress) void {
|
|
|
|
progress.terminal = null;
|
|
|
|
}
|
|
|
|
|
2019-10-17 17:20:22 -07:00
|
|
|
// ABI warning
|
|
|
|
export fn stage2_progress_start(
|
|
|
|
node: *std.Progress.Node,
|
|
|
|
name_ptr: [*]const u8,
|
|
|
|
name_len: usize,
|
|
|
|
estimated_total_items: usize,
|
|
|
|
) *std.Progress.Node {
|
|
|
|
const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory");
|
|
|
|
child_node.* = node.start(
|
|
|
|
name_ptr[0..name_len],
|
|
|
|
if (estimated_total_items == 0) null else estimated_total_items,
|
|
|
|
);
|
|
|
|
child_node.activate();
|
|
|
|
return child_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_progress_end(node: *std.Progress.Node) void {
|
|
|
|
node.end();
|
|
|
|
if (&node.context.root != node) {
|
|
|
|
std.heap.c_allocator.destroy(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_progress_complete_one(node: *std.Progress.Node) void {
|
|
|
|
node.completeOne();
|
|
|
|
}
|
2019-10-22 14:52:12 -07:00
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void {
|
|
|
|
node.completed_items = done_count;
|
|
|
|
node.estimated_total_items = total_count;
|
|
|
|
node.activate();
|
|
|
|
node.context.maybeRefresh();
|
|
|
|
}
|
2019-12-17 06:45:30 -08:00
|
|
|
|
2020-02-19 18:30:36 -08:00
|
|
|
fn detectNativeCpuWithLLVM(
|
|
|
|
arch: Target.Cpu.Arch,
|
2020-01-20 22:22:37 -08:00
|
|
|
llvm_cpu_name_z: ?[*:0]const u8,
|
|
|
|
llvm_cpu_features_opt: ?[*:0]const u8,
|
2020-02-19 18:30:36 -08:00
|
|
|
) !Target.Cpu {
|
|
|
|
var result = Target.Cpu.baseline(arch);
|
2020-01-20 22:22:37 -08:00
|
|
|
|
2020-01-22 14:13:31 -08:00
|
|
|
if (llvm_cpu_name_z) |cpu_name_z| {
|
2020-03-30 11:23:22 -07:00
|
|
|
const llvm_cpu_name = mem.spanZ(cpu_name_z);
|
2020-01-21 19:01:24 -08:00
|
|
|
|
2020-02-19 18:30:36 -08:00
|
|
|
for (arch.allCpuModels()) |model| {
|
|
|
|
const this_llvm_name = model.llvm_name orelse continue;
|
2020-01-22 14:13:31 -08:00
|
|
|
if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
|
|
|
|
// Here we use the non-dependencies-populated set,
|
|
|
|
// so that subtracting features later in this function
|
|
|
|
// affect the prepopulated set.
|
2020-02-19 18:30:36 -08:00
|
|
|
result = Target.Cpu{
|
|
|
|
.arch = arch,
|
|
|
|
.model = model,
|
|
|
|
.features = model.features,
|
2020-01-22 14:13:31 -08:00
|
|
|
};
|
2020-01-20 22:22:37 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-21 19:01:24 -08:00
|
|
|
|
2020-01-22 14:13:31 -08:00
|
|
|
const all_features = arch.allFeaturesList();
|
2020-01-21 19:01:24 -08:00
|
|
|
|
2020-01-22 14:13:31 -08:00
|
|
|
if (llvm_cpu_features_opt) |llvm_cpu_features| {
|
2020-03-30 11:23:22 -07:00
|
|
|
var it = mem.tokenize(mem.spanZ(llvm_cpu_features), ",");
|
2020-01-22 14:13:31 -08:00
|
|
|
while (it.next()) |decorated_llvm_feat| {
|
|
|
|
var op: enum {
|
|
|
|
add,
|
|
|
|
sub,
|
|
|
|
} = undefined;
|
|
|
|
var llvm_feat: []const u8 = undefined;
|
|
|
|
if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
|
|
|
|
op = .add;
|
|
|
|
llvm_feat = decorated_llvm_feat[1..];
|
|
|
|
} else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
|
|
|
|
op = .sub;
|
|
|
|
llvm_feat = decorated_llvm_feat[1..];
|
|
|
|
} else {
|
|
|
|
return error.InvalidLlvmCpuFeaturesFormat;
|
|
|
|
}
|
|
|
|
for (all_features) |feature, index_usize| {
|
|
|
|
const this_llvm_name = feature.llvm_name orelse continue;
|
|
|
|
if (mem.eql(u8, llvm_feat, this_llvm_name)) {
|
|
|
|
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
|
|
|
|
switch (op) {
|
|
|
|
.add => result.features.addFeature(index),
|
|
|
|
.sub => result.features.removeFeature(index),
|
|
|
|
}
|
|
|
|
break;
|
2020-01-21 19:01:24 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 14:13:31 -08:00
|
|
|
result.features.populateDependencies(all_features);
|
|
|
|
return result;
|
2020-01-20 22:22:37 -08:00
|
|
|
}
|
|
|
|
|
2019-12-17 06:45:30 -08:00
|
|
|
// ABI warning
|
2020-03-11 21:32:50 -07:00
|
|
|
export fn stage2_cmd_targets(
|
|
|
|
zig_triple: ?[*:0]const u8,
|
|
|
|
mcpu: ?[*:0]const u8,
|
|
|
|
dynamic_linker: ?[*:0]const u8,
|
|
|
|
) c_int {
|
|
|
|
cmdTargets(zig_triple, mcpu, dynamic_linker) catch |err| {
|
2020-01-19 22:42:31 -08:00
|
|
|
std.debug.warn("unable to list targets: {}\n", .{@errorName(err)});
|
|
|
|
return -1;
|
2019-12-17 06:45:30 -08:00
|
|
|
};
|
2020-01-19 22:42:31 -08:00
|
|
|
return 0;
|
2019-12-17 06:45:30 -08:00
|
|
|
}
|
2019-12-20 16:27:13 -08:00
|
|
|
|
2020-03-11 21:32:50 -07:00
|
|
|
fn cmdTargets(
|
|
|
|
zig_triple_oz: ?[*:0]const u8,
|
|
|
|
mcpu_oz: ?[*:0]const u8,
|
|
|
|
dynamic_linker_oz: ?[*:0]const u8,
|
|
|
|
) !void {
|
|
|
|
const cross_target = try stage2CrossTarget(zig_triple_oz, mcpu_oz, dynamic_linker_oz);
|
2020-02-25 22:18:23 -08:00
|
|
|
var dynamic_linker: ?[*:0]u8 = null;
|
|
|
|
const target = try crossTargetToTarget(cross_target, &dynamic_linker);
|
2020-01-20 22:22:37 -08:00
|
|
|
return @import("print_targets.zig").cmdTargets(
|
|
|
|
std.heap.c_allocator,
|
|
|
|
&[0][]u8{},
|
2020-03-10 12:27:45 -07:00
|
|
|
std.io.getStdOut().outStream(),
|
2020-01-20 22:22:37 -08:00
|
|
|
target,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-01-08 17:27:36 -08:00
|
|
|
// ABI warning
|
2020-02-19 18:30:36 -08:00
|
|
|
export fn stage2_target_parse(
|
|
|
|
target: *Stage2Target,
|
2020-01-22 14:13:31 -08:00
|
|
|
zig_triple: ?[*:0]const u8,
|
2020-02-19 18:30:36 -08:00
|
|
|
mcpu: ?[*:0]const u8,
|
2020-02-28 10:27:52 -08:00
|
|
|
dynamic_linker: ?[*:0]const u8,
|
2020-01-19 10:52:29 -08:00
|
|
|
) Error {
|
2020-02-28 10:27:52 -08:00
|
|
|
stage2TargetParse(target, zig_triple, mcpu, dynamic_linker) catch |err| switch (err) {
|
2020-01-19 10:52:29 -08:00
|
|
|
error.OutOfMemory => return .OutOfMemory,
|
2020-01-19 22:42:31 -08:00
|
|
|
error.UnknownArchitecture => return .UnknownArchitecture,
|
2020-01-20 21:34:54 -08:00
|
|
|
error.UnknownOperatingSystem => return .UnknownOperatingSystem,
|
|
|
|
error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
|
|
|
|
error.MissingOperatingSystem => return .MissingOperatingSystem,
|
2020-01-22 14:13:31 -08:00
|
|
|
error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
|
2020-02-19 18:30:36 -08:00
|
|
|
error.UnexpectedExtraField => return .SemanticAnalyzeFail,
|
2020-02-24 22:52:27 -08:00
|
|
|
error.InvalidAbiVersion => return .InvalidAbiVersion,
|
|
|
|
error.InvalidOperatingSystemVersion => return .InvalidOperatingSystemVersion,
|
|
|
|
error.FileSystem => return .FileSystem,
|
|
|
|
error.SymLinkLoop => return .SymLinkLoop,
|
|
|
|
error.SystemResources => return .SystemResources,
|
|
|
|
error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
|
|
|
|
error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
|
|
|
|
error.DeviceBusy => return .DeviceBusy,
|
2020-01-18 23:40:35 -08:00
|
|
|
};
|
2020-01-19 10:52:29 -08:00
|
|
|
return .None;
|
2020-01-18 23:40:35 -08:00
|
|
|
}
|
2020-01-08 18:35:26 -08:00
|
|
|
|
2020-03-11 21:32:50 -07:00
|
|
|
fn stage2CrossTarget(
|
2020-01-22 14:13:31 -08:00
|
|
|
zig_triple_oz: ?[*:0]const u8,
|
2020-02-19 18:30:36 -08:00
|
|
|
mcpu_oz: ?[*:0]const u8,
|
2020-02-28 10:27:52 -08:00
|
|
|
dynamic_linker_oz: ?[*:0]const u8,
|
2020-03-11 21:32:50 -07:00
|
|
|
) !CrossTarget {
|
2020-03-31 07:25:25 -07:00
|
|
|
const mcpu = mem.spanZ(mcpu_oz);
|
|
|
|
const dynamic_linker = mem.spanZ(dynamic_linker_oz);
|
2020-03-11 16:33:10 -07:00
|
|
|
var diags: CrossTarget.ParseOptions.Diagnostics = .{};
|
|
|
|
const target: CrossTarget = CrossTarget.parse(.{
|
2020-03-31 07:25:25 -07:00
|
|
|
.arch_os_abi = mem.spanZ(zig_triple_oz) orelse "native",
|
2020-03-11 16:33:10 -07:00
|
|
|
.cpu_features = mcpu,
|
|
|
|
.dynamic_linker = dynamic_linker,
|
|
|
|
.diagnostics = &diags,
|
|
|
|
}) catch |err| switch (err) {
|
|
|
|
error.UnknownCpuModel => {
|
|
|
|
std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
|
|
|
|
diags.cpu_name.?,
|
|
|
|
@tagName(diags.arch.?),
|
|
|
|
});
|
|
|
|
for (diags.arch.?.allCpuModels()) |cpu| {
|
|
|
|
std.debug.warn(" {}\n", .{cpu.name});
|
|
|
|
}
|
|
|
|
process.exit(1);
|
|
|
|
},
|
|
|
|
error.UnknownCpuFeature => {
|
|
|
|
std.debug.warn(
|
|
|
|
\\Unknown CPU feature: '{}'
|
|
|
|
\\Available CPU features for architecture '{}':
|
|
|
|
\\
|
|
|
|
, .{
|
|
|
|
diags.unknown_feature_name,
|
|
|
|
@tagName(diags.arch.?),
|
|
|
|
});
|
|
|
|
for (diags.arch.?.allFeaturesList()) |feature| {
|
|
|
|
std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
|
|
|
|
}
|
|
|
|
process.exit(1);
|
|
|
|
},
|
|
|
|
else => |e| return e,
|
|
|
|
};
|
2020-01-21 00:01:20 -08:00
|
|
|
|
2020-03-11 21:32:50 -07:00
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stage2TargetParse(
|
|
|
|
stage1_target: *Stage2Target,
|
|
|
|
zig_triple_oz: ?[*:0]const u8,
|
|
|
|
mcpu_oz: ?[*:0]const u8,
|
|
|
|
dynamic_linker_oz: ?[*:0]const u8,
|
|
|
|
) !void {
|
|
|
|
const target = try stage2CrossTarget(zig_triple_oz, mcpu_oz, dynamic_linker_oz);
|
2020-02-19 18:30:36 -08:00
|
|
|
try stage1_target.fromTarget(target);
|
|
|
|
}
|
2020-01-22 14:35:57 -08:00
|
|
|
|
2020-02-16 10:25:30 -08:00
|
|
|
// ABI warning
|
|
|
|
const Stage2LibCInstallation = extern struct {
|
2020-03-12 06:52:28 -07:00
|
|
|
include_dir: [*]const u8,
|
2020-02-16 10:25:30 -08:00
|
|
|
include_dir_len: usize,
|
2020-03-12 06:52:28 -07:00
|
|
|
sys_include_dir: [*]const u8,
|
2020-02-16 10:25:30 -08:00
|
|
|
sys_include_dir_len: usize,
|
2020-03-12 06:52:28 -07:00
|
|
|
crt_dir: [*]const u8,
|
2020-02-16 10:25:30 -08:00
|
|
|
crt_dir_len: usize,
|
2020-03-12 06:52:28 -07:00
|
|
|
msvc_lib_dir: [*]const u8,
|
2020-02-16 10:25:30 -08:00
|
|
|
msvc_lib_dir_len: usize,
|
2020-03-12 06:52:28 -07:00
|
|
|
kernel32_lib_dir: [*]const u8,
|
2020-02-16 10:25:30 -08:00
|
|
|
kernel32_lib_dir_len: usize,
|
|
|
|
|
|
|
|
fn initFromStage2(self: *Stage2LibCInstallation, libc: LibCInstallation) void {
|
|
|
|
if (libc.include_dir) |s| {
|
|
|
|
self.include_dir = s.ptr;
|
|
|
|
self.include_dir_len = s.len;
|
|
|
|
} else {
|
|
|
|
self.include_dir = "";
|
|
|
|
self.include_dir_len = 0;
|
|
|
|
}
|
|
|
|
if (libc.sys_include_dir) |s| {
|
|
|
|
self.sys_include_dir = s.ptr;
|
|
|
|
self.sys_include_dir_len = s.len;
|
|
|
|
} else {
|
|
|
|
self.sys_include_dir = "";
|
|
|
|
self.sys_include_dir_len = 0;
|
|
|
|
}
|
|
|
|
if (libc.crt_dir) |s| {
|
|
|
|
self.crt_dir = s.ptr;
|
|
|
|
self.crt_dir_len = s.len;
|
|
|
|
} else {
|
|
|
|
self.crt_dir = "";
|
|
|
|
self.crt_dir_len = 0;
|
|
|
|
}
|
|
|
|
if (libc.msvc_lib_dir) |s| {
|
|
|
|
self.msvc_lib_dir = s.ptr;
|
|
|
|
self.msvc_lib_dir_len = s.len;
|
|
|
|
} else {
|
|
|
|
self.msvc_lib_dir = "";
|
|
|
|
self.msvc_lib_dir_len = 0;
|
|
|
|
}
|
|
|
|
if (libc.kernel32_lib_dir) |s| {
|
|
|
|
self.kernel32_lib_dir = s.ptr;
|
|
|
|
self.kernel32_lib_dir_len = s.len;
|
|
|
|
} else {
|
|
|
|
self.kernel32_lib_dir = "";
|
|
|
|
self.kernel32_lib_dir_len = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn toStage2(self: Stage2LibCInstallation) LibCInstallation {
|
|
|
|
var libc: LibCInstallation = .{};
|
|
|
|
if (self.include_dir_len != 0) {
|
2020-03-12 06:52:28 -07:00
|
|
|
libc.include_dir = self.include_dir[0..self.include_dir_len];
|
2020-02-16 10:25:30 -08:00
|
|
|
}
|
|
|
|
if (self.sys_include_dir_len != 0) {
|
2020-03-12 06:52:28 -07:00
|
|
|
libc.sys_include_dir = self.sys_include_dir[0..self.sys_include_dir_len];
|
2020-02-16 10:25:30 -08:00
|
|
|
}
|
|
|
|
if (self.crt_dir_len != 0) {
|
2020-03-12 06:52:28 -07:00
|
|
|
libc.crt_dir = self.crt_dir[0..self.crt_dir_len];
|
2020-02-16 10:25:30 -08:00
|
|
|
}
|
|
|
|
if (self.msvc_lib_dir_len != 0) {
|
2020-03-12 06:52:28 -07:00
|
|
|
libc.msvc_lib_dir = self.msvc_lib_dir[0..self.msvc_lib_dir_len];
|
2020-02-16 10:25:30 -08:00
|
|
|
}
|
|
|
|
if (self.kernel32_lib_dir_len != 0) {
|
2020-03-12 06:52:28 -07:00
|
|
|
libc.kernel32_lib_dir = self.kernel32_lib_dir[0..self.kernel32_lib_dir_len];
|
2020-02-16 10:25:30 -08:00
|
|
|
}
|
|
|
|
return libc;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error {
|
|
|
|
stderr_file = std.io.getStdErr();
|
2020-03-10 12:27:45 -07:00
|
|
|
stderr = stderr_file.outStream();
|
2020-03-30 11:23:22 -07:00
|
|
|
const libc_file = mem.spanZ(libc_file_z);
|
2020-02-16 10:25:30 -08:00
|
|
|
var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) {
|
|
|
|
error.ParseError => return .SemanticAnalyzeFail,
|
|
|
|
error.DiskQuota => return .DiskQuota,
|
|
|
|
error.FileTooBig => return .FileTooBig,
|
|
|
|
error.InputOutput => return .FileSystem,
|
|
|
|
error.NoSpaceLeft => return .NoSpaceLeft,
|
|
|
|
error.AccessDenied => return .AccessDenied,
|
|
|
|
error.BrokenPipe => return .BrokenPipe,
|
|
|
|
error.SystemResources => return .SystemResources,
|
|
|
|
error.OperationAborted => return .OperationAborted,
|
|
|
|
error.WouldBlock => unreachable,
|
|
|
|
error.Unexpected => return .Unexpected,
|
|
|
|
error.EndOfStream => return .EndOfFile,
|
|
|
|
error.IsDir => return .IsDir,
|
|
|
|
error.ConnectionResetByPeer => unreachable,
|
2020-05-03 23:42:12 -07:00
|
|
|
error.ConnectionTimedOut => unreachable,
|
2020-02-16 10:25:30 -08:00
|
|
|
error.OutOfMemory => return .OutOfMemory,
|
|
|
|
error.Unseekable => unreachable,
|
|
|
|
error.SharingViolation => return .SharingViolation,
|
|
|
|
error.PathAlreadyExists => unreachable,
|
|
|
|
error.FileNotFound => return .FileNotFound,
|
|
|
|
error.PipeBusy => return .PipeBusy,
|
|
|
|
error.NameTooLong => return .PathTooLong,
|
|
|
|
error.InvalidUtf8 => return .BadPathName,
|
|
|
|
error.BadPathName => return .BadPathName,
|
|
|
|
error.SymLinkLoop => return .SymLinkLoop,
|
|
|
|
error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
|
|
|
|
error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
|
|
|
|
error.NoDevice => return .NoDevice,
|
|
|
|
error.NotDir => return .NotDir,
|
|
|
|
error.DeviceBusy => return .DeviceBusy,
|
2020-04-02 22:39:25 -07:00
|
|
|
error.FileLocksNotSupported => unreachable,
|
2020-02-16 10:25:30 -08:00
|
|
|
};
|
|
|
|
stage1_libc.initFromStage2(libc);
|
|
|
|
return .None;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error {
|
2020-02-22 10:43:48 -08:00
|
|
|
var libc = LibCInstallation.findNative(.{
|
|
|
|
.allocator = std.heap.c_allocator,
|
|
|
|
.verbose = true,
|
|
|
|
}) catch |err| switch (err) {
|
2020-02-16 10:25:30 -08:00
|
|
|
error.OutOfMemory => return .OutOfMemory,
|
|
|
|
error.FileSystem => return .FileSystem,
|
|
|
|
error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler,
|
|
|
|
error.CCompilerExitCode => return .CCompilerExitCode,
|
|
|
|
error.CCompilerCrashed => return .CCompilerCrashed,
|
|
|
|
error.CCompilerCannotFindHeaders => return .CCompilerCannotFindHeaders,
|
|
|
|
error.LibCRuntimeNotFound => return .LibCRuntimeNotFound,
|
|
|
|
error.LibCStdLibHeaderNotFound => return .LibCStdLibHeaderNotFound,
|
|
|
|
error.LibCKernel32LibNotFound => return .LibCKernel32LibNotFound,
|
|
|
|
error.UnsupportedArchitecture => return .UnsupportedArchitecture,
|
2020-02-16 16:58:27 -08:00
|
|
|
error.WindowsSdkNotFound => return .WindowsSdkNotFound,
|
2020-04-04 09:26:57 -07:00
|
|
|
error.ZigIsTheCCompiler => return .ZigIsTheCCompiler,
|
2020-02-16 10:25:30 -08:00
|
|
|
};
|
|
|
|
stage1_libc.initFromStage2(libc);
|
|
|
|
return .None;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error {
|
|
|
|
var libc = stage1_libc.toStage2();
|
2020-03-10 12:27:45 -07:00
|
|
|
const c_out_stream = std.io.cOutStream(output_file);
|
2020-02-16 10:25:30 -08:00
|
|
|
libc.render(c_out_stream) catch |err| switch (err) {
|
|
|
|
error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
|
|
|
|
error.SystemResources => return .SystemResources,
|
|
|
|
error.OperationAborted => return .OperationAborted,
|
|
|
|
error.BrokenPipe => return .BrokenPipe,
|
|
|
|
error.DiskQuota => return .DiskQuota,
|
|
|
|
error.FileTooBig => return .FileTooBig,
|
|
|
|
error.NoSpaceLeft => return .NoSpaceLeft,
|
|
|
|
error.AccessDenied => return .AccessDenied,
|
|
|
|
error.Unexpected => return .Unexpected,
|
|
|
|
error.InputOutput => return .FileSystem,
|
|
|
|
};
|
|
|
|
return .None;
|
|
|
|
}
|
|
|
|
|
2020-04-11 13:18:54 -07:00
|
|
|
fn enumToString(value: var, type_name: []const u8) ![]const u8 {
|
|
|
|
switch (@typeInfo(@TypeOf(value))) {
|
|
|
|
.Enum => |e| {
|
|
|
|
if (e.is_exhaustive) {
|
|
|
|
return std.fmt.allocPrint(std.heap.c_allocator, ".{}", .{@tagName(value)});
|
|
|
|
} else {
|
2020-04-15 05:15:32 -07:00
|
|
|
return std.fmt.allocPrint(
|
|
|
|
std.heap.c_allocator,
|
2020-04-11 13:18:54 -07:00
|
|
|
"@intToEnum({}, {})",
|
2020-04-15 05:15:32 -07:00
|
|
|
.{ type_name, @enumToInt(value) },
|
2020-04-11 13:18:54 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
2020-04-15 05:15:32 -07:00
|
|
|
else => unreachable,
|
2020-04-11 13:18:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-16 10:25:30 -08:00
|
|
|
// ABI warning
|
2020-02-17 12:23:59 -08:00
|
|
|
const Stage2Target = extern struct {
|
|
|
|
arch: c_int,
|
|
|
|
vendor: c_int,
|
2020-02-19 18:30:36 -08:00
|
|
|
|
2020-02-21 08:47:34 -08:00
|
|
|
abi: c_int,
|
2020-02-19 18:30:36 -08:00
|
|
|
os: c_int,
|
2020-02-21 08:47:34 -08:00
|
|
|
|
2020-03-25 17:32:40 -07:00
|
|
|
is_native_os: bool,
|
|
|
|
is_native_cpu: bool,
|
2020-02-19 18:30:36 -08:00
|
|
|
|
2020-02-27 23:36:16 -08:00
|
|
|
glibc_or_darwin_version: ?*Stage2SemVer,
|
2020-02-19 18:30:36 -08:00
|
|
|
|
|
|
|
llvm_cpu_name: ?[*:0]const u8,
|
|
|
|
llvm_cpu_features: ?[*:0]const u8,
|
2020-02-24 22:52:27 -08:00
|
|
|
cpu_builtin_str: ?[*:0]const u8,
|
2020-02-19 18:30:36 -08:00
|
|
|
cache_hash: ?[*:0]const u8,
|
2020-03-11 16:33:12 -07:00
|
|
|
cache_hash_len: usize,
|
2020-02-24 22:52:27 -08:00
|
|
|
os_builtin_str: ?[*:0]const u8,
|
|
|
|
|
|
|
|
dynamic_linker: ?[*:0]const u8,
|
2020-03-20 11:39:05 -07:00
|
|
|
standard_dynamic_linker_path: ?[*:0]const u8,
|
2020-02-19 18:30:36 -08:00
|
|
|
|
2020-03-22 18:47:19 -07:00
|
|
|
llvm_cpu_features_asm_ptr: [*]const [*:0]const u8,
|
|
|
|
llvm_cpu_features_asm_len: usize,
|
|
|
|
|
2020-02-25 22:18:23 -08:00
|
|
|
fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
|
2020-02-24 22:52:27 -08:00
|
|
|
const allocator = std.heap.c_allocator;
|
|
|
|
|
2020-02-25 22:18:23 -08:00
|
|
|
var dynamic_linker: ?[*:0]u8 = null;
|
|
|
|
const target = try crossTargetToTarget(cross_target, &dynamic_linker);
|
2020-02-24 22:52:27 -08:00
|
|
|
|
2020-04-01 09:44:45 -07:00
|
|
|
var cache_hash = try std.ArrayListSentineled(u8, 0).allocPrint(allocator, "{}\n{}\n", .{
|
2020-02-24 22:52:27 -08:00
|
|
|
target.cpu.model.name,
|
|
|
|
target.cpu.features.asBytes(),
|
|
|
|
});
|
|
|
|
defer cache_hash.deinit();
|
|
|
|
|
|
|
|
const generic_arch_name = target.cpu.arch.genericName();
|
2020-04-01 09:44:45 -07:00
|
|
|
var cpu_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
|
2020-02-24 22:52:27 -08:00
|
|
|
\\Cpu{{
|
|
|
|
\\ .arch = .{},
|
|
|
|
\\ .model = &Target.{}.cpu.{},
|
|
|
|
\\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
|
|
|
|
\\
|
|
|
|
, .{
|
|
|
|
@tagName(target.cpu.arch),
|
|
|
|
generic_arch_name,
|
|
|
|
target.cpu.model.name,
|
|
|
|
generic_arch_name,
|
|
|
|
generic_arch_name,
|
|
|
|
});
|
|
|
|
defer cpu_builtin_str_buffer.deinit();
|
|
|
|
|
2020-04-01 09:44:45 -07:00
|
|
|
var llvm_features_buffer = try std.ArrayListSentineled(u8, 0).initSize(allocator, 0);
|
2020-02-24 22:52:27 -08:00
|
|
|
defer llvm_features_buffer.deinit();
|
|
|
|
|
2020-03-22 18:47:19 -07:00
|
|
|
// Unfortunately we have to do the work twice, because Clang does not support
|
|
|
|
// the same command line parameters for CPU features when assembling code as it does
|
|
|
|
// when compiling C code.
|
|
|
|
var asm_features_list = std.ArrayList([*:0]const u8).init(allocator);
|
|
|
|
defer asm_features_list.deinit();
|
|
|
|
|
2020-02-24 22:52:27 -08:00
|
|
|
for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
|
|
|
|
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
|
|
|
|
const is_enabled = target.cpu.features.isEnabled(index);
|
|
|
|
|
|
|
|
if (feature.llvm_name) |llvm_name| {
|
|
|
|
const plus_or_minus = "-+"[@boolToInt(is_enabled)];
|
2020-04-01 09:44:45 -07:00
|
|
|
try llvm_features_buffer.append(plus_or_minus);
|
|
|
|
try llvm_features_buffer.appendSlice(llvm_name);
|
|
|
|
try llvm_features_buffer.appendSlice(",");
|
2020-02-24 22:52:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_enabled) {
|
|
|
|
// TODO some kind of "zig identifier escape" function rather than
|
|
|
|
// unconditionally using @"" syntax
|
2020-04-01 09:44:45 -07:00
|
|
|
try cpu_builtin_str_buffer.appendSlice(" .@\"");
|
|
|
|
try cpu_builtin_str_buffer.appendSlice(feature.name);
|
|
|
|
try cpu_builtin_str_buffer.appendSlice("\",\n");
|
2020-02-24 22:52:27 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 18:47:19 -07:00
|
|
|
switch (target.cpu.arch) {
|
|
|
|
.riscv32, .riscv64 => {
|
|
|
|
if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
|
|
|
|
try asm_features_list.append("-mrelax");
|
|
|
|
} else {
|
|
|
|
try asm_features_list.append("-mno-relax");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
else => {
|
|
|
|
// TODO
|
|
|
|
// Argh, why doesn't the assembler accept the list of CPU features?!
|
|
|
|
// I don't see a way to do this other than hard coding everything.
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-04-01 09:44:45 -07:00
|
|
|
try cpu_builtin_str_buffer.appendSlice(
|
2020-02-24 22:52:27 -08:00
|
|
|
\\ }),
|
|
|
|
\\};
|
|
|
|
\\
|
|
|
|
);
|
|
|
|
|
2020-03-30 11:23:22 -07:00
|
|
|
assert(mem.endsWith(u8, llvm_features_buffer.span(), ","));
|
2020-02-24 22:52:27 -08:00
|
|
|
llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
|
|
|
|
|
2020-04-01 09:44:45 -07:00
|
|
|
var os_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
|
2020-02-24 22:52:27 -08:00
|
|
|
\\Os{{
|
|
|
|
\\ .tag = .{},
|
|
|
|
\\ .version_range = .{{
|
|
|
|
, .{@tagName(target.os.tag)});
|
|
|
|
defer os_builtin_str_buffer.deinit();
|
|
|
|
|
|
|
|
// We'll re-use the OS version range builtin string for the cache hash.
|
|
|
|
const os_builtin_str_ver_start_index = os_builtin_str_buffer.len();
|
|
|
|
|
|
|
|
@setEvalBranchQuota(2000);
|
|
|
|
switch (target.os.tag) {
|
|
|
|
.freestanding,
|
|
|
|
.ananas,
|
|
|
|
.cloudabi,
|
|
|
|
.dragonfly,
|
|
|
|
.fuchsia,
|
|
|
|
.ios,
|
|
|
|
.kfreebsd,
|
|
|
|
.lv2,
|
|
|
|
.solaris,
|
|
|
|
.haiku,
|
|
|
|
.minix,
|
|
|
|
.rtems,
|
|
|
|
.nacl,
|
|
|
|
.cnk,
|
|
|
|
.aix,
|
|
|
|
.cuda,
|
|
|
|
.nvcl,
|
|
|
|
.amdhsa,
|
|
|
|
.ps4,
|
|
|
|
.elfiamcu,
|
|
|
|
.tvos,
|
|
|
|
.watchos,
|
|
|
|
.mesa3d,
|
|
|
|
.contiki,
|
|
|
|
.amdpal,
|
|
|
|
.hermit,
|
|
|
|
.hurd,
|
|
|
|
.wasi,
|
|
|
|
.emscripten,
|
|
|
|
.uefi,
|
|
|
|
.other,
|
2020-04-01 09:44:45 -07:00
|
|
|
=> try os_builtin_str_buffer.appendSlice(" .none = {} }\n"),
|
2020-02-24 22:52:27 -08:00
|
|
|
|
|
|
|
.freebsd,
|
|
|
|
.macosx,
|
|
|
|
.netbsd,
|
|
|
|
.openbsd,
|
2020-03-13 08:55:50 -07:00
|
|
|
=> try os_builtin_str_buffer.outStream().print(
|
2020-02-26 17:16:14 -08:00
|
|
|
\\ .semver = .{{
|
2020-02-24 22:52:27 -08:00
|
|
|
\\ .min = .{{
|
|
|
|
\\ .major = {},
|
|
|
|
\\ .minor = {},
|
|
|
|
\\ .patch = {},
|
|
|
|
\\ }},
|
|
|
|
\\ .max = .{{
|
|
|
|
\\ .major = {},
|
|
|
|
\\ .minor = {},
|
|
|
|
\\ .patch = {},
|
|
|
|
\\ }},
|
|
|
|
\\ }}}},
|
2020-02-26 17:16:14 -08:00
|
|
|
\\
|
2020-02-24 22:52:27 -08:00
|
|
|
, .{
|
|
|
|
target.os.version_range.semver.min.major,
|
|
|
|
target.os.version_range.semver.min.minor,
|
|
|
|
target.os.version_range.semver.min.patch,
|
|
|
|
|
|
|
|
target.os.version_range.semver.max.major,
|
|
|
|
target.os.version_range.semver.max.minor,
|
|
|
|
target.os.version_range.semver.max.patch,
|
|
|
|
}),
|
|
|
|
|
2020-03-13 08:55:50 -07:00
|
|
|
.linux => try os_builtin_str_buffer.outStream().print(
|
2020-02-26 17:16:14 -08:00
|
|
|
\\ .linux = .{{
|
2020-02-24 22:52:27 -08:00
|
|
|
\\ .range = .{{
|
|
|
|
\\ .min = .{{
|
|
|
|
\\ .major = {},
|
|
|
|
\\ .minor = {},
|
|
|
|
\\ .patch = {},
|
|
|
|
\\ }},
|
|
|
|
\\ .max = .{{
|
|
|
|
\\ .major = {},
|
|
|
|
\\ .minor = {},
|
|
|
|
\\ .patch = {},
|
|
|
|
\\ }},
|
|
|
|
\\ }},
|
|
|
|
\\ .glibc = .{{
|
|
|
|
\\ .major = {},
|
|
|
|
\\ .minor = {},
|
|
|
|
\\ .patch = {},
|
|
|
|
\\ }},
|
|
|
|
\\ }}}},
|
|
|
|
\\
|
|
|
|
, .{
|
|
|
|
target.os.version_range.linux.range.min.major,
|
|
|
|
target.os.version_range.linux.range.min.minor,
|
|
|
|
target.os.version_range.linux.range.min.patch,
|
|
|
|
|
|
|
|
target.os.version_range.linux.range.max.major,
|
|
|
|
target.os.version_range.linux.range.max.minor,
|
|
|
|
target.os.version_range.linux.range.max.patch,
|
|
|
|
|
|
|
|
target.os.version_range.linux.glibc.major,
|
|
|
|
target.os.version_range.linux.glibc.minor,
|
|
|
|
target.os.version_range.linux.glibc.patch,
|
|
|
|
}),
|
|
|
|
|
2020-03-13 08:55:50 -07:00
|
|
|
.windows => try os_builtin_str_buffer.outStream().print(
|
2020-02-26 17:16:14 -08:00
|
|
|
\\ .windows = .{{
|
2020-04-11 13:18:54 -07:00
|
|
|
\\ .min = {},
|
|
|
|
\\ .max = {},
|
2020-02-24 22:52:27 -08:00
|
|
|
\\ }}}},
|
2020-02-26 17:16:14 -08:00
|
|
|
\\
|
2020-02-24 22:52:27 -08:00
|
|
|
, .{
|
2020-04-11 13:18:54 -07:00
|
|
|
try enumToString(target.os.version_range.windows.min, "Target.Os.WindowsVersion"),
|
2020-04-15 05:15:32 -07:00
|
|
|
try enumToString(target.os.version_range.windows.max, "Target.Os.WindowsVersion"),
|
2020-02-24 22:52:27 -08:00
|
|
|
}),
|
|
|
|
}
|
2020-04-01 09:44:45 -07:00
|
|
|
try os_builtin_str_buffer.appendSlice("};\n");
|
2020-02-24 22:52:27 -08:00
|
|
|
|
2020-04-01 09:44:45 -07:00
|
|
|
try cache_hash.appendSlice(
|
2020-03-30 11:23:22 -07:00
|
|
|
os_builtin_str_buffer.span()[os_builtin_str_ver_start_index..os_builtin_str_buffer.len()],
|
2020-02-24 22:52:27 -08:00
|
|
|
);
|
|
|
|
|
2020-02-27 23:36:16 -08:00
|
|
|
const glibc_or_darwin_version = blk: {
|
|
|
|
if (target.isGnuLibC()) {
|
|
|
|
const stage1_glibc = try std.heap.c_allocator.create(Stage2SemVer);
|
|
|
|
const stage2_glibc = target.os.version_range.linux.glibc;
|
|
|
|
stage1_glibc.* = .{
|
|
|
|
.major = stage2_glibc.major,
|
|
|
|
.minor = stage2_glibc.minor,
|
|
|
|
.patch = stage2_glibc.patch,
|
|
|
|
};
|
|
|
|
break :blk stage1_glibc;
|
|
|
|
} else if (target.isDarwin()) {
|
|
|
|
const stage1_semver = try std.heap.c_allocator.create(Stage2SemVer);
|
|
|
|
const stage2_semver = target.os.version_range.semver.min;
|
|
|
|
stage1_semver.* = .{
|
|
|
|
.major = stage2_semver.major,
|
|
|
|
.minor = stage2_semver.minor,
|
|
|
|
.patch = stage2_semver.patch,
|
|
|
|
};
|
|
|
|
break :blk stage1_semver;
|
|
|
|
} else {
|
|
|
|
break :blk null;
|
|
|
|
}
|
|
|
|
};
|
2020-02-24 22:52:27 -08:00
|
|
|
|
2020-03-20 11:39:05 -07:00
|
|
|
const std_dl = target.standardDynamicLinkerPath();
|
|
|
|
const std_dl_z = if (std_dl.get()) |dl|
|
|
|
|
(try mem.dupeZ(std.heap.c_allocator, u8, dl)).ptr
|
|
|
|
else
|
|
|
|
null;
|
|
|
|
|
2020-03-11 16:33:12 -07:00
|
|
|
const cache_hash_slice = cache_hash.toOwnedSlice();
|
2020-03-22 18:47:19 -07:00
|
|
|
const asm_features = asm_features_list.toOwnedSlice();
|
2020-02-20 22:54:00 -08:00
|
|
|
self.* = .{
|
2020-02-24 22:52:27 -08:00
|
|
|
.arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
|
2020-02-20 22:54:00 -08:00
|
|
|
.vendor = 0,
|
2020-02-24 22:52:27 -08:00
|
|
|
.os = @enumToInt(target.os.tag),
|
|
|
|
.abi = @enumToInt(target.abi),
|
|
|
|
.llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
|
|
|
|
.llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
|
2020-03-22 18:47:19 -07:00
|
|
|
.llvm_cpu_features_asm_ptr = asm_features.ptr,
|
|
|
|
.llvm_cpu_features_asm_len = asm_features.len,
|
2020-02-24 22:52:27 -08:00
|
|
|
.cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
|
|
|
|
.os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
|
2020-03-11 16:33:12 -07:00
|
|
|
.cache_hash = cache_hash_slice.ptr,
|
|
|
|
.cache_hash_len = cache_hash_slice.len,
|
2020-03-25 17:32:40 -07:00
|
|
|
.is_native_os = cross_target.isNativeOs(),
|
|
|
|
.is_native_cpu = cross_target.isNativeCpu(),
|
2020-02-27 23:36:16 -08:00
|
|
|
.glibc_or_darwin_version = glibc_or_darwin_version,
|
2020-02-24 22:52:27 -08:00
|
|
|
.dynamic_linker = dynamic_linker,
|
2020-03-20 11:39:05 -07:00
|
|
|
.standard_dynamic_linker_path = std_dl_z,
|
2020-02-20 22:54:00 -08:00
|
|
|
};
|
2020-02-19 18:30:36 -08:00
|
|
|
}
|
2020-02-17 12:23:59 -08:00
|
|
|
};
|
|
|
|
|
2020-02-24 22:52:27 -08:00
|
|
|
fn enumInt(comptime Enum: type, int: c_int) Enum {
|
|
|
|
return @intToEnum(Enum, @intCast(@TagType(Enum), int));
|
|
|
|
}
|
|
|
|
|
2020-02-25 22:18:23 -08:00
|
|
|
fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
|
2020-02-28 14:23:16 -08:00
|
|
|
var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
|
2020-03-06 16:41:44 -08:00
|
|
|
if (info.cpu_detection_unimplemented) {
|
2020-02-28 14:23:16 -08:00
|
|
|
// TODO We want to just use detected_info.target but implementing
|
|
|
|
// CPU model & feature detection is todo so here we rely on LLVM.
|
|
|
|
const llvm = @import("llvm.zig");
|
|
|
|
const llvm_cpu_name = llvm.GetHostCPUName();
|
|
|
|
const llvm_cpu_features = llvm.GetNativeFeatures();
|
|
|
|
const arch = std.Target.current.cpu.arch;
|
|
|
|
info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
|
|
|
|
cross_target.updateCpuFeatures(&info.target.cpu.features);
|
2020-02-28 15:09:33 -08:00
|
|
|
info.target.cpu.arch = cross_target.getCpuArch();
|
2020-02-25 22:18:23 -08:00
|
|
|
}
|
2020-02-28 14:23:16 -08:00
|
|
|
if (info.dynamic_linker.get()) |dl| {
|
|
|
|
dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
|
|
|
|
} else {
|
|
|
|
dynamic_linker_ptr.* = null;
|
2020-02-26 13:32:28 -08:00
|
|
|
}
|
2020-02-28 14:23:16 -08:00
|
|
|
return info.target;
|
2020-02-25 22:18:23 -08:00
|
|
|
}
|
|
|
|
|
2020-02-17 12:23:59 -08:00
|
|
|
// ABI warning
|
2020-02-27 23:36:16 -08:00
|
|
|
const Stage2SemVer = extern struct {
|
2020-02-17 12:23:59 -08:00
|
|
|
major: u32,
|
|
|
|
minor: u32,
|
|
|
|
patch: u32,
|
|
|
|
};
|
|
|
|
|
2020-02-18 22:24:34 -08:00
|
|
|
// ABI warning
|
|
|
|
const Stage2NativePaths = extern struct {
|
|
|
|
include_dirs_ptr: [*][*:0]u8,
|
|
|
|
include_dirs_len: usize,
|
|
|
|
lib_dirs_ptr: [*][*:0]u8,
|
|
|
|
lib_dirs_len: usize,
|
|
|
|
rpaths_ptr: [*][*:0]u8,
|
|
|
|
rpaths_len: usize,
|
|
|
|
warnings_ptr: [*][*:0]u8,
|
|
|
|
warnings_len: usize,
|
|
|
|
};
|
|
|
|
// ABI warning
|
|
|
|
export fn stage2_detect_native_paths(stage1_paths: *Stage2NativePaths) Error {
|
|
|
|
stage2DetectNativePaths(stage1_paths) catch |err| switch (err) {
|
|
|
|
error.OutOfMemory => return .OutOfMemory,
|
|
|
|
};
|
|
|
|
return .None;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stage2DetectNativePaths(stage1_paths: *Stage2NativePaths) !void {
|
|
|
|
var paths = try std.zig.system.NativePaths.detect(std.heap.c_allocator);
|
|
|
|
errdefer paths.deinit();
|
|
|
|
|
2020-03-30 11:23:22 -07:00
|
|
|
try convertSlice(paths.include_dirs.span(), &stage1_paths.include_dirs_ptr, &stage1_paths.include_dirs_len);
|
|
|
|
try convertSlice(paths.lib_dirs.span(), &stage1_paths.lib_dirs_ptr, &stage1_paths.lib_dirs_len);
|
|
|
|
try convertSlice(paths.rpaths.span(), &stage1_paths.rpaths_ptr, &stage1_paths.rpaths_len);
|
|
|
|
try convertSlice(paths.warnings.span(), &stage1_paths.warnings_ptr, &stage1_paths.warnings_len);
|
2020-02-18 22:24:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void {
|
|
|
|
len.* = slice.len;
|
|
|
|
const new_slice = try std.heap.c_allocator.alloc([*:0]u8, slice.len);
|
|
|
|
for (slice) |item, i| {
|
|
|
|
new_slice[i] = item.ptr;
|
|
|
|
}
|
|
|
|
ptr.* = new_slice.ptr;
|
|
|
|
}
|
2020-03-21 07:12:28 -07:00
|
|
|
|
|
|
|
const clang_args = @import("clang_options.zig").list;
|
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
pub const ClangArgIterator = extern struct {
|
|
|
|
has_next: bool,
|
|
|
|
zig_equivalent: ZigEquivalent,
|
|
|
|
only_arg: [*:0]const u8,
|
|
|
|
second_arg: [*:0]const u8,
|
|
|
|
other_args_ptr: [*]const [*:0]const u8,
|
|
|
|
other_args_len: usize,
|
|
|
|
argv_ptr: [*]const [*:0]const u8,
|
|
|
|
argv_len: usize,
|
|
|
|
next_index: usize,
|
2020-03-27 19:24:40 -07:00
|
|
|
root_args: ?*Args,
|
2020-03-21 07:12:28 -07:00
|
|
|
|
|
|
|
// ABI warning
|
|
|
|
pub const ZigEquivalent = extern enum {
|
|
|
|
target,
|
|
|
|
o,
|
|
|
|
c,
|
|
|
|
other,
|
|
|
|
positional,
|
|
|
|
l,
|
2020-03-21 12:29:52 -07:00
|
|
|
ignore,
|
2020-03-21 13:38:58 -07:00
|
|
|
driver_punt,
|
2020-03-21 12:29:52 -07:00
|
|
|
pic,
|
|
|
|
no_pic,
|
|
|
|
nostdlib,
|
2020-03-26 19:48:37 -07:00
|
|
|
nostdlib_cpp,
|
2020-03-21 12:29:52 -07:00
|
|
|
shared,
|
|
|
|
rdynamic,
|
|
|
|
wl,
|
2020-04-01 13:01:06 -07:00
|
|
|
pp_or_asm,
|
2020-03-21 19:30:46 -07:00
|
|
|
optimize,
|
|
|
|
debug,
|
|
|
|
sanitize,
|
2020-03-25 09:05:33 -07:00
|
|
|
linker_script,
|
2020-03-25 16:32:12 -07:00
|
|
|
verbose_cmds,
|
2020-03-27 23:23:56 -07:00
|
|
|
for_linker,
|
2020-03-28 00:35:54 -07:00
|
|
|
linker_input_z,
|
2020-04-01 15:05:06 -07:00
|
|
|
lib_dir,
|
|
|
|
mcpu,
|
2020-04-02 12:47:27 -07:00
|
|
|
dep_file,
|
2020-04-02 12:59:48 -07:00
|
|
|
framework_dir,
|
|
|
|
framework,
|
2020-04-04 11:58:24 -07:00
|
|
|
nostdlibinc,
|
2020-03-21 07:12:28 -07:00
|
|
|
};
|
|
|
|
|
2020-03-27 19:24:40 -07:00
|
|
|
const Args = struct {
|
|
|
|
next_index: usize,
|
|
|
|
argv_ptr: [*]const [*:0]const u8,
|
|
|
|
argv_len: usize,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub fn init(argv: []const [*:0]const u8) ClangArgIterator {
|
2020-03-21 07:12:28 -07:00
|
|
|
return .{
|
|
|
|
.next_index = 2, // `zig cc foo` this points to `foo`
|
|
|
|
.has_next = argv.len > 2,
|
|
|
|
.zig_equivalent = undefined,
|
|
|
|
.only_arg = undefined,
|
|
|
|
.second_arg = undefined,
|
|
|
|
.other_args_ptr = undefined,
|
|
|
|
.other_args_len = undefined,
|
|
|
|
.argv_ptr = argv.ptr,
|
|
|
|
.argv_len = argv.len,
|
2020-03-27 19:24:40 -07:00
|
|
|
.root_args = null,
|
2020-03-21 07:12:28 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-03-27 19:24:40 -07:00
|
|
|
pub fn next(self: *ClangArgIterator) !void {
|
2020-03-21 07:12:28 -07:00
|
|
|
assert(self.has_next);
|
|
|
|
assert(self.next_index < self.argv_len);
|
|
|
|
// In this state we know that the parameter we are looking at is a root parameter
|
|
|
|
// rather than an argument to a parameter.
|
|
|
|
self.other_args_ptr = self.argv_ptr + self.next_index;
|
|
|
|
self.other_args_len = 1; // We adjust this value below when necessary.
|
2020-03-27 19:24:40 -07:00
|
|
|
var arg = mem.span(self.argv_ptr[self.next_index]);
|
|
|
|
self.incrementArgIndex();
|
|
|
|
|
|
|
|
if (mem.startsWith(u8, arg, "@")) {
|
|
|
|
if (self.root_args != null) return error.NestedResponseFile;
|
|
|
|
|
|
|
|
// This is a "compiler response file". We must parse the file and treat its
|
|
|
|
// contents as command line parameters.
|
|
|
|
const allocator = std.heap.c_allocator;
|
|
|
|
const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
|
|
|
|
const resp_file_path = arg[1..];
|
|
|
|
const resp_contents = fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes) catch |err| {
|
|
|
|
std.debug.warn("unable to read response file '{}': {}\n", .{ resp_file_path, @errorName(err) });
|
|
|
|
process.exit(1);
|
|
|
|
};
|
|
|
|
defer allocator.free(resp_contents);
|
|
|
|
// TODO is there a specification for this file format? Let's find it and make this parsing more robust
|
|
|
|
// at the very least I'm guessing this needs to handle quotes and `#` comments.
|
|
|
|
var it = mem.tokenize(resp_contents, " \t\r\n");
|
|
|
|
var resp_arg_list = std.ArrayList([*:0]const u8).init(allocator);
|
|
|
|
defer resp_arg_list.deinit();
|
|
|
|
{
|
|
|
|
errdefer {
|
|
|
|
for (resp_arg_list.span()) |item| {
|
|
|
|
allocator.free(mem.span(item));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (it.next()) |token| {
|
|
|
|
const dupe_token = try mem.dupeZ(allocator, u8, token);
|
|
|
|
errdefer allocator.free(dupe_token);
|
|
|
|
try resp_arg_list.append(dupe_token);
|
|
|
|
}
|
|
|
|
const args = try allocator.create(Args);
|
|
|
|
errdefer allocator.destroy(args);
|
|
|
|
args.* = .{
|
|
|
|
.next_index = self.next_index,
|
|
|
|
.argv_ptr = self.argv_ptr,
|
|
|
|
.argv_len = self.argv_len,
|
|
|
|
};
|
|
|
|
self.root_args = args;
|
|
|
|
}
|
|
|
|
const resp_arg_slice = resp_arg_list.toOwnedSlice();
|
|
|
|
self.next_index = 0;
|
|
|
|
self.argv_ptr = resp_arg_slice.ptr;
|
|
|
|
self.argv_len = resp_arg_slice.len;
|
|
|
|
|
|
|
|
if (resp_arg_slice.len == 0) {
|
|
|
|
self.resolveRespFileArgs();
|
|
|
|
return;
|
|
|
|
}
|
2020-03-21 07:12:28 -07:00
|
|
|
|
2020-03-27 19:24:40 -07:00
|
|
|
self.has_next = true;
|
|
|
|
self.other_args_ptr = self.argv_ptr + self.next_index;
|
|
|
|
self.other_args_len = 1; // We adjust this value below when necessary.
|
|
|
|
arg = mem.span(self.argv_ptr[self.next_index]);
|
|
|
|
self.incrementArgIndex();
|
|
|
|
}
|
2020-03-21 07:12:28 -07:00
|
|
|
if (!mem.startsWith(u8, arg, "-")) {
|
|
|
|
self.zig_equivalent = .positional;
|
|
|
|
self.only_arg = arg.ptr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) {
|
2020-03-21 19:30:46 -07:00
|
|
|
.flag => {
|
|
|
|
const prefix_len = clang_arg.matchEql(arg);
|
|
|
|
if (prefix_len > 0) {
|
|
|
|
self.zig_equivalent = clang_arg.zig_equivalent;
|
|
|
|
self.only_arg = arg.ptr + prefix_len;
|
2020-03-21 07:12:28 -07:00
|
|
|
|
2020-03-21 19:30:46 -07:00
|
|
|
break :find_clang_arg;
|
|
|
|
}
|
2020-03-21 07:12:28 -07:00
|
|
|
},
|
|
|
|
.joined, .comma_joined => {
|
2020-03-21 12:29:52 -07:00
|
|
|
// joined example: --target=foo
|
|
|
|
// comma_joined example: -Wl,-soname,libsoundio.so.2
|
2020-03-21 07:12:28 -07:00
|
|
|
const prefix_len = clang_arg.matchStartsWith(arg);
|
|
|
|
if (prefix_len != 0) {
|
|
|
|
self.zig_equivalent = clang_arg.zig_equivalent;
|
|
|
|
self.only_arg = arg.ptr + prefix_len; // This will skip over the "--target=" part.
|
|
|
|
|
|
|
|
break :find_clang_arg;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
.joined_or_separate => {
|
|
|
|
// Examples: `-lfoo`, `-l foo`
|
|
|
|
const prefix_len = clang_arg.matchStartsWith(arg);
|
|
|
|
if (prefix_len == arg.len) {
|
|
|
|
if (self.next_index >= self.argv_len) {
|
|
|
|
std.debug.warn("Expected parameter after '{}'\n", .{arg});
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
self.only_arg = self.argv_ptr[self.next_index];
|
2020-03-27 19:24:40 -07:00
|
|
|
self.incrementArgIndex();
|
2020-03-21 07:12:28 -07:00
|
|
|
self.other_args_len += 1;
|
|
|
|
self.zig_equivalent = clang_arg.zig_equivalent;
|
|
|
|
|
|
|
|
break :find_clang_arg;
|
|
|
|
} else if (prefix_len != 0) {
|
|
|
|
self.zig_equivalent = clang_arg.zig_equivalent;
|
|
|
|
self.only_arg = arg.ptr + prefix_len;
|
|
|
|
|
|
|
|
break :find_clang_arg;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
.joined_and_separate => {
|
|
|
|
// Example: `-Xopenmp-target=riscv64-linux-unknown foo`
|
|
|
|
const prefix_len = clang_arg.matchStartsWith(arg);
|
|
|
|
if (prefix_len != 0) {
|
|
|
|
self.only_arg = arg.ptr + prefix_len;
|
|
|
|
if (self.next_index >= self.argv_len) {
|
|
|
|
std.debug.warn("Expected parameter after '{}'\n", .{arg});
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
self.second_arg = self.argv_ptr[self.next_index];
|
2020-03-27 19:24:40 -07:00
|
|
|
self.incrementArgIndex();
|
2020-03-21 07:12:28 -07:00
|
|
|
self.other_args_len += 1;
|
|
|
|
self.zig_equivalent = clang_arg.zig_equivalent;
|
|
|
|
break :find_clang_arg;
|
|
|
|
}
|
|
|
|
},
|
2020-03-21 19:30:46 -07:00
|
|
|
.separate => if (clang_arg.matchEql(arg) > 0) {
|
2020-03-21 07:12:28 -07:00
|
|
|
if (self.next_index >= self.argv_len) {
|
|
|
|
std.debug.warn("Expected parameter after '{}'\n", .{arg});
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
self.only_arg = self.argv_ptr[self.next_index];
|
2020-03-27 19:24:40 -07:00
|
|
|
self.incrementArgIndex();
|
2020-03-21 07:12:28 -07:00
|
|
|
self.other_args_len += 1;
|
|
|
|
self.zig_equivalent = clang_arg.zig_equivalent;
|
|
|
|
break :find_clang_arg;
|
|
|
|
},
|
|
|
|
.remaining_args_joined => {
|
|
|
|
const prefix_len = clang_arg.matchStartsWith(arg);
|
|
|
|
if (prefix_len != 0) {
|
|
|
|
@panic("TODO");
|
|
|
|
}
|
|
|
|
},
|
2020-03-21 19:30:46 -07:00
|
|
|
.multi_arg => if (clang_arg.matchEql(arg) > 0) {
|
2020-03-21 07:12:28 -07:00
|
|
|
@panic("TODO");
|
|
|
|
},
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std.debug.warn("Unknown Clang option: '{}'\n", .{arg});
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
}
|
2020-03-27 19:24:40 -07:00
|
|
|
|
|
|
|
fn incrementArgIndex(self: *ClangArgIterator) void {
|
|
|
|
self.next_index += 1;
|
|
|
|
self.resolveRespFileArgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolveRespFileArgs(self: *ClangArgIterator) void {
|
|
|
|
const allocator = std.heap.c_allocator;
|
|
|
|
if (self.next_index >= self.argv_len) {
|
|
|
|
if (self.root_args) |root_args| {
|
|
|
|
self.next_index = root_args.next_index;
|
|
|
|
self.argv_ptr = root_args.argv_ptr;
|
|
|
|
self.argv_len = root_args.argv_len;
|
|
|
|
|
|
|
|
allocator.destroy(root_args);
|
|
|
|
self.root_args = null;
|
|
|
|
}
|
|
|
|
if (self.next_index >= self.argv_len) {
|
|
|
|
self.has_next = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-21 07:12:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
export fn stage2_clang_arg_iterator(
|
|
|
|
result: *ClangArgIterator,
|
|
|
|
argc: usize,
|
|
|
|
argv: [*]const [*:0]const u8,
|
|
|
|
) void {
|
|
|
|
result.* = ClangArgIterator.init(argv[0..argc]);
|
|
|
|
}
|
|
|
|
|
|
|
|
export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {
|
|
|
|
it.next() catch |err| switch (err) {
|
2020-03-27 19:24:40 -07:00
|
|
|
error.NestedResponseFile => return .NestedResponseFile,
|
|
|
|
error.OutOfMemory => return .OutOfMemory,
|
2020-03-21 07:12:28 -07:00
|
|
|
};
|
|
|
|
return .None;
|
|
|
|
}
|