port most of main.cpp to self hosted compiler

master
Andrew Kelley 2017-12-23 00:29:39 -05:00
parent 760b307e8a
commit 39c7bd24e4
10 changed files with 1156 additions and 78 deletions

View File

@ -119,31 +119,22 @@ libc. Create demo games using Zig.
[![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig)
[![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master)
### Dependencies
### Stage 1: Build Zig from C++ Source Code
#### Build Dependencies
These compile tools must be available on your system and are used to build
the Zig compiler itself:
#### Dependencies
##### POSIX
* gcc >= 5.0.0 or clang >= 3.6.0
* cmake >= 2.8.5
* LLVM, Clang, LLD libraries == 5.x, compiled with the same gcc or clang version above
##### Windows
* Microsoft Visual Studio 2015
* LLVM, Clang, LLD libraries == 5.x, compiled with the same MSVC version above
#### Library Dependencies
These libraries must be installed on your system, with the development files
available. The Zig compiler links against them. You have to use the same
compiler for these libraries as you do to compile Zig.
* LLVM, Clang, and LLD libraries == 5.x
### Debug / Development Build
#### Instructions
If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,
`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to
@ -158,7 +149,7 @@ make install
./zig build --build-file ../build.zig test
```
#### MacOS
##### MacOS
`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
@ -172,21 +163,35 @@ make install
./zig build --build-file ../build.zig test
```
#### Windows
##### Windows
See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows
### Release / Install Build
### Stage 2: Build Self-Hosted Zig from Zig Source Code
Once installed, `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_INCLUDE_DIR` can be overridden
by the `--libc-lib-dir` and `--libc-include-dir` parameters to the zig binary.
*Note: Stage 2 compiler is not complete. Beta users of Zig should use the
Stage 1 compiler for now.*
Dependencies are the same as Stage 1, except now you have a working zig compiler.
```
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_LIB_DIR=/some/path -DZIG_LIBC_INCLUDE_DIR=/some/path -DZIG_LIBC_STATIC_INCLUDE_DIR=/some/path
make
sudo make install
bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install
```
### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler
This is the actual compiler binary that we will install to the system.
#### Debug / Development Build
```
./stage2/bin/zig build --build-file ../build.zig --prefix $(pwd)/stage3 install
```
#### Release / Install Build
```
./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast
```
### Test Coverage

145
build.zig
View File

@ -32,15 +32,18 @@ pub fn build(b: &Builder) {
docs_step.dependOn(&docgen_cmd.step);
docs_step.dependOn(&docgen_home_cmd.step);
var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
exe.setBuildMode(mode);
exe.linkSystemLibrary("c");
dependOnLib(exe, findLLVM(b));
if (findLLVM(b)) |llvm| {
var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
exe.setBuildMode(mode);
exe.linkSystemLibrary("c");
dependOnLib(exe, llvm);
b.default_step.dependOn(&exe.step);
b.default_step.dependOn(docs_step);
b.default_step.dependOn(&exe.step);
b.default_step.dependOn(docs_step);
b.installArtifact(exe);
b.installArtifact(exe);
installStdLib(b);
}
const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
@ -91,7 +94,7 @@ const LibraryDep = struct {
includes: ArrayList([]const u8),
};
fn findLLVM(b: &Builder) -> LibraryDep {
fn findLLVM(b: &Builder) -> ?LibraryDep {
const llvm_config_exe = b.findProgram(
[][]const u8{"llvm-config-5.0", "llvm-config"},
[][]const u8{
@ -102,7 +105,8 @@ fn findLLVM(b: &Builder) -> LibraryDep {
"C:/Libraries/llvm-5.0.0/bin",
}) %% |err|
{
std.debug.panic("unable to find llvm-config: {}\n", err);
warn("unable to find llvm-config: {}\n", err);
return null;
};
const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"});
@ -143,3 +147,126 @@ fn findLLVM(b: &Builder) -> LibraryDep {
}
return result;
}
pub fn installStdLib(b: &Builder) {
const stdlib_files = []const []const u8 {
"array_list.zig",
"base64.zig",
"buf_map.zig",
"buf_set.zig",
"buffer.zig",
"build.zig",
"c/darwin.zig",
"c/index.zig",
"c/linux.zig",
"c/windows.zig",
"cstr.zig",
"debug.zig",
"dwarf.zig",
"elf.zig",
"empty.zig",
"endian.zig",
"fmt/errol/enum3.zig",
"fmt/errol/index.zig",
"fmt/errol/lookup.zig",
"fmt/index.zig",
"hash_map.zig",
"heap.zig",
"index.zig",
"io.zig",
"linked_list.zig",
"math/acos.zig",
"math/acosh.zig",
"math/asin.zig",
"math/asinh.zig",
"math/atan.zig",
"math/atan2.zig",
"math/atanh.zig",
"math/cbrt.zig",
"math/ceil.zig",
"math/copysign.zig",
"math/cos.zig",
"math/cosh.zig",
"math/exp.zig",
"math/exp2.zig",
"math/expm1.zig",
"math/expo2.zig",
"math/fabs.zig",
"math/floor.zig",
"math/fma.zig",
"math/frexp.zig",
"math/hypot.zig",
"math/ilogb.zig",
"math/index.zig",
"math/inf.zig",
"math/isfinite.zig",
"math/isinf.zig",
"math/isnan.zig",
"math/isnormal.zig",
"math/ln.zig",
"math/log.zig",
"math/log10.zig",
"math/log1p.zig",
"math/log2.zig",
"math/modf.zig",
"math/nan.zig",
"math/pow.zig",
"math/round.zig",
"math/scalbn.zig",
"math/signbit.zig",
"math/sin.zig",
"math/sinh.zig",
"math/sqrt.zig",
"math/tan.zig",
"math/tanh.zig",
"math/trunc.zig",
"mem.zig",
"net.zig",
"os/child_process.zig",
"os/darwin.zig",
"os/darwin_errno.zig",
"os/get_user_id.zig",
"os/index.zig",
"os/linux.zig",
"os/linux_errno.zig",
"os/linux_i386.zig",
"os/linux_x86_64.zig",
"os/path.zig",
"os/windows/error.zig",
"os/windows/index.zig",
"os/windows/util.zig",
"rand.zig",
"sort.zig",
"special/bootstrap.zig",
"special/bootstrap_lib.zig",
"special/build_file_template.zig",
"special/build_runner.zig",
"special/builtin.zig",
"special/compiler_rt/aulldiv.zig",
"special/compiler_rt/aullrem.zig",
"special/compiler_rt/comparetf2.zig",
"special/compiler_rt/fixuint.zig",
"special/compiler_rt/fixunsdfdi.zig",
"special/compiler_rt/fixunsdfsi.zig",
"special/compiler_rt/fixunsdfti.zig",
"special/compiler_rt/fixunssfdi.zig",
"special/compiler_rt/fixunssfsi.zig",
"special/compiler_rt/fixunssfti.zig",
"special/compiler_rt/fixunstfdi.zig",
"special/compiler_rt/fixunstfsi.zig",
"special/compiler_rt/fixunstfti.zig",
"special/compiler_rt/index.zig",
"special/compiler_rt/udivmod.zig",
"special/compiler_rt/udivmoddi4.zig",
"special/compiler_rt/udivmodti4.zig",
"special/compiler_rt/udivti3.zig",
"special/compiler_rt/umodti3.zig",
"special/panic.zig",
"special/test_runner.zig",
};
for (stdlib_files) |stdlib_file| {
const src_path = %%os.path.join(b.allocator, "std", stdlib_file);
const dest_path = %%os.path.join(b.allocator, "lib", "zig", "std", stdlib_file);
b.installFile(src_path, dest_path);
}
}

13
src-self-hosted/llvm.zig Normal file
View File

@ -0,0 +1,13 @@
const builtin = @import("builtin");
const c = @import("c.zig");
const assert = @import("std").debug.assert;
pub const ValueRef = removeNullability(c.LLVMValueRef);
pub const ModuleRef = removeNullability(c.LLVMModuleRef);
pub const ContextRef = removeNullability(c.LLVMContextRef);
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
fn removeNullability(comptime T: type) -> type {
comptime assert(@typeId(T) == builtin.TypeId.Nullable);
return T.Child;
}

View File

@ -4,71 +4,620 @@ const io = std.io;
const os = std.os;
const heap = std.heap;
const warn = std.debug.warn;
const Tokenizer = @import("tokenizer.zig").Tokenizer;
const Token = @import("tokenizer.zig").Token;
const Parser = @import("parser.zig").Parser;
const assert = std.debug.assert;
const target = @import("target.zig");
const Target = target.Target;
const Module = @import("module.zig").Module;
const ErrColor = Module.ErrColor;
const Emit = Module.Emit;
const builtin = @import("builtin");
const ArrayList = std.ArrayList;
error InvalidCommandLineArguments;
error ZigLibDirNotFound;
error ZigInstallationNotFound;
const default_zig_cache_name = "zig-cache";
pub fn main() -> %void {
main2() %% |err| {
warn("{}\n", @errorName(err));
if (err != error.InvalidCommandLineArguments) {
warn("{}\n", @errorName(err));
}
return err;
};
}
pub fn main2() -> %void {
var incrementing_allocator = %return heap.IncrementingAllocator.init(10 * 1024 * 1024);
defer incrementing_allocator.deinit();
const Cmd = enum {
None,
Build,
Test,
Version,
Zen,
TranslateC,
Targets,
};
const allocator = &incrementing_allocator.allocator;
fn badArgs(comptime format: []const u8, args: ...) -> error {
var stderr = %return io.getStdErr();
var stderr_stream_adapter = io.FileOutStream.init(&stderr);
const stderr_stream = &stderr_stream_adapter.stream;
%return stderr_stream.print(format ++ "\n\n", args);
%return printUsage(&stderr_stream_adapter.stream);
return error.InvalidCommandLineArguments;
}
pub fn main2() -> %void {
const allocator = std.heap.c_allocator;
const args = %return os.argsAlloc(allocator);
defer os.argsFree(allocator, args);
target.initializeAll();
var cmd = Cmd.None;
var build_kind: Module.Kind = undefined;
var build_mode: builtin.Mode = builtin.Mode.Debug;
var color = ErrColor.Auto;
var emit_file_type = Emit.Binary;
const target_file = args[1];
var strip = false;
var is_static = false;
var verbose_tokenize = false;
var verbose_ast_tree = false;
var verbose_ast_fmt = false;
var verbose_link = false;
var verbose_ir = false;
var verbose_llvm_ir = false;
var verbose_cimport = false;
var mwindows = false;
var mconsole = false;
var rdynamic = false;
var each_lib_rpath = false;
var timing_info = false;
const target_file_buf = %return io.readFileAlloc(target_file, allocator);
defer allocator.free(target_file_buf);
var in_file_arg: ?[]u8 = null;
var out_file: ?[]u8 = null;
var out_file_h: ?[]u8 = null;
var out_name_arg: ?[]u8 = null;
var libc_lib_dir_arg: ?[]u8 = null;
var libc_static_lib_dir_arg: ?[]u8 = null;
var libc_include_dir_arg: ?[]u8 = null;
var msvc_lib_dir_arg: ?[]u8 = null;
var kernel32_lib_dir_arg: ?[]u8 = null;
var zig_install_prefix: ?[]u8 = null;
var dynamic_linker_arg: ?[]u8 = null;
var cache_dir_arg: ?[]const u8 = null;
var target_arch: ?[]u8 = null;
var target_os: ?[]u8 = null;
var target_environ: ?[]u8 = null;
var mmacosx_version_min: ?[]u8 = null;
var mios_version_min: ?[]u8 = null;
var linker_script_arg: ?[]u8 = null;
var test_name_prefix_arg: ?[]u8 = null;
var stderr_file = %return std.io.getStdErr();
var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
const out_stream = &stderr_file_out_stream.stream;
var test_filters = ArrayList([]const u8).init(allocator);
defer test_filters.deinit();
warn("====input:====\n");
var lib_dirs = ArrayList([]const u8).init(allocator);
defer lib_dirs.deinit();
warn("{}", target_file_buf);
var clang_argv = ArrayList([]const u8).init(allocator);
defer clang_argv.deinit();
warn("====tokenization:====\n");
{
var tokenizer = Tokenizer.init(target_file_buf);
while (true) {
const token = tokenizer.next();
tokenizer.dump(token);
if (token.id == Token.Id.Eof) {
break;
var llvm_argv = ArrayList([]const u8).init(allocator);
defer llvm_argv.deinit();
var link_libs = ArrayList([]const u8).init(allocator);
defer link_libs.deinit();
var frameworks = ArrayList([]const u8).init(allocator);
defer frameworks.deinit();
var objects = ArrayList([]const u8).init(allocator);
defer objects.deinit();
var asm_files = ArrayList([]const u8).init(allocator);
defer asm_files.deinit();
var rpath_list = ArrayList([]const u8).init(allocator);
defer rpath_list.deinit();
var ver_major: u32 = 0;
var ver_minor: u32 = 0;
var ver_patch: u32 = 0;
var arg_i: usize = 1;
while (arg_i < args.len) : (arg_i += 1) {
const arg = args[arg_i];
if (arg.len != 0 and arg[0] == '-') {
if (mem.eql(u8, arg, "--release-fast")) {
build_mode = builtin.Mode.ReleaseFast;
} else if (mem.eql(u8, arg, "--release-safe")) {
build_mode = builtin.Mode.ReleaseSafe;
} else if (mem.eql(u8, arg, "--strip")) {
strip = true;
} else if (mem.eql(u8, arg, "--static")) {
is_static = true;
} else if (mem.eql(u8, arg, "--verbose-tokenize")) {
verbose_tokenize = true;
} else if (mem.eql(u8, arg, "--verbose-ast-tree")) {
verbose_ast_tree = true;
} else if (mem.eql(u8, arg, "--verbose-ast-fmt")) {
verbose_ast_fmt = true;
} else if (mem.eql(u8, arg, "--verbose-link")) {
verbose_link = true;
} else if (mem.eql(u8, arg, "--verbose-ir")) {
verbose_ir = true;
} else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
verbose_llvm_ir = true;
} else if (mem.eql(u8, arg, "--verbose-cimport")) {
verbose_cimport = true;
} else if (mem.eql(u8, arg, "-mwindows")) {
mwindows = true;
} else if (mem.eql(u8, arg, "-mconsole")) {
mconsole = true;
} else if (mem.eql(u8, arg, "-rdynamic")) {
rdynamic = true;
} else if (mem.eql(u8, arg, "--each-lib-rpath")) {
each_lib_rpath = true;
} else if (mem.eql(u8, arg, "--enable-timing-info")) {
timing_info = true;
} else if (mem.eql(u8, arg, "--test-cmd-bin")) {
@panic("TODO --test-cmd-bin");
} else if (arg[1] == 'L' and arg.len > 2) {
// alias for --library-path
%return lib_dirs.append(arg[1..]);
} else if (mem.eql(u8, arg, "--pkg-begin")) {
@panic("TODO --pkg-begin");
} else if (mem.eql(u8, arg, "--pkg-end")) {
@panic("TODO --pkg-end");
} else if (arg_i + 1 >= args.len) {
return badArgs("expected another argument after {}", arg);
} else {
arg_i += 1;
if (mem.eql(u8, arg, "--output")) {
out_file = args[arg_i];
} else if (mem.eql(u8, arg, "--output-h")) {
out_file_h = args[arg_i];
} else if (mem.eql(u8, arg, "--color")) {
if (mem.eql(u8, args[arg_i], "auto")) {
color = ErrColor.Auto;
} else if (mem.eql(u8, args[arg_i], "on")) {
color = ErrColor.On;
} else if (mem.eql(u8, args[arg_i], "off")) {
color = ErrColor.Off;
} else {
return badArgs("--color options are 'auto', 'on', or 'off'");
}
} else if (mem.eql(u8, arg, "--emit")) {
if (mem.eql(u8, args[arg_i], "asm")) {
emit_file_type = Emit.Assembly;
} else if (mem.eql(u8, args[arg_i], "bin")) {
emit_file_type = Emit.Binary;
} else if (mem.eql(u8, args[arg_i], "llvm-ir")) {
emit_file_type = Emit.LlvmIr;
} else {
return badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'");
}
} else if (mem.eql(u8, arg, "--name")) {
out_name_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--libc-lib-dir")) {
libc_lib_dir_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--libc-static-lib-dir")) {
libc_static_lib_dir_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--libc-include-dir")) {
libc_include_dir_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--msvc-lib-dir")) {
msvc_lib_dir_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--kernel32-lib-dir")) {
kernel32_lib_dir_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--zig-install-prefix")) {
zig_install_prefix = args[arg_i];
} else if (mem.eql(u8, arg, "--dynamic-linker")) {
dynamic_linker_arg = args[arg_i];
} else if (mem.eql(u8, arg, "-isystem")) {
%return clang_argv.append("-isystem");
%return clang_argv.append(args[arg_i]);
} else if (mem.eql(u8, arg, "-dirafter")) {
%return clang_argv.append("-dirafter");
%return clang_argv.append(args[arg_i]);
} else if (mem.eql(u8, arg, "-mllvm")) {
%return clang_argv.append("-mllvm");
%return clang_argv.append(args[arg_i]);
%return llvm_argv.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) {
%return lib_dirs.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--library")) {
%return link_libs.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--object")) {
%return objects.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--assembly")) {
%return asm_files.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--cache-dir")) {
cache_dir_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--target-arch")) {
target_arch = args[arg_i];
} else if (mem.eql(u8, arg, "--target-os")) {
target_os = args[arg_i];
} else if (mem.eql(u8, arg, "--target-environ")) {
target_environ = args[arg_i];
} else if (mem.eql(u8, arg, "-mmacosx-version-min")) {
mmacosx_version_min = args[arg_i];
} else if (mem.eql(u8, arg, "-mios-version-min")) {
mios_version_min = args[arg_i];
} else if (mem.eql(u8, arg, "-framework")) {
%return frameworks.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--linker-script")) {
linker_script_arg = args[arg_i];
} else if (mem.eql(u8, arg, "-rpath")) {
%return rpath_list.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--test-filter")) {
%return test_filters.append(args[arg_i]);
} else if (mem.eql(u8, arg, "--test-name-prefix")) {
test_name_prefix_arg = args[arg_i];
} else if (mem.eql(u8, arg, "--ver-major")) {
ver_major = %return std.fmt.parseUnsigned(u32, args[arg_i], 10);
} else if (mem.eql(u8, arg, "--ver-minor")) {
ver_minor = %return std.fmt.parseUnsigned(u32, args[arg_i], 10);
} else if (mem.eql(u8, arg, "--ver-patch")) {
ver_patch = %return std.fmt.parseUnsigned(u32, args[arg_i], 10);
} else if (mem.eql(u8, arg, "--test-cmd")) {
@panic("TODO --test-cmd");
} else {
return badArgs("invalid argument: {}", arg);
}
}
} else if (cmd == Cmd.None) {
if (mem.eql(u8, arg, "build-obj")) {
cmd = Cmd.Build;
build_kind = Module.Kind.Obj;
} else if (mem.eql(u8, arg, "build-exe")) {
cmd = Cmd.Build;
build_kind = Module.Kind.Exe;
} else if (mem.eql(u8, arg, "build-lib")) {
cmd = Cmd.Build;
build_kind = Module.Kind.Lib;
} else if (mem.eql(u8, arg, "version")) {
cmd = Cmd.Version;
} else if (mem.eql(u8, arg, "zen")) {
cmd = Cmd.Zen;
} else if (mem.eql(u8, arg, "translate-c")) {
cmd = Cmd.TranslateC;
} else if (mem.eql(u8, arg, "test")) {
cmd = Cmd.Test;
build_kind = Module.Kind.Exe;
} else {
return badArgs("unrecognized command: {}", arg);
}
} else switch (cmd) {
Cmd.Build, Cmd.TranslateC, Cmd.Test => {
if (in_file_arg == null) {
in_file_arg = arg;
} else {
return badArgs("unexpected extra parameter: {}", arg);
}
},
Cmd.Version, Cmd.Zen, Cmd.Targets => {
return badArgs("unexpected extra parameter: {}", arg);
},
Cmd.None => unreachable,
}
}
warn("====parse:====\n");
target.initializeAll();
var tokenizer = Tokenizer.init(target_file_buf);
var parser = Parser.init(&tokenizer, allocator, target_file);
defer parser.deinit();
// TODO
// ZigTarget alloc_target;
// ZigTarget *target;
// if (!target_arch && !target_os && !target_environ) {
// target = nullptr;
// } else {
// target = &alloc_target;
// get_unknown_target(target);
// if (target_arch) {
// if (parse_target_arch(target_arch, &target->arch)) {
// fprintf(stderr, "invalid --target-arch argument\n");
// return usage(arg0);
// }
// }
// if (target_os) {
// if (parse_target_os(target_os, &target->os)) {
// fprintf(stderr, "invalid --target-os argument\n");
// return usage(arg0);
// }
// }
// if (target_environ) {
// if (parse_target_environ(target_environ, &target->env_type)) {
// fprintf(stderr, "invalid --target-environ argument\n");
// return usage(arg0);
// }
// }
// }
const root_node = %return parser.parse();
defer parser.freeAst(root_node);
switch (cmd) {
Cmd.None => return badArgs("expected command"),
Cmd.Zen => return printZen(),
Cmd.Build, Cmd.Test, Cmd.TranslateC => {
if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) {
return badArgs("expected source file argument or at least one --object or --assembly argument");
} else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) {
return badArgs("expected source file argument");
} else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) {
return badArgs("When building an object file, --object arguments are invalid");
}
%return parser.renderAst(out_stream, root_node);
const root_name = switch (cmd) {
Cmd.Build, Cmd.TranslateC => x: {
if (out_name_arg) |out_name| {
break :x out_name;
} else if (in_file_arg) |in_file_path| {
const basename = os.path.basename(in_file_path);
var it = mem.split(basename, ".");
break :x it.next() ?? return badArgs("file name cannot be empty");
} else {
return badArgs("--name [name] not provided and unable to infer");
}
},
Cmd.Test => "test",
else => unreachable,
};
warn("====fmt:====\n");
%return parser.renderSource(out_stream, root_node);
const zig_root_source_file = if (cmd == Cmd.TranslateC) null else in_file_arg;
const chosen_cache_dir = cache_dir_arg ?? default_zig_cache_name;
const full_cache_dir = %return os.path.resolve(allocator, ".", chosen_cache_dir);
defer allocator.free(full_cache_dir);
const zig_lib_dir = %return resolveZigLibDir(allocator, zig_install_prefix);
%defer allocator.free(zig_lib_dir);
const module = %return Module.create(allocator, root_name, zig_root_source_file,
Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir);
defer module.destroy();
module.version_major = ver_major;
module.version_minor = ver_minor;
module.version_patch = ver_patch;
module.is_test = cmd == Cmd.Test;
if (linker_script_arg) |linker_script| {
module.linker_script = linker_script;
}
module.each_lib_rpath = each_lib_rpath;
module.clang_argv = clang_argv.toSliceConst();
module.llvm_argv = llvm_argv.toSliceConst();
module.strip = strip;
module.is_static = is_static;
if (libc_lib_dir_arg) |libc_lib_dir| {
module.libc_lib_dir = libc_lib_dir;
}
if (libc_static_lib_dir_arg) |libc_static_lib_dir| {
module.libc_static_lib_dir = libc_static_lib_dir;
}
if (libc_include_dir_arg) |libc_include_dir| {
module.libc_include_dir = libc_include_dir;
}
if (msvc_lib_dir_arg) |msvc_lib_dir| {
module.msvc_lib_dir = msvc_lib_dir;
}
if (kernel32_lib_dir_arg) |kernel32_lib_dir| {
module.kernel32_lib_dir = kernel32_lib_dir;
}
if (dynamic_linker_arg) |dynamic_linker| {
module.dynamic_linker = dynamic_linker;
}
module.verbose_tokenize = verbose_tokenize;
module.verbose_ast_tree = verbose_ast_tree;
module.verbose_ast_fmt = verbose_ast_fmt;
module.verbose_link = verbose_link;
module.verbose_ir = verbose_ir;
module.verbose_llvm_ir = verbose_llvm_ir;
module.verbose_cimport = verbose_cimport;
module.err_color = color;
module.lib_dirs = lib_dirs.toSliceConst();
module.darwin_frameworks = frameworks.toSliceConst();
module.rpath_list = rpath_list.toSliceConst();
for (link_libs.toSliceConst()) |name| {
_ = %return module.addLinkLib(name, true);
}
module.windows_subsystem_windows = mwindows;
module.windows_subsystem_console = mconsole;
module.linker_rdynamic = rdynamic;
if (mmacosx_version_min != null and mios_version_min != null) {
return badArgs("-mmacosx-version-min and -mios-version-min options not allowed together");
}
if (mmacosx_version_min) |ver| {
module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
} else if (mios_version_min) |ver| {
module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
}
module.test_filters = test_filters.toSliceConst();
module.test_name_prefix = test_name_prefix_arg;
module.out_h_path = out_file_h;
// TODO
//add_package(g, cur_pkg, g->root_package);
switch (cmd) {
Cmd.Build => {
module.emit_file_type = emit_file_type;
module.link_objects = objects.toSliceConst();
module.assembly_files = asm_files.toSliceConst();
%return module.build();
%return module.link(out_file);
},
Cmd.TranslateC => @panic("TODO translate-c"),
Cmd.Test => @panic("TODO test cmd"),
else => unreachable,
}
},
Cmd.Version => @panic("TODO zig version"),
Cmd.Targets => @panic("TODO zig targets"),
}
}
test "import other tests" {
_ = @import("parser.zig");
_ = @import("tokenizer.zig");
fn printUsage(stream: &io.OutStream) -> %void {
%return stream.write(
\\Usage: zig [command] [options]
\\
\\Commands:
\\ build build project from build.zig
\\ build-exe [source] create executable from source or object files
\\ build-lib [source] create library from source or object files
\\ build-obj [source] create object from source or assembly
\\ translate-c [source] convert c code to zig code
\\ targets list available compilation targets
\\ test [source] create and run a test build
\\ version print version number and exit
\\ zen print zen of zig and exit
\\Compile Options:
\\ --assembly [source] add assembly file to build
\\ --cache-dir [path] override the cache directory
\\ --color [auto|off|on] enable or disable colored error messages
\\ --emit [filetype] emit a specific file format as compilation output
\\ --enable-timing-info print timing diagnostics
\\ --libc-include-dir [path] directory where libc stdlib.h resides
\\ --name [name] override output name
\\ --output [file] override destination path
\\ --output-h [file] override generated header file path
\\ --pkg-begin [name] [path] make package available to import and push current pkg
\\ --pkg-end pop current pkg
\\ --release-fast build with optimizations on and safety off
\\ --release-safe build with optimizations on and safety on
\\ --static output will be statically linked
\\ --strip exclude debug symbols
\\ --target-arch [name] specify target architecture
\\ --target-environ [name] specify target environment
\\ --target-os [name] specify target operating system
\\ --verbose-tokenize enable compiler debug info: tokenization
\\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview)
\\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source)
\\ --verbose-cimport enable compiler debug info: C imports
\\ --verbose-ir enable compiler debug info: Zig IR
\\ --verbose-llvm-ir enable compiler debug info: LLVM IR
\\ --verbose-link enable compiler debug info: linking
\\ --zig-install-prefix [path] override directory where zig thinks it is installed
\\ -dirafter [dir] same as -isystem but do it last
\\ -isystem [dir] add additional search path for other .h files
\\ -mllvm [arg] additional arguments to forward to LLVM's option processing
\\Link Options:
\\ --ar-path [path] set the path to ar
\\ --dynamic-linker [path] set the path to ld.so
\\ --each-lib-rpath add rpath for each used dynamic library
\\ --libc-lib-dir [path] directory where libc crt1.o resides
\\ --libc-static-lib-dir [path] directory where libc crtbegin.o resides
\\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
\\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
\\ --library [lib] link against lib
\\ --library-path [dir] add a directory to the library search path
\\ --linker-script [path] use a custom linker script
\\ --object [obj] add object file to build
\\ -L[dir] alias for --library-path
\\ -rdynamic add all symbols to the dynamic symbol table
\\ -rpath [path] add directory to the runtime library search path
\\ -mconsole (windows) --subsystem console to the linker
\\ -mwindows (windows) --subsystem windows to the linker
\\ -framework [name] (darwin) link against framework
\\ -mios-version-min [ver] (darwin) set iOS deployment target
\\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target
\\ --ver-major [ver] dynamic library semver major version
\\ --ver-minor [ver] dynamic library semver minor version
\\ --ver-patch [ver] dynamic library semver patch version
\\Test Options:
\\ --test-filter [text] skip tests that do not match filter
\\ --test-name-prefix [text] add prefix to all tests
\\ --test-cmd [arg] specify test execution command one arg at a time
\\ --test-cmd-bin appends test binary path to test cmd args
\\
);
}
fn printZen() -> %void {
var stdout_file = %return io.getStdErr();
%return stdout_file.write(
\\
\\ * Communicate intent precisely.
\\ * Edge cases matter.
\\ * Favor reading code over writing code.
\\ * Only one obvious way to do things.
\\ * Runtime crashes are better than bugs.
\\ * Compile errors are better than runtime crashes.
\\ * Incremental improvements.
\\ * Avoid local maximums.
\\ * Reduce the amount one must remember.
\\ * Minimize energy spent on coding style.
\\ * Together we serve end users.
\\
\\
);
}
/// Caller must free result
fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) -> %[]u8 {
if (zig_install_prefix_arg) |zig_install_prefix| {
return testZigInstallPrefix(allocator, zig_install_prefix) %% |err| {
warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));
return error.ZigInstallationNotFound;
};
} else {
return findZigLibDir(allocator) %% |err| {
warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n",
@errorName(err));
return error.ZigLibDirNotFound;
};
}
}
/// Caller must free result
fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) -> %[]u8 {
const test_zig_dir = %return os.path.join(allocator, test_path, "lib", "zig");
%defer allocator.free(test_zig_dir);
const test_index_file = %return os.path.join(allocator, test_zig_dir, "std", "index.zig");
defer allocator.free(test_index_file);
var file = %return io.File.openRead(test_index_file, allocator);
file.close();
return test_zig_dir;
}
/// Caller must free result
fn findZigLibDir(allocator: &mem.Allocator) -> %[]u8 {
const self_exe_path = %return os.selfExeDirPath(allocator);
defer allocator.free(self_exe_path);
var cur_path: []const u8 = self_exe_path;
while (true) {
const test_dir = os.path.dirname(cur_path);
if (mem.eql(u8, test_dir, cur_path)) {
break;
}
return testZigInstallPrefix(allocator, test_dir) %% |err| {
cur_path = test_dir;
continue;
};
}
// TODO look in hard coded installation path from configuration
//if (ZIG_INSTALL_PREFIX != nullptr) {
// if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
// return 0;
// }
//}
return error.FileNotFound;
}

