diff options
| -rw-r--r-- | README.md | 5 | ||||
| -rwxr-xr-x | configure | 111 | ||||
| -rw-r--r-- | src/a_main.c | 70 | ||||
| -rw-r--r-- | src/a_targ.c | 14 | ||||
| -rw-r--r-- | src/antcc.h | 2 |
5 files changed, 155 insertions, 47 deletions
@@ -15,10 +15,7 @@ and backends like [QBE](https://c9x.me/compile/) and [LLVM](https://llvm.org/). ## Requirements `antcc` is written in standard C11 and can be built with any conforming -compiler toolchain. The `Makefile` requires GNU Make. At runtime, an existing -C compiler is currently required for calling the linker with the appropiate -libc runtime paths (eventually, the driver should only depend on the linker by -determining those linker paths and flags at `configure` time). +compiler toolchain. The `Makefile` requires GNU Make. ## Building @@ -14,15 +14,17 @@ Options: --help Print this help mesage --host=target-triple $host --cc=cc C compiler [cc] + --ld=ld Linker [ld] --prefix=PREFIX Installation path [/usr/local] - --sysroot=/path System root [/usr] + --sysroot=/path System root [] --includedir="/a/b",... System include dirs EOF } -sysroot=/usr +sysroot= prefix=/usr/local host= +linker= for arg ; do case "$arg" in @@ -31,6 +33,7 @@ for arg ; do --includedir=*) host_include_dirs=${arg#*=} ;; CC=*) CC=${arg#*=} ;; --cc=*) CC=${arg#*=} ;; + --ld=*) linker=${arg#*=} ;; CFLAGS=*) CFLAGS=${arg#*=} ;; --cflags=*) CFLAGS=${arg#*=} ;; --prefix=*) prefix=$(sh -c "echo ${arg#*=}") ;; @@ -40,7 +43,16 @@ for arg ; do done : ${CC:=cc} -: ${host:=$($CC -dumpmachine)} +if ! test -n "$host"; then + host=$($CC -dumpmachine) +else + # try target-triple-ld (cross compiling) + if ! test -n "$linker" && command -v "$host"-ld >/dev/null; then + linker="$host"-ld + sysroot=$(($host-cc -print-sysroot || $host-gcc -print-sysroot) 2>/dev/null) + fi +fi +: ${linker:=ld} test -n "$host" || die "cannot determine host" host_arch= @@ -54,26 +66,74 @@ x86_64-*) host_arch=x86_64 ;; amd64-*) host_arch=x86_64 ;; aarch64-*) host_arch=aarch64 ;; arm64-*) host_arch=aarch64 ;; -*) host_arch=unk ;; +*) die "unsupported target '$host'" esac +linkflags= + +findgcclibdir () { + : ${GCCLIBDIR:=$(dirname $(("$host"-gcc -print-file-name=crtbegin.o || $CC -print-file-name=crtbegin.o) 2>/dev/null))} + if ! test -n $GCCLIBDIR; then + die "cannot determine gcclibdir" + fi +} + case "$host" in -*-linux-*) - host_os=linux ;; +*-linux-*gnu*) + host_os=linux + host_abi=gnu + case $host_arch in + x86_64) DYNAMIC_LINKER=$sysroot/lib64/ld-linux-x86-64.so.2 ;; + aarch64) DYNAMIC_LINKER=$sysroot/lib/ld-linux-aarch64.so.1 + esac + ldstartfiles='"-l:crt1.o", "-l:crti.o", "-l:crtbegin.o"' + ldendfiles='"-lc", "-l:crtend.o", "-l:crtn.o"' + ldstartfiles_pie='"-l:Scrt1.o", "-l:crti.o", "-l:crtbeginS.o"' + ldendfiles_pie='"-lc", "-l:crtendS.o", "-l:crtn.o"' + findgcclibdir + linkflags='"-L", "'$GCCLIBDIR'",' + host_predefs=' + "__SIZE_TYPE__=unsigned long int", /* work around https://sourceware.org/bugzilla/show_bug.cgi?id=33969 */ + ' + ;; +*-linux-*musl*) + host_os=linux + host_abi=musl + case $host_arch in + x86_64) DYNAMIC_LINKER=$sysroot/lib/ld-musl-x86_64.so.1 ;; + aarch64) DYNAMIC_LINKER=$sysroot/lib/ld-linux-aarch64.so.1 ;; + esac + if test -d $sysroot/usr/lib/musl/lib; then + # musl cross compiler in glibc system (probably) + findgcclibdir + linkflags='"-nostdlib", "-L", "'$sysroot'/usr/lib/musl/lib", "-L", "'$GCCLIBDIR'",' + ldstartfiles='"'$sysroot'/usr/lib/musl/lib/crt1.o","'$sysroot'/usr/lib/musl/lib/crti.o", "-l:crtbeginS.o"' + ldendfiles='"-lc", "-l:crtendS.o", "'$sysroot'/usr/lib/musl/lib/crtn.o"' + ldstartfiles_pie='"'$sysroot'/usr/lib/musl/lib/Scrt1.o", "'$sysroot'/usr/lib/musl/lib/crti.o", "-l:crtbeginS.o"' + ldendfiles_pie="$ldendfiles" + else + ldstartfiles='"-l:crt1.o", "-l:crti.o"' + ldendfiles='"-lc", "-l:crtn.o"' + ldstartfiles_pie='"-l:Scrt1.o", "-l:crti.o"' + ldendfiles_pie="$ldendfiles" + fi + ;; *-openbsd*) host_os=openbsd + DYNAMIC_LINKER=$sysroot/usr/libexec/ld.so + ldstartfiles='"-l:crt0.o", "-l:crtbegin.o"' + ldendfiles='"-lc", "-l:crtend.o"' + ldstartfiles_pie='"-l:crt0.o", "-l:crtbeginS.o"' + ldendfiles_pie='"-lc", "-l:crtendS.o"' + linkflags='"-L'$sysroot'/usr/lib"' host_predefs=' "_ANSI_LIBRARY", /* works around __only_inline functions in libc headers */ ' ;; -*) host_os=unknown ;; -esac - -case "$host" in -*-gnu) host_abi=gnu ;; -*-musl) host_abi=musl ;; -*) host_abi=none ;; +*) + die "unknown/unsupported target '$host'" esac +echo dynamic linker: $DYNAMIC_LINKER tryincldir() { if stat "$1"/ >/dev/null 2>/dev/null; then @@ -83,11 +143,17 @@ tryincldir() { if ! test -n "$host_include_dirs"; then # try to query host toolchain first - if hostccdirs=$($CC -E -v -xc /dev/null 2>&1 | sed -n '/#include <...> search starts here:/,/End of search list./{ + for sfx in cc gcc; do + if command -v "$host"-$sfx > /dev/null; then + cc="$host"-$sfx + fi + done + : ${cc:=$CC} + if hostccdirs=$($cc -E -v -xc /dev/null 2>&1 | sed -n '/#include <...> search starts here:/,/End of search list./{ s/^[[:space:]]*// /^\/.*/p }') && test -n "$hostccdirs"; then - echo "Using $CC's system include paths:" + echo "Using $cc's system include paths:" for d in $hostccdirs; do dir=$(realpath "$d") case "$dir" in @@ -99,15 +165,16 @@ if ! test -n "$host_include_dirs"; then done else echo "Falling back to generic system include paths" - tryincldir "$sysroot/local/include/$host" - tryincldir "$sysroot/local/include" - tryincldir "$sysroot/include/$host" - tryincldir "$sysroot/include" + tryincldir "$sysroot/usr/local/include/$host" + tryincldir "$sysroot/usr/local/include" + tryincldir "$sysroot/usr/include/$host" + tryincldir "$sysroot/usr/include" fi fi set -e +echo using linker: "$linker" echo using arch: "$host_arch" echo using os: "$host_os" echo using abi: "$host_abi" @@ -119,9 +186,15 @@ echo "/** GENERATED WITH $0 $@ **/ #define HOST_OS OS$host_os #define HOST_ABI ABI$host_abi #define HOST_INCLUDE_DIRS $host_include_dirs +#define HOST_LD \"$linker\" #define HOST_CC \"$CC\" static const char *const host_predefs[] = {$host_predefs 0 }; +static const char *const host_linkcmd[] = {\"--dynamic-linker=$DYNAMIC_LINKER\", $linkflags}; +static const char *const host_ldstartfiles[] = {$ldstartfiles}; +static const char *const host_ldendfiles[] = {$ldendfiles}; +static const char *const host_ldstartfiles_pie[] = {$ldstartfiles_pie}; +static const char *const host_ldendfiles_pie[] = {$ldendfiles_pie}; " > src/hostconfig.h echo "# GENERATED WITH $0 $@ diff --git a/src/a_main.c b/src/a_main.c index 33f0919..b947d41 100644 --- a/src/a_main.c +++ b/src/a_main.c @@ -113,6 +113,7 @@ typedef struct Task { vec_of(InFile) inf; char **runargs; vec_of(const char *) linkargs; + bool link_with_cc; bool verbose, run, syntaxonly; } Task; static InFile infilebuf[16]; @@ -134,6 +135,7 @@ optparse(char **args) ft ? ft : ftdetect(arg-1), arg[-1] != '-' ? arg-1 : "/dev/stdin" })); + vpush(&task.linkargs, NULL); ft = IFTauto; if (task.run) { task.runargs = args+1; @@ -203,8 +205,24 @@ optparse(char **args) 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")) { + } else if (*arg == 'l' || *arg == 'L' || *arg == 'B' || !strcmp(arg, "shared") || !strcmp(arg, "pthread") || !strcmp(arg, "static")) { + /* XXX having some issues with linker commands for -shared */ + if (!strcmp(arg, "shared")) + task.link_with_cc = 1; vpush(&task.linkargs, arg-1); + } else if (!memcmp(arg, "Wl,", 3)) { + if (task.link_with_cc) { + vpush(&task.linkargs, arg-1); + } else { + for (char *larg = (char*)arg+3, *next; larg && *larg; larg = next) { + next = strchr(larg, ','); + if (next) { + *next = '\0'; + ++next; + } + vpush(&task.linkargs, larg); + } + } } else if (!strcmp(arg, "v") || !strcmp(arg, "-verbose")) { task.verbose = 1; } else if (!strcmp(arg, "c")) { @@ -429,6 +447,7 @@ static void findlinkcmd(CmdArgs *cmd) { if (task.targ && iscrosscc()) { + task.link_with_cc = 1; /* try to find a cross compiling toolchain, e.g. aarch64-linux-gnu-gcc */ static const char *ccs[] = {"cc", "gcc", "clang"}; char cross[1024]; @@ -451,8 +470,16 @@ findlinkcmd(CmdArgs *cmd) } else { fatal(NULL, "cannot link to cross-compilation target: no appropiate toolchain installed"); } - } else { + } else if (task.link_with_cc) { vpush(cmd, HOST_CC); + } else { + vpush(cmd, HOST_LD); + vpushn(cmd, host_linkcmd, countof(host_linkcmd)); + if (ccopt.pie) { + vpushn(cmd, host_ldstartfiles_pie, countof(host_ldstartfiles_pie)); + } else { + vpushn(cmd, host_ldstartfiles, countof(host_ldstartfiles)); + } } } @@ -476,19 +503,27 @@ dolink(void) 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?"); + + for (int l = 0, i = 0; l < task.linkargs.n; ++l) { + const char *a = task.linkargs.p[l]; + if (!a) { + switch (task.inf.p[i].ft) { + case IFTc: a = task.inf.p[i].temp; break; + case IFTobj: case IFTar: case IFTdll: + a = task.inf.p[i].path; break; + default: assert(!"link obj?"); + } + ++i; } - vpush(&cmd, o); + vpush(&cmd, a); + } + if (!task.link_with_cc) { + if (ccopt.pie) + vpushn(&cmd, host_ldendfiles_pie, countof(host_ldendfiles_pie)); + else + vpushn(&cmd, host_ldendfiles, countof(host_ldendfiles)); } - 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"); @@ -520,7 +555,7 @@ dorun(void) warn(NULL, "'-run' with cross-compiled binary"); } if (task.verbose) { - efmt("> exec %s", task.out); + efmt("exec %s", task.out); for (char **s = task.runargs; *s; ++s) efmt(" %s", *s); efmt("\n"); @@ -682,6 +717,8 @@ prihelp(void) ); } +static const TargTriple host_targ = { HOST_ARCH, HOST_OS, HOST_ABI }; + int main(int argc, char **argv) { @@ -694,6 +731,9 @@ main(int argc, char **argv) ccopt.cstd = STDC11; ccopt.pie = 1; ccopt.dbgout = &bstdout; + if (getenv("ANTCC_VERBOSE")) { + task.verbose = 1; + } /* parse cli ags */ if (argc == 1) { @@ -703,9 +743,9 @@ main(int argc, char **argv) optparse(argv); /* global init */ - targ_init(task.targ); - if (!target.arch) + if (!targ_init(task.targ, &host_targ) || !target.arch) { fatal(NULL, "unsupported target: %s", task.targ ? task.targ : HOST_TRIPLE); + } for (const char *const *p = host_predefs; *p; ++p) cpppredef(0, *p); diff --git a/src/a_targ.c b/src/a_targ.c index fab23e9..1513bc6 100644 --- a/src/a_targ.c +++ b/src/a_targ.c @@ -67,18 +67,14 @@ parsetriple(TargTriple *trg, const char *str) return 1; } -#include "hostconfig.h" /* run ./configure */ - -void -targ_init(const char *starg) +bool +targ_init(const char *starg, const TargTriple *dfault) { const struct Targ *t = NULL; uchar *sizes = targ_primsizes, *align = targ_primalign; if (!starg) { - target.arch = HOST_ARCH; - target.os = HOST_OS; - target.abi = HOST_ABI; + target = *dfault; } else if (!parsetriple(&target, starg)) { fatal(NULL, "unrecognized target: %s", starg); } @@ -91,7 +87,7 @@ targ_init(const char *starg) break; } } - if (!t) fatal(NULL, "unsupported target: %s", starg ? starg : HOST_TRIPLE); + if (!t) return 0; sizes[TYBOOL] = sizes[TYCHAR] = sizes[TYSCHAR] = sizes[TYUCHAR] = 1; sizes[TYSHORT] = sizes[TYUSHORT] = 2; @@ -123,4 +119,6 @@ targ_init(const char *starg) targ_64bit = t->ptrsize == 8; mctarg = t->mctarg; targ_arch = ISx86_64; + + return 1; } diff --git a/src/antcc.h b/src/antcc.h index a666a95..59ae690 100644 --- a/src/antcc.h +++ b/src/antcc.h @@ -156,7 +156,7 @@ typedef struct TargTriple { extern TargTriple target; enum objkind { OBJELF }; extern const struct MCTarg *mctarg; -void targ_init(const char *); +bool targ_init(const char *, const TargTriple *dfault); /*********/ /** MEM **/ |