Files
zig/src/stage1/zig0.cpp
Andrew Kelley 88dc688bbf restore the option to build with cmake
restore cmake to be capable of figuring out the zig version

restore config.h and config.zig. config.h is used to detect whether we
should propagate cmake configuration information to build.zig; however
it can be overridden with -Dstatic-llvm.

fix not passing -DZIG_LINK_MODE with zig build.

when using the cmake build path, build.zig no longer tries to call
llvm-config. Instead it relies 100% on the LLVM_LIBRARIES cmake variable.

build.zig logic reworked and simplified.
2020-12-07 17:27:09 -07:00

553 lines
20 KiB
C++

/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
// This file is the entry point for zig0, which is *only* used to build
// stage2, the self-hosted compiler, into an object file, which is then
// linked by the same build system (cmake) that linked this binary.
#include "stage1.h"
#include "heap.hpp"
#include "stage2.h"
#include "target.hpp"
#include "error.hpp"
#include "util.hpp"
#include "buffer.hpp"
#include "os.hpp"
// This is the only file allowed to include config.h because config.h is
// only produced when building with cmake. When using the zig build system,
// zig0.cpp is never touched.
#include "config.h"
#include <stdio.h>
#include <string.h>
static int print_error_usage(const char *arg0) {
fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0);
return EXIT_FAILURE;
}
static int print_full_usage(const char *arg0, FILE *file, int return_code) {
fprintf(file,
"Usage: %s [options] builds an object file\n"
"\n"
"Options:\n"
" --color [auto|off|on] enable or disable colored error messages\n"
" --name [name] override output name\n"
" -femit-bin=[path] Output machine code\n"
" --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
" --pkg-end pop current pkg\n"
" -ODebug build with optimizations on and safety off\n"
" -OReleaseFast build with optimizations on and safety off\n"
" -OReleaseSafe build with optimizations on and safety on\n"
" -OReleaseSmall build with size optimizations on and safety off\n"
" --single-threaded source may assume it is only used single-threaded\n"
" -dynamic create a shared library (.so; .dll; .dylib)\n"
" --strip exclude debug symbols\n"
" -target [name] <arch>-<os>-<abi> see the targets command\n"
" -mcpu [cpu] specify target CPU and feature set\n"
" --verbose-tokenize enable compiler debug output for tokenization\n"
" --verbose-ast enable compiler debug output for AST parsing\n"
" --verbose-ir enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
" --verbose-cimport enable compiler debug output for C imports\n"
" --verbose-llvm-cpu-features enable compiler debug output for LLVM CPU features\n"
"\n"
, arg0);
return return_code;
}
static Os get_zig_os_type(ZigLLVM_OSType os_type) {
switch (os_type) {
case ZigLLVM_UnknownOS:
return OsFreestanding;
case ZigLLVM_Ananas:
return OsAnanas;
case ZigLLVM_CloudABI:
return OsCloudABI;
case ZigLLVM_DragonFly:
return OsDragonFly;
case ZigLLVM_FreeBSD:
return OsFreeBSD;
case ZigLLVM_Fuchsia:
return OsFuchsia;
case ZigLLVM_IOS:
return OsIOS;
case ZigLLVM_KFreeBSD:
return OsKFreeBSD;
case ZigLLVM_Linux:
return OsLinux;
case ZigLLVM_Lv2:
return OsLv2;
case ZigLLVM_Darwin:
case ZigLLVM_MacOSX:
return OsMacOSX;
case ZigLLVM_NetBSD:
return OsNetBSD;
case ZigLLVM_OpenBSD:
return OsOpenBSD;
case ZigLLVM_Solaris:
return OsSolaris;
case ZigLLVM_Win32:
return OsWindows;
case ZigLLVM_Haiku:
return OsHaiku;
case ZigLLVM_Minix:
return OsMinix;
case ZigLLVM_RTEMS:
return OsRTEMS;
case ZigLLVM_NaCl:
return OsNaCl;
case ZigLLVM_CNK:
return OsCNK;
case ZigLLVM_AIX:
return OsAIX;
case ZigLLVM_CUDA:
return OsCUDA;
case ZigLLVM_NVCL:
return OsNVCL;
case ZigLLVM_AMDHSA:
return OsAMDHSA;
case ZigLLVM_PS4:
return OsPS4;
case ZigLLVM_ELFIAMCU:
return OsELFIAMCU;
case ZigLLVM_TvOS:
return OsTvOS;
case ZigLLVM_WatchOS:
return OsWatchOS;
case ZigLLVM_Mesa3D:
return OsMesa3D;
case ZigLLVM_Contiki:
return OsContiki;
case ZigLLVM_AMDPAL:
return OsAMDPAL;
case ZigLLVM_HermitCore:
return OsHermitCore;
case ZigLLVM_Hurd:
return OsHurd;
case ZigLLVM_WASI:
return OsWASI;
case ZigLLVM_Emscripten:
return OsEmscripten;
}
zig_unreachable();
}
static void get_native_target(ZigTarget *target) {
// first zero initialize
*target = {};
ZigLLVM_OSType os_type;
ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
ZigLLVM_VendorType trash;
ZigLLVMGetNativeTarget(
&target->arch,
&trash,
&os_type,
&target->abi,
&oformat);
target->os = get_zig_os_type(os_type);
target->is_native_os = true;
target->is_native_cpu = true;
if (target->abi == ZigLLVM_UnknownEnvironment) {
target->abi = target_default_abi(target->arch, target->os);
}
}
static Error target_parse_triple(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
const char *dynamic_linker)
{
Error err;
if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) {
zig_triple = nullptr;
}
if (zig_triple == nullptr) {
get_native_target(target);
if (mcpu == nullptr) {
target->llvm_cpu_name = ZigLLVMGetHostCPUName();
target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
} else if (strcmp(mcpu, "baseline") == 0) {
target->is_native_os = false;
target->is_native_cpu = false;
target->llvm_cpu_name = "";
target->llvm_cpu_features = "";
} else {
const char *msg = "stage0 can't handle CPU/features in the target";
stage2_panic(msg, strlen(msg));
}
} else {
// first initialize all to zero
*target = {};
SplitIterator it = memSplit(str(zig_triple), str("-"));
Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it);
Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it);
if (!opt_archsub.is_some)
return ErrorMissingArchitecture;
if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) {
return err;
}
if (!opt_os.is_some)
return ErrorMissingOperatingSystem;
if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
return err;
}
if (opt_abi.is_some) {
if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) {
return err;
}
} else {
target->abi = target_default_abi(target->arch, target->os);
}
if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) {
const char *msg = "stage0 can't handle CPU/features in the target";
stage2_panic(msg, strlen(msg));
}
}
return ErrorNone;
}
static bool str_starts_with(const char *s1, const char *s2) {
size_t s2_len = strlen(s2);
if (strlen(s1) < s2_len) {
return false;
}
return memcmp(s1, s2, s2_len) == 0;
}
int main_exit(Stage2ProgressNode *root_progress_node, int exit_code) {
if (root_progress_node != nullptr) {
stage2_progress_end(root_progress_node);
}
return exit_code;
}
int main(int argc, char **argv) {
zig_stage1_os_init();
char *arg0 = argv[0];
Error err;
const char *in_file = nullptr;
const char *emit_bin_path = nullptr;
bool strip = false;
const char *out_name = nullptr;
bool verbose_tokenize = false;
bool verbose_ast = false;
bool verbose_ir = false;
bool verbose_llvm_ir = false;
bool verbose_cimport = false;
bool verbose_llvm_cpu_features = false;
ErrColor color = ErrColorAuto;
const char *dynamic_linker = nullptr;
bool link_libc = false;
bool link_libcpp = false;
const char *target_string = nullptr;
ZigStage1Pkg *cur_pkg = heap::c_allocator.create<ZigStage1Pkg>();
BuildMode optimize_mode = BuildModeDebug;
TargetSubsystem subsystem = TargetSubsystemAuto;
const char *override_lib_dir = nullptr;
const char *mcpu = nullptr;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
if (arg[0] == '-') {
if (strcmp(arg, "--") == 0) {
fprintf(stderr, "Unexpected end-of-parameter mark: %s\n", arg);
} else if (strcmp(arg, "-ODebug") == 0) {
optimize_mode = BuildModeDebug;
} else if (strcmp(arg, "-OReleaseFast") == 0) {
optimize_mode = BuildModeFastRelease;
} else if (strcmp(arg, "-OReleaseSafe") == 0) {
optimize_mode = BuildModeSafeRelease;
} else if (strcmp(arg, "-OReleaseSmall") == 0) {
optimize_mode = BuildModeSmallRelease;
} else if (strcmp(arg, "--help") == 0) {
return print_full_usage(arg0, stdout, EXIT_SUCCESS);
} else if (strcmp(arg, "--strip") == 0) {
strip = true;
} else if (strcmp(arg, "--verbose-tokenize") == 0) {
verbose_tokenize = true;
} else if (strcmp(arg, "--verbose-ast") == 0) {
verbose_ast = true;
} else if (strcmp(arg, "--verbose-ir") == 0) {
verbose_ir = true;
} else if (strcmp(arg, "--verbose-llvm-ir") == 0) {
verbose_llvm_ir = true;
} else if (strcmp(arg, "--verbose-cimport") == 0) {
verbose_cimport = true;
} else if (strcmp(arg, "--verbose-llvm-cpu-features") == 0) {
verbose_llvm_cpu_features = true;
} else if (arg[1] == 'l' && arg[2] != 0) {
// alias for --library
const char *l = &arg[2];
if (strcmp(l, "c") == 0) {
link_libc = true;
} else if (strcmp(l, "c++") == 0 || strcmp(l, "stdc++") == 0) {
link_libcpp = true;
}
} else if (strcmp(arg, "--pkg-begin") == 0) {
if (i + 2 >= argc) {
fprintf(stderr, "Expected 2 arguments after --pkg-begin\n");
return print_error_usage(arg0);
}
ZigStage1Pkg *new_cur_pkg = heap::c_allocator.create<ZigStage1Pkg>();
i += 1;
new_cur_pkg->name_ptr = argv[i];
new_cur_pkg->name_len = strlen(argv[i]);
i += 1;
new_cur_pkg->path_ptr = argv[i];
new_cur_pkg->path_len = strlen(argv[i]);
new_cur_pkg->parent = cur_pkg;
cur_pkg->children_ptr = heap::c_allocator.reallocate<ZigStage1Pkg *>(cur_pkg->children_ptr,
cur_pkg->children_len, cur_pkg->children_len + 1);
cur_pkg->children_ptr[cur_pkg->children_len] = new_cur_pkg;
cur_pkg->children_len += 1;
cur_pkg = new_cur_pkg;
} else if (strcmp(arg, "--pkg-end") == 0) {
if (cur_pkg->parent == nullptr) {
fprintf(stderr, "Encountered --pkg-end with no matching --pkg-begin\n");
return EXIT_FAILURE;
}
cur_pkg = cur_pkg->parent;
} else if (str_starts_with(arg, "-mcpu=")) {
mcpu = arg + strlen("-mcpu=");
} else if (str_starts_with(arg, "-femit-bin=")) {
emit_bin_path = arg + strlen("-femit-bin=");
} else if (i + 1 >= argc) {
fprintf(stderr, "Expected another argument after %s\n", arg);
return print_error_usage(arg0);
} else {
i += 1;
if (strcmp(arg, "--color") == 0) {
if (strcmp(argv[i], "auto") == 0) {
color = ErrColorAuto;
} else if (strcmp(argv[i], "on") == 0) {
color = ErrColorOn;
} else if (strcmp(argv[i], "off") == 0) {
color = ErrColorOff;
} else {
fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
return print_error_usage(arg0);
}
} else if (strcmp(arg, "--name") == 0) {
out_name = argv[i];
} else if (strcmp(arg, "--dynamic-linker") == 0) {
dynamic_linker = argv[i];
} else if (strcmp(arg, "--override-lib-dir") == 0) {
override_lib_dir = argv[i];
} else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) {
if (strcmp(argv[i], "c") == 0) {
link_libc = true;
} else if (strcmp(argv[i], "c++") == 0 || strcmp(argv[i], "stdc++") == 0) {
link_libcpp = true;
}
} else if (strcmp(arg, "-target") == 0) {
target_string = argv[i];
} else if (strcmp(arg, "--subsystem") == 0) {
if (strcmp(argv[i], "console") == 0) {
subsystem = TargetSubsystemConsole;
} else if (strcmp(argv[i], "windows") == 0) {
subsystem = TargetSubsystemWindows;
} else if (strcmp(argv[i], "posix") == 0) {
subsystem = TargetSubsystemPosix;
} else if (strcmp(argv[i], "native") == 0) {
subsystem = TargetSubsystemNative;
} else if (strcmp(argv[i], "efi_application") == 0) {
subsystem = TargetSubsystemEfiApplication;
} else if (strcmp(argv[i], "efi_boot_service_driver") == 0) {
subsystem = TargetSubsystemEfiBootServiceDriver;
} else if (strcmp(argv[i], "efi_rom") == 0) {
subsystem = TargetSubsystemEfiRom;
} else if (strcmp(argv[i], "efi_runtime_driver") == 0) {
subsystem = TargetSubsystemEfiRuntimeDriver;
} else {
fprintf(stderr, "invalid: --subsystem %s\n"
"Options are:\n"
" console\n"
" windows\n"
" posix\n"
" native\n"
" efi_application\n"
" efi_boot_service_driver\n"
" efi_rom\n"
" efi_runtime_driver\n"
, argv[i]);
return EXIT_FAILURE;
}
} else if (strcmp(arg, "-mcpu") == 0) {
mcpu = argv[i];
} else {
fprintf(stderr, "Invalid argument: %s\n", arg);
return print_error_usage(arg0);
}
}
} else if (!in_file) {
in_file = arg;
} else {
fprintf(stderr, "Unexpected extra parameter: %s\n", arg);
return print_error_usage(arg0);
}
}
if (cur_pkg->parent != nullptr) {
fprintf(stderr, "Unmatched --pkg-begin\n");
return EXIT_FAILURE;
}
Stage2Progress *progress = stage2_progress_create();
Stage2ProgressNode *root_progress_node = stage2_progress_start_root(progress, "", 0, 0);
if (color == ErrColorOff) stage2_progress_disable_tty(progress);
ZigTarget target;
if ((err = target_parse_triple(&target, target_string, mcpu, dynamic_linker))) {
fprintf(stderr, "invalid target: %s\n", err_str(err));
return print_error_usage(arg0);
}
if (in_file == nullptr) {
fprintf(stderr, "missing zig file\n");
return print_error_usage(arg0);
}
if (out_name == nullptr) {
fprintf(stderr, "missing --name\n");
return print_error_usage(arg0);
}
if (override_lib_dir == nullptr) {
fprintf(stderr, "missing --override-lib-dir\n");
return print_error_usage(arg0);
}
if (emit_bin_path == nullptr) {
fprintf(stderr, "missing -femit-bin=\n");
return print_error_usage(arg0);
}
ZigStage1 *stage1 = zig_stage1_create(optimize_mode,
nullptr, 0,
in_file, strlen(in_file),
override_lib_dir, strlen(override_lib_dir),
&target, false);
stage1->main_progress_node = root_progress_node;
stage1->root_name_ptr = out_name;
stage1->root_name_len = strlen(out_name);
stage1->strip = strip;
stage1->verbose_tokenize = verbose_tokenize;
stage1->verbose_ast = verbose_ast;
stage1->verbose_ir = verbose_ir;
stage1->verbose_llvm_ir = verbose_llvm_ir;
stage1->verbose_cimport = verbose_cimport;
stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features;
stage1->emit_o_ptr = emit_bin_path;
stage1->emit_o_len = strlen(emit_bin_path);
stage1->root_pkg = cur_pkg;
stage1->err_color = color;
stage1->link_libc = link_libc;
stage1->link_libcpp = link_libcpp;
stage1->subsystem = subsystem;
stage1->pic = true;
zig_stage1_build_object(stage1);
zig_stage1_destroy(stage1);
return main_exit(root_progress_node, EXIT_SUCCESS);
}
void stage2_panic(const char *ptr, size_t len) {
fwrite(ptr, 1, len, stderr);
fprintf(stderr, "\n");
fflush(stderr);
abort();
}
struct Stage2Progress {
int trash;
};
struct Stage2ProgressNode {
int trash;
};
Stage2Progress *stage2_progress_create(void) {
return nullptr;
}
void stage2_progress_destroy(Stage2Progress *progress) {}
Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
const char *name_ptr, size_t name_len, size_t estimated_total_items)
{
return nullptr;
}
Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
const char *name_ptr, size_t name_len, size_t estimated_total_items)
{
return nullptr;
}
void stage2_progress_end(Stage2ProgressNode *node) {}
void stage2_progress_complete_one(Stage2ProgressNode *node) {}
void stage2_progress_disable_tty(Stage2Progress *progress) {}
void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len,
size_t *result_len)
{
Error err;
Buf contents_buf = BUF_INIT;
Buf path_buf = BUF_INIT;
buf_init_from_mem(&path_buf, path_ptr, path_len);
if ((err = os_fetch_file_path(&path_buf, &contents_buf))) {
return nullptr;
}
*result_len = buf_len(&contents_buf);
return buf_ptr(&contents_buf);
}
Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len,
const char **out_zig_path_ptr, size_t *out_zig_path_len,
struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len)
{
const char *msg = "stage0 called stage2_cimport";
stage2_panic(msg, strlen(msg));
}
const char *stage2_add_link_lib(struct ZigStage1 *stage1,
const char *lib_name_ptr, size_t lib_name_len,
const char *symbol_name_ptr, size_t symbol_name_len)
{
return nullptr;
}
const char *stage2_version_string(void) {
return ZIG_VERSION_STRING;
}
struct Stage2SemVer stage2_version(void) {
return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH};
}