pmaports/cross/crossdirect/crossdirect.c
Oliver Smith 958f597a6c cross/crossdirect: use ccache, execve, -Werror (!299)
Instead of running compilers directly, let them go through the native
ccache binary. Note that it will still use the foreign arches cache dir
because the native cache dir would be at /native/home/pmos/.ccache.

Use execve instead of setenv and execv, because that didn't work with
LD_LIBRARY_PATH (ccache was complaining that it couldn't load zlib).

Enable -Werror, because we are maintaining this program and it helps
us catching bugs early.
2019-04-03 21:26:12 +02:00

83 lines
2.7 KiB
C

// 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>
#define NATIVE_BIN_DIR "/native/usr/lib/ccache/bin"
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_BIN_DIR "/%s", executableName);
} else {
snprintf(newExecutable, sizeof(newExecutable), NATIVE_BIN_DIR "/" 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
char* env[] = {"LD_PRELOAD=",
"LD_LIBRARY_PATH=/native/lib:/native/usr/lib",
"CCACHE_PATH=/native/usr/bin",
NULL};
char* ldPreload = getenv("LD_PRELOAD");
if (ldPreload) {
if (strcmp(ldPreload, "/usr/lib/libfakeroot.so") == 0) {
env[0] = "LD_PRELOAD=/native/usr/lib/libfakeroot.so";
} else {
fprintf(stderr, "ERROR: crossdirect: can't handle LD_PRELOAD: %s\n", ldPreload);
exit_userfriendly();
}
}
if (execve(newExecutable, newargv, env) == -1) {
fprintf(stderr, "ERROR: crossdirect: failed to execute %s: %s\n", newExecutable, strerror(errno));
fprintf(stderr, "Maybe the target arch is missing in the ccache-cross-symlinks package?\n");
exit_userfriendly();
}
return 1;
}