add bootstrap.c for building from source without LLVM

When a zig compiler without LLVM extensions is satisfactory, this
greatly simplified build-from-source process can be used.

This could be useful for users who only want to contribute to the
standard library, for example.
This commit is contained in:
Andrew Kelley 2023-11-05 20:23:52 -07:00
parent 53500a5768
commit 621e89a863
2 changed files with 197 additions and 0 deletions

View File

@ -64,6 +64,20 @@ For more options, tips, and troubleshooting, please see the
[Building Zig From Source](https://github.com/ziglang/zig/wiki/Building-Zig-From-Source)
page on the wiki.
## Building from Source without LLVM
If you don't need your Zig compiler to have LLVM extensions enabled, you can
follow these instructions instead.
In this case, the only system dependency is a C compiler.
```
cc -o bootstrap bootstrap.c
./bootstrap build
```
You can pass any options to this that you would pass to `zig build`.
## Contributing
Zig is Free and Open Source Software. We welcome bug reports and patches from

183
bootstrap.c Normal file
View File

@ -0,0 +1,183 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
static const char *get_c_compiler(void) {
const char *cc = getenv("CC");
return (cc == NULL) ? "cc" : cc;
}
static void panic(const char *reason) {
fprintf(stderr, "%s\n", reason);
abort();
}
#if defined(__WIN32__)
#error TODO write the functionality for executing child process into this build script
#else
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
static void run(char **argv) {
pid_t pid = fork();
if (pid == -1)
panic("fork failed");
if (pid == 0) {
// child
execvp(argv[0], argv);
exit(1);
}
// parent
int status;
waitpid(pid, &status, 0);
if (!WIFEXITED(status))
panic("child process crashed");
if (WEXITSTATUS(status) != 0)
panic("child process failed");
}
static void run_execv(char **argv) {
if (execv(argv[0], argv) == -1 && errno == ENOENT) return;
perror("execv failed");
}
#endif
static void print_and_run(const char **argv) {
fprintf(stderr, "%s", argv[0]);
for (const char **arg = argv + 1; *arg; arg += 1) {
fprintf(stderr, " %s", *arg);
}
fprintf(stderr, "\n");
run((char **)argv);
}
static const char *get_host_os(void) {
#if defined(__WIN32__)
return "windows";
#elif defined(__APPLE__)
return "macos";
#elif defined(__linux__)
return "linux";
#else
#error TODO implement get_host_os in this build script for this target
#endif
}
static const char *get_host_arch(void) {
#if defined(__x86_64__ )
return "x86_64";
#elif defined(__aarch64__)
return "aarch64";
#else
#error TODO implement get_host_arch in this build script for this target
#endif
}
static const char *get_host_triple(void) {
static char global_buffer[100];
sprintf(global_buffer, "%s-%s", get_host_arch(), get_host_os());
return global_buffer;
}
int main(int argc, char **argv) {
argv[0] = "./zig2";
run_execv(argv);
const char *cc = get_c_compiler();
const char *host_triple = get_host_triple();
{
const char *child_argv[] = {
cc, "-o", "zig-wasm2c", "stage1/wasm2c.c", "-O2", "-std=c99", NULL,
};
print_and_run(child_argv);
}
{
const char *child_argv[] = {
"./zig-wasm2c", "stage1/zig1.wasm", "zig1.c", NULL,
};
print_and_run(child_argv);
}
{
const char *child_argv[] = {
cc, "-o", "zig1", "zig1.c", "stage1/wasi.c", "-std=c99", "-Os", "-lm", NULL,
};
print_and_run(child_argv);
}
{
FILE *f = fopen("config.zig", "wb");
if (f == NULL)
panic("unable to open config.zig for writing");
const char *zig_version = "0.12.0-dev.bootstrap";
int written = fprintf(f,
"pub const have_llvm = false;\n"
"pub const llvm_has_m68k = false;\n"
"pub const llvm_has_csky = false;\n"
"pub const llvm_has_arc = false;\n"
"pub const llvm_has_xtensa = false;\n"
"pub const version: [:0]const u8 = \"%s\";\n"
"pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"
"pub const enable_logging: bool = false;\n"
"pub const enable_link_snapshots: bool = false;\n"
"pub const enable_tracy = false;\n"
"pub const value_tracing = false;\n"
"pub const skip_non_native = false;\n"
"pub const only_c = false;\n"
"pub const force_gpa = false;\n"
"pub const only_core_functionality = true;\n"
"pub const only_reduce = false;\n"
, zig_version);
if (written < 100)
panic("unable to write to config.zig file");
if (fclose(f) != 0)
panic("unable to finish writing to config.zig file");
}
{
const char *child_argv[] = {
"./zig1", "lib", "build-exe", "src/main.zig",
"-ofmt=c", "-lc", "-OReleaseSmall",
"--name", "zig2", "-femit-bin=zig2.c",
"--mod", "build_options::config.zig",
"--mod", "aro::deps/aro/lib.zig",
"--deps", "build_options,aro",
"-target", host_triple,
NULL,
};
print_and_run(child_argv);
}
{
const char *child_argv[] = {
"./zig1", "lib", "build-obj", "lib/compiler_rt.zig",
"-ofmt=c", "-OReleaseSmall",
"--name", "compiler_rt", "-femit-bin=compiler_rt.c",
"--mod", "build_options::config.zig",
"--deps", "build_options",
"-target", host_triple,
NULL,
};
print_and_run(child_argv);
}
{
const char *child_argv[] = {
cc, "-o", "zig2", "zig2.c", "compiler_rt.c",
"-std=c99", "-O2", "-fno-stack-protector",
"-Wl,-z,stack-size=0x10000000", "-Istage1", NULL,
};
print_and_run(child_argv);
}
run_execv(argv);
panic("build script failed to create valid zig2 executable");
}