2 relocate.cc -- implement relocation based on argv0
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
10 #include "relocate.hh"
15 /* TODO: autoconf support */
17 #include <sys/types.h>
24 #include "file-name.hh"
25 #include "file-path.hh"
26 #include "international.hh"
27 #include "lily-guile.hh"
28 #include "lily-version.hh"
33 #define FRAMEWORKDIR ".."
36 sane_putenv (char const *key, string value, bool overwrite)
38 if (overwrite || !getenv (key))
40 string combine = string (key) + "=" + value;
41 char *s = strdup (combine.c_str ());
43 if (be_verbose_global)
44 progress_indication (_f ("Setting %s to %s\n" , key, value.c_str ()));
53 set_env_file (char const *key, string value, bool overwrite = false)
56 return sane_putenv (key, value, overwrite);
57 else if (be_verbose_global)
58 warning (_f ("no such file: %s for %s", value, key));
63 set_env_dir (char const *key, string value)
66 return sane_putenv (key, value, false);
67 else if (be_verbose_global)
68 warning (_f ("no such directory: %s for %s", value, key));
73 prepend_env_path (char const *key, string value)
77 if (be_verbose_global)
78 progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ()));
80 if (char const *cur = getenv (key))
81 value += to_string (PATHSEP) + cur;
83 return sane_putenv (key, value.c_str (), true);
85 else if (be_verbose_global)
86 warning (_f ("no such directory: %s for %s", value, key));
95 prefix_relocation (string prefix)
97 if (be_verbose_global)
98 warning (_f ("Relocation: compile prefix=%s, new prefix=%s",
102 string bindir = prefix + "/bin";
103 string datadir = prefix + "/share";
104 string localedir = datadir + "/locale";
105 string lilypond_datadir = datadir + "/lilypond/";
107 if (is_dir (lilypond_datadir + "/" + TOPLEVEL_VERSION))
108 prefix_directory = lilypond_datadir + "/" + TOPLEVEL_VERSION;
109 else if (is_dir (lilypond_datadir + "/current"))
110 prefix_directory = lilypond_datadir + "/current";
113 if (is_dir (localedir))
114 bindtextdomain ("lilypond", localedir.c_str ());
117 prepend_env_path ("PATH", bindir);
121 UGH : this is a complete mess.
125 framework_relocation (string prefix)
127 if (be_verbose_global)
128 warning (_f ("Relocation: framework_prefix=%s", prefix));
130 sane_putenv ("INSTALLER_PREFIX", prefix, true);
132 read_relocation_dir (prefix + "/etc/relocate/");
134 string bindir = prefix + "/bin";
136 #ifdef OLD_RELOCATION
137 string datadir = prefix + "/share";
138 string libdir = prefix + "/lib";
139 string sysconfdir = prefix + "/etc";
141 /* need otherwise dynamic .so's aren't found. */
142 prepend_env_path ("DYLD_LIBRARY_PATH", libdir);
144 set_env_file ("FONTCONFIG_FILE", sysconfdir + "/fonts/fonts.conf", true);
145 set_env_dir ("FONTCONFIG_PATH", sysconfdir + "/fonts");
148 char font_dir[PATH_MAX];
149 ExpandEnvironmentStrings ("%windir%/fonts", font_dir, sizeof (font_dir));
150 prepend_env_path ("GS_FONTPATH", font_dir);
154 #ifdef GHOSTSCRIPT_VERSION
157 "ghostscript-version-undefined"
161 if (char const *cur = getenv ("LILYPOND_GS_VERSION"))
164 prepend_env_path ("GS_FONTPATH", datadir + "/ghostscript/" + gs_version + "/fonts");
165 prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/Resource");
166 prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/lib");
168 prepend_env_path ("GS_FONTPATH", datadir + "/gs/fonts");
169 prepend_env_path ("GS_LIB", datadir + "/gs/Resource");
170 prepend_env_path ("GS_LIB", datadir + "/gs/lib");
172 prepend_env_path ("GUILE_LOAD_PATH", datadir
173 + to_string ("/guile/%d.%d",
174 SCM_MAJOR_VERSION, SCM_MINOR_VERSION));
175 set_env_file ("PANGO_RC_FILE", sysconfdir + "/pango/pangorc");
176 set_env_dir ("PANGO_PREFIX", prefix);
180 prepend_env_path ("PATH", bindir);
184 UGH : this is a complete mess.
187 setup_paths (char const *argv0_ptr)
189 File_name argv0_filename (argv0_ptr);
191 prefix_directory = LILYPOND_DATADIR;
193 && getenv ("LILYPOND_RELOCATE_PREFIX"))
195 prefix_directory = getenv ("LILYPOND_RELOCATE_PREFIX");
197 /* Normalize file name. */
198 prefix_directory = File_name (prefix_directory).to_string ();
199 #endif /* __MINGW32__ */
201 prefix_relocation (prefix_directory);
202 string bindir = prefix_directory + "/bin";
203 framework_relocation (bindir);
205 else if (relocate_binary)
208 if (argv0_filename.is_absolute ())
210 argv0_abs = argv0_filename.to_string ();
211 if (be_verbose_global)
212 warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
214 else if (argv0_filename.dir_.length ())
216 argv0_abs = get_working_directory ()
217 + "/" + string (argv0_filename.to_string ());
218 if (be_verbose_global)
219 warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
223 /* Find absolute ARGV0 name, using PATH. */
225 path.parse_path (getenv ("PATH"));
227 if (be_verbose_global)
228 warning (_f ("Relocation: from PATH=%s\nargv0=%s",
229 path.to_string ().c_str (), argv0_ptr));
232 argv0_abs = path.find (argv0_filename.to_string ());
233 #else /* __MINGW32__ */
234 char const *ext[] = {"exe", "", 0 };
235 argv0_abs = path.find (argv0_filename.to_string (), ext);
236 #endif /* __MINGW32__ */
238 if (argv0_abs.empty ())
239 programming_error ("can't find absolute argv0.");
242 string bindir = dir_name (argv0_abs);
243 string argv0_prefix = dir_name (bindir);
244 string compile_prefix = dir_name (dir_name (dir_name (prefix_directory)));
245 if (argv0_prefix != compile_prefix)
247 prefix_relocation (argv0_prefix);
248 prefix_directory = argv0_prefix;
250 if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
252 framework_relocation (bindir + "/" + FRAMEWORKDIR);
253 prefix_directory = bindir + "/" + FRAMEWORKDIR;
257 /* FIXME: use LILYPOND_DATADIR. */
258 if (char const *env = getenv ("LILYPONDPREFIX"))
261 /* Normalize file name. */
262 prefix_directory = File_name (env).to_string ();
264 prefix_directory = env;
268 global_path.append ("");
272 When running from build dir, a full LILYPOND_PREFIX is set-up at
274 $(OUTBASE)/share/lilypond/TOPLEVEL_VERSION
276 This historical hack will allow the shorthand
278 LILYPONDPREFIX=out lily/out/lilypond ...
282 string build_prefix_current = prefix_directory + "/share/lilypond/" "current";
283 string build_prefix_version = prefix_directory + "/share/lilypond/" TOPLEVEL_VERSION;
284 if (is_dir (build_prefix_version.c_str ()))
285 prefix_directory = build_prefix_version;
286 else if (is_dir (build_prefix_current.c_str ()))
287 prefix_directory = build_prefix_current;
289 /* Adding mf/out make lilypond unchanged source directory, when setting
290 LILYPONDPREFIX to lilypond-x.y.z */
291 char const *suffixes[] = {"ly", "ps", "scm", 0 };
294 for (char const **s = suffixes; *s; s++)
296 string path = prefix_directory + to_string ('/') + string (*s);
297 dirs.push_back (path);
300 dirs.push_back (prefix_directory + "/fonts/otf/");
301 dirs.push_back (prefix_directory + "/fonts/type1/");
302 dirs.push_back (prefix_directory + "/fonts/svg/");
304 for (vsize i = 0; i < dirs.size (); i++)
305 global_path.prepend (dirs[i]);
311 expand_environment_variables (string orig)
313 const char *start_ptr = orig.c_str();
314 const char *ptr = orig.c_str();
315 size_t len = orig.length();
318 while (ptr < start_ptr + len)
320 char *dollar = strchr (ptr, '$');
324 char *start_var = dollar + 1;
325 char *end_var = start_var;
326 char *start_next = end_var;
328 out += string (ptr, dollar - ptr);
331 if (*start_var == '{')
335 end_var = strchr (start_var, '}');
339 end_var = start_var + len;
340 start_next = end_var;
344 start_next = end_var + 1;
350 Hmm. what to do for $1 , $~ etc.?
356 while (isalnum (*end_var) || *end_var == '_');
357 start_next = end_var;
360 if (start_var < end_var)
362 string var_name (start_var, end_var - start_var);
363 const char *value = getenv (var_name.c_str());
365 out += string (value);
387 while ((c = fgetc (f)) != EOF && c != '\n')
394 read_relocation_file (string filename)
396 if (be_verbose_global)
397 progress_indication (_f ("Relocation file %s\n", filename.c_str ()));
399 char const *cname = filename.c_str ();
400 FILE *f = fopen (cname, "r");
402 error (_f ("can't open file %s", cname));
406 string line = read_line (f);
407 size_t idx = line.find (' ');
411 string command = line.substr (0, idx);
412 line = line.substr (idx + 1);
416 idx = line.find ('=');
418 string variable = line.substr (0, idx);
419 string value = line.substr (idx + 1);
421 value = expand_environment_variables (value);
423 if (command == "set")
424 sane_putenv (variable.c_str(), value, true);
425 else if (command == "setdir")
426 set_env_dir (variable.c_str(), value);
427 else if (command == "setfile")
428 set_env_file (variable.c_str(), value);
429 else if (command == "prependdir")
430 prepend_env_path (variable.c_str (), value);
432 error ( _f("Unknown relocation command %s", command));
439 read_relocation_dir (string dirname)
441 DIR *dir = opendir (dirname.c_str ());
443 while (struct dirent *ent = readdir (dir))
445 File_name name (ent->d_name);
446 if (name.ext_ == "reloc")
448 read_relocation_file (dirname + "/" + name.to_string ());