aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-03-20 22:35:49 +0100
committerlemon <lsof@mailbox.org>2026-03-20 22:36:24 +0100
commita49b92988ceb810c8e6044d44f855616b4d6e5ab (patch)
tree0848511760a4ecc9fe3049343349ab9846ad090b
parent31032275a618f74865bdc877b569eae2227e79b4 (diff)
driver: only depend on ld for linking (todo)
-rw-r--r--README.md5
-rwxr-xr-xconfigure111
-rw-r--r--src/a_main.c70
-rw-r--r--src/a_targ.c14
-rw-r--r--src/antcc.h2
5 files changed, 155 insertions, 47 deletions
diff --git a/README.md b/README.md
index 3665d6c..ec9979b 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/configure b/configure
index 54199fc..43c7ad0 100755
--- a/configure
+++ b/configure
@@ -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 **/