diff --git a/cross/crossdirect/APKBUILD b/cross/crossdirect/APKBUILD
new file mode 100644
index 000000000..1cd2ba968
--- /dev/null
+++ b/cross/crossdirect/APKBUILD
@@ -0,0 +1,60 @@
+# Wrapper for the "crossdirect" compilation method.
+# pmbootstrap mounts the native chroot in the foreign arch (e.g. armhf) chroot
+# as /native. This package gets installed into the native chroot, and creates
+# wrappers like:
+#
+# /native/usr/lib/crossdirect/armhf/gcc
+# -> /native/usr/bin/armv6-alpine-linux-muslgnueabihf-gcc
+#
+# When building packages in the armhf chroot, PATH will get prepended with
+# "/native/usr/lib/crossdirect/armhf". The end game is of course invoking the
+# cross compiler from the native chroot, running at native speed, whenever
+# calling the compiler from the foreign arch chroot. See crossdirect.c for
+# implementation details (llvm, fakeroot, rpath).
+
+pkgname=crossdirect
+pkgver=1
+pkgrel=0
+pkgdesc="Wrappers to launch native cross compilers in foreign chroots"
+url="https://postmarketOS.org"
+arch="all"
+license="MIT"
+options=""
+source="crossdirect.c"
+
+build() {
+	cd "$srcdir"
+	# Architectures and binaries
+	_archs="x86_64 armhf armv7 aarch64"
+	for _arch in $_archs; do
+		[ "$_arch" == "$CARCH" ] && continue
+		_hostspec="$(arch_to_hostspec $_arch)"
+		$CC -o "crossdirect-$_arch" -static -DHOSTSPEC="\"$_hostspec\"" \
+			crossdirect.c
+	done
+}
+
+package() {
+	# Architectures and binaries
+	_archs="x86_64 armhf armv7 aarch64"
+	_bins="c++ cc cpp g++ gcc clang clang++"
+
+	# Iterate over architectures
+	for _arch in $_archs; do
+		[ "$_arch" == "$CARCH" ] && continue
+
+		# Put arch-specific crossdirect wrapper in arch-specific bin folder
+		_bindir="$pkgdir/usr/lib/crossdirect/$_arch"
+		_hostspec="$(arch_to_hostspec $_arch)"
+		mkdir -p "$_bindir"
+		cd "$_bindir"
+		cp "$srcdir/crossdirect-$_arch" "./"
+
+		# Create compiler symlinks
+		for _bin in $_bins; do
+			ln -s "crossdirect-$_arch" "$_bin"
+			ln -s "crossdirect-$_arch" "$_hostspec-$_bin"
+		done
+	done
+}
+sha512sums="12801031928103bd898a0d54a5c68b33da9bded10a3d145fdf5ce8b70eb0bbbcdd50764279004b6997d85d710fa581dc8b05aa5e0eb62d50c1054cc6d66db87f  crossdirect.c"
diff --git a/cross/crossdirect/crossdirect.c b/cross/crossdirect/crossdirect.c
new file mode 100644
index 000000000..5cff6cccb
--- /dev/null
+++ b/cross/crossdirect/crossdirect.c
@@ -0,0 +1,77 @@
+// HOSTSPEC is defined at compile time, see APKBUILD
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <libgen.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+void exit_userfriendly() {
+	fprintf(stderr, "Please report this at: https://gitlab.com/postmarketOS/pmaports/issues\n");
+	fprintf(stderr, "As a workaround, you can compile without crossdirect.\n");
+	fprintf(stderr, "See 'pmbootstrap -h' for related options.\n");
+	exit(1);
+}
+
+int main(int argc, char** argv) {
+	// we have a max of four extra args ("-target", "HOSTSPEC", "--sysroot=/", "-Wl,-rpath-link=/lib:/usr/lib"), plus one ending null
+	char* newargv[argc + 5];
+	char* executableName = basename(argv[0]);
+	char newExecutable[PATH_MAX];
+	bool isClang = (strcmp(executableName, "clang") == 0 || strcmp(executableName, "clang++") == 0);
+	bool startsWithHostSpec = (strncmp(HOSTSPEC, executableName, sizeof(HOSTSPEC) -1) == 0);
+
+	if (isClang || startsWithHostSpec) {
+	   snprintf(newExecutable, sizeof(newExecutable), "/native/usr/bin/%s", executableName);
+	} else {
+	   snprintf(newExecutable, sizeof(newExecutable), "/native/usr/bin/" HOSTSPEC "-%s", executableName);
+	}
+
+	char** newArgsPtr = newargv;
+	*newArgsPtr++ = newExecutable;
+	if (isClang) {
+		*newArgsPtr++ = "-target";
+		*newArgsPtr++ = HOSTSPEC;
+	}
+	*newArgsPtr++ = "--sysroot=/";
+	bool addrpath = true;
+	if (isClang) {
+		// clang gives a warning if the rpath parameter is passed when linker isn't invoked.
+		// to avoid this warning, only add if we're actually linking at least one library.
+		addrpath = false;
+		for (int i = 1; i < argc; i++) {
+			char* arg = argv[i];
+			if (strlen(arg) >= 2 && arg[0] == '-' && arg[1] == 'l') {
+				addrpath = true;
+				break;
+			}
+		}
+	}
+	if (addrpath) {
+		*newArgsPtr++ = "-Wl,-rpath-link=/lib:/usr/lib";
+	}
+	memcpy(newArgsPtr, argv + 1, sizeof(char*)*(argc - 1));
+	newArgsPtr += (argc - 1);
+	*newArgsPtr = NULL;
+
+	// new arguments prepared; now setup environmental vars
+	setenv("LD_LIBRARY_PATH", "/native/lib:/native/usr/lib", true);
+	char* ldPreload = getenv("LD_PRELOAD");
+	if (ldPreload) {
+		if (strcmp(ldPreload, "/usr/lib/libfakeroot.so") == 0) {
+			setenv("LD_PRELOAD", "/native/usr/lib/libfakeroot.so", true);
+		} else {
+			fprintf(stderr, "ERROR: crossdirect: can't handle LD_PRELOAD: %s\n", ldPreload);
+			exit_userfriendly();
+		}
+	}
+
+	if (execv(newExecutable, newargv) == -1) {
+		fprintf(stderr, "ERROR: crossdirect: failed to execute %s: %s\n", newExecutable, strerror(errno));
+		exit_userfriendly();
+	}
+	return 1;
+}