2 relocate.cc -- implement relocation based on argv0
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2007 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" , key, value.c_str ())
54 set_env_file (char const *key, string value, bool overwrite = false)
57 return sane_putenv (key, value, overwrite);
58 else if (be_verbose_global)
59 warning (_f ("no such file: %s for %s", value, key));
64 set_env_dir (char const *key, string value)
67 return sane_putenv (key, value, false);
68 else if (be_verbose_global)
69 warning (_f ("no such directory: %s for %s", value, key));
74 prepend_env_path (char const *key, string value)
78 if (be_verbose_global)
79 progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ()));
81 if (char const *cur = getenv (key))
82 value += to_string (PATHSEP) + cur;
84 return sane_putenv (key, value.c_str (), true);
86 else if (be_verbose_global)
87 warning (_f ("no such directory: %s for %s", value, key));
96 prefix_relocation (string prefix)
98 if (be_verbose_global)
99 warning (_f ("Relocation: compile prefix=%s, new prefix=%s",
103 string bindir = prefix + "/bin";
104 string datadir = prefix + "/share";
105 string localedir = datadir + "/locale";
106 string lilypond_datadir = datadir + "/lilypond/";
108 if (is_dir (lilypond_datadir + "/" + TOPLEVEL_VERSION))
109 prefix_directory = lilypond_datadir + "/" + TOPLEVEL_VERSION;
110 else if (is_dir (lilypond_datadir + "/current"))
111 prefix_directory = lilypond_datadir + "/current";
114 if (is_dir (localedir))
115 bindtextdomain ("lilypond", localedir.c_str ());
118 prepend_env_path ("PATH", bindir);
122 UGH : this is a complete mess.
126 framework_relocation (string prefix)
128 if (be_verbose_global)
129 warning (_f ("Relocation: framework_prefix=%s", prefix));
131 sane_putenv ("INSTALLER_PREFIX", prefix, true);
133 read_relocation_dir (prefix + "/etc/relocate/");
135 string bindir = prefix + "/bin";
137 prepend_env_path ("PATH", bindir);
141 UGH : this is a complete mess.
144 setup_paths (char const *argv0_ptr)
146 File_name argv0_filename (argv0_ptr);
148 prefix_directory = LILYPOND_DATADIR;
150 && getenv ("LILYPOND_RELOCATE_PREFIX"))
152 prefix_directory = getenv ("LILYPOND_RELOCATE_PREFIX");
154 /* Normalize file name. */
155 prefix_directory = File_name (prefix_directory).to_string ();
156 #endif /* __MINGW32__ */
158 prefix_relocation (prefix_directory);
159 string bindir = prefix_directory + "/bin";
160 framework_relocation (bindir);
162 else if (relocate_binary)
165 if (argv0_filename.is_absolute ())
167 argv0_abs = argv0_filename.to_string ();
168 if (be_verbose_global)
169 warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
171 else if (argv0_filename.dir_.length ())
173 argv0_abs = get_working_directory ()
174 + "/" + string (argv0_filename.to_string ());
175 if (be_verbose_global)
176 warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
180 /* Find absolute ARGV0 name, using PATH. */
182 path.parse_path (getenv ("PATH"));
184 if (be_verbose_global)
185 warning (_f ("Relocation: from PATH=%s\nargv0=%s",
186 path.to_string ().c_str (), argv0_ptr));
189 argv0_abs = path.find (argv0_filename.to_string ());
190 #else /* __MINGW32__ */
191 char const *ext[] = {"exe", "", 0 };
192 argv0_abs = path.find (argv0_filename.to_string (), ext);
193 #endif /* __MINGW32__ */
195 if (argv0_abs.empty ())
196 programming_error ("cannot find absolute argv0");
199 string bindir = dir_name (argv0_abs);
200 string argv0_prefix = dir_name (bindir);
201 string compile_prefix = dir_name (dir_name (dir_name (prefix_directory)));
202 if (argv0_prefix != compile_prefix)
204 prefix_relocation (argv0_prefix);
205 prefix_directory = argv0_prefix;
207 if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
209 framework_relocation (bindir + "/" + FRAMEWORKDIR);
210 prefix_directory = bindir + "/" + FRAMEWORKDIR;
214 /* FIXME: use LILYPOND_DATADIR. */
215 if (char const *env = getenv ("LILYPONDPREFIX"))
218 /* Normalize file name. */
219 prefix_directory = File_name (env).to_string ();
221 prefix_directory = env;
225 global_path.append ("");
229 When running from build dir, a full LILYPOND_PREFIX is set-up at
231 $(OUTBASE)/share/lilypond/TOPLEVEL_VERSION
233 This historical hack will allow the shorthand
235 LILYPONDPREFIX=out lily/out/lilypond ...
239 string build_prefix_current = prefix_directory + "/share/lilypond/" "current";
240 string build_prefix_version = prefix_directory + "/share/lilypond/" TOPLEVEL_VERSION;
241 if (is_dir (build_prefix_version.c_str ()))
242 prefix_directory = build_prefix_version;
243 else if (is_dir (build_prefix_current.c_str ()))
244 prefix_directory = build_prefix_current;
246 /* Adding mf/out make lilypond unchanged source directory, when setting
247 LILYPONDPREFIX to lilypond-x.y.z */
248 char const *suffixes[] = {"ly", "ps", "scm", 0 };
251 for (char const **s = suffixes; *s; s++)
253 string path = prefix_directory + to_string ('/') + string (*s);
254 dirs.push_back (path);
257 dirs.push_back (prefix_directory + "/fonts/otf/");
258 dirs.push_back (prefix_directory + "/fonts/type1/");
259 dirs.push_back (prefix_directory + "/fonts/svg/");
261 for (vsize i = 0; i < dirs.size (); i++)
262 global_path.prepend (dirs[i]);
268 expand_environment_variables (string orig)
270 const char *start_ptr = orig.c_str();
271 const char *ptr = orig.c_str();
272 size_t len = orig.length();
275 while (ptr < start_ptr + len)
277 char *dollar = strchr (ptr, '$');
281 char *start_var = dollar + 1;
282 char *end_var = start_var;
283 char *start_next = end_var;
285 out += string (ptr, dollar - ptr);
288 if (*start_var == '{')
292 end_var = strchr (start_var, '}');
296 end_var = start_var + len;
297 start_next = end_var;
301 start_next = end_var + 1;
307 Hmm. what to do for $1 , $~ etc.?
313 while (isalnum (*end_var) || *end_var == '_');
314 start_next = end_var;
317 if (start_var < end_var)
319 string var_name (start_var, end_var - start_var);
320 const char *value = getenv (var_name.c_str());
322 out += string (value);
344 while ((c = fgetc (f)) != EOF && c != '\n')
351 read_relocation_file (string filename)
353 if (be_verbose_global)
354 progress_indication (_f ("Relocation file: %s", filename.c_str ())
357 char const *cname = filename.c_str ();
358 FILE *f = fopen (cname, "r");
360 error (_f ("cannot open file: `%s'", cname));
364 string line = read_line (f);
365 size_t idx = line.find (' ');
369 string command = line.substr (0, idx);
370 line = line.substr (idx + 1);
374 idx = line.find ('=');
376 string variable = line.substr (0, idx);
377 string value = line.substr (idx + 1);
379 value = expand_environment_variables (value);
381 if (command == "set")
382 sane_putenv (variable.c_str(), value, true);
383 else if (command == "setdir")
384 set_env_dir (variable.c_str(), value);
385 else if (command == "setfile")
386 set_env_file (variable.c_str(), value);
387 else if (command == "prependdir")
388 prepend_env_path (variable.c_str (), value);
390 error (_f ("Unknown relocation command %s", command));
397 read_relocation_dir (string dirname)
399 if (DIR *dir = opendir (dirname.c_str ()))
400 while (struct dirent *ent = readdir (dir))
402 File_name name (ent->d_name);
403 if (name.ext_ == "reloc")
404 read_relocation_file (dirname + "/" + name.to_string ());