mirror of
https://github.com/ziglang/zig.git
synced 2025-01-08 11:12:14 +00:00
port most of main.cpp to self hosted compiler
This commit is contained in:
parent
760b307e8a
commit
39c7bd24e4
53
README.md
53
README.md
@ -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
145
build.zig
@ -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
13
src-self-hosted/llvm.zig
Normal 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;
|
||||
}
|
@ -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
295
src-self-hosted/module.zig
Normal 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);
|
||||
}
|
@ -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();
|
||||
|
@ -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" {
|
||||
|
@ -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;
|
||||
|
15
std/heap.zig
15
std/heap.zig
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user