295
src-self-hosted/module.zig Normal file
View File

@ -0,0 +1,295 @@
const std = @import("std");
const os = std.os;
const io = std.io;
const mem = std.mem;
const Buffer = std.Buffer;
const llvm = @import("llvm.zig");
const c = @import("c.zig");
const builtin = @import("builtin");
const Target = @import("target.zig").Target;
const warn = std.debug.warn;
const Tokenizer = @import("tokenizer.zig").Tokenizer;
const Token = @import("tokenizer.zig").Token;
const Parser = @import("parser.zig").Parser;
const ArrayList = std.ArrayList;
pub const Module = struct {
allocator: &mem.Allocator,
name: Buffer,
root_src_path: ?[]const u8,
module: llvm.ModuleRef,
context: llvm.ContextRef,
builder: llvm.BuilderRef,
target: Target,
build_mode: builtin.Mode,
zig_lib_dir: []const u8,
version_major: u32,
version_minor: u32,
version_patch: u32,
linker_script: ?[]const u8,
cache_dir: []const u8,
libc_lib_dir: ?[]const u8,
libc_static_lib_dir: ?[]const u8,
libc_include_dir: ?[]const u8,
msvc_lib_dir: ?[]const u8,
kernel32_lib_dir: ?[]const u8,
dynamic_linker: ?[]const u8,
out_h_path: ?[]const u8,
is_test: bool,
each_lib_rpath: bool,
strip: bool,
is_static: bool,
linker_rdynamic: bool,
clang_argv: []const []const u8,
llvm_argv: []const []const u8,
lib_dirs: []const []const u8,
rpath_list: []const []const u8,
assembly_files: []const []const u8,
link_objects: []const []const u8,
windows_subsystem_windows: bool,
windows_subsystem_console: bool,
link_libs_list: ArrayList(&LinkLib),
libc_link_lib: ?&LinkLib,
err_color: ErrColor,
verbose_tokenize: bool,
verbose_ast_tree: bool,
verbose_ast_fmt: bool,
verbose_cimport: bool,
verbose_ir: bool,
verbose_llvm_ir: bool,
verbose_link: bool,
darwin_frameworks: []const []const u8,
darwin_version_min: DarwinVersionMin,
test_filters: []const []const u8,
test_name_prefix: ?[]const u8,
emit_file_type: Emit,
kind: Kind,
pub const DarwinVersionMin = union(enum) {
None,
MacOS: []const u8,
Ios: []const u8,
};
pub const Kind = enum {
Exe,
Lib,
Obj,
};
pub const ErrColor = enum {
Auto,
Off,
On,
};
pub const LinkLib = struct {
name: []const u8,
path: ?[]const u8,
/// the list of symbols we depend on from this lib
symbols: ArrayList([]u8),
provided_explicitly: bool,
};
pub const Emit = enum {
Binary,
Assembly,
LlvmIr,
};
pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) -> %&Module
{
var name_buffer = %return Buffer.init(allocator, name);
%defer name_buffer.deinit();
const context = c.LLVMContextCreate() ?? return error.OutOfMemory;
%defer c.LLVMContextDispose(context);
const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory;
%defer c.LLVMDisposeModule(module);
const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory;
%defer c.LLVMDisposeBuilder(builder);
const module_ptr = %return allocator.create(Module);
%defer allocator.destroy(module_ptr);
*module_ptr = Module {
.allocator = allocator,
.name = name_buffer,
.root_src_path = root_src_path,
.module = module,
.context = context,
.builder = builder,
.target = *target,
.kind = kind,
.build_mode = build_mode,
.zig_lib_dir = zig_lib_dir,
.cache_dir = cache_dir,
.version_major = 0,
.version_minor = 0,
.version_patch = 0,
.verbose_tokenize = false,
.verbose_ast_tree = false,
.verbose_ast_fmt = false,
.verbose_cimport = false,
.verbose_ir = false,
.verbose_llvm_ir = false,
.verbose_link = false,
.linker_script = null,
.libc_lib_dir = null,
.libc_static_lib_dir = null,
.libc_include_dir = null,
.msvc_lib_dir = null,
.kernel32_lib_dir = null,
.dynamic_linker = null,
.out_h_path = null,
.is_test = false,
.each_lib_rpath = false,
.strip = false,
.is_static = false,
.linker_rdynamic = false,
.clang_argv = [][]const u8{},
.llvm_argv = [][]const u8{},
.lib_dirs = [][]const u8{},
.rpath_list = [][]const u8{},
.assembly_files = [][]const u8{},
.link_objects = [][]const u8{},
.windows_subsystem_windows = false,
.windows_subsystem_console = false,
.link_libs_list = ArrayList(&LinkLib).init(allocator),
.libc_link_lib = null,
.err_color = ErrColor.Auto,
.darwin_frameworks = [][]const u8{},
.darwin_version_min = DarwinVersionMin.None,
.test_filters = [][]const u8{},
.test_name_prefix = null,
.emit_file_type = Emit.Binary,
};
return module_ptr;
}
fn dump(self: &Module) {
c.LLVMDumpModule(self.module);
}
pub fn destroy(self: &Module) {
c.LLVMDisposeBuilder(self.builder);
c.LLVMDisposeModule(self.module);
c.LLVMContextDispose(self.context);
self.name.deinit();
self.allocator.destroy(self);
}
pub fn build(self: &Module) -> %void {
const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path");
const root_src_real_path = os.path.real(self.allocator, root_src_path) %% |err| {
%return printError("unable to open '{}': {}", root_src_path, err);
return err;
};
%defer self.allocator.free(root_src_real_path);
const source_code = io.readFileAlloc(root_src_real_path, self.allocator) %% |err| {
%return printError("unable to open '{}': {}", root_src_real_path, err);
return err;
};
%defer self.allocator.free(source_code);
warn("====input:====\n");
warn("{}", source_code);
warn("====tokenization:====\n");
{
var tokenizer = Tokenizer.init(source_code);
while (true) {
const token = tokenizer.next();
tokenizer.dump(token);
if (token.id == Token.Id.Eof) {
break;
}
}
}
warn("====parse:====\n");
var tokenizer = Tokenizer.init(source_code);
var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path);
defer parser.deinit();
const root_node = %return parser.parse();
defer parser.freeAst(root_node);
var stderr_file = %return std.io.getStdErr();
var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
const out_stream = &stderr_file_out_stream.stream;
%return parser.renderAst(out_stream, root_node);
warn("====fmt:====\n");
%return parser.renderSource(out_stream, root_node);
warn("====ir:====\n");
warn("TODO\n\n");
warn("====llvm ir:====\n");
self.dump();
}
pub fn link(self: &Module, out_file: ?[]const u8) -> %void {
warn("TODO link");
}
pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) -> %&LinkLib {
const is_libc = mem.eql(u8, name, "c");
if (is_libc) {
if (self.libc_link_lib) |libc_link_lib| {
return libc_link_lib;
}
}
for (self.link_libs_list.toSliceConst()) |existing_lib| {
if (mem.eql(u8, name, existing_lib.name)) {
return existing_lib;
}
}
const link_lib = %return self.allocator.create(LinkLib);
*link_lib = LinkLib {
.name = name,
.path = null,
.provided_explicitly = provided_explicitly,
.symbols = ArrayList([]u8).init(self.allocator),
};
%return self.link_libs_list.append(link_lib);
if (is_libc) {
self.libc_link_lib = link_lib;
}
return link_lib;
}
};
fn printError(comptime format: []const u8, args: ...) -> %void {
var stderr_file = %return std.io.getStdErr();
var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
const out_stream = &stderr_file_out_stream.stream;
%return out_stream.print(format, args);
}

