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"
18 #include "file-name.hh"
19 #include "file-path.hh"
20 #include "international.hh"
21 #include "lily-guile.hh"
22 #include "lily-version.hh"
27 #define FRAMEWORKDIR ".."
31 sane_putenv (char const *key, string value, bool overwrite)
33 if (overwrite || !getenv (key))
35 string combine = string (key) + "=" + value;
36 char *s = strdup (combine.c_str ());
44 set_env_file (char const *key, string value, bool overwrite = false)
47 return sane_putenv (key, value, overwrite);
48 else if (be_verbose_global)
49 warning (_f ("no such file: %s for %s", value, key));
54 set_env_dir (char const *key, string value)
57 return sane_putenv (key, value, false);
58 else if (be_verbose_global)
59 warning (_f ("no such directory: %s for %s", value, key));
64 prepend_env_path (char const *key, string value)
68 if (be_verbose_global)
69 progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ()));
71 if (char const *cur = getenv (key))
72 value += to_string (PATHSEP) + cur;
74 return sane_putenv (key, value.c_str (), true);
76 else if (be_verbose_global)
77 warning (_f ("no such directory: %s for %s", value, key));
86 prefix_relocation (string prefix)
88 if (be_verbose_global)
89 warning (_f ("Relocation: compile prefix=%s, new prefix=%s",
93 string bindir = prefix + "/bin";
94 string datadir = prefix + "/share";
95 string localedir = datadir + "/locale";
96 string lilypond_datadir = datadir + "/lilypond/";
98 if (is_dir (lilypond_datadir + "/" + TOPLEVEL_VERSION))
99 prefix_directory = lilypond_datadir + "/" + TOPLEVEL_VERSION;
100 else if (is_dir (lilypond_datadir + "/current"))
101 prefix_directory = lilypond_datadir + "/current";
104 if (is_dir (localedir))
105 bindtextdomain ("lilypond", localedir.c_str ());
108 prepend_env_path ("PATH", bindir);
112 framework_relocation (string prefix)
114 if (be_verbose_global)
115 warning (_f ("Relocation: framework_prefix=%s", prefix));
117 string bindir = prefix + "/bin";
118 string datadir = prefix + "/share";
119 string libdir = prefix + "/lib";
120 string sysconfdir = prefix + "/etc";
122 /* need otherwise dynamic .so's aren't found. */
123 prepend_env_path ("DYLD_LIBRARY_PATH", libdir);
125 set_env_file ("FONTCONFIG_FILE", sysconfdir + "/fonts/fonts.conf", true);
126 set_env_dir ("FONTCONFIG_PATH", sysconfdir + "/fonts");
129 char font_dir[PATH_MAX];
130 ExpandEnvironmentStrings ("%windir%/fonts", font_dir, sizeof (font_dir));
131 prepend_env_path ("GS_FONTPATH", font_dir);
135 #ifdef GHOSTSCRIPT_VERSION
138 "ghostscript-version-undefined"
142 if (char const *cur = getenv ("LILYPOND_GS_VERSION"))
145 prepend_env_path ("GS_FONTPATH", datadir + "/ghostscript/" + gs_version + "/fonts");
146 prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/Resource");
147 prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/lib");
149 prepend_env_path ("GS_FONTPATH", datadir + "/gs/fonts");
150 prepend_env_path ("GS_LIB", datadir + "/gs/Resource");
151 prepend_env_path ("GS_LIB", datadir + "/gs/lib");
153 prepend_env_path ("GUILE_LOAD_PATH", datadir
154 + to_string ("/guile/%d.%d",
155 SCM_MAJOR_VERSION, SCM_MINOR_VERSION));
157 set_env_file ("PANGO_RC_FILE", sysconfdir + "/pango/pangorc");
158 set_env_dir ("PANGO_PREFIX", prefix);
160 prepend_env_path ("PATH", bindir);
164 setup_paths (char const *argv0_ptr)
166 File_name argv0_filename (argv0_ptr);
168 prefix_directory = LILYPOND_DATADIR;
170 && getenv ("LILYPOND_RELOCATE_PREFIX"))
172 string prefix = getenv ("LILYPOND_RELOCATE_PREFIX");
174 /* Normalize file name. */
175 prefix = File_name (prefix).to_string ();
176 #endif /* __MINGW32__ */
177 prefix_relocation (prefix);
178 string bindir = prefix + "/bin";
179 framework_relocation (bindir);
181 else if (relocate_binary)
184 if (argv0_filename.is_absolute ())
186 argv0_abs = argv0_filename.to_string ();
187 if (be_verbose_global)
188 warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
190 else if (argv0_filename.dir_.length ())
192 argv0_abs = get_working_directory ()
193 + "/" + string (argv0_filename.to_string ());
194 if (be_verbose_global)
195 warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
199 /* Find absolute ARGV0 name, using PATH. */
201 path.parse_path (getenv ("PATH"));
203 if (be_verbose_global)
204 warning (_f ("Relocation: from PATH=%s\nargv0=%s",
205 path.to_string ().c_str (), argv0_ptr));
208 argv0_abs = path.find (argv0_filename.to_string ());
209 #else /* __MINGW32__ */
210 char const *ext[] = {"exe", "", 0 };
211 argv0_abs = path.find (argv0_filename.to_string (), ext);
212 #endif /* __MINGW32__ */
214 if (argv0_abs.empty ())
215 programming_error ("can't find absolute argv0.");
218 string bindir = dir_name (argv0_abs);
219 string argv0_prefix = dir_name (bindir);
220 string compile_prefix = dir_name (dir_name (dir_name (prefix_directory)));
221 if (argv0_prefix != compile_prefix)
222 prefix_relocation (argv0_prefix);
223 if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
224 framework_relocation (bindir + "/" + FRAMEWORKDIR);
227 /* FIXME: use LILYPOND_DATADIR. */
228 if (char const *env = getenv ("LILYPONDPREFIX"))
232 /* Normalize file name. */
233 prefix_directory = File_name (env).to_string ();
235 prefix_directory = env;
239 global_path.append ("");
243 When running from build dir, a full LILYPOND_PREFIX is set-up at
245 $(OUTBASE)/share/lilypond/TOPLEVEL_VERSION
247 This historical hack will allow the shorthand
249 LILYPONDPREFIX=out lily/out/lilypond ...
253 string build_prefix_current = prefix_directory + "/share/lilypond/" "current";
254 string build_prefix_version = prefix_directory + "/share/lilypond/" TOPLEVEL_VERSION;
255 if (is_dir (build_prefix_version.c_str ()))
256 prefix_directory = build_prefix_version;
257 else if (is_dir (build_prefix_current.c_str ()))
258 prefix_directory = build_prefix_current;
260 /* Adding mf/out make lilypond unchanged source directory, when setting
261 LILYPONDPREFIX to lilypond-x.y.z */
262 char const *suffixes[] = {"ly", "ps", "scm", 0 };
266 for (char const **s = suffixes; *s; s++)
268 string path = prefix_directory + to_string ('/') + string (*s);
269 dirs.push_back (path);
273 dirs.push_back (prefix_directory + "/fonts/otf/");
274 dirs.push_back (prefix_directory + "/fonts/type1/");
275 dirs.push_back (prefix_directory + "/fonts/svg/");
277 for (vsize i = 0; i < dirs.size (); i++)
278 global_path.prepend (dirs[i]);
284 expand_environment_variables (string orig)
286 const char *start_ptr = orig.c_str();
287 const char *ptr = orig.c_str();
288 size_t len = orig.length();
291 while (ptr < start_ptr + len)
293 char *dollar = strchr (ptr, '$');
297 char *start_var = dollar + 1;
298 char *end_var = start_var;
299 char *start_next = end_var;
301 out += string (ptr, dollar - ptr);
304 if (*start_var == '{')
308 end_var = strchr (start_var, '}');
312 end_var = start_var + len;
313 start_next = end_var;
317 start_next = end_var + 1;
323 Hmm. what to do for $1 , $~ etc.?
329 while (isalnum (*end_var) || *end_var == '_');
330 start_next = end_var;
333 if (start_var < end_var)
335 string var_name (start_var, end_var - start_var);
336 const char *value = getenv (var_name.c_str());
338 out += string (value);
360 while ((c = fgetc (f)) != EOF && c != '\n')
367 read_relocation_file (string filename)
369 char const *cname = filename.c_str ();
370 FILE *f = fopen (cname, "r");
372 error (_f ("can't open file %s", cname));
376 string line = read_line (f);
377 size_t idx = line.find (' ');
381 string command = line.substr (0, idx);
382 line = line.substr (idx + 1);
386 idx = line.find ('=');
388 string variable = line.substr (0, idx);
389 string value = line.substr (idx + 1);
391 value = expand_environment_variables (value);
393 if (command == "set")
394 sane_putenv (variable.c_str(), value, true);
395 else if (command == "setdir")
396 set_env_dir (variable.c_str(), value);
397 else if (command == "setfile")
398 set_env_file (variable.c_str(), value);
399 else if (command == "prependdir")
400 prepend_env_path (variable.c_str (), value);
402 error ( _f("Unknown relocation command %s", command));