2017-12-26 16:44:08 -08:00
|
|
|
const builtin = @import("builtin");
|
2017-12-11 20:34:59 -08:00
|
|
|
const std = @import("std");
|
|
|
|
const Builder = std.build.Builder;
|
2017-04-18 22:13:15 -07:00
|
|
|
const tests = @import("test/tests.zig");
|
2017-12-11 20:34:59 -08:00
|
|
|
const os = std.os;
|
|
|
|
const BufMap = std.BufMap;
|
|
|
|
const warn = std.debug.warn;
|
|
|
|
const mem = std.mem;
|
|
|
|
const ArrayList = std.ArrayList;
|
|
|
|
const Buffer = std.Buffer;
|
|
|
|
const io = std.io;
|
2017-04-18 22:13:15 -07:00
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
pub fn build(b: *Builder) !void {
|
2017-10-21 14:31:06 -07:00
|
|
|
const mode = b.standardReleaseOptions();
|
|
|
|
|
2017-11-07 00:22:27 -08:00
|
|
|
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
|
|
|
|
2018-01-16 22:50:35 -08:00
|
|
|
const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
|
2019-02-06 21:42:41 -08:00
|
|
|
const langref_out_path = os.path.join(
|
|
|
|
b.allocator,
|
|
|
|
[][]const u8{ b.cache_root, "langref.html" },
|
|
|
|
) catch unreachable;
|
breaking changes to zig build API and improved caching
* in Zig build scripts, getOutputPath() is no longer a valid function
to call, unless setOutputDir() was used, or within a custom make()
function. Instead there is more convenient API to use which takes
advantage of the caching system. Search this commit diff for
`exe.run()` for an example.
* Zig build by default enables caching. All build artifacts will go
into zig-cache. If you want to access build artifacts in a convenient
location, it is recommended to add an `install` step. Otherwise
you can use the `run()` API mentioned above to execute programs
directly from their location in the cache. Closes #330.
`addSystemCommand` is available for programs not built with Zig
build.
* Please note that Zig does no cache evicting yet. You may have to
manually delete zig-cache directories periodically to keep disk
usage down. It's planned for this to be a simple Least Recently
Used eviction system eventually.
* `--output`, `--output-lib`, and `--output-h` are removed. Instead,
use `--output-dir` which defaults to the current working directory.
Or take advantage of `--cache on`, which will print the main output
path to stdout, and the other artifacts will be in the same directory
with predictable file names. `--disable-gen-h` is available when
one wants to prevent .h file generation.
* `@cImport` is always independently cached now. Closes #2015.
It always writes the generated Zig code to disk which makes debug
info and compile errors better. No more "TODO: remember C source
location to display here"
* Fix .d file parsing. (Fixes the MacOS CI failure)
* Zig no longer creates "temporary files" other than inside a
zig-cache directory.
This breaks the CLI API that Godbolt uses. The suggested new invocation
can be found in this commit diff, in the changes to `test/cli.zig`.
2019-03-08 19:53:35 -08:00
|
|
|
var docgen_cmd = docgen_exe.run();
|
|
|
|
docgen_cmd.addArgs([][]const u8{
|
2018-01-16 22:50:35 -08:00
|
|
|
rel_zig_exe,
|
2018-08-21 18:01:37 -07:00
|
|
|
"doc" ++ os.path.sep_str ++ "langref.html.in",
|
2018-09-12 08:49:46 -07:00
|
|
|
langref_out_path,
|
2017-11-07 00:22:27 -08:00
|
|
|
});
|
|
|
|
docgen_cmd.step.dependOn(&docgen_exe.step);
|
|
|
|
|
|
|
|
const docs_step = b.step("docs", "Build documentation");
|
|
|
|
docs_step.dependOn(&docgen_cmd.step);
|
|
|
|
|
2018-01-03 15:25:17 -08:00
|
|
|
const test_step = b.step("test", "Run all the tests");
|
|
|
|
|
2018-01-03 18:32:50 -08:00
|
|
|
// find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
|
2018-11-13 05:08:37 -08:00
|
|
|
const build_info = try b.exec([][]const u8{
|
2018-05-17 20:21:44 -07:00
|
|
|
b.zig_exe,
|
|
|
|
"BUILD_INFO",
|
|
|
|
});
|
2018-01-03 18:32:50 -08:00
|
|
|
var index: usize = 0;
|
2018-11-13 05:08:37 -08:00
|
|
|
var ctx = Context{
|
2018-07-10 17:18:43 -07:00
|
|
|
.cmake_binary_dir = nextValue(&index, build_info),
|
|
|
|
.cxx_compiler = nextValue(&index, build_info),
|
|
|
|
.llvm_config_exe = nextValue(&index, build_info),
|
|
|
|
.lld_include_dir = nextValue(&index, build_info),
|
|
|
|
.lld_libraries = nextValue(&index, build_info),
|
|
|
|
.std_files = nextValue(&index, build_info),
|
|
|
|
.c_header_files = nextValue(&index, build_info),
|
|
|
|
.dia_guids_lib = nextValue(&index, build_info),
|
|
|
|
.llvm = undefined,
|
|
|
|
};
|
|
|
|
ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
|
2018-01-03 18:32:50 -08:00
|
|
|
|
2018-07-10 17:18:43 -07:00
|
|
|
var test_stage2 = b.addTest("src-self-hosted/test.zig");
|
|
|
|
test_stage2.setBuildMode(builtin.Mode.Debug);
|
2018-01-03 18:32:50 -08:00
|
|
|
|
2019-02-26 15:10:40 -08:00
|
|
|
const fmt_build_zig = b.addFmt([][]const u8{"build.zig"});
|
|
|
|
|
2018-01-03 18:32:50 -08:00
|
|
|
var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
|
|
|
|
exe.setBuildMode(mode);
|
2018-03-31 13:34:55 -07:00
|
|
|
|
2018-07-10 17:18:43 -07:00
|
|
|
try configureStage2(b, test_stage2, ctx);
|
|
|
|
try configureStage2(b, exe, ctx);
|
2018-01-03 15:25:17 -08:00
|
|
|
|
2018-01-03 18:32:50 -08:00
|
|
|
b.default_step.dependOn(&exe.step);
|
2018-01-04 20:30:03 -08:00
|
|
|
|
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
|
|
|
addLibUserlandStep(b);
|
|
|
|
|
2018-07-11 11:09:05 -07:00
|
|
|
const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
|
2018-09-12 11:50:26 -07:00
|
|
|
const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
|
|
|
|
const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;
|
|
|
|
const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release;
|
2018-06-09 22:13:51 -07:00
|
|
|
const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") orelse false;
|
2018-01-04 20:30:03 -08:00
|
|
|
if (!skip_self_hosted) {
|
|
|
|
test_step.dependOn(&exe.step);
|
|
|
|
}
|
2018-06-09 22:13:51 -07:00
|
|
|
const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") orelse false;
|
2018-01-04 20:43:46 -08:00
|
|
|
exe.setVerboseLink(verbose_link_exe);
|
2017-10-21 14:31:06 -07:00
|
|
|
|
2018-01-03 18:32:50 -08:00
|
|
|
b.installArtifact(exe);
|
2018-07-10 17:18:43 -07:00
|
|
|
installStdLib(b, ctx.std_files);
|
|
|
|
installCHeaders(b, ctx.c_header_files);
|
2017-10-21 14:31:06 -07:00
|
|
|
|
2017-04-18 22:13:15 -07:00
|
|
|
const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
|
|
|
|
|
2018-07-10 17:18:43 -07:00
|
|
|
const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
|
|
|
|
test_stage2_step.dependOn(&test_stage2.step);
|
2018-09-11 08:52:16 -07:00
|
|
|
|
|
|
|
// TODO see https://github.com/ziglang/zig/issues/1364
|
|
|
|
if (false) {
|
|
|
|
test_step.dependOn(test_stage2_step);
|
|
|
|
}
|
2018-07-10 17:18:43 -07:00
|
|
|
|
2018-09-12 11:50:26 -07:00
|
|
|
var chosen_modes: [4]builtin.Mode = undefined;
|
|
|
|
var chosen_mode_index: usize = 0;
|
|
|
|
chosen_modes[chosen_mode_index] = builtin.Mode.Debug;
|
|
|
|
chosen_mode_index += 1;
|
|
|
|
if (!skip_release_safe) {
|
|
|
|
chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSafe;
|
|
|
|
chosen_mode_index += 1;
|
|
|
|
}
|
|
|
|
if (!skip_release_fast) {
|
|
|
|
chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseFast;
|
|
|
|
chosen_mode_index += 1;
|
|
|
|
}
|
|
|
|
if (!skip_release_small) {
|
|
|
|
chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSmall;
|
|
|
|
chosen_mode_index += 1;
|
|
|
|
}
|
|
|
|
const modes = chosen_modes[0..chosen_mode_index];
|
2017-11-07 00:22:27 -08:00
|
|
|
|
2019-02-26 15:10:40 -08:00
|
|
|
// run stage1 `zig fmt` on this build.zig file just to make sure it works
|
|
|
|
test_step.dependOn(&fmt_build_zig.step);
|
|
|
|
const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
|
|
|
|
fmt_step.dependOn(&fmt_build_zig.step);
|
|
|
|
|
2019-01-29 18:47:26 -08:00
|
|
|
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
|
2017-04-19 01:12:22 -07:00
|
|
|
|
2019-03-02 13:46:04 -08:00
|
|
|
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes));
|
2017-04-19 23:26:36 -07:00
|
|
|
|
2019-03-02 13:46:04 -08:00
|
|
|
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes));
|
2017-08-18 10:51:16 -07:00
|
|
|
|
2018-07-11 16:38:01 -07:00
|
|
|
test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
|
2018-07-18 01:28:14 -07:00
|
|
|
test_step.dependOn(tests.addBuildExampleTests(b, test_filter, modes));
|
2018-09-17 14:08:56 -07:00
|
|
|
test_step.dependOn(tests.addCliTests(b, test_filter, modes));
|
2018-07-11 16:38:01 -07:00
|
|
|
test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
|
|
|
|
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
|
|
|
|
test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
|
2017-11-24 11:56:05 -08:00
|
|
|
test_step.dependOn(tests.addTranslateCTests(b, test_filter));
|
2018-01-22 19:24:07 -08:00
|
|
|
test_step.dependOn(tests.addGenHTests(b, test_filter));
|
2018-07-11 11:09:05 -07:00
|
|
|
test_step.dependOn(docs_step);
|
2017-04-18 22:13:15 -07:00
|
|
|
}
|
2017-12-11 20:34:59 -08:00
|
|
|
|
2018-11-01 21:07:43 -07:00
|
|
|
fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
|
2017-12-11 20:34:59 -08:00
|
|
|
for (dep.libdirs.toSliceConst()) |lib_dir| {
|
|
|
|
lib_exe_obj.addLibPath(lib_dir);
|
|
|
|
}
|
2019-02-06 21:42:41 -08:00
|
|
|
const lib_dir = os.path.join(
|
|
|
|
b.allocator,
|
|
|
|
[][]const u8{ dep.prefix, "lib" },
|
|
|
|
) catch unreachable;
|
2017-12-23 17:21:57 -08:00
|
|
|
for (dep.system_libs.toSliceConst()) |lib| {
|
2018-11-01 21:07:43 -07:00
|
|
|
const static_bare_name = if (mem.eql(u8, lib, "curses"))
|
|
|
|
([]const u8)("libncurses.a")
|
|
|
|
else
|
|
|
|
b.fmt("lib{}.a", lib);
|
2019-02-06 21:42:41 -08:00
|
|
|
const static_lib_name = os.path.join(
|
|
|
|
b.allocator,
|
|
|
|
[][]const u8{ lib_dir, static_bare_name },
|
|
|
|
) catch unreachable;
|
2018-11-01 21:07:43 -07:00
|
|
|
const have_static = fileExists(static_lib_name) catch unreachable;
|
|
|
|
if (have_static) {
|
|
|
|
lib_exe_obj.addObjectFile(static_lib_name);
|
|
|
|
} else {
|
|
|
|
lib_exe_obj.linkSystemLibrary(lib);
|
|
|
|
}
|
2017-12-11 20:34:59 -08:00
|
|
|
}
|
2017-12-23 17:21:57 -08:00
|
|
|
for (dep.libs.toSliceConst()) |lib| {
|
|
|
|
lib_exe_obj.addObjectFile(lib);
|
|
|
|
}
|
2017-12-11 20:34:59 -08:00
|
|
|
for (dep.includes.toSliceConst()) |include_path| {
|
|
|
|
lib_exe_obj.addIncludeDir(include_path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 21:07:43 -07:00
|
|
|
fn fileExists(filename: []const u8) !bool {
|
|
|
|
os.File.access(filename) catch |err| switch (err) {
|
|
|
|
error.PermissionDenied,
|
|
|
|
error.FileNotFound,
|
|
|
|
=> return false,
|
|
|
|
else => return err,
|
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-10 17:18:43 -07:00
|
|
|
fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
|
2018-01-03 01:55:16 -08:00
|
|
|
const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
|
2019-02-06 21:42:41 -08:00
|
|
|
lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{
|
|
|
|
cmake_binary_dir,
|
|
|
|
"zig_cpp",
|
|
|
|
b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()),
|
|
|
|
}) catch unreachable);
|
2017-12-26 16:44:08 -08:00
|
|
|
}
|
|
|
|
|
2018-11-13 05:08:37 -08:00
|
|
|
const LibraryDep = struct {
|
2018-11-01 21:07:43 -07:00
|
|
|
prefix: []const u8,
|
2017-12-11 20:34:59 -08:00
|
|
|
libdirs: ArrayList([]const u8),
|
|
|
|
libs: ArrayList([]const u8),
|
2017-12-23 17:21:57 -08:00
|
|
|
system_libs: ArrayList([]const u8),
|
2017-12-11 20:34:59 -08:00
|
|
|
includes: ArrayList([]const u8),
|
|
|
|
};
|
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
|
2018-11-13 05:08:37 -08:00
|
|
|
const shared_mode = try b.exec([][]const u8{ llvm_config_exe, "--shared-mode" });
|
2018-11-01 21:07:43 -07:00
|
|
|
const is_static = mem.startsWith(u8, shared_mode, "static");
|
|
|
|
const libs_output = if (is_static)
|
2018-11-13 05:08:37 -08:00
|
|
|
try b.exec([][]const u8{
|
2018-11-01 21:07:43 -07:00
|
|
|
llvm_config_exe,
|
|
|
|
"--libfiles",
|
|
|
|
"--system-libs",
|
|
|
|
})
|
|
|
|
else
|
2018-11-13 05:08:37 -08:00
|
|
|
try b.exec([][]const u8{
|
2018-11-01 21:07:43 -07:00
|
|
|
llvm_config_exe,
|
|
|
|
"--libs",
|
|
|
|
});
|
2018-11-13 05:08:37 -08:00
|
|
|
const includes_output = try b.exec([][]const u8{ llvm_config_exe, "--includedir" });
|
|
|
|
const libdir_output = try b.exec([][]const u8{ llvm_config_exe, "--libdir" });
|
|
|
|
const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" });
|
2017-12-11 20:34:59 -08:00
|
|
|
|
2018-11-13 05:08:37 -08:00
|
|
|
var result = LibraryDep{
|
2019-02-04 12:24:06 -08:00
|
|
|
.prefix = mem.tokenize(prefix_output, " \r\n").next().?,
|
2017-12-11 20:34:59 -08:00
|
|
|
.libs = ArrayList([]const u8).init(b.allocator),
|
2017-12-23 17:21:57 -08:00
|
|
|
.system_libs = ArrayList([]const u8).init(b.allocator),
|
2017-12-11 20:34:59 -08:00
|
|
|
.includes = ArrayList([]const u8).init(b.allocator),
|
|
|
|
.libdirs = ArrayList([]const u8).init(b.allocator),
|
|
|
|
};
|
|
|
|
{
|
2019-02-04 12:24:06 -08:00
|
|
|
var it = mem.tokenize(libs_output, " \r\n");
|
2017-12-11 20:34:59 -08:00
|
|
|
while (it.next()) |lib_arg| {
|
|
|
|
if (mem.startsWith(u8, lib_arg, "-l")) {
|
2018-01-08 21:07:01 -08:00
|
|
|
try result.system_libs.append(lib_arg[2..]);
|
2017-12-23 17:21:57 -08:00
|
|
|
} else {
|
2017-12-23 18:19:48 -08:00
|
|
|
if (os.path.isAbsolute(lib_arg)) {
|
2018-01-08 21:07:01 -08:00
|
|
|
try result.libs.append(lib_arg);
|
2017-12-23 18:19:48 -08:00
|
|
|
} else {
|
2018-01-08 21:07:01 -08:00
|
|
|
try result.system_libs.append(lib_arg);
|
2017-12-23 18:19:48 -08:00
|
|
|
}
|
2017-12-11 20:34:59 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
2019-02-04 12:24:06 -08:00
|
|
|
var it = mem.tokenize(includes_output, " \r\n");
|
2017-12-11 20:34:59 -08:00
|
|
|
while (it.next()) |include_arg| {
|
|
|
|
if (mem.startsWith(u8, include_arg, "-I")) {
|
2018-01-08 21:07:01 -08:00
|
|
|
try result.includes.append(include_arg[2..]);
|
2017-12-11 20:34:59 -08:00
|
|
|
} else {
|
2018-01-08 21:07:01 -08:00
|
|
|
try result.includes.append(include_arg);
|
2017-12-11 20:34:59 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
2019-02-04 12:24:06 -08:00
|
|
|
var it = mem.tokenize(libdir_output, " \r\n");
|
2017-12-11 20:34:59 -08:00
|
|
|
while (it.next()) |libdir| {
|
|
|
|
if (mem.startsWith(u8, libdir, "-L")) {
|
2018-01-08 21:07:01 -08:00
|
|
|
try result.libdirs.append(libdir[2..]);
|
2017-12-11 20:34:59 -08:00
|
|
|
} else {
|
2018-01-08 21:07:01 -08:00
|
|
|
try result.libdirs.append(libdir);
|
2017-12-11 20:34:59 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2017-12-22 21:29:39 -08:00
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
|
2019-02-04 12:24:06 -08:00
|
|
|
var it = mem.tokenize(stdlib_files, ";");
|
2018-01-03 16:39:04 -08:00
|
|
|
while (it.next()) |stdlib_file| {
|
2019-02-06 21:42:41 -08:00
|
|
|
const src_path = os.path.join(b.allocator, [][]const u8{ "std", stdlib_file }) catch unreachable;
|
|
|
|
const dest_path = os.path.join(
|
|
|
|
b.allocator,
|
|
|
|
[][]const u8{ "lib", "zig", "std", stdlib_file },
|
|
|
|
) catch unreachable;
|
2017-12-22 21:29:39 -08:00
|
|
|
b.installFile(src_path, dest_path);
|
|
|
|
}
|
|
|
|
}
|
2018-01-03 01:55:16 -08:00
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
|
2019-02-04 12:24:06 -08:00
|
|
|
var it = mem.tokenize(c_header_files, ";");
|
2018-01-03 16:39:04 -08:00
|
|
|
while (it.next()) |c_header_file| {
|
2019-02-06 21:42:41 -08:00
|
|
|
const src_path = os.path.join(b.allocator, [][]const u8{ "c_headers", c_header_file }) catch unreachable;
|
|
|
|
const dest_path = os.path.join(
|
|
|
|
b.allocator,
|
|
|
|
[][]const u8{ "lib", "zig", "include", c_header_file },
|
|
|
|
) catch unreachable;
|
2018-01-03 16:39:04 -08:00
|
|
|
b.installFile(src_path, dest_path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
fn nextValue(index: *usize, build_info: []const u8) []const u8 {
|
2018-05-17 20:21:44 -07:00
|
|
|
const start = index.*;
|
|
|
|
while (true) : (index.* += 1) {
|
|
|
|
switch (build_info[index.*]) {
|
2018-01-03 19:38:13 -08:00
|
|
|
'\n' => {
|
2018-05-17 20:21:44 -07:00
|
|
|
const result = build_info[start..index.*];
|
|
|
|
index.* += 1;
|
2018-01-03 19:38:13 -08:00
|
|
|
return result;
|
|
|
|
},
|
|
|
|
'\r' => {
|
2018-05-17 20:21:44 -07:00
|
|
|
const result = build_info[start..index.*];
|
|
|
|
index.* += 2;
|
2018-01-03 19:38:13 -08:00
|
|
|
return result;
|
|
|
|
},
|
|
|
|
else => continue,
|
|
|
|
}
|
|
|
|
}
|
2018-01-03 01:55:16 -08:00
|
|
|
}
|
2018-07-10 17:18:43 -07:00
|
|
|
|
|
|
|
fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
|
|
|
|
exe.addIncludeDir("src");
|
|
|
|
exe.addIncludeDir(ctx.cmake_binary_dir);
|
|
|
|
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
|
|
|
|
if (ctx.lld_include_dir.len != 0) {
|
|
|
|
exe.addIncludeDir(ctx.lld_include_dir);
|
2019-02-04 12:24:06 -08:00
|
|
|
var it = mem.tokenize(ctx.lld_libraries, ";");
|
2018-07-10 17:18:43 -07:00
|
|
|
while (it.next()) |lib| {
|
|
|
|
exe.addObjectFile(lib);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_wasm");
|
|
|
|
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_elf");
|
|
|
|
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_coff");
|
|
|
|
addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_lib");
|
|
|
|
}
|
2018-11-01 21:07:43 -07:00
|
|
|
dependOnLib(b, exe, ctx.llvm);
|
2018-07-10 17:18:43 -07:00
|
|
|
|
|
|
|
if (exe.target.getOs() == builtin.Os.linux) {
|
2018-11-01 21:07:43 -07:00
|
|
|
try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
|
|
|
|
\\Unable to determine path to libstdc++.a
|
|
|
|
\\On Fedora, install libstdc++-static and try again.
|
|
|
|
);
|
2018-07-10 17:18:43 -07:00
|
|
|
|
|
|
|
exe.linkSystemLibrary("pthread");
|
2018-12-17 18:19:52 -08:00
|
|
|
} else if (exe.target.isFreeBSD()) {
|
|
|
|
try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
|
|
|
|
exe.linkSystemLibrary("pthread");
|
2019-01-29 18:47:26 -08:00
|
|
|
} else if (exe.target.isDarwin()) {
|
2018-11-01 21:07:43 -07:00
|
|
|
if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
|
|
|
|
// Compiler is GCC.
|
|
|
|
try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);
|
|
|
|
exe.linkSystemLibrary("pthread");
|
|
|
|
// TODO LLD cannot perform this link.
|
|
|
|
// See https://github.com/ziglang/zig/issues/1535
|
|
|
|
exe.enableSystemLinkerHack();
|
|
|
|
} else |err| switch (err) {
|
|
|
|
error.RequiredLibraryNotFound => {
|
|
|
|
// System compiler, not gcc.
|
|
|
|
exe.linkSystemLibrary("c++");
|
|
|
|
},
|
|
|
|
else => return err,
|
|
|
|
}
|
2018-07-10 17:18:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx.dia_guids_lib.len != 0) {
|
|
|
|
exe.addObjectFile(ctx.dia_guids_lib);
|
|
|
|
}
|
|
|
|
|
|
|
|
exe.linkSystemLibrary("c");
|
|
|
|
}
|
|
|
|
|
2018-11-01 21:07:43 -07:00
|
|
|
fn addCxxKnownPath(
|
|
|
|
b: *Builder,
|
|
|
|
ctx: Context,
|
|
|
|
exe: var,
|
|
|
|
objname: []const u8,
|
|
|
|
errtxt: ?[]const u8,
|
|
|
|
) !void {
|
2018-11-13 05:08:37 -08:00
|
|
|
const path_padded = try b.exec([][]const u8{
|
2018-11-01 21:07:43 -07:00
|
|
|
ctx.cxx_compiler,
|
|
|
|
b.fmt("-print-file-name={}", objname),
|
|
|
|
});
|
2019-02-04 12:24:06 -08:00
|
|
|
const path_unpadded = mem.tokenize(path_padded, "\r\n").next().?;
|
2018-11-01 21:07:43 -07:00
|
|
|
if (mem.eql(u8, path_unpadded, objname)) {
|
|
|
|
if (errtxt) |msg| {
|
|
|
|
warn("{}", msg);
|
|
|
|
} else {
|
|
|
|
warn("Unable to determine path to {}\n", objname);
|
|
|
|
}
|
|
|
|
return error.RequiredLibraryNotFound;
|
|
|
|
}
|
|
|
|
exe.addObjectFile(path_unpadded);
|
|
|
|
}
|
|
|
|
|
2018-11-13 05:08:37 -08:00
|
|
|
const Context = struct {
|
2018-07-10 17:18:43 -07:00
|
|
|
cmake_binary_dir: []const u8,
|
|
|
|
cxx_compiler: []const u8,
|
|
|
|
llvm_config_exe: []const u8,
|
|
|
|
lld_include_dir: []const u8,
|
|
|
|
lld_libraries: []const u8,
|
|
|
|
std_files: []const u8,
|
|
|
|
c_header_files: []const u8,
|
|
|
|
dia_guids_lib: []const u8,
|
|
|
|
llvm: LibraryDep,
|
|
|
|
};
|
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
|
|
|
|
|
|
|
fn addLibUserlandStep(b: *Builder) void {
|
|
|
|
const artifact = if (builtin.os == .macosx)
|
|
|
|
b.addObject("userland", "src-self-hosted/stage1.zig")
|
|
|
|
else
|
|
|
|
b.addStaticLibrary("userland", "src-self-hosted/stage1.zig");
|
|
|
|
artifact.disable_gen_h = true;
|
2019-04-24 11:13:55 -07:00
|
|
|
artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
|
2019-04-16 16:13:46 -07:00
|
|
|
artifact.linkSystemLibrary("c");
|
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
|
|
|
const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
|
|
|
|
libuserland_step.dependOn(&artifact.step);
|
|
|
|
|
|
|
|
const output_dir = b.option(
|
|
|
|
[]const u8,
|
|
|
|
"output-dir",
|
|
|
|
"For libuserland step, where to put the output",
|
|
|
|
) orelse return;
|
|
|
|
artifact.setOutputDir(output_dir);
|
|
|
|
}
|