aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/a_main.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-03-17 13:22:00 +0100
committerlemon <lsof@mailbox.org>2026-03-17 13:22:00 +0100
commita8d6f8bf30c07edb775e56889f568ca20240bedf (patch)
treeb5a452b2675b2400f15013617291fe6061180bbf /src/a_main.c
parent24f14b7ad1af08d872971d72ce089a529911f657 (diff)
REFACTOR: move sources to src/
Diffstat (limited to 'src/a_main.c')
-rw-r--r--src/a_main.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/src/a_main.c b/src/a_main.c
new file mode 100644
index 0000000..9710814
--- /dev/null
+++ b/src/a_main.c
@@ -0,0 +1,710 @@
+#include "common.h"
+#include "version.h"
+#include "hostconfig.h" /* run ./configure */
+#include "obj/obj.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <time.h>
+
+struct option ccopt;
+struct cinclpaths cinclpaths[5];
+
+static void
+addinclpath(int ord, const char *path)
+{
+ struct inclpath *p = alloc(&globarena, sizeof *p, 0);
+ assert((uint)ord < countof(cinclpaths));
+ p->path = path;
+ p->next = NULL;
+ if (cinclpaths[ord].list) {
+ *cinclpaths[ord].tail = p;
+ } else {
+ cinclpaths[ord].list = p;
+ }
+ cinclpaths[ord].tail = &p->next;
+}
+
+/* parse an argument of the form 'opt=abcd'
+ * e.g. arg="foo=bar123"; opt="foo"; returns "bar123" */
+static const char *
+optval(const char *arg, const char *opt)
+{
+ uint n1 = strlen(arg), n2 = strlen(opt);
+ if (n1 < n2+1 || memcmp(arg, opt, n2) != 0 || arg[n2] != '=')
+ return NULL;
+ return arg + n2 + 1;
+}
+
+/* "foo.bar" -> "bar"; ".dotfile" -> "" */
+static const char *
+fileext(const char *path)
+{
+ const char *dot = NULL;
+ assert(path && *path && "empty");
+
+ for (++path; *path; ++path) {
+ if (*path == '.') dot = path;
+ }
+ return dot ? dot+1 : "";
+}
+
+enum inft { IFTauto, IFTc, IFTasm, IFTobj, IFTar, IFTdll };
+
+static enum inft
+ftdetect(const char *s)
+{
+ const char *ext = fileext(s);
+ if (!strcmp(ext, "c")) return IFTc;
+ if (!strcmp(ext, "o")) return IFTobj;
+ if (!strcmp(ext, "a")) return IFTar;
+ if (!strcmp(ext, "s")) return IFTasm;
+ if (!strcmp(ext, "so")) return IFTdll;
+ warn(NULL, "assuming %'s is C source file", s);
+ return IFTc;
+}
+
+static union {
+ struct arena a;
+ char mem[sizeof(struct arena) + (1<<10)];
+} _arenamem;
+struct arena *globarena = &_arenamem.a;
+
+/* withext("x/y.c", "o") -> "y.o"; withext("f9", "s") -> "f9.s" */
+static const char *
+withext(const char *path, const char *ext)
+{
+ char *res;
+ size_t len;
+ const char *oext, *file = path;
+
+ while (*path)
+ if (*path++ == '/')
+ file = path;
+ assert(*file && "no filename");
+ oext = fileext(file);
+ if (!*oext)
+ len = strlen(file);
+ else
+ len = oext - file - 1;
+ res = alloc(&globarena, len + 1 + (ext ? strlen(ext) + 1 : 0), 1);
+ memcpy(res, file, len);
+ if (ext) {
+ res[len] = '.';
+ memcpy(res + len + 1, ext, strlen(ext));
+ } else {
+ res[len] = 0;
+ }
+ return res;
+}
+
+struct infile {
+ enum inft ft;
+ const char *path, *temp;
+};
+static struct infile infilebuf[16];
+static struct task {
+ enum outft { OFTexe, OFTdll, OFTobj, OFTasm, OFTc } outft;
+ const char *out;
+ const char *targ;
+ vec_of(struct infile) inf;
+ char **runargs;
+ vec_of(const char *) linkargs;
+ bool verbose, run, syntaxonly;
+} task = { .inf = VINIT(infilebuf, countof(infilebuf)) };
+
+static void prihelp(void);
+
+static void
+optparse(char **args)
+{
+ const char *arg, *x;
+ enum inft ft = IFTauto;
+
+ while ((arg = *++args)) {
+ if (*arg++ != '-' || !*arg) {
+ vpush(&task.inf, ((struct infile) {
+ ft ? ft : ftdetect(arg-1),
+ arg[-1] != '-' ? arg-1 : "/dev/stdin"
+ }));
+ ft = IFTauto;
+ if (task.run) {
+ task.runargs = args+1;
+ return;
+ }
+ continue;
+ }
+ int cinclord;
+ if (!strcmp(arg, "help") || !strcmp(arg, "h") || !strcmp(arg, "-help")) {
+ prihelp();
+ exit(0);
+ } else if (!strcmp(arg, "dumpmachine")) {
+ pfmt("%s\n", HOST_TRIPLE);
+ exit(0);
+ } else if (!strcmp(arg, "-version")) {
+ pfmt("antcc version "ANTCC_VERSION_STR"\n"
+ "target: "HOST_TRIPLE"\n"
+ "include paths: "XSTR(HOST_INCLUDE_DIRS)"\n"
+ "host cc for linking: " HOST_CC "\n");
+ exit(0);
+ } else if (!strcmp(arg, "dumpversion")) {
+ pfmt("%s\n", ANTCC_VERSION_STR);
+ exit(0);
+ } else if ((x = optval(arg, "std"))) {
+ if (!strcmp(x, "c89") || !strcmp(x, "c90")) ccopt.cstd = STDC89;
+ else if (!strcmp(x, "c99")) ccopt.cstd = STDC99;
+ else if (!strcmp(x, "c11")) ccopt.cstd = STDC11;
+ else if (!strcmp(x, "c2x")) ccopt.cstd = STDC23;
+ else if (!strcmp(x, "c23")) ccopt.cstd = STDC23;
+ else goto Bad;
+ } else if (!strcmp(arg, "pedantic")) {
+ ccopt.pedant = 1;
+ } else if (!strcmp(arg, "trigraphs")) {
+ ccopt.trigraph = 1;
+ } else if (*arg == 'd' && arg[1]) {
+ /* see common.h§struct option */
+ while (*++arg) switch (*arg | 32) {
+ case 'p': ccopt.dbg.p = 1; break;
+ case 'a': ccopt.dbg.a = 1; break;
+ case 'm': ccopt.dbg.m = 1; break;
+ case 'o': ccopt.dbg.o = 1; break;
+ case 's': ccopt.dbg.s = 1; break;
+ case 'i': ccopt.dbg.i = 1; break;
+ case 'y': ccopt.dbg.y = 1; break;
+ case 'l': ccopt.dbg.l = 1; break;
+ case 'r': ccopt.dbg.r = 1; break;
+ default: warn(NULL, "-d: invalid debug flag %'c", *arg);
+ }
+ } else if (*arg == 'o') {
+ if (arg[1]) task.out = arg+1;
+ else if (args[1]) task.out = *++args;
+ else fatal(NULL, "missing path after `-o`");
+ } else if (!strcmp(arg, "fsyntax-only")) {
+ task.syntaxonly = 1;
+ } else if (*arg == 'f') {
+ /* -fabc / -fno-abc flags */
+ const char *flag = arg+1;
+ bool set = 1;
+ if (!strncmp(flag, "no-", 3)) {
+ set = 0;
+ flag += 3;
+ }
+ if (!strcmp(flag, "pie") || !strcmp(flag, "PIE")) ccopt.pie = set;
+ else if (!strcmp(flag, "pic") || !strcmp(flag, "PIC")) ccopt.pic = set;
+ else goto Bad;
+ } else if (!strcmp(arg, "target") || !strcmp(arg, "-target")) {
+ const char *s = *++args;
+ if (!s) fatal(NULL, "missing target name");
+ task.targ = s;
+ } else if (*arg == 'l' || *arg == 'L' || *arg == 'B' || !strcmp(arg, "shared") || !strcmp(arg, "pthread")) {
+ vpush(&task.linkargs, arg-1);
+ } else if (!strcmp(arg, "v") || !strcmp(arg, "-verbose")) {
+ task.verbose = 1;
+ } else if (!strcmp(arg, "c")) {
+ task.outft = OFTobj;
+ } else if (!strcmp(arg, "E")) {
+ task.outft = OFTc;
+ } else if (!strcmp(arg, "xc")) {
+ ft = IFTc;
+ } else if (!strcmp(arg, "xo")) {
+ ft = IFTobj;
+ } else if (!strcmp(arg, "run")) {
+ task.run = 1;
+ if (task.inf.n > 0) {
+ task.runargs = args+1;
+ return;
+ }
+ } else if (*arg == 'g') {
+ /* TODO debug info */
+ } else if (*arg == 'O') {
+ char o = arg[1];
+ if (!o || o == 'g') ccopt.o = 0; /* default opts */
+ else if (o == '1' || o == 's' || o == 'z') ccopt.o = OPT1;
+ else if ((uint)o - '1' < 9) ccopt.o = OPT2;
+ else if (o == '0') ccopt.o = OPT0;
+ else goto Bad;
+ } else if (*arg == 'D' || *arg == 'U') {
+ void cpppredef(bool undef, const char *cmd);
+ const char *def = arg[1] ? arg+1 : *++args;
+ if (!def) fatal(NULL, "macro name missing after `-%c`", *arg);
+ cpppredef(*arg == 'U', def);
+ } else if (*arg == 'O') {
+ /* TODO optimization level */
+ } else if (*arg == 'I' || !strcmp(arg, "-include-directory")) {
+ const char *p;
+ cinclord = CINCL_I;
+ if (*arg == 'I' && arg[1]) p = arg+1;
+ else CIncl: p = *++args;
+ if (!p) fatal(NULL, "missing path after `%s`", arg-1);
+ addinclpath(cinclord, p);
+ } else if (!strcmp(arg, "iquote")) {
+ cinclord = CINCL_iquote;
+ goto CIncl;
+ } else if (!strcmp(arg, "isystem")) {
+ cinclord = CINCL_isystem;
+ goto CIncl;
+ } else if (!strcmp(arg, "idirafter")) {
+ cinclord = CINCL_idirafter;
+ goto CIncl;
+ } else if (!strcmp(arg, "nostdinc") || !strcmp(arg, "-no-standard-includes")) {
+ cinclpaths[CINCLsys].list = NULL;
+ } else if (*arg == 'M') {
+ ++arg;
+ if (*arg == 'F' || *arg == 'T' || *arg == 'Q') {
+ const char *p = arg[1] ? arg+1 : *++args;
+ if (!p) fatal(NULL, "missing path after `-M%c`", *arg);
+ }
+ /* TODO depfiles */
+ } else if (*arg == 'W') {
+ if (!strcmp(arg+1, "error")) {
+ ccopt.werror = 1;
+ }
+ /* TODO warning switches */
+ } else if (*arg == 'w') {
+ ccopt.wnone = 1;
+ /* TODO warning switches */
+ } else Bad: warn(NULL, "unrecognized option: %'s", arg-1);
+ }
+
+ if (task.inf.n == 0) fatal(NULL, "no input files");
+
+ if (!task.out && !task.syntaxonly) {
+ switch (task.outft) {
+ case OFTdll:
+ case OFTexe: if (!task.run) task.out = "a.out"; break;
+ case OFTasm: task.out = withext(task.inf.p[0].path, "s"); break;
+ case OFTobj: task.out = withext(task.inf.p[0].path, "o"); break;
+ case OFTc: break;
+ }
+ }
+ if (!in_range(task.outft, OFTexe, OFTdll) && task.outft != OFTc && task.inf.n > 1)
+ fatal(NULL, "too many input files");
+}
+
+static const char *
+tempfile(const char *path, const char *ext)
+{
+ int id;
+ static int id2;
+ static char sbuf[1024];
+ const char *tmpdir;
+ const char *file = path;
+ struct wbuf fbuf = MEMBUF(sbuf, sizeof sbuf);
+
+ tmpdir = getenv("TMPDIR");
+ tmpdir = tmpdir ? tmpdir : "/tmp";
+ id = getpid();
+ id = id < 0 ? time(NULL) : id;
+
+ while (*path)
+ if (*path++ == '/')
+ file = path;
+ bfmt(&fbuf, "%s/antcc-%x@%u@", tmpdir, id, id2++);
+ while (*file++) {
+ char c = file[-1];
+ if (in_range(c, 'a', 'z') || in_range(c, 'A', 'Z') || in_range(c, '0', '9')
+ || c == '_' || c == '-')
+ {
+ ioputc(&fbuf, c);
+ } else if (c == '.') break;
+ else ioputc(&fbuf, '_');
+ }
+ bfmt(&fbuf, "%s%s", &"."[!ext], ext ? ext : "");
+ ioputc(&fbuf, 0);
+ assert(!fbuf.err);
+ return alloccopy(&globarena, fbuf.buf, fbuf.len, 1);
+}
+
+static int cc1(const char *out, const char *in);
+
+static const char *tempout;
+static pid_t rootp;
+static void
+mktemps(void) {
+ rootp = getpid();
+ for (int i = 0; i < task.inf.n; ++i) {
+ if (task.inf.p[i].ft == IFTc)
+ task.inf.p[i].temp = tempfile(task.inf.p[i].path, "o");
+ }
+ if (!task.out)
+ task.out = tempout = tempfile(task.inf.n > 1 ? "run" : withext(task.inf.p[0].path, NULL), NULL);
+}
+
+static void
+cleantemps(void)
+{
+ if (getpid() != rootp) return;
+ for (int i = 0; i < task.inf.n; ++i) {
+ if (task.inf.p[i].temp) {
+ unlink(task.inf.p[i].temp);
+ task.inf.p[i].temp = NULL;
+ }
+ }
+ if (tempout)
+ unlink(tempout), tempout = NULL;
+}
+static void
+sigcleantemps(int _)
+{
+ cleantemps();
+}
+
+static void
+compileobjs(void)
+{
+ int wstat;
+ pid_t p;
+
+ if (!ccopt.dbg.any && !task.syntaxonly) mktemps();
+ for (int i = 0; i < task.inf.n; ++i) {
+ enum inft ft = task.inf.p[i].ft;
+ if (ft == IFTc) {
+ if ((p = fork()) < 0) {
+ error(NULL, "fork(): %s\n", strerror(errno));
+ exit(1);
+ } else if (p == 0) {
+ exit(cc1(task.inf.p[i].temp, task.inf.p[i].path));
+ }
+ waitpid(p, &wstat, 0);
+ if (!WIFEXITED(wstat)) exit(127);
+ if (WEXITSTATUS(wstat) != 0) {
+ cleantemps();
+ exit(WEXITSTATUS(wstat));
+ }
+ } else if (ft == IFTobj || ft == IFTar || ft == IFTdll) {
+ // passthru
+ } else assert(!"not obj");
+ }
+ if (!ccopt.dbg.any && !task.syntaxonly) {
+ atexit(cleantemps);
+ signal(SIGINT, sigcleantemps);
+ signal(SIGABRT, sigcleantemps);
+ signal(SIGILL, sigcleantemps);
+ }
+}
+
+#include <fcntl.h>
+
+static bool
+hasprog(const char *prog)
+{
+ pid_t p;
+ if ((p = fork()) < 0) {
+ return 0;
+ } else if (p == 0) {
+ int nulfd = open("/dev/null", O_WRONLY);
+ if (nulfd < 0) return 0;
+ for (int fd = 0; fd <= 2; ++fd) {
+ dup2(fd, nulfd);
+ close(fd);
+ }
+ const char *cmd[] = {prog, NULL};
+ if (execvp(*cmd, (char **)cmd)) {
+ close(nulfd);
+ error(NULL, "execvp: %s", strerror(errno));
+ exit(125);
+ }
+ }
+ int wstat;
+ waitpid(p, &wstat, 0);
+ if (!WIFEXITED(wstat)) return 0;
+ return WEXITSTATUS(wstat) < 125;
+}
+
+static bool
+iscrosscc(void)
+{
+ return target.os != HOST_OS || target.arch != HOST_ARCH || target.abi != HOST_ABI;
+}
+
+struct cmdargs { vec_of(const char *); };
+
+static void
+findlinkcmd(struct cmdargs *cmd)
+{
+ if (task.targ && iscrosscc()) {
+ /* try to find a cross compiling toolchain, e.g. aarch64-linux-gnu-gcc */
+ static const char *ccs[] = {"cc", "gcc", "clang"};
+ char cross[1024];
+ for (int i = 0; i < countof(ccs); ++i) {
+ struct wbuf wbuf = MEMBUF(cross, sizeof cross);
+ int n = bfmt(&wbuf, "%s-%s", task.targ, ccs[i]);
+ assert(n < sizeof cross-1);
+ cross[n] = 0;
+ if (hasprog(cross)) {
+ vpush(cmd, alloccopy(&globarena, cross, n, 1));
+ return;
+ }
+ }
+ /* zig cc fallback, which works great as cross compiler toolchain */
+ if (hasprog("zig")) {
+ vpush(cmd, "zig");
+ vpush(cmd, "cc");
+ vpush(cmd, "-target");
+ vpush(cmd, task.targ);
+ } else {
+ fatal(NULL, "cannot link to cross-compilation target: no appropiate toolchain installed");
+ }
+ } else {
+ vpush(cmd, HOST_CC);
+ }
+}
+
+static int
+dolink(void)
+{
+ const char *cmdbuf[100];
+ pid_t p;
+ int wstat;
+ struct cmdargs cmd = VINIT(cmdbuf, countof(cmdbuf));
+
+ findlinkcmd(&cmd);
+ if (!strcmp(cmd.p[0], "zig")) {
+ note(NULL, "using 'zig cc' as a cross-compiler");
+ }
+ if (task.outft == OFTdll) {
+ vpush(&cmd, "-shared");
+ } else if (task.outft == OFTexe) {
+ vpush(&cmd, ccopt.pie ? "-pie" : "-no-pie");
+ }
+ vpush(&cmd, "-o");
+ vpush(&cmd, task.out);
+ assert(task.inf.n > 0);
+ for (int i = 0; i < task.inf.n; ++i) {
+ const char *o;
+ switch (task.inf.p[i].ft) {
+ case IFTc: o = task.inf.p[i].temp; break;
+ case IFTobj: case IFTar: case IFTdll:
+ o = task.inf.p[i].path; break;
+ default: assert(!"link obj?");
+ }
+ vpush(&cmd, o);
+ }
+ vpushn(&cmd, task.linkargs.p, task.linkargs.n);
+ if (task.verbose) {
+ efmt("> ");
+ for (int i = 0; i < cmd.n; ++i)
+ efmt("%s ", cmd.p[i]);
+ efmt("\n");
+ }
+ vpush(&cmd, NULL);
+ if ((p = fork()) < 0) {
+ error(NULL, "fork: %s\n", strerror(errno));
+ exit(1);
+ } else if (p == 0) {
+ if (execvp(cmd.p[0], (char **)cmd.p)) {
+ error(NULL, "execvp: %s\n", strerror(errno));
+ exit(1);
+ }
+ }
+ vfree(&cmd);
+ waitpid(p, &wstat, 0);
+ if (!WIFEXITED(wstat)) return 127;
+ if (WEXITSTATUS(wstat) != 0) {
+ error(NULL, "link command failed");
+ return 1;
+ }
+ return 0;
+}
+
+static int
+dorun(void)
+{
+ if (target.arch != HOST_ARCH || target.os != HOST_OS) {
+ warn(NULL, "'-run' with cross-compiled binary");
+ }
+ if (task.verbose) {
+ efmt("> exec %s", task.out);
+ for (char **s = task.runargs; *s; ++s)
+ efmt(" %s", *s);
+ efmt("\n");
+ }
+#if _POSIX_C_SOURCE >= 200809L
+ /* use fexecve */
+ int fexecve(int fd, char *const argv[], char *const envp[]);
+ int fd = open(task.out, O_RDONLY);
+ if (fd < 0) {
+ error(NULL, "open: %s\n", strerror(errno));
+ return 1;
+ }
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+ error(NULL, "fcntl: %s\n", strerror(errno));
+ return 1;
+ }
+ cleantemps();
+ extern char **environ;
+ fexecve(fd, task.runargs - 1, environ);
+ error(NULL, "fexecv: %s\n", strerror(errno));
+ return 1;
+#else
+ pid_t p;
+ if ((p = fork()) < 0) {
+ error(NULL, "fork(): %s\n", strerror(errno));
+ exit(1);
+ } else if (p == 0) {
+ if (!execv(task.out, task.runargs - 1)) {
+ error(NULL, "execv(): %s\n", strerror(errno));
+ exit(1);
+ }
+ }
+ int wstat;
+ waitpid(p, &wstat, 0);
+ if (!WIFEXITED(wstat)) return 127;
+ return WEXITSTATUS(wstat);
+#endif
+}
+
+static int
+driver(void)
+{
+ void cpp(struct wbuf *, const char *);
+ if (task.verbose)
+ efmt("# Target: %s\n", task.targ ? task.targ : HOST_TRIPLE);
+ if (task.syntaxonly)
+ task.out = "/dev/null"; // HACK
+ if (task.outft == OFTobj) {
+ assert(task.inf.n == 1);
+ if (task.inf.p[0].ft != IFTc)
+ fatal(NULL, "not a C source file: %s", task.inf.p[0].path);
+ return cc1(task.out, task.inf.p[0].path);
+ } else if (task.outft == OFTc) {
+ struct wbuf _buf = {0}, *buf = &bstdout;
+ if (task.out) {
+ buf = &_buf;
+ buf->buf = alloc(&globarena, buf->cap = 1<<12, 1);
+ buf->fd = open(task.out, O_CREAT | O_TRUNC | O_WRONLY, 0777);
+ if (buf->fd < 0) {
+ error(NULL, "open(%'s): %s", task.out, strerror(errno));
+ return 1;
+ }
+ }
+ bool ok = 1;
+ if (!task.out && task.inf.n == 1)
+ cpp(buf, task.inf.p[0].path);
+ else for (int i = 0; i < task.inf.n; ++i) {
+ pid_t p;
+ int wstat;
+
+ if ((p = fork()) < 0) {
+ error(NULL, "fork(): %s\n", strerror(errno));
+ ok = 0;
+ } else if (p == 0) {
+ cpp(buf, task.inf.p[i].path);
+ exit(0);
+ }
+ waitpid(p, &wstat, 0);
+ if (!WIFEXITED(wstat)) ok = 0;
+ ok = ok && WEXITSTATUS(wstat) == 0;
+ }
+ ioflush(buf);
+ if (task.out)
+ close(buf->fd);
+ return ok ? 0 : 1;
+ } else if (task.outft == OFTexe || task.outft == OFTdll) {
+ compileobjs();
+ if (ccopt.dbg.any || task.syntaxonly) return 0;
+ if (!task.run) return dolink();
+ int st = dolink();
+ if (st == 0) st = dorun();
+ return st;
+ }
+ assert(0);
+}
+
+static int
+cc1(const char *out, const char *in)
+{
+ void ccomp(const char *);
+ extern int nerror;
+
+ if (task.verbose) efmt("cc1(/*out*/ %'s, /*in*/ %'s)\n", out, in);
+ if (!ccopt.dbg.any && !task.syntaxonly) objini(in, out);
+ ccomp(in);
+ if (!ccopt.dbg.any && !task.syntaxonly && !nerror) objfini();
+ return !!nerror;
+}
+
+static void
+detectcolor(void)
+{
+ const char *s;
+ if (!isatty(STDERR_FILENO)
+ || ((s = getenv("NO_COLOR")) && *s)
+ || ((s = getenv("TERM")) && !strcmp(s, "dumb")))
+ ccopt.nocolor = 1;
+}
+
+static void
+sysinclpaths(void)
+{
+ static const char *paths[] = {
+ HOST_INCLUDE_DIRS
+ };
+ for (int i = 0; i < countof(paths); ++i)
+ addinclpath(CINCLsys, paths[i]);
+}
+
+static void
+prihelp(void)
+{
+ pfmt("antcc version "ANTCC_VERSION_STR"\n"
+ "Usage: antcc [options] infile(s)...\n"
+ " antcc [options] -run infile [arguments...]\n"
+ " antcc [options] infile(s)... -run [arguments...]\n"
+ "Options:\n"
+ " -help \tPrint this help message\n"
+ " -std=<..> \tSet C standard (c89, c99, c11, c23)\n"
+ " -pedantic \tWarnings for strict standards compliance\n"
+ " -d{pamyosilr} \tDebug print IR after {parse, abi, mem, inlining, opts, stack, isel, live, rega}\n"
+ " -o <file> \tPlace the output into <file>\n"
+ " -v \tVerbose output\n"
+ " -c \tEmit object file but do not link\n"
+ " -run \tRun compiled sources\n"
+ " -Idir \tAdd include path\n"
+ " -Dsym[=val] \tDefine macro\n"
+ " -Usym \tUndefine macro\n"
+ " -E \tPreprocess only\n"
+ " -llib \tLink with library\n"
+ " -fpie \tEmit code for position independent executable\n"
+ " -fpic \tEmit position independent code\n"
+ " -O<..> \tSet optimization level (0|g|1|2|s|z) (default: -Og)\n"
+ " -x<c|o> \tSpecify type of next input file (C, object)\n"
+ " -W[...] \tTurn on warnings (stub)\n"
+ " -Werror \tTurn warnings into errors\n"
+ " -w \tSuppress warnings\n"
+ " --version \tPrint version\n"
+ );
+}
+
+int
+main(int argc, char **argv)
+{
+ globarena->cap = sizeof(_arenamem.mem) - sizeof(struct arena);
+
+ ioinit();
+ /* setup defaults */
+ detectcolor();
+ sysinclpaths();
+ ccopt.cstd = STDC11;
+ ccopt.pie = 1;
+ ccopt.dbgout = &bstdout;
+
+ /* parse cli ags */
+ if (argc == 1) {
+ prihelp();
+ return 1;
+ }
+ optparse(argv);
+
+ /* global init */
+ targ_init(task.targ);
+ if (!target.arch)
+ fatal(NULL, "unsupported target: %s", task.targ ? task.targ : HOST_TRIPLE);
+
+ return driver();
+}
+
+/* vim:set ts=3 sw=3 expandtab: */