static wchar_t *get_target(wchar_t *path, wchar_t *base, int type) { if (type == 0 && base == NULL) { /* Relative to base, if no base then shim location */ base = my_dir(); } else if (type == 1) { /* Relative to an exe on PATH */ base = find_on_path(base); } else if (type == 2) { /* Relative to env variable */ base = _wgetenv(base); } else if (type == 3) { /* Relative to registry entry */ /* TODO: add this later */ } }
int main(int argc, char **argv) { char *prog; char *dir, *dirup; char *p; char **args, **argp; char is_verbose = 0; char **argi, *arg; struct stat st; dir = find_on_path(argv[0]); if (!dir) { fdprint(2, "xstatic: error: could not find myself on $PATH\n"); return 122; } dir = readlink_alloc_all(dir); for (p = dir + strlen(dir); p != dir && p[-1] != '/'; --p) {} if (p == dir) { strcpy(dir, "."); } else { for (; p != dir && p[-1] == '/'; --p) {} p[p == dir] = '\0'; /* Remove basename of dir. */ } dirup = get_up_dir_alloc(dir); if (detect_linker(argv)) { /* clang trampoline runs as as ld. */ char is_static = 0; char **argli; /* Where to add the -L flags. */ /* All we do is exec()ing ld.bin with the following dropped from argv: * * -L/usr/lib... * -L/lib... * --hash-style=both (because not supported by old ld) * --build-id (because not supported by old ld) * -z relro (because it increases the binary size and it's useless for static) */ check_ld_crtoarg(argv); argp = args = malloc(sizeof(*args) * (argc + 5)); *argp++ = *argv; for (argi = argv + 1; (arg = *argi); ++argi) { if (0 == strcmp(arg, "--do-xstaticldv")) { is_verbose = 1; } else if (0 == strcmp(arg, "-static")) { is_static = 1; } } if (!is_static) { fdprint(2, "xstatic: error: missing -static\n"); exit(1); } *argp++ = "-nostdlib"; /* No system directories to find .a files. */ /* Find argli: in front of the last -L (which will be removed), but no * later than just before the first -l. */ argli = NULL; for (argi = argv + 1; (arg = *argi); ++argi) { if (arg[0] == '-') { if (arg[1] == 'L') { /* "-L". */ argli = argi; } else if (arg[1] == 'l') { /* "-l". */ if (!argli) argli = argi; break; } } } if (!argli) argli = argv + 1; for (argi = argv + 1; (arg = *argi); ++argi) { if (argi == argli) { char **argj; /* Add the user-specified link dirs first (just like non-xstatic). */ for (argj = argv + 1; *argj; ++argj) { if (0 == strncmp(*argj, "-=L", 3)) { *argp++ = strdupcat("-L", "", *argj + 3); } } /* We put xstaticcld with libgcc.a first, because clang puts * /usr/lib/gcc/i486-linux-gnu/4.4 with libgcc.a before /usr/lib with * libc.a . * * We add these -L flags even if compiler -nostdlib was specified, * because non-xstatic compilers do the same. */ *argp++ = strdupcat("-L", dirup, "/xstaticcld"); *argp++ = strdupcat("-L", dirup, "/xstaticusr/lib"); argli = NULL; /* Don't insert the -L flags again. */ } if (0 == strcmp(arg, "-z") && argi[1] && 0 == strcmp(argi[1], "relro")) { /* Would increase size. */ ++argi; /* Omit both arguments: -z relro */ } else if (arg[0] == '-' && arg[1] == 'L') { /* "-L". */ if (arg[2] == '\0' && argi[1]) ++argi; /* Omit -L... containing the system link dirs, the user-specified link * dir flags were passed as -=L... */ } else if (0 == strncmp(arg, "-=L", 3)) { /* Omit -=L here, gets added at position argli. */ } else if ( 0 == strcmp(arg, "-nostdlib") || 0 == strcmp(arg, "--do-xstaticcld") || 0 == strcmp(arg, "--do-xstaticldv") || 0 == strncmp(arg, "--hash-style=", 13) || /* Would increase size. */ 0 == strcmp(arg, "--build-id") || 0 == strncmp(arg, "--sysroot=", 10)) { /* Omit this argument. */ } else { *argp++ = *argi; } } *argp = NULL; prog = strdupcat(argv[0], ".bin", ""); /* "ld.bin". */ args[0] = prog; if (is_verbose) { fdprint(2, escape_argv("xstatic-ld: info: running ld:\n", args, "\n")); } execv(prog, args); fdprint(2, strdupcat("xstatic-ld: error: exec failed: ", prog, "\n")); return 120; } if (!argv[1] || 0 == strcmp(argv[1], "--help")) { fdprint(1, strdupcat( "Usage: ", argv[0], " <gcc|g++|clang|clang++> [<compiler-arg>...]\n" "Invokes the C/C++ compiler with -static against the xstatic uClibc.\n" )); return 1; } if (argv[1][0] == '-') { fdprint(2, "xstatic: error: please specify gcc|clang prog in 1st arg\n"); return 1; } check_bflags(argv); check_xflags(argv); p = strdupcat(dirup, "/xstaticcld/ld.bin", ""); if (0 != stat(p, &st) || !S_ISREG(st.st_mode)) { file_missing: fdprint(2, strdupcat( "xstatic: error: file missing, please install: ", p, "\n")); return 123; } p = strdupcat(dirup, "/xstaticusr/lib/libc.a", ""); if (0 != stat(p, &st) || !S_ISREG(st.st_mode)) goto file_missing; p = strdupcat(dirup, "/xstaticusr/include/stdio.h", ""); if (0 != stat(p, &st) || !S_ISREG(st.st_mode)) goto file_missing; p = strdupcat(dirup, "/xstaticusr/lib/crt1.o", ""); if (0 != stat(p, &st) || !S_ISREG(st.st_mode)) goto file_missing; p = strdupcat(dirup, "/xstaticcld/crtbeginT.o", ""); if (0 != stat(p, &st) || !S_ISREG(st.st_mode)) goto file_missing; prog = find_on_path(argv[1]); if (!prog) { fdprint(2, strdupcat( "xstatic: error: compiler not found: ", argv[1], "\n")); return 119; } argv[1] = argv[0]; ++argv; --argc; argp = args = malloc(sizeof(*args) * (argc + 20)); *argp++ = prog; /* Set destination argv[0]. */ /* No need to check for -m64, check_bflags has already done that. */ if (!argv[1] || (!argv[2] && (0 == strcmp(argv[1], "-v") || 0 == strcmp(argv[1], "-m32"))) || (argv[2] && !argv[3] && 0 == strcmp(argv[1], "-m32") && 0 == strcmp(argv[2], "-v"))) { /* This changes the `Target: ...' of Clang to i386, but of GCC. */ if (!argv[1] || (!argv[2] && 0 != strcmp(argv[1], "-m32"))) { *argp++ = "-m32"; } /* Don't add any flags, because the user wants some version info, and with * `-Wl,... -v' gcc and clang won't display version info. */ memcpy(argp, argv + 1, argc * sizeof(*argp)); } else { char need_linker; char has_nostdinc, has_nostdincxx; lang_t lang; need_linker = detect_need_linker(argv); detect_nostdinc(argv, &has_nostdinc, &has_nostdincxx); detect_lang(prog, argv, &lang); /* When adding more arguments here, increase the args malloc count. */ /* We don't need get_autodetect_archflag(argv), we always send "-m32". */ *argp++ = "-m32"; *argp++ = "-static"; /* The linker would be ../xstaticcld/ld, which is also a trampoline binary * of ours. */ *argp++ = strdupcat("-B", dirup, "/xstaticcld"); /* This puts xstaticusr/include to the top of the include path, and keeps * the gcc or clang headers below that. Specifying --nostdinc (when * lang.is_compiling) would remove these compiler-specific headers (e.g. * stdarg.h), which we don't want removed, because libc headers depend * on them. * * TODO(pts): Make /usr/local/bin/clang also work. */ *argp++ = strdupcat("--sysroot=", dirup, lang.is_clang && is_dirprefix(prog, "/usr/bin") ? "/xstaticclangempty" : "/xstaticempty"); if (lang.is_compiling) { /* * Without this we get the following error compiling binutils 2.20.1: * chew.c:(.text+0x233f): undefined reference to `__stack_chk_fail' * We can't implement this in a compatible way, glibc gcc generates %gs:20, * uClibc-0.9.33 has symbol __stack_chk_guard. */ *argp++ = "-fno-stack-protector"; if (lang.is_cxx) { /* Glitch: It's not possible to disable the gcc warning ``cc1: warning: * command line option "-nostdinc++" is valid for C++/ObjC++ but not * for C'', there is no such clang warning. Example invocation (with * both .c and .cc files): ``xstatic gcc -c -W -Wall -O2 co.c * hello.cc''. */ *argp++ = "-nostdinc++"; if (!has_nostdincxx) { /* Clang has -cxx-isystem, which is a no-op when compiling C code, * but it adds the directory after the regular -isystem. But we need * the C++ headers in front of the C headers (because of conflicting * files, e.g. complex.h, tgmath.h, fenv.h). * * So we don't use -cxx-isystem, but we use -isystem uniformly for * Clang and GCC. * * A small glitch: if there are both C and C++ source files * specified (because C source files mustn't have C++ headers on * their include path), and a non-C++ compiler is used (e.g. * ``xstatic gcc -c -W -Wall -O2 helloco.c hello.cc''), then * `#include <vector>' in the .c file would find the C++ vector * header, and fail with a confusing error message when parsing it. */ *argp++ = "-isystem"; *argp++ = strdupcat(dirup, "/xstaticusr/c++include", ""); /* Regular g++ libstdc++ has non-backward and then backward. */ *argp++ = "-isystem"; *argp++ = strdupcat(dirup, "/xstaticusr/c++include/backward", ""); } } if (!has_nostdinc) { *argp++ = "-isystem"; *argp++ = strdupcat(dirup, "/xstaticusr/include", ""); } } for (argi = argv + 1; (arg = *argi); ++argi) { if (0 == strcmp(arg, "-v")) { is_verbose = 1; *argp++ = arg; } else if (0 == strcmp(arg, "-static") || 0 == strcmp(arg, "-xstatic") || 0 == strcmp(arg, "--xstatic") || 0 == strcmp(arg, "-nostdinc") || 0 == strcmp(arg, "-nostdinc++") || 0 == strcmp(arg, "-m32")) { } else if (arg[0] == '-' && arg[1] == 'L') { /* "-L". */ /* Convert -L to -=L in the linker command-line on which our ld wrapper * code can trigger. */ if (arg[2] == '\0' && argi[1]) { *argp++ = strdupcat("-Wl,-=L", "", *++argi); } else { *argp++ = strdupcat("-Wl,-=L", "", arg + 2); } } else { *argp++ = arg; } } if (need_linker) { *argp++ = "-Wl,--do-xstaticcld"; if (is_verbose) *argp++ = "-Wl,--do-xstaticldv"; } *argp++ = NULL; } if (is_verbose) { fdprint(2, escape_argv("xstatic: info: running compiler:\n", args, "\n")); } execv(prog, args); fdprint(2, strdupcat("xstatic: error: exec failed: ", prog, "\n")); return 120; }
int main(int argc, char **argv) { char python_bin[PATH_MAX + 1], argv0_bin[PATH_MAX + 1], *p, *q; char prog_py[PATH_MAX + 1]; const char *moreargv[ARGV_MAX + 1]; int i; (void)argc; p = argv[0]; q = NULL; while (*p != '\0') { if (*p++ == FILE_SEP) q = p; } if (q == NULL) { // Try to find argv[0] on $PATH. p = argv[0]; strncpy(argv0_bin, p, sizeof argv0_bin); q = NULL; while (*p != '\0') { if (*p++ == '.') q = p; } if (q == NULL) { argv0_bin[sizeof argv0_bin - 5] = '\0'; strcat(argv0_bin, ".exe"); } else { argv0_bin[sizeof argv0_bin - 1] = '\0'; } find_on_path(argv0_bin, python_bin); } else { // Put dirname(argv[0]) to python_bin. p = argv[0]; --q; if (q - p > PATH_MAX) { q = p + PATH_MAX; } strncpy(python_bin, p, q - p); python_bin[q - p] = '\0'; } if (python_bin[0] == '\0') { python_bin[0] = '.'; python_bin[1] = '\0'; } strcpy(prog_py, python_bin); i = strlen(python_bin); if (i + strlen(python_exe) > PATH_MAX) { i = PATH_MAX - strlen(python_exe); } python_bin[i] = FILE_SEP; strcpy(python_bin + i + 1, python_exe); i = strlen(prog_py); if (i + strlen(pdfsizeopt_py) > PATH_MAX) { i = PATH_MAX - strlen(pdfsizeopt_py); } prog_py[i] = FILE_SEP; strcpy(prog_py + i + 1, pdfsizeopt_py); moreargv[0] = "python26"; moreargv[1] = prog_py; for (i = 1; argv[i] != NULL; ++i) { moreargv[i + 1] = argv[i]; } moreargv[i + 1] = NULL; // execv(...) and P_OVERLAY don't work well in wine-1.2.2 and Windows XP, // because they make this process return before the started process finishes. i = spawnv(P_WAIT, python_bin, moreargv); if (i < 0) { fprintf(stderr, "error: could not start %s: %s\n", python_bin, strerror(errno)); return 120; } return i; }