805 lines
33 KiB
Zig
805 lines
33 KiB
Zig
const std = @import("std");
|
|
const mem = std.mem;
|
|
const io = std.io;
|
|
const os = std.os;
|
|
const heap = std.heap;
|
|
const warn = std.debug.warn;
|
|
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;
|
|
const c = @import("c.zig");
|
|
|
|
const default_zig_cache_name = "zig-cache";
|
|
|
|
const Cmd = enum {
|
|
None,
|
|
Build,
|
|
Test,
|
|
Version,
|
|
Zen,
|
|
TranslateC,
|
|
Targets,
|
|
};
|
|
|
|
fn badArgs(comptime format: []const u8, args: ...) noreturn {
|
|
var stderr = io.getStdErr() catch std.os.exit(1);
|
|
var stderr_stream_adapter = io.FileOutStream.init(&stderr);
|
|
const stderr_stream = &stderr_stream_adapter.stream;
|
|
stderr_stream.print(format ++ "\n\n", args) catch std.os.exit(1);
|
|
printUsage(&stderr_stream_adapter.stream) catch std.os.exit(1);
|
|
std.os.exit(1);
|
|
}
|
|
|
|
pub fn main() !void {
|
|
const allocator = std.heap.c_allocator;
|
|
|
|
const args = try os.argsAlloc(allocator);
|
|
defer os.argsFree(allocator, args);
|
|
|
|
if (args.len >= 2 and mem.eql(u8, args[1], "build")) {
|
|
return buildMain(allocator, args[2..]);
|
|
}
|
|
|
|
if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {
|
|
return fmtMain(allocator, args[2..]);
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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 test_filters = ArrayList([]const u8).init(allocator);
|
|
defer test_filters.deinit();
|
|
|
|
var lib_dirs = ArrayList([]const u8).init(allocator);
|
|
defer lib_dirs.deinit();
|
|
|
|
var clang_argv = ArrayList([]const u8).init(allocator);
|
|
defer clang_argv.deinit();
|
|
|
|
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
|
|
try 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) {
|
|
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 {
|
|
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 {
|
|
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")) {
|
|
try clang_argv.append("-isystem");
|
|
try clang_argv.append(args[arg_i]);
|
|
} else if (mem.eql(u8, arg, "-dirafter")) {
|
|
try clang_argv.append("-dirafter");
|
|
try clang_argv.append(args[arg_i]);
|
|
} else if (mem.eql(u8, arg, "-mllvm")) {
|
|
try clang_argv.append("-mllvm");
|
|
try clang_argv.append(args[arg_i]);
|
|
|
|
try llvm_argv.append(args[arg_i]);
|
|
} else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) {
|
|
try lib_dirs.append(args[arg_i]);
|
|
} else if (mem.eql(u8, arg, "--library")) {
|
|
try link_libs.append(args[arg_i]);
|
|
} else if (mem.eql(u8, arg, "--object")) {
|
|
try objects.append(args[arg_i]);
|
|
} else if (mem.eql(u8, arg, "--assembly")) {
|
|
try 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")) {
|
|
try 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")) {
|
|
try rpath_list.append(args[arg_i]);
|
|
} else if (mem.eql(u8, arg, "--test-filter")) {
|
|
try 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 = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
|
|
} else if (mem.eql(u8, arg, "--ver-minor")) {
|
|
ver_minor = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
|
|
} else if (mem.eql(u8, arg, "--ver-patch")) {
|
|
ver_patch = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
|
|
} else if (mem.eql(u8, arg, "--test-cmd")) {
|
|
@panic("TODO --test-cmd");
|
|
} else {
|
|
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 {
|
|
badArgs("unrecognized command: {}", arg);
|
|
}
|
|
} else switch (cmd) {
|
|
Cmd.Build, Cmd.TranslateC, Cmd.Test => {
|
|
if (in_file_arg == null) {
|
|
in_file_arg = arg;
|
|
} else {
|
|
badArgs("unexpected extra parameter: {}", arg);
|
|
}
|
|
},
|
|
Cmd.Version, Cmd.Zen, Cmd.Targets => {
|
|
badArgs("unexpected extra parameter: {}", arg);
|
|
},
|
|
Cmd.None => unreachable,
|
|
}
|
|
}
|
|
|
|
target.initializeAll();
|
|
|
|
// 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);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
switch (cmd) {
|
|
Cmd.None => 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) {
|
|
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) {
|
|
badArgs("expected source file argument");
|
|
} else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) {
|
|
badArgs("When building an object file, --object arguments are invalid");
|
|
}
|
|
|
|
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() ?? badArgs("file name cannot be empty");
|
|
} else {
|
|
badArgs("--name [name] not provided and unable to infer");
|
|
}
|
|
},
|
|
Cmd.Test => "test",
|
|
else => unreachable,
|
|
};
|
|
|
|
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 = try os.path.resolve(allocator, ".", chosen_cache_dir);
|
|
defer allocator.free(full_cache_dir);
|
|
|
|
const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
|
|
errdefer allocator.free(zig_lib_dir);
|
|
|
|
const module = try 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| {
|
|
_ = try 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) {
|
|
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();
|
|
|
|
try module.build();
|
|
try module.link(out_file);
|
|
},
|
|
Cmd.TranslateC => @panic("TODO translate-c"),
|
|
Cmd.Test => @panic("TODO test cmd"),
|
|
else => unreachable,
|
|
}
|
|
},
|
|
Cmd.Version => {
|
|
var stdout_file = try io.getStdErr();
|
|
try stdout_file.write(std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
|
|
try stdout_file.write("\n");
|
|
},
|
|
Cmd.Targets => @panic("TODO zig targets"),
|
|
}
|
|
}
|
|
|
|
fn printUsage(stream: var) !void {
|
|
try 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
|
|
\\ fmt [file] parse file and render in canonical zig format
|
|
\\ 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 = try io.getStdErr();
|
|
try 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.
|
|
\\
|
|
\\
|
|
);
|
|
}
|
|
|
|
fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void {
|
|
var build_file: [] const u8 = "build.zig";
|
|
var cache_dir: ?[] const u8 = null;
|
|
var zig_install_prefix: ?[] const u8 = null;
|
|
var asked_for_help = false;
|
|
var asked_for_init = false;
|
|
|
|
var args = ArrayList([] const u8).init(allocator);
|
|
defer args.deinit();
|
|
|
|
var zig_exe_path = try os.selfExePath(allocator);
|
|
defer allocator.free(zig_exe_path);
|
|
|
|
try args.append(""); // Placeholder for zig-cache/build
|
|
try args.append(""); // Placeholder for zig_exe_path
|
|
try args.append(""); // Placeholder for build_file_dirname
|
|
try args.append(""); // Placeholder for full_cache_dir
|
|
|
|
var i: usize = 0;
|
|
while (i < argv.len) : (i += 1) {
|
|
var arg = argv[i];
|
|
if (mem.eql(u8, arg, "--help")) {
|
|
asked_for_help = true;
|
|
try args.append(argv[i]);
|
|
} else if (mem.eql(u8, arg, "--init")) {
|
|
asked_for_init = true;
|
|
try args.append(argv[i]);
|
|
} else if (i + 1 < argv.len and mem.eql(u8, arg, "--build-file")) {
|
|
build_file = argv[i + 1];
|
|
i += 1;
|
|
} else if (i + 1 < argv.len and mem.eql(u8, arg, "--cache-dir")) {
|
|
cache_dir = argv[i + 1];
|
|
i += 1;
|
|
} else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) {
|
|
try args.append(arg);
|
|
i += 1;
|
|
zig_install_prefix = argv[i];
|
|
try args.append(argv[i]);
|
|
} else {
|
|
try args.append(arg);
|
|
}
|
|
}
|
|
|
|
const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
|
|
defer allocator.free(zig_lib_dir);
|
|
|
|
const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");
|
|
defer allocator.free(zig_std_dir);
|
|
|
|
const special_dir = try os.path.join(allocator, zig_std_dir, "special");
|
|
defer allocator.free(special_dir);
|
|
|
|
const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
|
|
defer allocator.free(build_runner_path);
|
|
|
|
// g = codegen_create(build_runner_path, ...)
|
|
// codegen_set_out_name(g, "build")
|
|
|
|
const build_file_abs = try os.path.resolve(allocator, ".", build_file);
|
|
defer allocator.free(build_file_abs);
|
|
|
|
const build_file_basename = os.path.basename(build_file_abs);
|
|
const build_file_dirname = os.path.dirname(build_file_abs);
|
|
|
|
var full_cache_dir: []u8 = undefined;
|
|
if (cache_dir == null) {
|
|
full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
|
|
} else {
|
|
full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir);
|
|
}
|
|
defer allocator.free(full_cache_dir);
|
|
|
|
const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
|
|
defer allocator.free(path_to_build_exe);
|
|
// codegen_set_cache_dir(g, full_cache_dir)
|
|
|
|
args.items[0] = path_to_build_exe;
|
|
args.items[1] = zig_exe_path;
|
|
args.items[2] = build_file_dirname;
|
|
args.items[3] = full_cache_dir;
|
|
|
|
var build_file_exists: bool = undefined;
|
|
if (os.File.openRead(allocator, build_file_abs)) |*file| {
|
|
file.close();
|
|
build_file_exists = true;
|
|
} else |_| {
|
|
build_file_exists = false;
|
|
}
|
|
|
|
if (!build_file_exists and asked_for_help) {
|
|
// TODO(bnoordhuis) Print help message from std/special/build_runner.zig
|
|
return;
|
|
}
|
|
|
|
if (!build_file_exists and asked_for_init) {
|
|
const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
|
|
defer allocator.free(build_template_path);
|
|
|
|
var srcfile = try os.File.openRead(allocator, build_template_path);
|
|
defer srcfile.close();
|
|
|
|
var dstfile = try os.File.openWrite(allocator, build_file_abs);
|
|
defer dstfile.close();
|
|
|
|
while (true) {
|
|
var buffer: [4096]u8 = undefined;
|
|
const n = try srcfile.read(buffer[0..]);
|
|
if (n == 0) break;
|
|
try dstfile.write(buffer[0..n]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (!build_file_exists) {
|
|
warn(
|
|
\\No 'build.zig' file found.
|
|
\\Initialize a 'build.zig' template file with `zig build --init`,
|
|
\\or build an executable directly with `zig build-exe $FILENAME.zig`.
|
|
\\See: `zig build --help` or `zig help` for more options.
|
|
\\
|
|
);
|
|
os.exit(1);
|
|
}
|
|
|
|
// codegen_build(g)
|
|
// codegen_link(g, path_to_build_exe)
|
|
// codegen_destroy(g)
|
|
|
|
var proc = try os.ChildProcess.init(args.toSliceConst(), allocator);
|
|
defer proc.deinit();
|
|
|
|
var term = try proc.spawnAndWait();
|
|
switch (term) {
|
|
os.ChildProcess.Term.Exited => |status| {
|
|
if (status != 0) {
|
|
warn("{} exited with status {}\n", args.at(0), status);
|
|
os.exit(1);
|
|
}
|
|
},
|
|
os.ChildProcess.Term.Signal => |signal| {
|
|
warn("{} killed by signal {}\n", args.at(0), signal);
|
|
os.exit(1);
|
|
},
|
|
os.ChildProcess.Term.Stopped => |signal| {
|
|
warn("{} stopped by signal {}\n", args.at(0), signal);
|
|
os.exit(1);
|
|
},
|
|
os.ChildProcess.Term.Unknown => |status| {
|
|
warn("{} encountered unknown failure {}\n", args.at(0), status);
|
|
os.exit(1);
|
|
},
|
|
}
|
|
}
|
|
|
|
fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
|
|
for (file_paths) |file_path| {
|
|
var file = try os.File.openRead(allocator, file_path);
|
|
defer file.close();
|
|
|
|
const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
|
|
warn("unable to open '{}': {}", file_path, err);
|
|
continue;
|
|
};
|
|
defer allocator.free(source_code);
|
|
|
|
var tokenizer = std.zig.Tokenizer.init(source_code);
|
|
var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
|
|
defer parser.deinit();
|
|
|
|
var tree = try parser.parse();
|
|
defer tree.deinit();
|
|
|
|
const baf = try io.BufferedAtomicFile.create(allocator, file_path);
|
|
defer baf.destroy();
|
|
|
|
try parser.renderSource(baf.stream(), tree.root_node);
|
|
}
|
|
}
|
|
|
|
/// 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) catch |err| {
|
|
warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));
|
|
return error.ZigInstallationNotFound;
|
|
};
|
|
} else {
|
|
return findZigLibDir(allocator) catch |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 = try os.path.join(allocator, test_path, "lib", "zig");
|
|
errdefer allocator.free(test_zig_dir);
|
|
|
|
const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
|
|
defer allocator.free(test_index_file);
|
|
|
|
var file = try os.File.openRead(allocator, test_index_file);
|
|
file.close();
|
|
|
|
return test_zig_dir;
|
|
}
|
|
|
|
/// Caller must free result
|
|
fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
|
|
const self_exe_path = try 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) catch |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;
|
|
}
|