diff options
| author | Eli Zaretskii | 2021-04-17 16:49:16 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2021-04-17 16:49:16 +0300 |
| commit | 9aa5203b542f0c9ea7d074c6cfde2a28b466f5d1 (patch) | |
| tree | 0eb9faeeb7b1881aafca2795036e1989dae9d35d /src | |
| parent | f9c1008ced59f003d48dd7be39e9ec4aa0f02484 (diff) | |
| download | emacs-9aa5203b542f0c9ea7d074c6cfde2a28b466f5d1.tar.gz emacs-9aa5203b542f0c9ea7d074c6cfde2a28b466f5d1.zip | |
Fix loading *.eln files when Emacs is installed via symlinks
* src/emacs.c (real_filename, set_invocation_vars)
(init_vars_for_load): Functions deleted; callers adjusted.
(init_cmdargs): Put back all the code which was extracted into
set_invocation_vars.
(load_pdump_find_executable): Make sure the return value has any
symlinks in it expanded.
(load_pdump): Accept only 2 arguments, not 3. Determine both the
file name of the Emacs executable and of the dump file in
synchronized manner, so that if we decided to look for the dump
file in its hardcoded installation directory, the directory of the
Emacs executable will also be where we expect it to be installed.
Pass only 2 arguments to pdumper_load. (Bug#47800) (Bug#44128)
* src/pdumper.c (dump_do_dump_relocation): Use emacs_execdir
instead of Vinvocation_directory to produce absolute file names of
*.eln files that are recorded in the pdumper file. Pass the full
.eln file name to fixup_eln_load_path.
(pdumper_set_emacs_execdir) [HAVE_NATIVE_COMP]: New function.
(pdumper_load) [HAVE_NATIVE_COMP]: Call pdumper_set_emacs_execdir.
* src/comp.c (fixup_eln_load_path): Use Fsubstring_no_properties
instead of Fsubstring. No need to cons a file name, as the caller
already did that. Use explicit const string to avoid "magic"
values.
* lisp/startup.el (normal-top-level): Use expand-file-name instead
of concat. Decode comp-eln-load-path and expand-file-name its
members.
Diffstat (limited to 'src')
| -rw-r--r-- | src/comp.c | 35 | ||||
| -rw-r--r-- | src/comp.h | 6 | ||||
| -rw-r--r-- | src/emacs.c | 223 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/pdumper.c | 93 | ||||
| -rw-r--r-- | src/pdumper.h | 3 |
6 files changed, 188 insertions, 173 deletions
diff --git a/src/comp.c b/src/comp.c index c4b9b4b6c10..50947316df8 100644 --- a/src/comp.c +++ b/src/comp.c | |||
| @@ -4749,29 +4749,30 @@ maybe_defer_native_compilation (Lisp_Object function_name, | |||
| 4749 | /* Functions used to load eln files. */ | 4749 | /* Functions used to load eln files. */ |
| 4750 | /**************************************/ | 4750 | /**************************************/ |
| 4751 | 4751 | ||
| 4752 | /* Fixup the system eln-cache dir. This is the last entry in | 4752 | /* Fixup the system eln-cache directory, which is the last entry in |
| 4753 | `comp-eln-load-path'. */ | 4753 | `comp-eln-load-path'. Argument is a .eln file in that directory. */ |
| 4754 | void | 4754 | void |
| 4755 | fixup_eln_load_path (Lisp_Object eln_filename) | 4755 | fixup_eln_load_path (Lisp_Object eln_filename) |
| 4756 | { | 4756 | { |
| 4757 | Lisp_Object last_cell = Qnil; | 4757 | Lisp_Object last_cell = Qnil; |
| 4758 | Lisp_Object tmp = Vcomp_eln_load_path; | 4758 | Lisp_Object tem = Vcomp_eln_load_path; |
| 4759 | FOR_EACH_TAIL (tmp) | 4759 | FOR_EACH_TAIL (tem) |
| 4760 | if (CONSP (tmp)) | 4760 | if (CONSP (tem)) |
| 4761 | last_cell = tmp; | 4761 | last_cell = tem; |
| 4762 | 4762 | ||
| 4763 | Lisp_Object eln_cache_sys = | 4763 | const char preloaded[] = "preloaded"; |
| 4764 | Ffile_name_directory (concat2 (Vinvocation_directory, | 4764 | ptrdiff_t preloaded_len = sizeof (preloaded) - 1; |
| 4765 | eln_filename)); | 4765 | Lisp_Object eln_cache_sys = Ffile_name_directory (eln_filename); |
| 4766 | bool preloaded = | 4766 | bool preloaded_p = |
| 4767 | !NILP (Fequal (Fsubstring (eln_cache_sys, make_fixnum (-10), | 4767 | !NILP (Fequal (Fsubstring_no_properties (eln_cache_sys, |
| 4768 | make_fixnum (-1)), | 4768 | make_fixnum (-preloaded_len - 1), |
| 4769 | build_string ("preloaded"))); | 4769 | make_fixnum (-1)), |
| 4770 | build_string (preloaded))); | ||
| 4770 | /* One or two directories up... */ | 4771 | /* One or two directories up... */ |
| 4771 | for (int i = 0; i < (preloaded ? 2 : 1); i++) | 4772 | for (int i = 0; i < (preloaded_p ? 2 : 1); i++) |
| 4772 | eln_cache_sys = | 4773 | eln_cache_sys = |
| 4773 | Ffile_name_directory (Fsubstring (eln_cache_sys, Qnil, | 4774 | Ffile_name_directory (Fsubstring_no_properties (eln_cache_sys, Qnil, |
| 4774 | make_fixnum (-1))); | 4775 | make_fixnum (-1))); |
| 4775 | Fsetcar (last_cell, eln_cache_sys); | 4776 | Fsetcar (last_cell, eln_cache_sys); |
| 4776 | } | 4777 | } |
| 4777 | 4778 | ||
diff --git a/src/comp.h b/src/comp.h index e17b843d139..03d22dfaa0e 100644 --- a/src/comp.h +++ b/src/comp.h | |||
| @@ -34,7 +34,11 @@ enum { | |||
| 34 | struct Lisp_Native_Comp_Unit | 34 | struct Lisp_Native_Comp_Unit |
| 35 | { | 35 | { |
| 36 | union vectorlike_header header; | 36 | union vectorlike_header header; |
| 37 | /* Original eln file loaded. */ | 37 | /* The original eln file loaded. In the pdumper file this is stored |
| 38 | as a cons cell of 2 alternative file names: the car is the | ||
| 39 | filename relative to the directory of an installed binary, the | ||
| 40 | cdr is the filename relative to the directory of an uninstalled | ||
| 41 | binary. This is arranged in loadup.el. */ | ||
| 38 | Lisp_Object file; | 42 | Lisp_Object file; |
| 39 | Lisp_Object optimize_qualities; | 43 | Lisp_Object optimize_qualities; |
| 40 | /* Guard anonymous lambdas against Garbage Collection and serve | 44 | /* Guard anonymous lambdas against Garbage Collection and serve |
diff --git a/src/emacs.c b/src/emacs.c index a2565645c6c..d27b1c1351d 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -440,53 +440,33 @@ terminate_due_to_signal (int sig, int backtrace_limit) | |||
| 440 | exit (1); | 440 | exit (1); |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | /* Return the real filename following symlinks in case. | 443 | |
| 444 | The caller should deallocate the returned buffer. */ | 444 | /* Code for dealing with Lisp access to the Unix command line. */ |
| 445 | |||
| 446 | static char * | ||
| 447 | real_filename (char *filename) | ||
| 448 | { | ||
| 449 | char *real_name; | ||
| 450 | #ifdef WINDOWSNT | ||
| 451 | /* w32_my_exename resolves symlinks internally, so no need to | ||
| 452 | call realpath. */ | ||
| 453 | real_name = xstrdup (filename); | ||
| 454 | #else | ||
| 455 | real_name = realpath (filename, NULL); | ||
| 456 | if (!real_name) | ||
| 457 | fatal ("could not resolve realpath of \"%s\": %s", | ||
| 458 | filename, strerror (errno)); | ||
| 459 | #endif | ||
| 460 | return real_name; | ||
| 461 | } | ||
| 462 | |||
| 463 | /* Set `invocation-name' `invocation-directory'. */ | ||
| 464 | |||
| 465 | static void | 445 | static void |
| 466 | set_invocation_vars (char *argv0, char const *original_pwd) | 446 | init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd) |
| 467 | { | 447 | { |
| 468 | Lisp_Object raw_name, handler; | 448 | int i; |
| 449 | Lisp_Object name, dir, handler; | ||
| 450 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 451 | Lisp_Object raw_name; | ||
| 469 | AUTO_STRING (slash_colon, "/:"); | 452 | AUTO_STRING (slash_colon, "/:"); |
| 470 | 453 | ||
| 454 | initial_argv = argv; | ||
| 455 | initial_argc = argc; | ||
| 456 | |||
| 471 | #ifdef WINDOWSNT | 457 | #ifdef WINDOWSNT |
| 472 | /* Must use argv0 converted to UTF-8, as it begets many standard | 458 | /* Must use argv[0] converted to UTF-8, as it begets many standard |
| 473 | file and directory names. */ | 459 | file and directory names. */ |
| 474 | { | 460 | { |
| 475 | char argv0_1[MAX_UTF8_PATH]; | 461 | char argv0[MAX_UTF8_PATH]; |
| 476 | 462 | ||
| 477 | /* Avoid calling 'openp' below, as we aren't ready for that yet: | 463 | if (filename_from_ansi (argv[0], argv0) == 0) |
| 478 | emacs_dir is not yet defined in the environment, and therefore | ||
| 479 | emacs_root_dir, called by expand-file-name, will abort. */ | ||
| 480 | if (!IS_ABSOLUTE_FILE_NAME (argv0)) | ||
| 481 | argv0 = w32_my_exename (); | ||
| 482 | |||
| 483 | if (filename_from_ansi (argv0, argv0_1) == 0) | ||
| 484 | raw_name = build_unibyte_string (argv0_1); | ||
| 485 | else | ||
| 486 | raw_name = build_unibyte_string (argv0); | 464 | raw_name = build_unibyte_string (argv0); |
| 465 | else | ||
| 466 | raw_name = build_unibyte_string (argv[0]); | ||
| 487 | } | 467 | } |
| 488 | #else | 468 | #else |
| 489 | raw_name = build_unibyte_string (argv0); | 469 | raw_name = build_unibyte_string (argv[0]); |
| 490 | #endif | 470 | #endif |
| 491 | 471 | ||
| 492 | /* Add /: to the front of the name | 472 | /* Add /: to the front of the name |
| @@ -495,26 +475,16 @@ set_invocation_vars (char *argv0, char const *original_pwd) | |||
| 495 | if (! NILP (handler)) | 475 | if (! NILP (handler)) |
| 496 | raw_name = concat2 (slash_colon, raw_name); | 476 | raw_name = concat2 (slash_colon, raw_name); |
| 497 | 477 | ||
| 498 | char *filename = real_filename (SSDATA (raw_name)); | ||
| 499 | raw_name = build_unibyte_string (filename); | ||
| 500 | xfree (filename); | ||
| 501 | |||
| 502 | Vinvocation_name = Ffile_name_nondirectory (raw_name); | 478 | Vinvocation_name = Ffile_name_nondirectory (raw_name); |
| 503 | Vinvocation_directory = Ffile_name_directory (raw_name); | 479 | Vinvocation_directory = Ffile_name_directory (raw_name); |
| 504 | 480 | ||
| 505 | #ifdef WINDOWSNT | 481 | /* If we got no directory in argv[0], search PATH to find where |
| 506 | eassert (!NILP (Vinvocation_directory) | ||
| 507 | && !NILP (Ffile_name_absolute_p (Vinvocation_directory))); | ||
| 508 | #endif | ||
| 509 | |||
| 510 | /* If we got no directory in argv0, search PATH to find where | ||
| 511 | Emacs actually came from. */ | 482 | Emacs actually came from. */ |
| 512 | if (NILP (Vinvocation_directory)) | 483 | if (NILP (Vinvocation_directory)) |
| 513 | { | 484 | { |
| 514 | Lisp_Object found; | 485 | Lisp_Object found; |
| 515 | int yes = | 486 | int yes = openp (Vexec_path, Vinvocation_name, Vexec_suffixes, |
| 516 | openp (Vexec_path, Vinvocation_name, Vexec_suffixes, &found, | 487 | &found, make_fixnum (X_OK), false, false); |
| 517 | make_fixnum (X_OK), false, false); | ||
| 518 | if (yes == 1) | 488 | if (yes == 1) |
| 519 | { | 489 | { |
| 520 | /* Add /: to the front of the name | 490 | /* Add /: to the front of the name |
| @@ -536,38 +506,6 @@ set_invocation_vars (char *argv0, char const *original_pwd) | |||
| 536 | 506 | ||
| 537 | Vinvocation_directory = Fexpand_file_name (Vinvocation_directory, odir); | 507 | Vinvocation_directory = Fexpand_file_name (Vinvocation_directory, odir); |
| 538 | } | 508 | } |
| 539 | } | ||
| 540 | |||
| 541 | /* Initialize a number of variables (ultimately | ||
| 542 | 'Vinvocation_directory') needed by pdumper to complete native code | ||
| 543 | load. */ | ||
| 544 | |||
| 545 | void | ||
| 546 | init_vars_for_load (char *argv0, char const *original_pwd) | ||
| 547 | { | ||
| 548 | /* This function is called from within pdumper while loading (as | ||
| 549 | soon as we are able to allocate) or later during boot if pdumper | ||
| 550 | is not used. No need to run it twice. */ | ||
| 551 | static bool double_run_guard; | ||
| 552 | if (double_run_guard) | ||
| 553 | return; | ||
| 554 | double_run_guard = true; | ||
| 555 | |||
| 556 | init_callproc_1 (); /* Must precede init_cmdargs and init_sys_modes. */ | ||
| 557 | set_invocation_vars (argv0, original_pwd); | ||
| 558 | } | ||
| 559 | |||
| 560 | |||
| 561 | /* Code for dealing with Lisp access to the Unix command line. */ | ||
| 562 | static void | ||
| 563 | init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd) | ||
| 564 | { | ||
| 565 | int i; | ||
| 566 | Lisp_Object name, dir; | ||
| 567 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 568 | |||
| 569 | initial_argv = argv; | ||
| 570 | initial_argc = argc; | ||
| 571 | 509 | ||
| 572 | Vinstallation_directory = Qnil; | 510 | Vinstallation_directory = Qnil; |
| 573 | 511 | ||
| @@ -801,6 +739,8 @@ load_pdump_find_executable (char const *argv0, ptrdiff_t *candidate_size) | |||
| 801 | implementation of malloc, since the caller calls our free. */ | 739 | implementation of malloc, since the caller calls our free. */ |
| 802 | #ifdef WINDOWSNT | 740 | #ifdef WINDOWSNT |
| 803 | char *prog_fname = w32_my_exename (); | 741 | char *prog_fname = w32_my_exename (); |
| 742 | if (prog_fname) | ||
| 743 | *candidate_size = strlen (prog_fname) + 1; | ||
| 804 | return prog_fname ? xstrdup (prog_fname) : NULL; | 744 | return prog_fname ? xstrdup (prog_fname) : NULL; |
| 805 | #else /* !WINDOWSNT */ | 745 | #else /* !WINDOWSNT */ |
| 806 | char *candidate = NULL; | 746 | char *candidate = NULL; |
| @@ -846,7 +786,19 @@ load_pdump_find_executable (char const *argv0, ptrdiff_t *candidate_size) | |||
| 846 | struct stat st; | 786 | struct stat st; |
| 847 | if (file_access_p (candidate, X_OK) | 787 | if (file_access_p (candidate, X_OK) |
| 848 | && stat (candidate, &st) == 0 && S_ISREG (st.st_mode)) | 788 | && stat (candidate, &st) == 0 && S_ISREG (st.st_mode)) |
| 849 | return candidate; | 789 | { |
| 790 | /* People put on PATH a symlink to the real Emacs | ||
| 791 | executable, with all the auxiliary files where the real | ||
| 792 | executable lives. Support that. */ | ||
| 793 | if (lstat (candidate, &st) == 0 && S_ISLNK (st.st_mode)) | ||
| 794 | { | ||
| 795 | char *real_name = realpath (candidate, NULL); | ||
| 796 | |||
| 797 | if (real_name) | ||
| 798 | return real_name; | ||
| 799 | } | ||
| 800 | return candidate; | ||
| 801 | } | ||
| 850 | *candidate = '\0'; | 802 | *candidate = '\0'; |
| 851 | } | 803 | } |
| 852 | while (*path++ != '\0'); | 804 | while (*path++ != '\0'); |
| @@ -856,10 +808,11 @@ load_pdump_find_executable (char const *argv0, ptrdiff_t *candidate_size) | |||
| 856 | } | 808 | } |
| 857 | 809 | ||
| 858 | static void | 810 | static void |
| 859 | load_pdump (int argc, char **argv, char const *original_pwd) | 811 | load_pdump (int argc, char **argv) |
| 860 | { | 812 | { |
| 861 | const char *const suffix = ".pdmp"; | 813 | const char *const suffix = ".pdmp"; |
| 862 | int result; | 814 | int result; |
| 815 | char *emacs_executable = argv[0]; | ||
| 863 | const char *strip_suffix = | 816 | const char *strip_suffix = |
| 864 | #if defined DOS_NT || defined CYGWIN | 817 | #if defined DOS_NT || defined CYGWIN |
| 865 | ".exe" | 818 | ".exe" |
| @@ -889,9 +842,19 @@ load_pdump (int argc, char **argv, char const *original_pwd) | |||
| 889 | skip_args++; | 842 | skip_args++; |
| 890 | } | 843 | } |
| 891 | 844 | ||
| 845 | /* Where's our executable? */ | ||
| 846 | ptrdiff_t bufsize, exec_bufsize; | ||
| 847 | emacs_executable = load_pdump_find_executable (argv[0], &bufsize); | ||
| 848 | exec_bufsize = bufsize; | ||
| 849 | |||
| 850 | /* If we couldn't find our executable, go straight to looking for | ||
| 851 | the dump in the hardcoded location. */ | ||
| 852 | if (!(emacs_executable && *emacs_executable)) | ||
| 853 | goto hardcoded; | ||
| 854 | |||
| 892 | if (dump_file) | 855 | if (dump_file) |
| 893 | { | 856 | { |
| 894 | result = pdumper_load (dump_file, argv[0], original_pwd); | 857 | result = pdumper_load (dump_file, emacs_executable); |
| 895 | 858 | ||
| 896 | if (result != PDUMPER_LOAD_SUCCESS) | 859 | if (result != PDUMPER_LOAD_SUCCESS) |
| 897 | fatal ("could not load dump file \"%s\": %s", | 860 | fatal ("could not load dump file \"%s\": %s", |
| @@ -905,42 +868,29 @@ load_pdump (int argc, char **argv, char const *original_pwd) | |||
| 905 | so we can't use decode_env_path. We're working in whatever | 868 | so we can't use decode_env_path. We're working in whatever |
| 906 | encoding the system natively uses for filesystem access, so | 869 | encoding the system natively uses for filesystem access, so |
| 907 | there's no need for character set conversion. */ | 870 | there's no need for character set conversion. */ |
| 908 | ptrdiff_t bufsize; | 871 | ptrdiff_t exenamelen = strlen (emacs_executable); |
| 909 | dump_file = load_pdump_find_executable (argv[0], &bufsize); | 872 | if (strip_suffix) |
| 910 | 873 | { | |
| 911 | /* If we couldn't find our executable, go straight to looking for | 874 | ptrdiff_t strip_suffix_length = strlen (strip_suffix); |
| 912 | the dump in the hardcoded location. */ | 875 | ptrdiff_t prefix_length = exenamelen - strip_suffix_length; |
| 913 | if (dump_file && *dump_file) | 876 | if (0 <= prefix_length |
| 914 | { | 877 | && !memcmp (&emacs_executable[prefix_length], strip_suffix, |
| 915 | char *real_exename = real_filename (dump_file); | 878 | strip_suffix_length)) |
| 916 | xfree (dump_file); | 879 | exenamelen = prefix_length; |
| 917 | dump_file = real_exename; | 880 | } |
| 918 | ptrdiff_t exenamelen = strlen (dump_file); | 881 | ptrdiff_t needed = exenamelen + strlen (suffix) + 1; |
| 919 | #ifndef WINDOWSNT | 882 | dump_file = xpalloc (NULL, &bufsize, needed - bufsize, -1, 1); |
| 920 | bufsize = exenamelen + 1; | 883 | memcpy (dump_file, emacs_executable, exenamelen); |
| 921 | #endif | 884 | strcpy (dump_file + exenamelen, suffix); |
| 922 | if (strip_suffix) | 885 | result = pdumper_load (dump_file, emacs_executable); |
| 923 | { | 886 | if (result == PDUMPER_LOAD_SUCCESS) |
| 924 | ptrdiff_t strip_suffix_length = strlen (strip_suffix); | 887 | goto out; |
| 925 | ptrdiff_t prefix_length = exenamelen - strip_suffix_length; | 888 | |
| 926 | if (0 <= prefix_length | 889 | if (result != PDUMPER_LOAD_FILE_NOT_FOUND) |
| 927 | && !memcmp (&dump_file[prefix_length], strip_suffix, | 890 | fatal ("could not load dump file \"%s\": %s", |
| 928 | strip_suffix_length)) | 891 | dump_file, dump_error_to_string (result)); |
| 929 | exenamelen = prefix_length; | 892 | |
| 930 | } | 893 | hardcoded: |
| 931 | ptrdiff_t needed = exenamelen + strlen (suffix) + 1; | ||
| 932 | if (bufsize < needed) | ||
| 933 | dump_file = xpalloc (dump_file, &bufsize, needed - bufsize, -1, 1); | ||
| 934 | strcpy (dump_file + exenamelen, suffix); | ||
| 935 | result = pdumper_load (dump_file, argv[0], original_pwd); | ||
| 936 | if (result == PDUMPER_LOAD_SUCCESS) | ||
| 937 | goto out; | ||
| 938 | |||
| 939 | if (result != PDUMPER_LOAD_FILE_NOT_FOUND) | ||
| 940 | fatal ("could not load dump file \"%s\": %s", | ||
| 941 | dump_file, dump_error_to_string (result)); | ||
| 942 | } | ||
| 943 | |||
| 944 | #ifdef WINDOWSNT | 894 | #ifdef WINDOWSNT |
| 945 | /* On MS-Windows, PATH_EXEC normally starts with a literal | 895 | /* On MS-Windows, PATH_EXEC normally starts with a literal |
| 946 | "%emacs_dir%", so it will never work without some tweaking. */ | 896 | "%emacs_dir%", so it will never work without some tweaking. */ |
| @@ -951,11 +901,11 @@ load_pdump (int argc, char **argv, char const *original_pwd) | |||
| 951 | "emacs.pdmp" so that the Emacs binary still works if the user | 901 | "emacs.pdmp" so that the Emacs binary still works if the user |
| 952 | copies and renames it. */ | 902 | copies and renames it. */ |
| 953 | const char *argv0_base = "emacs"; | 903 | const char *argv0_base = "emacs"; |
| 954 | ptrdiff_t needed = (strlen (path_exec) | 904 | needed = (strlen (path_exec) |
| 955 | + 1 | 905 | + 1 |
| 956 | + strlen (argv0_base) | 906 | + strlen (argv0_base) |
| 957 | + strlen (suffix) | 907 | + strlen (suffix) |
| 958 | + 1); | 908 | + 1); |
| 959 | if (bufsize < needed) | 909 | if (bufsize < needed) |
| 960 | { | 910 | { |
| 961 | xfree (dump_file); | 911 | xfree (dump_file); |
| @@ -963,7 +913,19 @@ load_pdump (int argc, char **argv, char const *original_pwd) | |||
| 963 | } | 913 | } |
| 964 | sprintf (dump_file, "%s%c%s%s", | 914 | sprintf (dump_file, "%s%c%s%s", |
| 965 | path_exec, DIRECTORY_SEP, argv0_base, suffix); | 915 | path_exec, DIRECTORY_SEP, argv0_base, suffix); |
| 966 | result = pdumper_load (dump_file, argv[0], original_pwd); | 916 | /* Assume the Emacs binary lives in a sibling directory as set up by |
| 917 | the default installation configuration. */ | ||
| 918 | const char *go_up = "../../../../bin/"; | ||
| 919 | needed += strlen (strip_suffix) - strlen (suffix) + strlen (go_up); | ||
| 920 | if (exec_bufsize < needed) | ||
| 921 | { | ||
| 922 | xfree (emacs_executable); | ||
| 923 | emacs_executable = xpalloc (NULL, &exec_bufsize, needed - exec_bufsize, | ||
| 924 | -1, 1); | ||
| 925 | } | ||
| 926 | sprintf (emacs_executable, "%s%c%s%s%s", | ||
| 927 | path_exec, DIRECTORY_SEP, go_up, argv0_base, strip_suffix); | ||
| 928 | result = pdumper_load (dump_file, emacs_executable); | ||
| 967 | 929 | ||
| 968 | if (result == PDUMPER_LOAD_FILE_NOT_FOUND) | 930 | if (result == PDUMPER_LOAD_FILE_NOT_FOUND) |
| 969 | { | 931 | { |
| @@ -998,7 +960,7 @@ load_pdump (int argc, char **argv, char const *original_pwd) | |||
| 998 | #endif | 960 | #endif |
| 999 | sprintf (dump_file, "%s%c%s%s", | 961 | sprintf (dump_file, "%s%c%s%s", |
| 1000 | path_exec, DIRECTORY_SEP, argv0_base, suffix); | 962 | path_exec, DIRECTORY_SEP, argv0_base, suffix); |
| 1001 | result = pdumper_load (dump_file, argv[0], original_pwd); | 963 | result = pdumper_load (dump_file, emacs_executable); |
| 1002 | } | 964 | } |
| 1003 | 965 | ||
| 1004 | if (result != PDUMPER_LOAD_SUCCESS) | 966 | if (result != PDUMPER_LOAD_SUCCESS) |
| @@ -1010,6 +972,7 @@ load_pdump (int argc, char **argv, char const *original_pwd) | |||
| 1010 | 972 | ||
| 1011 | out: | 973 | out: |
| 1012 | xfree (dump_file); | 974 | xfree (dump_file); |
| 975 | xfree (emacs_executable); | ||
| 1013 | } | 976 | } |
| 1014 | #endif /* HAVE_PDUMPER */ | 977 | #endif /* HAVE_PDUMPER */ |
| 1015 | 978 | ||
| @@ -1320,10 +1283,9 @@ main (int argc, char **argv) | |||
| 1320 | w32_init_main_thread (); | 1283 | w32_init_main_thread (); |
| 1321 | #endif | 1284 | #endif |
| 1322 | 1285 | ||
| 1323 | emacs_wd = emacs_get_current_dir_name (); | ||
| 1324 | #ifdef HAVE_PDUMPER | 1286 | #ifdef HAVE_PDUMPER |
| 1325 | if (attempt_load_pdump) | 1287 | if (attempt_load_pdump) |
| 1326 | load_pdump (argc, argv, emacs_wd); | 1288 | load_pdump (argc, argv); |
| 1327 | #endif | 1289 | #endif |
| 1328 | 1290 | ||
| 1329 | argc = maybe_disable_address_randomization (argc, argv); | 1291 | argc = maybe_disable_address_randomization (argc, argv); |
| @@ -1395,6 +1357,7 @@ main (int argc, char **argv) | |||
| 1395 | exit (0); | 1357 | exit (0); |
| 1396 | } | 1358 | } |
| 1397 | 1359 | ||
| 1360 | emacs_wd = emacs_get_current_dir_name (); | ||
| 1398 | #ifdef HAVE_PDUMPER | 1361 | #ifdef HAVE_PDUMPER |
| 1399 | if (dumped_with_pdumper_p ()) | 1362 | if (dumped_with_pdumper_p ()) |
| 1400 | pdumper_record_wd (emacs_wd); | 1363 | pdumper_record_wd (emacs_wd); |
| @@ -2038,8 +2001,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2038 | /* Init buffer storage and default directory of main buffer. */ | 2001 | /* Init buffer storage and default directory of main buffer. */ |
| 2039 | init_buffer (); | 2002 | init_buffer (); |
| 2040 | 2003 | ||
| 2041 | init_vars_for_load (argv[0], original_pwd); | ||
| 2042 | |||
| 2043 | /* Must precede init_lread. */ | 2004 | /* Must precede init_lread. */ |
| 2044 | init_cmdargs (argc, argv, skip_args, original_pwd); | 2005 | init_cmdargs (argc, argv, skip_args, original_pwd); |
| 2045 | 2006 | ||
diff --git a/src/lisp.h b/src/lisp.h index 474e49c8e1e..f83c55f827d 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4450,7 +4450,6 @@ extern bool display_arg; | |||
| 4450 | extern Lisp_Object decode_env_path (const char *, const char *, bool); | 4450 | extern Lisp_Object decode_env_path (const char *, const char *, bool); |
| 4451 | extern Lisp_Object empty_unibyte_string, empty_multibyte_string; | 4451 | extern Lisp_Object empty_unibyte_string, empty_multibyte_string; |
| 4452 | extern AVOID terminate_due_to_signal (int, int); | 4452 | extern AVOID terminate_due_to_signal (int, int); |
| 4453 | extern void init_vars_for_load (char *, char const *); | ||
| 4454 | #ifdef WINDOWSNT | 4453 | #ifdef WINDOWSNT |
| 4455 | extern Lisp_Object Vlibrary_cache; | 4454 | extern Lisp_Object Vlibrary_cache; |
| 4456 | #endif | 4455 | #endif |
diff --git a/src/pdumper.c b/src/pdumper.c index dc893c59bfa..c9285ddbc78 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -4356,6 +4356,16 @@ pdumper_remember_lv_ptr_raw_impl (void *ptr, enum Lisp_Type type) | |||
| 4356 | } | 4356 | } |
| 4357 | 4357 | ||
| 4358 | 4358 | ||
| 4359 | #ifdef HAVE_NATIVE_COMP | ||
| 4360 | /* This records the directory where the Emacs executable lives, to be | ||
| 4361 | used for locating the native-lisp directory from which we need to | ||
| 4362 | load the preloaded *.eln files. See pdumper_set_emacs_execdir | ||
| 4363 | below. */ | ||
| 4364 | static char *emacs_execdir; | ||
| 4365 | static ptrdiff_t execdir_size; | ||
| 4366 | static ptrdiff_t execdir_len; | ||
| 4367 | #endif | ||
| 4368 | |||
| 4359 | /* Dump runtime */ | 4369 | /* Dump runtime */ |
| 4360 | enum dump_memory_protection | 4370 | enum dump_memory_protection |
| 4361 | { | 4371 | { |
| @@ -5269,35 +5279,54 @@ dump_do_dump_relocation (const uintptr_t dump_base, | |||
| 5269 | struct Lisp_Native_Comp_Unit *comp_u = | 5279 | struct Lisp_Native_Comp_Unit *comp_u = |
| 5270 | dump_ptr (dump_base, reloc_offset); | 5280 | dump_ptr (dump_base, reloc_offset); |
| 5271 | comp_u->lambda_gc_guard_h = CALLN (Fmake_hash_table, QCtest, Qeq); | 5281 | comp_u->lambda_gc_guard_h = CALLN (Fmake_hash_table, QCtest, Qeq); |
| 5272 | if (!CONSP (comp_u->file)) | 5282 | if (STRINGP (comp_u->file)) |
| 5273 | error ("Trying to load incoherent dumped eln file %s", | 5283 | error ("Trying to load incoherent dumped eln file %s", |
| 5274 | SSDATA (comp_u->file)); | 5284 | SSDATA (comp_u->file)); |
| 5275 | 5285 | ||
| 5286 | /* emacs_execdir is always unibyte, but the file names in | ||
| 5287 | comp_u->file could be multibyte, so we need to encode | ||
| 5288 | them. */ | ||
| 5289 | Lisp_Object cu_file1 = ENCODE_FILE (XCAR (comp_u->file)); | ||
| 5290 | Lisp_Object cu_file2 = ENCODE_FILE (XCDR (comp_u->file)); | ||
| 5291 | ptrdiff_t fn1_len = SBYTES (cu_file1), fn2_len = SBYTES (cu_file2); | ||
| 5292 | Lisp_Object eln_fname; | ||
| 5293 | char *fndata; | ||
| 5294 | |||
| 5276 | /* Check just once if this is a local build or Emacs was installed. */ | 5295 | /* Check just once if this is a local build or Emacs was installed. */ |
| 5296 | /* Can't use expand-file-name here, because we are too early | ||
| 5297 | in the startup, and we will crash at least on WINDOWSNT. */ | ||
| 5277 | if (installation_state == UNKNOWN) | 5298 | if (installation_state == UNKNOWN) |
| 5278 | { | 5299 | { |
| 5279 | /* Can't use expand-file-name here, because we are too | 5300 | eln_fname = make_uninit_string (execdir_len + fn1_len); |
| 5280 | early in the startup, and we will crash at least on | 5301 | fndata = SSDATA (eln_fname); |
| 5281 | WINDOWSNT. */ | 5302 | memcpy (fndata, emacs_execdir, execdir_len); |
| 5282 | Lisp_Object fname = | 5303 | memcpy (fndata + execdir_len, SSDATA (cu_file1), fn1_len); |
| 5283 | concat2 (Vinvocation_directory, XCAR (comp_u->file)); | 5304 | if (file_access_p (fndata, F_OK)) |
| 5284 | if (file_access_p (SSDATA (ENCODE_FILE (fname)), F_OK)) | 5305 | installation_state = INSTALLED; |
| 5285 | { | ||
| 5286 | installation_state = INSTALLED; | ||
| 5287 | fixup_eln_load_path (XCAR (comp_u->file)); | ||
| 5288 | } | ||
| 5289 | else | 5306 | else |
| 5290 | { | 5307 | { |
| 5308 | eln_fname = make_uninit_string (execdir_len + fn2_len); | ||
| 5309 | fndata = SSDATA (eln_fname); | ||
| 5310 | memcpy (fndata, emacs_execdir, execdir_len); | ||
| 5311 | memcpy (fndata + execdir_len, SSDATA (cu_file2), fn2_len); | ||
| 5291 | installation_state = LOCAL_BUILD; | 5312 | installation_state = LOCAL_BUILD; |
| 5292 | fixup_eln_load_path (XCDR (comp_u->file)); | ||
| 5293 | } | 5313 | } |
| 5314 | fixup_eln_load_path (eln_fname); | ||
| 5315 | } | ||
| 5316 | else | ||
| 5317 | { | ||
| 5318 | ptrdiff_t fn_len = | ||
| 5319 | installation_state == INSTALLED ? fn1_len : fn2_len; | ||
| 5320 | Lisp_Object cu_file = | ||
| 5321 | installation_state == INSTALLED ? cu_file1 : cu_file2; | ||
| 5322 | eln_fname = make_uninit_string (execdir_len + fn_len); | ||
| 5323 | fndata = SSDATA (eln_fname); | ||
| 5324 | memcpy (fndata, emacs_execdir, execdir_len); | ||
| 5325 | memcpy (fndata + execdir_len, SSDATA (cu_file), fn_len); | ||
| 5294 | } | 5326 | } |
| 5295 | 5327 | ||
| 5296 | comp_u->file = | 5328 | comp_u->file = eln_fname; |
| 5297 | concat2 (Vinvocation_directory, | 5329 | comp_u->handle = dynlib_open (SSDATA (eln_fname)); |
| 5298 | installation_state == INSTALLED | ||
| 5299 | ? XCAR (comp_u->file) : XCDR (comp_u->file)); | ||
| 5300 | comp_u->handle = dynlib_open (SSDATA (ENCODE_FILE (comp_u->file))); | ||
| 5301 | if (!comp_u->handle) | 5330 | if (!comp_u->handle) |
| 5302 | error ("%s", dynlib_error ()); | 5331 | error ("%s", dynlib_error ()); |
| 5303 | load_comp_unit (comp_u, true, false); | 5332 | load_comp_unit (comp_u, true, false); |
| @@ -5435,6 +5464,26 @@ dump_do_all_emacs_relocations (const struct dump_header *const header, | |||
| 5435 | dump_do_emacs_relocation (dump_base, r[i]); | 5464 | dump_do_emacs_relocation (dump_base, r[i]); |
| 5436 | } | 5465 | } |
| 5437 | 5466 | ||
| 5467 | #ifdef HAVE_NATIVE_COMP | ||
| 5468 | /* Compute and record the directory of the Emacs executable given the | ||
| 5469 | file name of that executable. */ | ||
| 5470 | static void | ||
| 5471 | pdumper_set_emacs_execdir (char *emacs_executable) | ||
| 5472 | { | ||
| 5473 | char *p = emacs_executable + strlen (emacs_executable); | ||
| 5474 | |||
| 5475 | while (p > emacs_executable | ||
| 5476 | && !IS_DIRECTORY_SEP (p[-1])) | ||
| 5477 | --p; | ||
| 5478 | eassert (p > emacs_executable); | ||
| 5479 | emacs_execdir = xpalloc (emacs_execdir, &execdir_size, | ||
| 5480 | p - emacs_executable + 1 - execdir_size, -1, 1); | ||
| 5481 | memcpy (emacs_execdir, emacs_executable, p - emacs_executable); | ||
| 5482 | execdir_len = p - emacs_executable; | ||
| 5483 | emacs_execdir[execdir_len] = '\0'; | ||
| 5484 | } | ||
| 5485 | #endif | ||
| 5486 | |||
| 5438 | enum dump_section | 5487 | enum dump_section |
| 5439 | { | 5488 | { |
| 5440 | DS_HOT, | 5489 | DS_HOT, |
| @@ -5451,7 +5500,7 @@ static Lisp_Object *pdumper_hashes = &zero_vector; | |||
| 5451 | N.B. We run very early in initialization, so we can't use lisp, | 5500 | N.B. We run very early in initialization, so we can't use lisp, |
| 5452 | unwinding, xmalloc, and so on. */ | 5501 | unwinding, xmalloc, and so on. */ |
| 5453 | int | 5502 | int |
| 5454 | pdumper_load (const char *dump_filename, char *argv0, char const *original_pwd) | 5503 | pdumper_load (const char *dump_filename, char *argv0) |
| 5455 | { | 5504 | { |
| 5456 | intptr_t dump_size; | 5505 | intptr_t dump_size; |
| 5457 | struct stat stat; | 5506 | struct stat stat; |
| @@ -5607,9 +5656,11 @@ pdumper_load (const char *dump_filename, char *argv0, char const *original_pwd) | |||
| 5607 | for (int i = 0; i < nr_dump_hooks; ++i) | 5656 | for (int i = 0; i < nr_dump_hooks; ++i) |
| 5608 | dump_hooks[i] (); | 5657 | dump_hooks[i] (); |
| 5609 | 5658 | ||
| 5610 | /* Once we can allocate and before loading .eln files we must set | 5659 | #ifdef HAVE_NATIVE_COMP |
| 5611 | Vinvocation_directory (.eln paths are relative to it). */ | 5660 | pdumper_set_emacs_execdir (argv0); |
| 5612 | init_vars_for_load (argv0, original_pwd); | 5661 | #else |
| 5662 | (void) argv0; | ||
| 5663 | #endif | ||
| 5613 | 5664 | ||
| 5614 | dump_do_all_dump_reloc_for_phase (header, dump_base, LATE_RELOCS); | 5665 | dump_do_all_dump_reloc_for_phase (header, dump_base, LATE_RELOCS); |
| 5615 | dump_do_all_dump_reloc_for_phase (header, dump_base, VERY_LATE_RELOCS); | 5666 | dump_do_all_dump_reloc_for_phase (header, dump_base, VERY_LATE_RELOCS); |
diff --git a/src/pdumper.h b/src/pdumper.h index 49e6739b0dc..deec9af046d 100644 --- a/src/pdumper.h +++ b/src/pdumper.h | |||
| @@ -140,8 +140,7 @@ enum pdumper_load_result | |||
| 140 | PDUMPER_LOAD_ERROR /* Must be last, as errno may be added. */ | 140 | PDUMPER_LOAD_ERROR /* Must be last, as errno may be added. */ |
| 141 | }; | 141 | }; |
| 142 | 142 | ||
| 143 | int pdumper_load (const char *dump_filename, char *argv0, | 143 | int pdumper_load (const char *dump_filename, char *argv0); |
| 144 | char const *original_pwd); | ||
| 145 | 144 | ||
| 146 | struct pdumper_loaded_dump | 145 | struct pdumper_loaded_dump |
| 147 | { | 146 | { |