4 * This file is part of LyX, the document processor.
5 * Licence details can be found in the file COPYING.
7 * \author Angus Leeming
9 * Full author contact details are available in file CREDITS.
11 * Warning! This file is autogenerated from package.C.in.
12 * All changes to this file will be lost.
17 #include "support/package.h"
22 #include "support/environment.h"
23 #include "support/filetools.h"
24 #include "support/lstrings.h"
25 #include "support/os.h"
27 #if defined (USE_WINDOWS_PACKAGING)
28 # include "support/os_win32.h"
31 #include <boost/filesystem/operations.hpp>
32 #include <boost/tuple/tuple.hpp>
37 #if !defined (USE_WINDOWS_PACKAGING) && \
38 !defined (USE_MACOSX_PACKAGING) && \
39 !defined (USE_POSIX_PACKAGING)
40 #error USE_FOO_PACKAGING must be defined for FOO = WINDOWS, MACOSX or POSIX.
43 #if defined (USE_MACOSX_PACKAGING)
44 # include <CoreServices/CoreServices.h> // FSFindFolder, FSRefMakePath
49 namespace fs = boost::filesystem;
57 bool initialised_ = false;
62 void init_package(string const & command_line_arg0,
63 string const & command_line_system_support_dir,
64 string const & command_line_user_support_dir,
65 exe_build_dir_to_top_build_dir top_build_dir_location)
67 // Can do so only once.
71 package_ = Package(command_line_arg0,
72 command_line_system_support_dir,
73 command_line_user_support_dir,
74 top_build_dir_location);
79 Package const & package()
81 // Commented out because package().locale_dir() can be called
82 // from the message translation code in messages.C before
83 // init_package() is called. Lars is on the case...
84 // BOOST_ASSERT(initialised_);
91 string const abs_path_from_binary_name(string const & exe);
93 std::pair<string, string> const
94 get_build_dirs(string const & abs_binary,
95 exe_build_dir_to_top_build_dir top_build_dir_location);
97 string const get_document_dir(string const & home_dir);
99 string const get_home_dir();
101 string const get_locale_dir(string const & system_support_dir);
103 string const get_system_support_dir(string const & abs_binary,
104 string const & command_line_system_support_dir);
106 string const get_temp_dir();
108 string const get_default_user_support_dir(string const & home_dir);
110 std::pair<string, bool> const
111 get_user_support_dir(string const & default_user_support_dir,
112 string const & command_line_user_support_dir);
115 string const & with_version_suffix();
120 Package::Package(string const & command_line_arg0,
121 string const & command_line_system_support_dir,
122 string const & command_line_user_support_dir,
123 exe_build_dir_to_top_build_dir top_build_dir_location)
124 : explicit_user_support_dir_(false)
126 home_dir_ = get_home_dir();
127 system_temp_dir_ = get_temp_dir();
128 temp_dir_ = system_temp_dir_;
129 document_dir_ = get_document_dir(home_dir_);
131 string const abs_binary = abs_path_from_binary_name(command_line_arg0);
132 binary_dir_ = onlyPath(abs_binary);
134 // Is LyX being run in-place from the build tree?
135 boost::tie(build_support_dir_, system_support_dir_) =
136 get_build_dirs(abs_binary, top_build_dir_location);
138 if (build_support_dir_.empty())
139 system_support_dir_ =
140 get_system_support_dir(abs_binary,
141 command_line_system_support_dir);
143 locale_dir_ = get_locale_dir(system_support_dir_);
145 string const default_user_support_dir =
146 get_default_user_support_dir(home_dir_);
147 boost::tie(user_support_dir_, explicit_user_support_dir_) =
148 get_user_support_dir(default_user_support_dir,
149 command_line_user_support_dir);
151 string const configure_script = addName(system_support(), "configure.py");
152 configure_command_ = os::python() + ' ' + quoteName(configure_script)
153 + with_version_suffix();
157 << "\tbinary_dir " << binary_dir() << '\n'
158 << "\tsystem_support " << system_support() << '\n'
159 << "\tbuild_support " << build_support() << '\n'
160 << "\tuser_support " << user_support() << '\n'
161 << "\tlocale_dir " << locale_dir() << '\n'
162 << "\tdocument_dir " << document_dir() << '\n'
163 << "\ttemp_dir " << temp_dir() << '\n'
164 << "\thome_dir " << home_dir() << '\n'
165 << "</package>\n" << std::endl;
171 // These next three functions contain the stuff that is substituted at
172 // configuration-time.
173 string const top_srcdir()
175 static string const dir("%TOP_SRCDIR%");
180 string const hardcoded_localedir()
182 return string("%LOCALEDIR%");
186 string const hardcoded_system_support_dir()
188 return string("%LYX_DIR%");
192 string const & with_version_suffix()
194 static string const program_suffix("%PROGRAM_SUFFIX%");
196 with_version_suffix(" --with-version-suffix=%PROGRAM_SUFFIX%");
197 return program_suffix.empty() ? program_suffix : with_version_suffix;
203 string const & Package::top_srcdir() const
205 static string const dir("%TOP_SRCDIR%");
212 bool check_command_line_dir(string const & dir,
214 string const & command_line_switch);
216 string const extract_env_var_dir(string const & env_var);
218 bool check_env_var_dir(string const & dir,
219 string const & env_var);
221 bool check_env_var_dir(string const & dir,
223 string const & env_var);
225 string const relative_locale_dir();
227 string const relative_system_support_dir();
231 get_build_support_dir(std::string const & binary_dir,
232 exe_build_dir_to_top_build_dir top_build_dir_location)
235 switch (top_build_dir_location) {
236 case top_build_dir_is_one_level_up:
237 indirection = "../lib";
239 case top_build_dir_is_two_levels_up:
240 indirection = "../../lib";
244 return normalizePath(addPath(binary_dir, indirection));
248 std::pair<string, string> const
249 get_build_dirs(string const & abs_binary,
250 exe_build_dir_to_top_build_dir top_build_dir_location)
252 string const check_text = "Checking whether LyX is run in place...";
254 // We're looking for "Makefile" in a directory
256 // We're also looking for "chkconfig.ltx" in a directory
258 // If both are found, then we're running LyX in-place.
260 // Note that the name of the lyx binary may be a symbolic link.
261 // If that is the case, then we follow the links too.
262 string binary = abs_binary;
264 // Try and find "lyxrc.defaults".
265 string const binary_dir = onlyPath(binary);
266 string const build_support_dir =
267 get_build_support_dir(binary_dir, top_build_dir_location);
269 if (!fileSearch(build_support_dir, "Makefile").empty()) {
270 // Try and find "chkconfig.ltx".
271 string const system_support_dir =
272 addPath(top_srcdir(), "lib");
274 if (!fileSearch(system_support_dir, "chkconfig.ltx").empty()) {
275 lyxerr[Debug::INIT] << check_text << " yes"
277 return std::make_pair(build_support_dir, system_support_dir);
281 // Check whether binary is a symbolic link.
282 // If so, resolve it and repeat the exercise.
283 if (!fs::symbolic_link_exists(FileName(binary).toFilesystemEncoding()))
287 if (readLink(binary, link, true)) {
290 // Unable to resolve the link.
295 lyxerr[Debug::INIT] << check_text << " no" << std::endl;
296 return std::make_pair(string(), string());
300 // Specification of document_dir_ may be reset by LyXRC,
301 // but the default is fixed for a given OS.
302 string const get_document_dir(string const & home_dir)
304 #if defined (USE_WINDOWS_PACKAGING)
305 (void)home_dir; // Silence warning about unused variable.
306 os::GetFolderPath win32_folder_path;
307 return win32_folder_path(os::GetFolderPath::PERSONAL);
314 // The specification of home_dir_ is fixed for a given OS.
315 // A typical example on Windows: "C:/Documents and Settings/USERNAME"
316 // and on a Posix-like machine: "/home/USERNAME".
317 string const get_home_dir()
319 #if defined (USE_WINDOWS_PACKAGING)
320 string const home_dir = getEnv("USERPROFILE");
322 string const home_dir = getEnv("HOME");
325 return os::internal_path(home_dir);
329 // Several sources are probed to ascertain the locale directory.
330 // The only requirement is that the result is indeed a directory.
331 string const get_locale_dir(string const & system_support_dir)
333 // 1. Use the "LYX_LOCALEDIR" environment variable.
334 string const path_env = extract_env_var_dir("LYX_LOCALEDIR");
335 if (!path_env.empty() && check_env_var_dir(path_env, "LYX_LOCALEDIR"))
338 // 2. Search for system_support_dir / <relative locale dir>
339 // The <relative locale dir> is OS-dependent. (On Unix, it will
341 FileName path(normalizePath(addPath(system_support_dir, relative_locale_dir())));
343 if (fs::exists(path.toFilesystemEncoding()) &&
344 fs::is_directory(path.toFilesystemEncoding()))
345 return path.absFilename();
347 // 3. Fall back to the hard-coded LOCALEDIR.
348 path = FileName(hardcoded_localedir());
349 if (fs::exists(path.toFilesystemEncoding()) &&
350 fs::is_directory(path.toFilesystemEncoding()))
351 return path.absFilename();
357 // Specification of temp_dir_ may be reset by LyXRC,
358 // but the default is fixed for a given OS.
359 string const get_temp_dir()
361 #if defined (USE_WINDOWS_PACKAGING)
362 // Typical example: C:/TEMP/.
364 GetTempPath(MAX_PATH, path);
365 return os::internal_path(path);
374 #ifndef CXX_GLOBAL_CSTD
381 // Extracts the absolute path from the foo of "-sysdir foo" or "-userdir foo"
382 string const abs_path_from_command_line(string const & command_line)
384 if (command_line.empty())
387 string const path = os::internal_path(command_line);
388 return os::is_absolute_path(path) ? path : makeAbsPath(path);
392 // Does the grunt work for abs_path_from_binary_name()
393 string const get_binary_path(string const & exe)
395 #if defined (USE_WINDOWS_PACKAGING)
396 // The executable may have been invoked either with or
397 // without the .exe extension.
398 // Ensure that it is present.
399 string const as_internal_path = os::internal_path(exe);
400 string const exe_path = suffixIs(as_internal_path, ".exe") ?
401 as_internal_path : as_internal_path + ".exe";
403 string const exe_path = os::internal_path(exe);
405 if (os::is_absolute_path(exe_path))
408 // Two possibilities present themselves.
409 // 1. The binary is relative to the CWD.
410 string const abs_exe_path = makeAbsPath(exe_path);
411 if (fs::exists(FileName(abs_exe_path).toFilesystemEncoding()))
414 // 2. exe must be the name of the binary only and it
415 // can be found on the PATH.
416 string const exe_name = onlyFilename(exe_path);
417 if (exe_name != exe_path)
420 std::vector<string> const path = getEnvPath("PATH");
421 std::vector<string>::const_iterator it = path.begin();
422 std::vector<string>::const_iterator const end = path.end();
423 for (; it != end; ++it) {
424 // This will do nothing if *it is already absolute.
425 string const exe_dir = makeAbsPath(*it);
427 string const exe_path = addName(exe_dir, exe_name);
428 if (fs::exists(FileName(exe_path).toFilesystemEncoding()))
432 // Didn't find anything.
437 // Extracts the absolute path to the binary name received as argv[0].
438 string const abs_path_from_binary_name(string const & exe)
440 string const abs_binary = get_binary_path(exe);
441 if (abs_binary.empty()) {
443 lyxerr << lyx::to_utf8(bformat(_("Unable to determine the path to the "
444 "LyX binary from the command line %1$s"),
445 lyx::from_utf8(exe)))
453 // A plethora of directories is searched to ascertain the system
454 // lyxdir which is defined as the first directory to contain
457 get_system_support_dir(string const & abs_binary,
458 string const & command_line_system_support_dir)
460 string const chkconfig_ltx = "chkconfig.ltx";
462 // searched_dirs is used for diagnostic purposes only in the case
463 // that "chkconfig.ltx" is not found.
464 std::list<string> searched_dirs;
466 // 1. Use the -sysdir command line parameter.
467 string path = abs_path_from_command_line(command_line_system_support_dir);
469 searched_dirs.push_back(path);
470 if (check_command_line_dir(path, chkconfig_ltx, "-sysdir"))
474 // 2. Use the "LYX_DIR_14x" environment variable.
475 path = extract_env_var_dir("LYX_DIR_14x");
477 searched_dirs.push_back(path);
478 if (check_env_var_dir(path, chkconfig_ltx, "LYX_DIR_14x"))
482 // 3. Search relative to the lyx binary.
483 // We're looking for "chkconfig.ltx" in a directory
484 // OnlyPath(abs_binary) / <relative dir> / PACKAGE /
485 // PACKAGE is hardcoded in config.h. Eg "lyx" or "lyx-1.3.6cvs".
486 // <relative dir> is OS-dependent; on Unix, it will be "../share/".
487 string const relative_lyxdir = relative_system_support_dir();
489 // One subtlety to be aware of. The name of the lyx binary may be
490 // a symbolic link. If that is the case, then we follow the links too.
491 string binary = abs_binary;
493 // Try and find "chkconfig.ltx".
494 string const binary_dir = onlyPath(binary);
496 string const lyxdir =
497 normalizePath(addPath(binary_dir, relative_lyxdir));
498 searched_dirs.push_back(lyxdir);
500 if (!fileSearch(lyxdir, chkconfig_ltx).empty()) {
501 // Success! "chkconfig.ltx" has been found.
505 // Check whether binary is a symbolic link.
506 // If so, resolve it and repeat the exercise.
507 if (!fs::symbolic_link_exists(FileName(binary).toFilesystemEncoding()))
511 if (readLink(binary, link, true)) {
514 // Unable to resolve the link.
519 // 4. Repeat the exercise on the directory itself.
520 string binary_dir = onlyPath(abs_binary);
522 // This time test whether the directory is a symbolic link
523 // *before* looking for "chkconfig.ltx".
524 // (We've looked relative to the original already.)
525 if (!fs::symbolic_link_exists(FileName(binary).toFilesystemEncoding()))
529 if (readLink(binary_dir, link, true)) {
532 // Unable to resolve the link.
536 // Try and find "chkconfig.ltx".
537 string const lyxdir =
538 normalizePath(addPath(binary_dir, relative_lyxdir));
539 searched_dirs.push_back(lyxdir);
541 if (!fileSearch(lyxdir, chkconfig_ltx).empty()) {
542 // Success! "chkconfig.ltx" has been found.
547 // 5. In desparation, try the hard-coded system support dir.
548 path = hardcoded_system_support_dir();
549 if (!fileSearch(path, chkconfig_ltx).empty())
552 // Everything has failed :-(
553 // So inform the user and exit.
554 string searched_dirs_str;
555 typedef std::list<string>::const_iterator iterator;
556 iterator const begin = searched_dirs.begin();
557 iterator const end = searched_dirs.end();
558 for (iterator it = begin; it != end; ++it) {
560 searched_dirs_str += "\n\t";
561 searched_dirs_str += *it;
565 lyxerr << lyx::to_utf8(bformat(_("Unable to determine the system directory "
568 "Use the '-sysdir' command line parameter or "
569 "set the environment variable LYX_DIR_14x to "
570 "the LyX system directory containing the file "
572 lyx::from_utf8(searched_dirs_str)))
576 // Keep the compiler happy.
581 // Returns the absolute path to the user lyxdir, together with a flag
582 // indicating whether this directory was specified explicitly (as -userdir
583 // or through an environment variable) or whether it was deduced.
584 std::pair<string, bool> const
585 get_user_support_dir(string const & default_user_support_dir,
586 string const & command_line_user_support_dir)
588 bool explicit_userdir = true;
590 // 1. Use the -userdir command line parameter.
592 abs_path_from_command_line(command_line_user_support_dir);
594 return std::make_pair(path, explicit_userdir);
596 // 2. Use the LYX_USERDIR_14x environment variable.
597 path = extract_env_var_dir("LYX_USERDIR_14x");
599 return std::make_pair(path, explicit_userdir);
601 // 3. Use the OS-dependent default_user_support_dir
602 explicit_userdir = false;
603 return std::make_pair(default_user_support_dir, explicit_userdir);
607 // $HOME/.lyx on POSIX but on Win32 it will be something like
608 // "C:/Documents and Settings/USERNAME/Application Data/LyX"
609 string const get_default_user_support_dir(string const & home_dir)
611 #if defined (USE_WINDOWS_PACKAGING)
612 (void)home_dir; // Silence warning about unused variable.
614 os::GetFolderPath win32_folder_path;
615 return addPath(win32_folder_path(os::GetFolderPath::APPDATA), PACKAGE);
617 #elif defined (USE_MACOSX_PACKAGING)
618 (void)home_dir; // Silence warning about unused variable.
621 OSErr const error_code =
622 FSFindFolder(kUserDomain, kApplicationSupportFolderType,
623 kDontCreateFolder, &fsref);
627 char store[PATH_MAX + 1];
628 OSStatus const status_code =
629 FSRefMakePath(&fsref,
630 reinterpret_cast<UInt8*>(store), PATH_MAX);
631 if (status_code != 0)
634 return addPath(reinterpret_cast<char const *>(store), PACKAGE);
636 #else // USE_POSIX_PACKAGING
637 return addPath(home_dir, string(".") + PACKAGE);
642 // Check that directory @c dir contains @c file.
643 // Else emit a warning about an invalid @c command_line_switch.
644 bool check_command_line_dir(string const & dir,
646 string const & command_line_switch)
648 FileName const abs_path = fileSearch(dir, file);
649 if (abs_path.empty()) {
651 lyxerr << lyx::to_utf8(bformat(_("Invalid %1$s switch.\n"
652 "Directory %2$s does not contain %3$s."),
653 lyx::from_utf8(command_line_switch), lyx::from_utf8(dir),
654 lyx::from_utf8(file)))
658 return !abs_path.empty();
662 // The environment variable @c env_var expands to a (single) file path.
663 string const extract_env_var_dir(string const & env_var)
665 string const dir = os::internal_path(getEnv(env_var));
666 return dir.empty() ? dir : makeAbsPath(dir);
670 // Check that directory @c dir contains @c file.
671 // Else emit a warning about an invalid @c env_var.
672 bool check_env_var_dir(string const & dir,
674 string const & env_var)
676 FileName const abs_path = fileSearch(dir, file);
677 if (abs_path.empty()) {
679 lyxerr << lyx::to_utf8(bformat(_("Invalid %1$s environment variable.\n"
680 "Directory %2$s does not contain %3$s."),
681 lyx::from_utf8(env_var), lyx::from_utf8(dir), lyx::from_utf8(file)))
685 return !abs_path.empty();
689 // Check that directory @c dir is indeed a directory.
690 // Else emit a warning about an invalid @c env_var.
691 bool check_env_var_dir(string const & dir,
692 string const & env_var)
694 string const encoded(FileName(dir).toFilesystemEncoding());
695 bool const success = (fs::exists(encoded) && fs::is_directory(encoded));
698 // Put this string on a single line so that the gettext
699 // search mechanism in po/Makefile.in.in will register
700 // package.C.in as a file containing strings that need
703 docstring const fmt =
704 _("Invalid %1$s environment variable.\n%2$s is not a directory.");
706 lyxerr << lyx::to_utf8(bformat(fmt, lyx::from_utf8(env_var), lyx::from_utf8(dir)))
714 // The locale directory relative to the LyX system directory.
715 string const relative_locale_dir()
717 #if defined (USE_WINDOWS_PACKAGING) || defined (USE_MACOSX_PACKAGING)
725 // The system lyxdir is relative to the directory containing the LyX binary.
726 string const relative_system_support_dir()
730 #if defined (USE_WINDOWS_PACKAGING) || defined (USE_MACOSX_PACKAGING)
731 result = "../Resources/";
733 result = addPath("../share/", PACKAGE);
741 } // namespace support