View File

@ -1,5 +1,56 @@
const builtin = @import("builtin");
const c = @import("c.zig");
pub const CrossTarget = struct {
arch: builtin.Arch,
os: builtin.Os,
environ: builtin.Environ,
};
pub const Target = union(enum) {
Native,
Cross: CrossTarget,
pub fn oFileExt(self: &const Target) -> []const u8 {
const environ = switch (*self) {
Target.Native => builtin.environ,
Target.Cross => |t| t.environ,
};
return switch (environ) {
builtin.Environ.msvc => ".obj",
else => ".o",
};
}
pub fn exeFileExt(self: &const Target) -> []const u8 {
return switch (self.getOs()) {
builtin.Os.windows => ".exe",
else => "",
};
}
pub fn getOs(self: &const Target) -> builtin.Os {
return switch (*self) {
Target.Native => builtin.os,
Target.Cross => |t| t.os,
};
}
pub fn isDarwin(self: &const Target) -> bool {
return switch (self.getOs()) {
builtin.Os.darwin, builtin.Os.ios, builtin.Os.macosx => true,
else => false,
};
}
pub fn isWindows(self: &const Target) -> bool {
return switch (self.getOs()) {
builtin.Os.windows => true,
else => false,
};
}
};
pub fn initializeAll() {
c.LLVMInitializeAllTargets();
c.LLVMInitializeAllTargetInfos();

View File

@ -139,6 +139,11 @@ pub const Buffer = struct {
%return self.resize(m.len);
mem.copy(u8, self.list.toSlice(), m);
}
/// For passing to C functions.
pub fn ptr(self: &const Buffer) -> &u8 {
return self.list.items.ptr;
}
};
test "simple Buffer" {

View File

@ -48,3 +48,4 @@ pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) -> c_int;
pub extern "c" fn malloc(usize) -> ?&c_void;
pub extern "c" fn realloc(&c_void, usize) -> ?&c_void;
pub extern "c" fn free(&c_void);
pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) -> c_int;

