diff --git a/pkgs/racket-doc/scribblings/reference/startup.scrbl b/pkgs/racket-doc/scribblings/reference/startup.scrbl index dbba5e786c..063fc18454 100644 --- a/pkgs/racket-doc/scribblings/reference/startup.scrbl +++ b/pkgs/racket-doc/scribblings/reference/startup.scrbl @@ -201,6 +201,11 @@ flags: @racket[module-predefined?]. This option is normally embedded in a stand-alone binary that also embeds Racket code.} + @item{@FlagFirst{Y} @nonterm{file} @nonterm{n} @nonterm{m} @nonterm{p} : + Like @Flag{k} @nonterm{n} @nonterm{m} @nonterm{p}, but reading + from @nonterm{file} (without any adjustment on Mac OS or Windows + for a segment or resource offset).} + @item{@FlagFirst{m} or @DFlagFirst{main} : Evaluates a call to @racketidfont{main} as bound in the top-level environment. All of the command-line arguments that are not processed as @@ -473,7 +478,8 @@ Extra arguments following the last option are available from the @history[#:changed "6.90.0.17" @elem{Added @Flag{O}/@DFlag{stdout}.} #:changed "7.1.0.5" @elem{Added @Flag{M}/@DFlag{compile-any}.} #:changed "7.8.0.6" @elem{Added @Flag{Z}.} - #:changed "8.0.0.10" @elem{Added @Flag{E}.}] + #:changed "8.0.0.10" @elem{Added @Flag{E}.} + #:changed "8.0.0.11" @elem{Added @Flag{Y}.}] @; ---------------------------------------------------------------------- diff --git a/racket/src/bc/cmdline.inc b/racket/src/bc/cmdline.inc index b08b4e5a24..04c354aeeb 100644 --- a/racket/src/bc/cmdline.inc +++ b/racket/src/bc/cmdline.inc @@ -53,13 +53,13 @@ char *add_to_str(const char *addr, long amt) } #endif -static char *make_embedded_load(const char *start, const char *end) +static char *make_embedded_load(const char *file, const char *start, const char *end) { char *s; - int slen, elen; + int slen, elen, flen; #if defined(OS_X) || defined(DOS_FILE_SYSTEM) - { + if (file == NULL) { long fileoff; fileoff = get_segment_offset(); start = add_to_str(start, fileoff); @@ -67,12 +67,16 @@ static char *make_embedded_load(const char *start, const char *end) } #endif + if (!file) file = ""; + slen = strlen(start); elen = strlen(end); + flen = strlen(file); - s = (char *)malloc(slen + elen + 2); + s = (char *)malloc(slen + elen + flen + 3); memcpy(s, start, slen + 1); memcpy(s + slen + 1, end, elen + 1); + memcpy(s + slen + elen + 2, file, flen + 1); return s; } @@ -701,6 +705,7 @@ static int run_from_cmd_line(int argc, char *_argv[], int *eval_kind, num_enl; int no_more_switches = 0; int show_vers = 0; + char *embedding_file; #endif #if !defined(DONT_RUN_REP) || !defined(DONT_PARSE_COMMAND_LINE) int use_repl = 0; @@ -998,6 +1003,18 @@ static int run_from_cmd_line(int argc, char *_argv[], no_init_ns = 1; break; case 'k': + case 'Y': + if (*str == 'Y') { + if (argc < 2) { + PRINTF("%s: missing file name after %s switch\n", + prog, real_switch); + goto show_need_help; + } + argv++; + --argc; + embedding_file = argv[0]; + } else + embedding_file = NULL; if (argc < 4) { PRINTF("%s: missing %s after %s switch\n", prog, @@ -1007,12 +1024,12 @@ static int run_from_cmd_line(int argc, char *_argv[], } argv++; --argc; - se = make_embedded_load(argv[0], argv[1]); + se = make_embedded_load(embedding_file, argv[0], argv[1]); evals_and_loads[num_enl] = se; argv++; --argc; eval_kind[num_enl++] = mzcmd_EMBEDDED_REG; - se = make_embedded_load(argv[0], argv[1]); + se = make_embedded_load(embedding_file, argv[0], argv[1]); evals_and_loads[num_enl] = se; argv++; --argc; @@ -1418,6 +1435,7 @@ static int run_from_cmd_line(int argc, char *_argv[], " -r , --script : Same as -f -N --\n" " -u , --require-script : Same as -t -N --\n" " -k

: Load executable-embedded code from offset to

\n" + " -Y

: Like -k

, but from \n" " -m, --main : Call `main' with command-line arguments, print results\n" " [*] Also `require's a `main' submodule, if any\n" " Interaction options:\n" diff --git a/racket/src/bc/dynsrc/Makefile.in b/racket/src/bc/dynsrc/Makefile.in index da7872d8ca..13d63d1c6a 100644 --- a/racket/src/bc/dynsrc/Makefile.in +++ b/racket/src/bc/dynsrc/Makefile.in @@ -60,7 +60,7 @@ MZDYNDEP = ../mzdyn.o $(srcdir)/../include/ext.exp $(srcdir)/../include/racket.e dynexmpl.o: $(srcdir)/dynexmpl.c $(HEADERS) $(PLAIN_CC) $(ALL_CFLAGS) -c $(srcdir)/dynexmpl.c -o dynexmpl.o -../starter@NOT_MINGW@@EXE_SUFFIX@: $(srcdir)/../../start/ustart.c +../starter@NOT_MINGW@@EXE_SUFFIX@: $(srcdir)/../../start/ustart.c $(srcdir)/../../start/unix_self.inc $(PLAIN_CC) $(ALL_CFLAGS) -o ../starter@EXE_SUFFIX@ $(srcdir)/../../start/ustart.c PARSE_CMDL = $(srcdir)/../../start/parse_cmdl.inc diff --git a/racket/src/bc/src/eval.c b/racket/src/bc/src/eval.c index dbcd9372b8..4469263c97 100644 --- a/racket/src/bc/src/eval.c +++ b/racket/src/bc/src/eval.c @@ -3756,15 +3756,28 @@ Scheme_Object *scheme_eval_string_multi_with_prompt(const char *str, Scheme_Env void scheme_embedded_load(intptr_t len, const char *desc, int predefined) { - Scheme_Object *s, *e, *a[4], *eload; + Scheme_Object *s, *e, *f, *a[5], *eload; + int argc = 4; eload = scheme_get_startup_export("embedded-load"); if (len < 0) { - /* description mode */ + /* description mode: string embeds start, end, and filename, where + a 0-length filename means to find the executable via + `(system-path 'exec-file)`. */ + int slen, elen, foff; + slen = strlen(desc); + elen = strlen(desc XFORM_OK_PLUS (slen + 1)); + foff = slen + 1 + elen + 1; s = scheme_make_utf8_string(desc); - e = scheme_make_utf8_string(desc XFORM_OK_PLUS strlen(desc) XFORM_OK_PLUS 1); + e = scheme_make_utf8_string(desc XFORM_OK_PLUS (slen + 1)); + if (desc[foff] != 0) { + f = scheme_make_byte_string(desc XFORM_OK_PLUS foff); + argc = 5; + } else + f = scheme_false; a[0] = s; a[1] = e; a[2] = scheme_false; + a[4] = f; } else { /* content mode */ a[0] = scheme_false; @@ -3773,7 +3786,7 @@ void scheme_embedded_load(intptr_t len, const char *desc, int predefined) a[2] = s; } a[3] = (predefined ? scheme_true : scheme_false); - (void)scheme_apply(eload, 4, a); + (void)scheme_apply(eload, argc, a); } int scheme_is_predefined_module_path(Scheme_Object *m) diff --git a/racket/src/cs/c/Makefile.in b/racket/src/cs/c/Makefile.in index 4b6ee90816..2ffa00dfb1 100644 --- a/racket/src/cs/c/Makefile.in +++ b/racket/src/cs/c/Makefile.in @@ -421,7 +421,9 @@ DEF_COLLECTS_DIR@MINGW@ = DEF_CONFIG_DIR@MINGW@ = DEF_C_DIRS = $(DEF_COLLECTS_DIR) $(DEF_CONFIG_DIR) -MAIN_DEPS = $(srcdir)/main.c $(srcdir)/boot.h $(srcdir)/../../start/config.inc cs_config.h +MAIN_DEPS = $(srcdir)/main.c $(srcdir)/boot.h cs_config.h \ + $(srcdir)/../../start/config.inc \ + $(srcdir)/../../start/unix_self.inc main.o: $(MAIN_DEPS) $(CC) $(CFLAGS) $(DEF_C_DIRS) -c -o main.o $(srcdir)/main.c @@ -432,7 +434,7 @@ grmain.o: $(srcdir)/grmain.c $(MAIN_DEPS) $(srcdir)/../../start/gui_filter.inc boot.o: $(srcdir)/boot.c $(srcdir)/../../rktio/rktio.inc $(srcdir)/boot.h $(CC) $(CFLAGS) -c -o boot.o $(srcdir)/boot.c -starter@NOT_MINGW@: $(srcdir)/../../start/ustart.c +starter@NOT_MINGW@: $(srcdir)/../../start/ustart.c $(srcdir)/../../start/unix_self.inc $(CC) $(CFLAGS) -o starter $(srcdir)/../../start/ustart.c diff --git a/racket/src/cs/c/main.c b/racket/src/cs/c/main.c index de5e564c91..c8457a4e8a 100644 --- a/racket/src/cs/c/main.c +++ b/racket/src/cs/c/main.c @@ -57,30 +57,10 @@ PRESERVE_IN_EXECUTABLE char *boot_file_data = "BooT FilE OffsetS:\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; static int boot_file_offset = 18; -#define USE_GENERIC_GET_SELF_PATH +#include "../../start/unix_self.inc" #ifdef OS_X # include -static char *get_self_path(char *exec_file) -{ - char buf[1024], *s; - uint32_t size = sizeof(buf); - int r; - - r = _NSGetExecutablePath(buf, &size); - if (!r) - return strdup(buf); - else { - s = malloc(size); - r = _NSGetExecutablePath(s, &size); - if (!r) - return s; - fprintf(stderr, "failed to get self\n"); - exit(1); - } -} -# undef USE_GENERIC_GET_SELF_PATH - static long find_rktboot_section(char *me) { const struct mach_header *mh; @@ -147,68 +127,6 @@ static char *path_append(const char *p1, char *p2) { #endif -#if defined(__linux__) -# include -static char *get_self_path(char *exec_file) -{ - char buf[256], *s = buf; - ssize_t len, blen = sizeof(buf); - - while (1) { - len = readlink("/proc/self/exe", s, blen-1); - if (len == (blen-1)) { - if (s != buf) free(s); - blen *= 2; - s = malloc(blen); - } else if (len < 0) { - fprintf(stderr, "failed to get self (%d)\n", errno); - exit(1); - } else - break; - } - buf[len] = 0; - return strdup(buf); -} -# undef USE_GENERIC_GET_SELF_PATH -#endif - -#if defined(__FreeBSD__) || defined(__NetBSD__) -# include -# include -static char *get_self_path(char *exec_file) -{ - int mib[4]; - char *s; - size_t len; - int r; - - mib[0] = CTL_KERN; -#if defined(__NetBSD__) - mib[1] = KERN_PROC_ARGS; - mib[2] = getpid(); - mib[3] = KERN_PROC_PATHNAME; -#else - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PATHNAME; - mib[3] = -1; -#endif - - r = sysctl(mib, 4, NULL, &len, NULL, 0); - if (r < 0) { - fprintf(stderr, "failed to get self (%d)\n", errno); - exit(1); - } - s = malloc(len); - r = sysctl(mib, 4, s, &len, NULL, 0); - if (r < 0) { - fprintf(stderr, "failed to get self (%d)\n", errno); - exit(1); - } - return s; -} -# undef USE_GENERIC_GET_SELF_PATH -#endif - #ifdef ELF_FIND_BOOT_SECTION # include # include @@ -289,7 +207,7 @@ static int scheme_utf8_encode(unsigned int *path, int zero_offset, int len, #endif #ifdef USE_GENERIC_GET_SELF_PATH -/* Get executable path via argv[0] and the `PATH` encironment variable */ +/* Get executable path via argv[0] and the `PATH` environment variable */ static int has_slash(char *s) { diff --git a/racket/src/cs/main.sps b/racket/src/cs/main.sps index 8230fef269..fd5333779a 100644 --- a/racket/src/cs/main.sps +++ b/racket/src/cs/main.sps @@ -403,10 +403,13 @@ (loop)))) loads)) (flags-loop rest-args (see saw 'non-config 'top)))] - [("-k") - (let*-values ([(n rest-args) (next-arg "starting and ending offsets" arg within-arg args)] - [(m rest-args) (next-arg "first ending offset" arg within-arg (cons "-k" rest-args))] - [(p rest-args) (next-arg "second ending offset" arg within-arg (cons "-k" rest-args))]) + [("-k" "-Y") + (let*-values ([(f rest-args) (if (equal? arg "-Y") + (next-arg "file" arg within-arg args) + (values #f (cdr args)))] + [(n rest-args) (next-arg "starting and ending offsets" arg within-arg (cons arg rest-args))] + [(m rest-args) (next-arg "first ending offset" arg within-arg (cons arg rest-args))] + [(p rest-args) (next-arg "second ending offset" arg within-arg (cons arg rest-args))]) (let* ([add-segment-offset (lambda (s what) (let ([n (#%string->number s)]) @@ -419,9 +422,9 @@ (set! loads (cons (lambda () - (set! embedded-load-in-places (cons (list #f n m #f) embedded-load-in-places)) - (embedded-load n m #f #t) - (embedded-load m p #f #f)) + (set! embedded-load-in-places (cons (list f n m #f) embedded-load-in-places)) + (embedded-load n m #f #t f) + (embedded-load m p #f #f f)) loads))) (no-init! saw) (flags-loop rest-args (see saw 'non-config)))] diff --git a/racket/src/cs/main/help.ss b/racket/src/cs/main/help.ss index 20c3101c92..ca31a0357a 100644 --- a/racket/src/cs/main/help.ss +++ b/racket/src/cs/main/help.ss @@ -22,6 +22,7 @@ " -r , --script : Same as -f -N --\n" " -u , --require-script : Same as -t -N --\n" " -k

: Load executable-embedded code from offset to

\n" + " -Y

: Like -k

, but from \n" " -m, --main : Call `main' with command-line arguments, print results\n" " [*] Also `require's a `main' submodule, if any\n" " Interaction options:\n" @@ -70,6 +71,7 @@ " --cross-server : Drive cross-compiler (as only option)\n" " Meta options:\n" " -- : No argument following this switch is used as a switch\n" + " -Z : Ignore the argument following this switch\n" " -h, --help : Show this information and exits, ignoring other options\n" "Default options:\n" " If only configuration options are provided, -i is added\n" diff --git a/racket/src/start/unix_self.inc b/racket/src/start/unix_self.inc new file mode 100644 index 0000000000..b2ee738eba --- /dev/null +++ b/racket/src/start/unix_self.inc @@ -0,0 +1,86 @@ +#define USE_GENERIC_GET_SELF_PATH + +#if defined(__linux__) +# include +static char *get_self_path(char *exec_file) +{ + char buf[256], *s = buf; + ssize_t len, blen = sizeof(buf); + + while (1) { + len = readlink("/proc/self/exe", s, blen-1); + if (len == (blen-1)) { + if (s != buf) free(s); + blen *= 2; + s = malloc(blen); + } else if (len < 0) { + fprintf(stderr, "failed to get self (%d)\n", errno); + exit(1); + } else + break; + } + buf[len] = 0; + return strdup(buf); +} +# undef USE_GENERIC_GET_SELF_PATH +#endif + +#if defined(__FreeBSD__) || defined(__NetBSD__) +# include +# include +static char *get_self_path(char *exec_file) +{ + int mib[4]; + char *s; + size_t len; + int r; + + mib[0] = CTL_KERN; +#if defined(__NetBSD__) + mib[1] = KERN_PROC_ARGS; + mib[2] = getpid(); + mib[3] = KERN_PROC_PATHNAME; +#else + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; +#endif + + r = sysctl(mib, 4, NULL, &len, NULL, 0); + if (r < 0) { + fprintf(stderr, "failed to get self (%d)\n", errno); + exit(1); + } + s = malloc(len); + r = sysctl(mib, 4, s, &len, NULL, 0); + if (r < 0) { + fprintf(stderr, "failed to get self (%d)\n", errno); + exit(1); + } + return s; +} +# undef USE_GENERIC_GET_SELF_PATH +#endif + +#if defined(__APPLE__) && defined(__MACH__) +# include +static char *get_self_path(char *exec_file) +{ + char buf[1024], *s; + uint32_t size = sizeof(buf); + int r; + + r = _NSGetExecutablePath(buf, &size); + if (!r) + return strdup(buf); + else { + s = malloc(size); + r = _NSGetExecutablePath(s, &size); + if (!r) + return s; + fprintf(stderr, "failed to get self\n"); + exit(1); + } +} +# undef USE_GENERIC_GET_SELF_PATH +#endif diff --git a/racket/src/start/ustart.c b/racket/src/start/ustart.c index 07c2aa363f..1dc24888c6 100644 --- a/racket/src/start/ustart.c +++ b/racket/src/start/ustart.c @@ -262,6 +262,20 @@ static char *next_string(char *s) return s + strlen(s) + 1; } +#include "unix_self.inc" + +#ifdef USE_GENERIC_GET_SELF_PATH +static char *adjust_self_reference(char *me) +{ + return me; +} +#else +static char *adjust_self_reference(char *me) +{ + return get_self_path(me); +} +#endif + typedef unsigned short ELF__Half; typedef unsigned int ELF__Word; typedef unsigned long ELF__Xword; @@ -353,7 +367,7 @@ static int try_elf_section(const char *me, int *_start, int *_decl_end, int *_pr int main(int argc, char **argv) { - char *me = argv[0], *data, **new_argv; + char *me = argv[0], *embedding_me, *data, **new_argv; char *exe_path, *lib_path, *dll_path; int start, decl_end, prog_end, end, count, fd, v, en, x11; int argpos, inpos, collcount = 1, fix_argv; @@ -434,6 +448,11 @@ int main(int argc, char **argv) } } + /* use `me` for `-k`, unless we have a way to more directly get the + executable file that contains embedded code; if we do, then + argv[0] doesn't have to match the executable */ + embedding_me = adjust_self_reference(me); + start = as_int(config + 8); decl_end = as_int(config + 12); prog_end = as_int(config + 16); @@ -441,7 +460,7 @@ int main(int argc, char **argv) count = as_int(config + 24); x11 = as_int(config + 28); - fix_argv = try_elf_section(me, &start, &decl_end, &prog_end, &end); + fix_argv = try_elf_section(embedding_me, &start, &decl_end, &prog_end, &end); { int offset, len; @@ -456,14 +475,14 @@ int main(int argc, char **argv) } data = (char *)malloc(end - prog_end); - new_argv = (char **)malloc((count + argc + (2 * collcount) + 12) * sizeof(char*)); + new_argv = (char **)malloc((count + argc + (2 * collcount) + 13) * sizeof(char*)); - fd = open(me, O_RDONLY, 0); + fd = open(embedding_me, O_RDONLY, 0); lseek(fd, prog_end, SEEK_SET); { int expected_length = end - prog_end; if (expected_length != read(fd, data, expected_length)) { - printf("read failed to read all %i bytes from file %s\n", expected_length, me); + printf("read failed to read all %i bytes from file %s\n", expected_length, embedding_me); abort(); } } @@ -548,9 +567,11 @@ int main(int argc, char **argv) new_argv[argpos++] = absolutize(_configdir + _configdir_offset, me); if (fix_argv) { - /* next three args are "-k" and numbers; fix - the numbers to match start, decl_end, and prog_end */ - fix_argv = argpos + 1; + /* next four args are "-k" and numbers; leave room to insert the + filename in place of "-k", and fix the numbers to match start, + decl_end, and prog_end */ + new_argv[argpos++] = "-Y"; + fix_argv = argpos; } /* Add built-in flags: */ @@ -567,9 +588,10 @@ int main(int argc, char **argv) new_argv[argpos] = NULL; if (fix_argv) { - new_argv[fix_argv] = num_to_string(start); - new_argv[fix_argv+1] = num_to_string(decl_end); - new_argv[fix_argv+2] = num_to_string(prog_end); + new_argv[fix_argv] = embedding_me; + new_argv[fix_argv+1] = num_to_string(start); + new_argv[fix_argv+2] = num_to_string(decl_end); + new_argv[fix_argv+3] = num_to_string(prog_end); } /* Execute the original binary: */