aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-12-17 20:32:10 +0100
committerlemon <lsof@mailbox.org>2025-12-17 20:32:23 +0100
commit4545928179837c75ab1357b77e5723a4fdb60b98 (patch)
tree5d864232cda0ff32f1d53d7a5a01daeb53b90873
parent8b486bc9a1333d368538f91e046bf30f68798ce3 (diff)
nicer defaults and facilities for cross-compilation
-rw-r--r--c/lex.c18
-rw-r--r--common.h8
-rw-r--r--hostconfig.h27
-rw-r--r--io.c2
-rw-r--r--main.c108
-rw-r--r--obj/elf.c7
-rw-r--r--targ.c57
7 files changed, 195 insertions, 32 deletions
diff --git a/c/lex.c b/c/lex.c
index 246d686..25cd50c 100644
--- a/c/lex.c
+++ b/c/lex.c
@@ -1963,7 +1963,6 @@ addpredefmacros(struct arena **tmparena)
{ "__has_builtin", { .predef = 1, .nparam = 1, .fnlike = 1, .special = 1, .handlerfn = mac__has_builtin }},
{ "__STDC__", { .predef = 1, .rlist = { &tok_1, 1 } }},
{ "__STDC_VERSION__", { .predef = 1, .rlist = { &tok_ver, 1 } }},
- { "__STDC_HOSTED__", { .predef = 1, .rlist = { &tok_1, 1 } }},
{ "__antcc__", { .predef = 1, .rlist = { &tok_1, 1 } }},
};
switch (ccopt.cstd) {
@@ -1978,13 +1977,28 @@ addpredefmacros(struct arena **tmparena)
putmac(intern(macs[i].name), &macs[i].m);
}
- switch (targ_mcisa) {
+ switch (target.arch) {
+ default: assert(0);
case ISx86_64:
putdef1("__x86_64__");
putdef1("__x86_64");
break;
}
+ if (target.os != OSunknown) putdef1("__STDC_HOSTED__");
+ switch (target.os) {
+ default: assert(0);
+ case OSunknown: break;
+ case OSlinux:
+ putdef1("__linux__");
+ putdef1("__linux");
+ putdef1("linux");
+ putdef1("unix");
+ putdef1("__unix");
+ putdef1("__unix__");
+ break;
+ }
+
if (ppcmdline.n) {
struct memfile *f;
struct lexer lx[1] = {0};
diff --git a/common.h b/common.h
index c3ccc63..862a271 100644
--- a/common.h
+++ b/common.h
@@ -160,9 +160,13 @@ extern struct inclpaths {
/* Target */
/**********/
-enum mcisa { ISx86_64 };
+struct targtriple {
+ enum mcarch { ISxxx, ISx86_64 } arch;
+ enum mcos { OSunknown, OSlinux } os;
+ enum mcabi { ABInone, ABIgnu, ABImusl } abi;
+};
extern const struct mctarg *mctarg;
-extern enum mcisa targ_mcisa;
+extern struct targtriple target;
void targ_init(const char *);
/*********/
diff --git a/hostconfig.h b/hostconfig.h
new file mode 100644
index 0000000..b333ad2
--- /dev/null
+++ b/hostconfig.h
@@ -0,0 +1,27 @@
+#ifndef HOST_CONFIG_H
+#define HOST_CONFIG_H
+
+#if defined __x86_64 || defined __x86_64__
+#define HOST_ARCH ISx86_64
+#else
+#define HOST_ARCH ISxxx
+#endif
+
+#if defined __linux__
+#define HOST_OS OSlinux
+#else
+#define HOST_OS OSunknown
+#endif
+
+#if defined __linux__
+#define HOST_ABI ABIgnu
+#else
+#define HOST_ABI ABInone
+#endif
+
+#ifndef HOST_INCLUDE_DIRS
+#define HOST_INCLUDE_DIRS "/usr/include", "/usr/local/include"
+#endif
+
+#endif
+
diff --git a/io.c b/io.c
index e3af76b..59481bd 100644
--- a/io.c
+++ b/io.c
@@ -1094,7 +1094,7 @@ fatal(const struct span *span, const char *fmt, ...)
va_start(ap, fmt);
vdiag(span, DGERROR, fmt, ap);
va_end(ap);
- efmt("Aborting due to previous error.\n");
+ if (span) efmt("Aborting due to previous error.\n");
exit(1);
}
diff --git a/main.c b/main.c
index 5fa90fd..f84c106 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,5 @@
#include "common.h"
+#include "hostconfig.h"
#include "obj/obj.h"
#include <errno.h>
#include <stdlib.h>
@@ -165,6 +166,10 @@ optparse(char **args)
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') {
vpush(&task.linkargs, arg-1);
} else if (!strcmp(arg, "v") || !strcmp(arg, "-verbose")) {
@@ -249,7 +254,7 @@ tempfile(const char *path, const char *ext)
while (*path)
if (*path++ == '/')
file = path;
- bfmt(&fbuf, "%s/cc%x@%u@", tmpdir, id, id2++);
+ 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')
@@ -322,18 +327,78 @@ compileobjs(void)
}
}
+#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[] = {"/bin/env", prog, NULL};
+ if (execv(*cmd, (char **)cmd)) {
+ close(nulfd);
+ error(NULL, "execv: %s", strerror(errno));
+ exit(125);
+ }
+ }
+ int wstat;
+ waitpid(p, &wstat, 0);
+ if (!WIFEXITED(wstat)) return 0;
+ return WEXITSTATUS(wstat) < 125;
+}
+
+struct cmdargs { vec_of(const char *); };
+
+static void
+findlinkcmd(struct cmdargs *cmd)
+{
+ if (task.targ && (target.os != HOST_OS || target.arch != HOST_ARCH || target.abi != HOST_ABI)) {
+ 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;
+ }
+ }
+ 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, "cc");
+ }
+}
+
static int
dolink(void)
{
- static const char *cmdbuf[10];
+ const char *cmdbuf[100];
pid_t p;
int wstat;
- vec_of(const char *) cmd = VINIT(cmdbuf, countof(cmdbuf));
-
- /* TODO don't depend on external c compiler, find lib and runtime paths and
- * invoke linker directly.. */
+ struct cmdargs cmd = VINIT(cmdbuf, countof(cmdbuf));
- vpush(&cmd, "/bin/gcc");
+ vpush(&cmd, "/bin/env");
+ findlinkcmd(&cmd);
+ if (!strcmp(cmd.p[1], "zig")) {
+ note(NULL, "using 'zig cc' as a cross-compiler");
+ }
if (task.outft == OFTdll) {
vpush(&cmd, "-shared");
} else if (task.outft == OFTexe) {
@@ -361,25 +426,30 @@ dolink(void)
}
vpush(&cmd, NULL);
if ((p = fork()) < 0) {
- error(NULL, "fork(): %s\n", strerror(errno));
+ error(NULL, "fork: %s\n", strerror(errno));
exit(1);
} else if (p == 0) {
- if (!execv(cmd.p[0], (char **)cmd.p)) {
- error(NULL, "execv(): %s\n", strerror(errno));
+ if (execv(cmd.p[0], (char **)cmd.p)) {
+ error(NULL, "execv: %s\n", strerror(errno));
exit(1);
}
}
vfree(&cmd);
waitpid(p, &wstat, 0);
if (!WIFEXITED(wstat)) return 127;
- return WEXITSTATUS(wstat);
+ if (WEXITSTATUS(wstat) != 0) {
+ error(NULL, "link command failed");
+ return 1;
+ }
+ return 0;
}
-#include <fcntl.h> /* open */
-
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)
@@ -388,18 +458,18 @@ dorun(void)
}
int fd = open(task.out, O_RDONLY);
if (fd < 0) {
- error(NULL, "open(): %s\n", strerror(errno));
+ error(NULL, "open: %s\n", strerror(errno));
return 1;
}
if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
- error(NULL, "fcntl(): %s\n", strerror(errno));
+ error(NULL, "fcntl: %s\n", strerror(errno));
return 1;
}
cleantemps();
extern char **environ;
int fexecve(int fd, char *const argv[], char *const envp[]);
fexecve(fd, task.runargs - 1, environ);
- error(NULL, "fexecv(): %s\n", strerror(errno));
+ error(NULL, "fexecv: %s\n", strerror(errno));
return 1;
}
@@ -485,8 +555,7 @@ static void
sysinclpaths(void)
{
static const char *paths[] = {
- "/usr/local/include",
- "/usr/include"
+ HOST_INCLUDE_DIRS
};
for (int i = 0; i < countof(paths); ++i)
addinclpath(paths[i]);
@@ -541,8 +610,9 @@ main(int argc, char **argv)
optparse(argv);
/* global init */
- task.targ = task.targ ? task.targ : "x86_64-sysv";
targ_init(task.targ);
+ if (!target.arch)
+ fatal(NULL, "unsupported target: %s", task.targ ? task.targ : "(host)");
return driver();
}
diff --git a/obj/elf.c b/obj/elf.c
index ea326b6..512e710 100644
--- a/obj/elf.c
+++ b/obj/elf.c
@@ -46,7 +46,8 @@ elfinit(void)
hdr.i_osabi = ELFOSABI_SYSV;
hdr.i_abiversion = 0;
hdr.h32.type = ET_REL;
- switch (targ_mcisa) {
+ switch (target.arch) {
+ default: assert(!"arch?");
case ISx86_64: hdr.h32.machine = EM_X86_64; break;
}
hdr.h32.version = ELFVERSION;
@@ -154,7 +155,7 @@ elfreloc(internstr sym, enum relockind kind, enum section section, uint off, vlo
case Sdata: ++ndatarel; break;
}
assert(kind < NRELOCKIND);
- vpush(&relocs, ((struct reloc) { section, relktab[targ_mcisa][kind], off, addend, .symname = sym }));
+ vpush(&relocs, ((struct reloc) { section, relktab[target.arch][kind], off, addend, .symname = sym }));
}
static void
@@ -372,7 +373,7 @@ elffini(struct wbuf *out)
shnam_strtab = 36, shnam_symtab = 44, shnam_reltext = 52, shnam_relrodata = 63, shnam_reldata = 76
};
int align = targ_64bit ? 8 : 4;
- bool userela = userelatab[targ_mcisa];
+ bool userela = userelatab[target.arch];
char shstrs[] = "\0.text\0.rodata\0.data\0.bss\0.shstrtab\0.strtab\0.symtab\0"
".rela.text\0.rela.rodata\0.rela.data";
if (!userela) {
diff --git a/targ.c b/targ.c
index 9821e39..c715ed7 100644
--- a/targ.c
+++ b/targ.c
@@ -3,32 +3,78 @@
extern const struct mctarg t_x86_64_sysv;
static const struct targ {
- const char *name;
+ struct { enum mcarch arch; uint oss, abis; };
struct { uchar longsize, vlongsize, ptrsize, valistsize; };
struct { uchar longalign, vlongalign, doublealign, ptralign; };
bool charsigned;
uchar sizetype, ptrdifftype, wchartype;
const struct mctarg *mctarg;
- enum mcisa isa;
} targs[] = {
- { "x86_64-sysv", {8, 8, 8, 24}, {8, 8, 8, 8}, 1, TYULONG, TYLONG, TYINT, &t_x86_64_sysv, ISx86_64 },
- { "i686-sysv", {4, 8, 4, 8}, {4, 4, 4, 4}, 1, TYUINT, TYINT, TYINT }
+ { {ISx86_64, -1, 1<<ABIgnu | 1<<ABImusl}, {8,8,8,24}, {8,8,8,8}, 1, TYULONG, TYLONG, TYINT, &t_x86_64_sysv },
};
+struct targtriple target;
uchar targ_primsizes[TYPTR+1];
uchar targ_primalign[TYPTR+1];
uint targ_valistsize;
enum typetag targ_sizetype, targ_ptrdifftype, targ_wchartype;
bool targ_charsigned, targ_bigendian, targ_64bit;
-enum mcisa targ_mcisa;
+enum mcarch targ_arch;
const struct mctarg *mctarg;
+static bool
+matchstr(const char **s, const char *pat)
+{
+ const char *p;
+ for (p = *s; *pat; ++p, ++pat) {
+ if (*pat == '$') { if (*p) return 0; else break; }
+ else if (*p != *pat) return 0;
+ }
+ *s = p;
+ return 1;
+}
+
+static bool
+parsetriple(struct targtriple *trg, const char *str)
+{
+ if (matchstr(&str, "x86_64-")) {
+ trg->arch = ISx86_64;
+ } else return 0;
+
+ if (matchstr(&str, "unknown-") || matchstr(&str, "pc-")) {}
+
+ if (matchstr(&str, "linux-")) {
+ trg->os = OSlinux;
+ } else if (matchstr(&str, "linux$")) {
+ trg->os = OSlinux;
+ trg->abi = ABIgnu;
+ } else return 0;
+
+ if (matchstr(&str, "gnu")) {
+ trg->abi = ABIgnu;
+ } else if (matchstr(&str, "musl")) {
+ trg->abi = ABImusl;
+ } else return 0;
+
+ return 1;
+}
+
+#include "hostconfig.h"
+
void
targ_init(const char *starg)
{
const struct targ *t = &targs[0];
uchar *sizes = targ_primsizes, *align = targ_primalign;
+ if (!starg) {
+ target.arch = HOST_ARCH;
+ target.os = HOST_OS;
+ target.abi = HOST_ABI;
+ } else if (!parsetriple(&target, starg)) {
+ fatal(NULL, "unrecognized target: %s", starg);
+ }
+
sizes[TYBOOL] = sizes[TYCHAR] = sizes[TYSCHAR] = sizes[TYUCHAR] = 1;
sizes[TYSHORT] = sizes[TYUSHORT] = 2;
sizes[TYUINT] = sizes[TYINT] = 4;
@@ -52,4 +98,5 @@ targ_init(const char *starg)
targ_bigendian = 0;
targ_64bit = t->ptrsize == 8;
mctarg = t->mctarg;
+ targ_arch = ISx86_64;
}