Skip to content

Instantly share code, notes, and snippets.

@Low-power
Created May 3, 2022 03:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Low-power/fae01385544ed39352f3687a57aa78be to your computer and use it in GitHub Desktop.
Save Low-power/fae01385544ed39352f3687a57aa78be to your computer and use it in GitHub Desktop.
/* Copyright 2015-2022 Rivoreo
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//#define GCC_INSTALL_PREFIX "/opt/gcc.3.3"
//#define GCC_INSTALL_PREFIX "/opt/toolchains"
//#define GCC_INSTALL_PREFIX "/usr/sfw"
#define GCC_INSTALL_PREFIX "/usr/local"
//#define GCC_INSTALL_PREFIX "/usr"
//#define GCC_INSTALL_PREFIX "/media/f01a9cd1-2570-4619-b4cd-41a27bdcfbd3/arm-linux-gnueabi-gcc/4.3.2"
//#define GCC_INSTALL_PREFIX "/media/f01a9cd1-2570-4619-b4cd-41a27bdcfbd3/arm-linux-androideabi-gcc/4.4.3"
//#define GCC_INSTALL_PREFIX "/opt/arm-linux-gnueabi-gcc/4.5.2"
// Platform string prepend to the command name, optional
//#define GCC_PLATFORM_PREFIX "arm-none-linux-gnueabi"
//#define GCC_PLATFORM_PREFIX "arm-linux-gnueabi"
//#define GCC_PLATFORM_PREFIX "arm-linux-uceabi"
//#define GCC_PLATFORM_PREFIX "arm-linux-androideabi"
//#define GCC_PLATFORM_PREFIX "arm-unknown-freebsd11eabihf"
//#define GCC_PLATFORM_PREFIX "arm-linux-gnueabihf"
//#define GCC_PLATFORM_PREFIX "i386-pc-solaris2.10"
//#define GCC_PLATFORM_PREFIX "i386-pc-solaris2.11"
//#define GCC_PLATFORM_PREFIX "i386-linux-gnu"
//#define GCC_PLATFORM_PREFIX "i486-linux-gnu"
//#define GCC_PLATFORM_PREFIX "i686-linux-gnu"
//#define GCC_PLATFORM_PREFIX "i686-pc-cygwin"
#define GCC_PLATFORM_PREFIX "x86_64-unknown-freebsd10"
//#define GCC_PLATFORM_PREFIX "powerpc-unknown-linux-gnu"
// GCC version string append to the command name, optional
//#define GCC_VERSION_SUFFIX "3.4.3"
//#define GCC_VERSION_SUFFIX "4.3.2"
//#define GCC_VERSION_SUFFIX "4.4.3"
//#define GCC_VERSION_SUFFIX "4.5"
//#define GCC_VERSION_SUFFIX "4.7.3"
#define GCC_VERSION_SUFFIX "4.7.4"
#define _ALL_SOURCE
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#if defined __CYGWIN__ && !defined NO_CYGWIN_OUTPUT_FILE_NAME_HACK
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#endif
#ifdef EXTRA_FLAGS
static char *extra_flags[] = { EXTRA_FLAGS };
#endif
#if defined __CYGWIN__ && !defined NO_CYGWIN_OUTPUT_FILE_NAME_HACK
static int get_last_dot(const char *s, size_t len) {
while(--len) {
if(s[len] == '.') break;
if(s[len] == '/' || s[len] == '\\') return -1;
}
if(!len) return -1;
return len;
}
static int wait_and_rename_output_file(pid_t pid, const char *program, const char *exe_name, const char *output_file_name) {
struct stat st;
int status;
while(waitpid(pid, &status, 0) < 0) {
if(errno == EINTR) continue;
perror("waitpid");
return 1;
}
if(WIFSIGNALED(status)) {
fprintf(stderr, "program %s terminated by signal %d\n", program, WTERMSIG(status));
return WTERMSIG(status) + 128;
}
if(status) return WEXITSTATUS(status);
if(stat(exe_name, &st) < 0) return 0;
if(rename(exe_name, output_file_name) < 0) {
perror("rename");
return 1;
}
return 0;
}
#endif
int main(int argc, char **argv) {
#if defined __CYGWIN__ && !defined NO_CYGWIN_OUTPUT_FILE_NAME_HACK
const char *output_file_name = NULL;
#endif
char **p = argv;
while(*++p) {
if(strncmp(*p, "-R", 2) == 0) {
#ifdef ALLOW_RPATH_ORIGIN
const char *o = (*p)[2] ? *p + 2 : ({ if(!*++p) break; *p; });
if(strcmp(o, "$ORIGIN")) {
fprintf(stderr, "%s: error: only '$ORIGIN' is allowed as rpath\n", argv[0]);
return 1;
}
#else
fprintf(stderr, "%s: error: option '-R' is not available\n", argv[0]);
return 1;
#endif
} else if(strncmp(*p, "-Wl,", 4) == 0 || strcmp(*p, "-Xlinker") == 0) {
const char *sp = (*p)[1] == 'W' ? *p + 4 : ({ if(!*++p) break; *p; });
#ifdef ALLOW_RPATH_ORIGIN
unsigned int opt_len;
if((strncmp(sp, "-R", 2) == 0 && (opt_len = 2)) ||
(strncmp(sp, "--rpath", 7) == 0 && (opt_len = 7)) ||
(strncmp(sp, "-rpath", 6) == 0 && (opt_len = 6))) {
const char *o = (sp == *p) ?
(sp[opt_len] ? (sp + opt_len) : ((*++p && strcmp(*p, "-Xlinker") == 0 && *++p) ? (*p) : ({ if(!*p) break; ""; }))) :
sp[opt_len] ? (sp + opt_len + (sp[opt_len] == ',')) : (*++p && strncmp(*p, "-Wl,", 4) == 0 ? *p + 4 : "");
if(strcmp(o, "$ORIGIN")) {
fprintf(stderr, "%s: error: only '$ORIGIN' is allowed as rpath\n", argv[0]);
return 1;
}
}
#else
if(strncmp(sp, "-R", 2) == 0 || strncmp(sp, "--rpath", 7) == 0 || strncmp(sp, "-rpath", 6) == 0) {
fprintf(stderr, "%s: error: passing rpath to the linker is not allowed\n", argv[0]);
return 1;
}
#endif
}
#if defined __CYGWIN__ && !defined NO_CYGWIN_OUTPUT_FILE_NAME_HACK
else if(strncmp(*p, "-o", 2) == 0) {
output_file_name = (*p)[2] ? *p + 2 : ({ if(!*++p) break; *p; });
}
#endif
}
const char *rpath_in_env = getenv("LD_RUN_PATH");
if(rpath_in_env) {
fprintf(stderr, "%s: warning: clearing environment variable LD_RUN_PATH='%s'\n", argv[0], rpath_in_env);
unsetenv("LD_RUN_PATH");
}
size_t argv0_len = strlen(argv[0]);
char *program = GCC_INSTALL_PREFIX "/bin/"
#ifdef GCC_PLATFORM_PREFIX
GCC_PLATFORM_PREFIX "-"
#endif
"gcc"
#ifdef GCC_VERSION_SUFFIX
"-" GCC_VERSION_SUFFIX
#endif
;
if(argv0_len > 2) {
if(strcmp(argv[0] + (argv0_len - 3), "g++") == 0) {
program = GCC_INSTALL_PREFIX "/bin/"
#ifdef GCC_PLATFORM_PREFIX
GCC_PLATFORM_PREFIX "-"
#endif
"g++"
#ifdef GCC_VERSION_SUFFIX
"-" GCC_VERSION_SUFFIX
#endif
;
} else if(argv0_len > 7 && strcmp(argv[0] + (argv0_len - 8), "gfortran") == 0) {
program = GCC_INSTALL_PREFIX "/bin/"
#ifdef GCC_PLATFORM_PREFIX
GCC_PLATFORM_PREFIX "-"
#endif
"gfortran"
#ifdef GCC_VERSION_SUFFIX
"-" GCC_VERSION_SUFFIX
#endif
;
} else if(strcmp(argv[0] + (argv0_len - 3), "gcj") == 0) {
program = GCC_INSTALL_PREFIX "/bin/"
#ifdef GCC_PLATFORM_PREFIX
GCC_PLATFORM_PREFIX "-"
#endif
"gcj"
#ifdef GCC_VERSION_SUFFIX
"-" GCC_VERSION_SUFFIX
#endif
;
}
}
#if defined __CYGWIN__ && !defined NO_CYGWIN_OUTPUT_FILE_NAME_HACK
if(output_file_name) {
size_t len = strlen(output_file_name);
//output_file_name = getbasename(output_file_name);
//if(!strchr(output_file_name, '.')) {
if(get_last_dot(output_file_name, len) == -1) {
struct stat st;
char exe_name[len + 4 + 1];
memcpy(exe_name, output_file_name, len);
strcpy(exe_name + len, ".exe");
if(lstat(exe_name, &st) == 0 && !S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
fprintf(stderr, "error: redirected output file %s exists and it is not a regular file\n", exe_name);
return 1;
}
pid_t pid = fork();
if(pid > 0) {
// fork(2) successed and this is the parent process
return wait_and_rename_output_file(pid, program, exe_name, output_file_name);
}
}
}
#ifdef CYGWIN_HACK_A_EXE
else {
struct stat st;
if(lstat("a.out", &st) == 0 && !S_ISREG(st.st_mode)) {
fprintf(stderr, "error: a.out: %s\n", strerror(EEXIST));
return 1;
}
pid_t pid = fork();
if(pid > 0) return wait_and_rename_output_file(pid, program, "a.exe", "a.out");
}
#endif
#endif
#ifdef EXTRA_FLAGS
//[argc + (sizeof extra_flags / sizeof *extra_flags) + 1]
char **new_argv = malloc(argc * sizeof(char *) + sizeof extra_flags);
if(!new_argv) {
fputs("error: out of memory\n", stderr);
return 1;
}
new_argv[0] = program;
memcpy(new_argv + 1, extra_flags, sizeof extra_flags);
memcpy(new_argv + 1 + (sizeof extra_flags / sizeof *extra_flags), argv + 1, argc * sizeof(char *));
execv(program, new_argv);
free(new_argv);
#else
argv[0] = program;
execv(program, argv);
#endif
perror(program);
return 2;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment