exit (1);
}
-/* Return the real filename following symlinks in case.
- The caller should deallocate the returned buffer. */
-
-static char *
-real_filename (char *filename)
-{
- char *real_name;
-#ifdef WINDOWSNT
- /* w32_my_exename resolves symlinks internally, so no need to
- call realpath. */
- real_name = xstrdup (filename);
-#else
- real_name = realpath (filename, NULL);
- if (!real_name)
- fatal ("could not resolve realpath of \"%s\": %s",
- filename, strerror (errno));
-#endif
- return real_name;
-}
-
-/* Set `invocation-name' `invocation-directory'. */
-
+\f
+/* Code for dealing with Lisp access to the Unix command line. */
static void
-set_invocation_vars (char *argv0, char const *original_pwd)
+init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
{
- Lisp_Object raw_name, handler;
+ int i;
+ Lisp_Object name, dir, handler;
+ ptrdiff_t count = SPECPDL_INDEX ();
+ Lisp_Object raw_name;
AUTO_STRING (slash_colon, "/:");
+ initial_argv = argv;
+ initial_argc = argc;
+
#ifdef WINDOWSNT
- /* Must use argv0 converted to UTF-8, as it begets many standard
+ /* Must use argv[0] converted to UTF-8, as it begets many standard
file and directory names. */
{
- char argv0_1[MAX_UTF8_PATH];
+ char argv0[MAX_UTF8_PATH];
- /* Avoid calling 'openp' below, as we aren't ready for that yet:
- emacs_dir is not yet defined in the environment, and therefore
- emacs_root_dir, called by expand-file-name, will abort. */
- if (!IS_ABSOLUTE_FILE_NAME (argv0))
- argv0 = w32_my_exename ();
-
- if (filename_from_ansi (argv0, argv0_1) == 0)
- raw_name = build_unibyte_string (argv0_1);
- else
+ if (filename_from_ansi (argv[0], argv0) == 0)
raw_name = build_unibyte_string (argv0);
+ else
+ raw_name = build_unibyte_string (argv[0]);
}
#else
- raw_name = build_unibyte_string (argv0);
+ raw_name = build_unibyte_string (argv[0]);
#endif
/* Add /: to the front of the name
if (! NILP (handler))
raw_name = concat2 (slash_colon, raw_name);
- char *filename = real_filename (SSDATA (raw_name));
- raw_name = build_unibyte_string (filename);
- xfree (filename);
-
Vinvocation_name = Ffile_name_nondirectory (raw_name);
Vinvocation_directory = Ffile_name_directory (raw_name);
-#ifdef WINDOWSNT
- eassert (!NILP (Vinvocation_directory)
- && !NILP (Ffile_name_absolute_p (Vinvocation_directory)));
-#endif
-
- /* If we got no directory in argv0, search PATH to find where
+ /* If we got no directory in argv[0], search PATH to find where
Emacs actually came from. */
if (NILP (Vinvocation_directory))
{
Lisp_Object found;
- int yes =
- openp (Vexec_path, Vinvocation_name, Vexec_suffixes, &found,
- make_fixnum (X_OK), false, false);
+ int yes = openp (Vexec_path, Vinvocation_name, Vexec_suffixes,
+ &found, make_fixnum (X_OK), false, false);
if (yes == 1)
{
/* Add /: to the front of the name
Vinvocation_directory = Fexpand_file_name (Vinvocation_directory, odir);
}
-}
-
-/* Initialize a number of variables (ultimately
- 'Vinvocation_directory') needed by pdumper to complete native code
- load. */
-
-void
-init_vars_for_load (char *argv0, char const *original_pwd)
-{
- /* This function is called from within pdumper while loading (as
- soon as we are able to allocate) or later during boot if pdumper
- is not used. No need to run it twice. */
- static bool double_run_guard;
- if (double_run_guard)
- return;
- double_run_guard = true;
-
- init_callproc_1 (); /* Must precede init_cmdargs and init_sys_modes. */
- set_invocation_vars (argv0, original_pwd);
-}
-
-\f
-/* Code for dealing with Lisp access to the Unix command line. */
-static void
-init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
-{
- int i;
- Lisp_Object name, dir;
- ptrdiff_t count = SPECPDL_INDEX ();
-
- initial_argv = argv;
- initial_argc = argc;
Vinstallation_directory = Qnil;
implementation of malloc, since the caller calls our free. */
#ifdef WINDOWSNT
char *prog_fname = w32_my_exename ();
+ if (prog_fname)
+ *candidate_size = strlen (prog_fname) + 1;
return prog_fname ? xstrdup (prog_fname) : NULL;
#else /* !WINDOWSNT */
char *candidate = NULL;
struct stat st;
if (file_access_p (candidate, X_OK)
&& stat (candidate, &st) == 0 && S_ISREG (st.st_mode))
- return candidate;
+ {
+ /* People put on PATH a symlink to the real Emacs
+ executable, with all the auxiliary files where the real
+ executable lives. Support that. */
+ if (lstat (candidate, &st) == 0 && S_ISLNK (st.st_mode))
+ {
+ char *real_name = realpath (candidate, NULL);
+
+ if (real_name)
+ return real_name;
+ }
+ return candidate;
+ }
*candidate = '\0';
}
while (*path++ != '\0');
}
static void
-load_pdump (int argc, char **argv, char const *original_pwd)
+load_pdump (int argc, char **argv)
{
const char *const suffix = ".pdmp";
int result;
+ char *emacs_executable = argv[0];
const char *strip_suffix =
#if defined DOS_NT || defined CYGWIN
".exe"
skip_args++;
}
+ /* Where's our executable? */
+ ptrdiff_t bufsize, exec_bufsize;
+ emacs_executable = load_pdump_find_executable (argv[0], &bufsize);
+ exec_bufsize = bufsize;
+
+ /* If we couldn't find our executable, go straight to looking for
+ the dump in the hardcoded location. */
+ if (!(emacs_executable && *emacs_executable))
+ goto hardcoded;
+
if (dump_file)
{
- result = pdumper_load (dump_file, argv[0], original_pwd);
+ result = pdumper_load (dump_file, emacs_executable);
if (result != PDUMPER_LOAD_SUCCESS)
fatal ("could not load dump file \"%s\": %s",
so we can't use decode_env_path. We're working in whatever
encoding the system natively uses for filesystem access, so
there's no need for character set conversion. */
- ptrdiff_t bufsize;
- dump_file = load_pdump_find_executable (argv[0], &bufsize);
-
- /* If we couldn't find our executable, go straight to looking for
- the dump in the hardcoded location. */
- if (dump_file && *dump_file)
- {
- char *real_exename = real_filename (dump_file);
- xfree (dump_file);
- dump_file = real_exename;
- ptrdiff_t exenamelen = strlen (dump_file);
-#ifndef WINDOWSNT
- bufsize = exenamelen + 1;
-#endif
- if (strip_suffix)
- {
- ptrdiff_t strip_suffix_length = strlen (strip_suffix);
- ptrdiff_t prefix_length = exenamelen - strip_suffix_length;
- if (0 <= prefix_length
- && !memcmp (&dump_file[prefix_length], strip_suffix,
- strip_suffix_length))
- exenamelen = prefix_length;
- }
- ptrdiff_t needed = exenamelen + strlen (suffix) + 1;
- if (bufsize < needed)
- dump_file = xpalloc (dump_file, &bufsize, needed - bufsize, -1, 1);
- strcpy (dump_file + exenamelen, suffix);
- result = pdumper_load (dump_file, argv[0], original_pwd);
- if (result == PDUMPER_LOAD_SUCCESS)
- goto out;
-
- if (result != PDUMPER_LOAD_FILE_NOT_FOUND)
- fatal ("could not load dump file \"%s\": %s",
- dump_file, dump_error_to_string (result));
- }
-
+ ptrdiff_t exenamelen = strlen (emacs_executable);
+ if (strip_suffix)
+ {
+ ptrdiff_t strip_suffix_length = strlen (strip_suffix);
+ ptrdiff_t prefix_length = exenamelen - strip_suffix_length;
+ if (0 <= prefix_length
+ && !memcmp (&emacs_executable[prefix_length], strip_suffix,
+ strip_suffix_length))
+ exenamelen = prefix_length;
+ }
+ ptrdiff_t needed = exenamelen + strlen (suffix) + 1;
+ dump_file = xpalloc (NULL, &bufsize, needed - bufsize, -1, 1);
+ memcpy (dump_file, emacs_executable, exenamelen);
+ strcpy (dump_file + exenamelen, suffix);
+ result = pdumper_load (dump_file, emacs_executable);
+ if (result == PDUMPER_LOAD_SUCCESS)
+ goto out;
+
+ if (result != PDUMPER_LOAD_FILE_NOT_FOUND)
+ fatal ("could not load dump file \"%s\": %s",
+ dump_file, dump_error_to_string (result));
+
+ hardcoded:
#ifdef WINDOWSNT
/* On MS-Windows, PATH_EXEC normally starts with a literal
"%emacs_dir%", so it will never work without some tweaking. */
"emacs.pdmp" so that the Emacs binary still works if the user
copies and renames it. */
const char *argv0_base = "emacs";
- ptrdiff_t needed = (strlen (path_exec)
- + 1
- + strlen (argv0_base)
- + strlen (suffix)
- + 1);
+ needed = (strlen (path_exec)
+ + 1
+ + strlen (argv0_base)
+ + strlen (suffix)
+ + 1);
if (bufsize < needed)
{
xfree (dump_file);
}
sprintf (dump_file, "%s%c%s%s",
path_exec, DIRECTORY_SEP, argv0_base, suffix);
- result = pdumper_load (dump_file, argv[0], original_pwd);
+ /* Assume the Emacs binary lives in a sibling directory as set up by
+ the default installation configuration. */
+ const char *go_up = "../../../../bin/";
+ needed += strlen (strip_suffix) - strlen (suffix) + strlen (go_up);
+ if (exec_bufsize < needed)
+ {
+ xfree (emacs_executable);
+ emacs_executable = xpalloc (NULL, &exec_bufsize, needed - exec_bufsize,
+ -1, 1);
+ }
+ sprintf (emacs_executable, "%s%c%s%s%s",
+ path_exec, DIRECTORY_SEP, go_up, argv0_base, strip_suffix);
+ result = pdumper_load (dump_file, emacs_executable);
if (result == PDUMPER_LOAD_FILE_NOT_FOUND)
{
#endif
sprintf (dump_file, "%s%c%s%s",
path_exec, DIRECTORY_SEP, argv0_base, suffix);
- result = pdumper_load (dump_file, argv[0], original_pwd);
+ result = pdumper_load (dump_file, emacs_executable);
}
if (result != PDUMPER_LOAD_SUCCESS)
out:
xfree (dump_file);
+ xfree (emacs_executable);
}
#endif /* HAVE_PDUMPER */
w32_init_main_thread ();
#endif
- emacs_wd = emacs_get_current_dir_name ();
#ifdef HAVE_PDUMPER
if (attempt_load_pdump)
- load_pdump (argc, argv, emacs_wd);
+ load_pdump (argc, argv);
#endif
argc = maybe_disable_address_randomization (argc, argv);
exit (0);
}
+ emacs_wd = emacs_get_current_dir_name ();
#ifdef HAVE_PDUMPER
if (dumped_with_pdumper_p ())
pdumper_record_wd (emacs_wd);
/* Init buffer storage and default directory of main buffer. */
init_buffer ();
- init_vars_for_load (argv[0], original_pwd);
-
/* Must precede init_lread. */
init_cmdargs (argc, argv, skip_args, original_pwd);
}
\f
+#ifdef HAVE_NATIVE_COMP
+/* This records the directory where the Emacs executable lives, to be
+ used for locating the native-lisp directory from which we need to
+ load the preloaded *.eln files. See pdumper_set_emacs_execdir
+ below. */
+static char *emacs_execdir;
+static ptrdiff_t execdir_size;
+static ptrdiff_t execdir_len;
+#endif
+
/* Dump runtime */
enum dump_memory_protection
{
struct Lisp_Native_Comp_Unit *comp_u =
dump_ptr (dump_base, reloc_offset);
comp_u->lambda_gc_guard_h = CALLN (Fmake_hash_table, QCtest, Qeq);
- if (!CONSP (comp_u->file))
+ if (STRINGP (comp_u->file))
error ("Trying to load incoherent dumped eln file %s",
SSDATA (comp_u->file));
+ /* emacs_execdir is always unibyte, but the file names in
+ comp_u->file could be multibyte, so we need to encode
+ them. */
+ Lisp_Object cu_file1 = ENCODE_FILE (XCAR (comp_u->file));
+ Lisp_Object cu_file2 = ENCODE_FILE (XCDR (comp_u->file));
+ ptrdiff_t fn1_len = SBYTES (cu_file1), fn2_len = SBYTES (cu_file2);
+ Lisp_Object eln_fname;
+ char *fndata;
+
/* Check just once if this is a local build or Emacs was installed. */
+ /* Can't use expand-file-name here, because we are too early
+ in the startup, and we will crash at least on WINDOWSNT. */
if (installation_state == UNKNOWN)
{
- /* Can't use expand-file-name here, because we are too
- early in the startup, and we will crash at least on
- WINDOWSNT. */
- Lisp_Object fname =
- concat2 (Vinvocation_directory, XCAR (comp_u->file));
- if (file_access_p (SSDATA (ENCODE_FILE (fname)), F_OK))
- {
- installation_state = INSTALLED;
- fixup_eln_load_path (XCAR (comp_u->file));
- }
+ eln_fname = make_uninit_string (execdir_len + fn1_len);
+ fndata = SSDATA (eln_fname);
+ memcpy (fndata, emacs_execdir, execdir_len);
+ memcpy (fndata + execdir_len, SSDATA (cu_file1), fn1_len);
+ if (file_access_p (fndata, F_OK))
+ installation_state = INSTALLED;
else
{
+ eln_fname = make_uninit_string (execdir_len + fn2_len);
+ fndata = SSDATA (eln_fname);
+ memcpy (fndata, emacs_execdir, execdir_len);
+ memcpy (fndata + execdir_len, SSDATA (cu_file2), fn2_len);
installation_state = LOCAL_BUILD;
- fixup_eln_load_path (XCDR (comp_u->file));
}
+ fixup_eln_load_path (eln_fname);
+ }
+ else
+ {
+ ptrdiff_t fn_len =
+ installation_state == INSTALLED ? fn1_len : fn2_len;
+ Lisp_Object cu_file =
+ installation_state == INSTALLED ? cu_file1 : cu_file2;
+ eln_fname = make_uninit_string (execdir_len + fn_len);
+ fndata = SSDATA (eln_fname);
+ memcpy (fndata, emacs_execdir, execdir_len);
+ memcpy (fndata + execdir_len, SSDATA (cu_file), fn_len);
}
- comp_u->file =
- concat2 (Vinvocation_directory,
- installation_state == INSTALLED
- ? XCAR (comp_u->file) : XCDR (comp_u->file));
- comp_u->handle = dynlib_open (SSDATA (ENCODE_FILE (comp_u->file)));
+ comp_u->file = eln_fname;
+ comp_u->handle = dynlib_open (SSDATA (eln_fname));
if (!comp_u->handle)
error ("%s", dynlib_error ());
load_comp_unit (comp_u, true, false);
dump_do_emacs_relocation (dump_base, r[i]);
}
+#ifdef HAVE_NATIVE_COMP
+/* Compute and record the directory of the Emacs executable given the
+ file name of that executable. */
+static void
+pdumper_set_emacs_execdir (char *emacs_executable)
+{
+ char *p = emacs_executable + strlen (emacs_executable);
+
+ while (p > emacs_executable
+ && !IS_DIRECTORY_SEP (p[-1]))
+ --p;
+ eassert (p > emacs_executable);
+ emacs_execdir = xpalloc (emacs_execdir, &execdir_size,
+ p - emacs_executable + 1 - execdir_size, -1, 1);
+ memcpy (emacs_execdir, emacs_executable, p - emacs_executable);
+ execdir_len = p - emacs_executable;
+ emacs_execdir[execdir_len] = '\0';
+}
+#endif
+
enum dump_section
{
DS_HOT,
N.B. We run very early in initialization, so we can't use lisp,
unwinding, xmalloc, and so on. */
int
-pdumper_load (const char *dump_filename, char *argv0, char const *original_pwd)
+pdumper_load (const char *dump_filename, char *argv0)
{
intptr_t dump_size;
struct stat stat;
for (int i = 0; i < nr_dump_hooks; ++i)
dump_hooks[i] ();
- /* Once we can allocate and before loading .eln files we must set
- Vinvocation_directory (.eln paths are relative to it). */
- init_vars_for_load (argv0, original_pwd);
+#ifdef HAVE_NATIVE_COMP
+ pdumper_set_emacs_execdir (argv0);
+#else
+ (void) argv0;
+#endif
dump_do_all_dump_reloc_for_phase (header, dump_base, LATE_RELOCS);
dump_do_all_dump_reloc_for_phase (header, dump_base, VERY_LATE_RELOCS);