View File

@ -10,7 +10,8 @@ const Allocator = mem.Allocator;
error OutOfMemory;
pub var c_allocator = Allocator {
pub const c_allocator = &c_allocator_state;
var c_allocator_state = Allocator {
.allocFn = cAlloc,
.reallocFn = cRealloc,
.freeFn = cFree,
@ -24,15 +25,13 @@ fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
}
fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
if (new_size <= old_mem.len) {
const old_ptr = @ptrCast(&c_void, old_mem.ptr);
if (c.realloc(old_ptr, new_size)) |buf| {
return @ptrCast(&u8, buf)[0..new_size];
} else if (new_size <= old_mem.len) {
return old_mem[0..new_size];
} else {
const old_ptr = @ptrCast(&c_void, old_mem.ptr);
if (c.realloc(old_ptr, usize(new_size))) |buf| {
return @ptrCast(&u8, buf)[0..new_size];
} else {
return error.OutOfMemory;
}
return error.OutOfMemory;
}
}

View File

@ -1543,6 +1543,39 @@ pub fn openSelfExe() -> %io.File {
}
}
/// Get the directory path that contains the current executable.
/// Caller owns returned memory.
pub fn selfExeDirPath(allocator: &mem.Allocator) -> %[]u8 {
switch (builtin.os) {
Os.linux => {
// If the currently executing binary has been deleted,
// the file path looks something like `/a/b/c/exe (deleted)`
// This path cannot be opened, but it's valid for determining the directory
// the executable was in when it was run.
const full_exe_path = %return readLink(allocator, "/proc/self/exe");
%defer allocator.free(full_exe_path);
const dir = path.dirname(full_exe_path);
return allocator.shrink(u8, full_exe_path, dir.len);
},
Os.windows => {
@panic("TODO windows std.os.selfExeDirPath");
//buf_resize(out_path, 256);
//for (;;) {
// DWORD copied_amt = GetModuleFileName(nullptr, buf_ptr(out_path), buf_len(out_path));
// if (copied_amt <= 0) {
// return ErrorFileNotFound;
// }
// if (copied_amt < buf_len(out_path)) {
// buf_resize(out_path, copied_amt);
// return 0;
// }
// buf_resize(out_path, buf_len(out_path) * 2);
//}
},
else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)),
}
}
pub fn isTty(handle: FileHandle) -> bool {
if (is_windows) {
return windows_util.windowsIsTty(handle);