Created
May 3, 2022 03:04
-
-
Save Low-power/fae01385544ed39352f3687a57aa78be to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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