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 ())
47 int retval = putenv (s);
49 unfortunately, we can't portably free S here,
50 due to various bugs in glibc prior to 2.1.1
59 set_env_file (char const *key, string value, bool overwrite = false)
62 return sane_putenv (key, value, overwrite);
63 else if (be_verbose_global)
64 warning (_f ("no such file: %s for %s", value, key));
69 set_env_dir (char const *key, string value)
72 return sane_putenv (key, value, false);
73 else if (be_verbose_global)
74 warning (_f ("no such directory: %s for %s", value, key));
79 prepend_env_path (char const *key, string value)
83 if (be_verbose_global)
84 progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ()));
86 if (char const *cur = getenv (key))
87 value += to_string (PATHSEP) + cur;
89 return sane_putenv (key, value.c_str (), true);
91 else if (be_verbose_global)
92 warning (_f ("no such directory: %s for %s", value, key));
101 prefix_relocation (string prefix)
103 string bindir = prefix + "/bin";
104 string datadir = prefix + "/share";
105 string localedir = datadir + "/locale";
106 string package_datadir = datadir + "/lilypond/";
107 string old_lilypond_datadir = lilypond_datadir;
109 if (is_dir (package_datadir + "/" + TOPLEVEL_VERSION))
110 lilypond_datadir = package_datadir + "/" + TOPLEVEL_VERSION;
111 else if (is_dir (package_datadir + "/current"))
112 lilypond_datadir = package_datadir + "/current";
114 warning (_f ("not relocating, no %s/ or current/ found under %s",
115 TOPLEVEL_VERSION, package_datadir.c_str ()));
118 if (is_dir (localedir))
119 bindtextdomain ("lilypond", localedir.c_str ());
122 prepend_env_path ("PATH", bindir);
124 if (be_verbose_global)
125 warning (_f ("Relocation: compile datadir=%s, new datadir=%s",
126 old_lilypond_datadir.c_str (),
127 lilypond_datadir.c_str ()));
131 UGH : this is a complete mess.
135 framework_relocation (string prefix)
137 if (be_verbose_global)
138 warning (_f ("Relocation: framework_prefix=%s", prefix));
140 sane_putenv ("INSTALLER_PREFIX", prefix, true);
142 read_relocation_dir (prefix + "/etc/relocate/");
144 string bindir = prefix + "/bin";
146 prepend_env_path ("PATH", bindir);
150 UGH : this is a complete mess.
153 setup_paths (char const *argv0_ptr)
155 File_name argv0_filename (argv0_ptr);
159 string prefix_directory;
160 if (getenv ("LILYPOND_RELOCATE_PREFIX"))
162 prefix_directory = getenv ("LILYPOND_RELOCATE_PREFIX");
164 /* Normalize file name. */
165 prefix_directory = File_name (prefix_directory).to_string ();
166 #endif /* __MINGW32__ */
168 prefix_relocation (prefix_directory);
169 string bindir = prefix_directory + "/bin";
170 framework_relocation (bindir);
172 else if (relocate_binary)
175 if (argv0_filename.is_absolute ())
177 argv0_abs = argv0_filename.to_string ();
178 if (be_verbose_global)
179 warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
181 else if (argv0_filename.dir_.length ())
183 argv0_abs = get_working_directory ()
184 + "/" + string (argv0_filename.to_string ());
185 if (be_verbose_global)
186 warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
190 /* Find absolute ARGV0 name, using PATH. */
192 path.parse_path (getenv ("PATH"));
194 if (be_verbose_global)
195 warning (_f ("Relocation: from PATH=%s\nargv0=%s",
196 path.to_string ().c_str (), argv0_ptr));
199 argv0_abs = path.find (argv0_filename.to_string ());
200 #else /* __MINGW32__ */
201 char const *ext[] = {"exe", "", 0 };
202 argv0_abs = path.find (argv0_filename.to_string (), ext);
203 #endif /* __MINGW32__ */
205 if (argv0_abs.empty ())
206 programming_error ("cannot find absolute argv0");
209 string bindir = dir_name (argv0_abs);
210 string argv0_prefix = dir_name (bindir);
211 string compile_prefix = dir_name (dir_name (dir_name (lilypond_datadir)));
212 if (argv0_prefix != compile_prefix)
214 prefix_relocation (argv0_prefix);
215 prefix_directory = argv0_prefix;
217 if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
219 framework_relocation (bindir + "/" + FRAMEWORKDIR);
220 prefix_directory = bindir + "/" + FRAMEWORKDIR;
224 lilypond_datadir = prefix_directory
225 + "/share/lilypond/" TOPLEVEL_VERSION;
228 if (getenv ("LILYPONDPREFIX"))
229 error (_ ("LILYPONDPREFIX is obsolete, use LILYPOND_DATADIR"));
231 if (char const *env = getenv ("LILYPOND_DATADIR"))
234 /* Normalize file name. */
235 lilypond_datadir = File_name (env).to_string ();
237 lilypond_datadir = env;
241 /* When running from build dir, a full LILYPOND_DATADIR is set-up at
242 $(OUTBASE)/{share, lib}/lilypond/current. Configure lily using
243 ./configure --prefix=$(pwd)/out */
244 string build_datadir_current = dir_name (lilypond_datadir) + "/current";
245 if (!is_dir (lilypond_datadir.c_str ())
246 && is_dir (build_datadir_current.c_str ()))
247 lilypond_datadir = build_datadir_current;
249 global_path.append ("");
251 /* Adding mf/out make lilypond unchanged source directory, when setting
252 LILYPONDPREFIX to lilypond-x.y.z */
253 char const *suffixes[] = {"ly", "ps", "scm", 0 };
256 for (char const **s = suffixes; *s; s++)
258 string path = lilypond_datadir + to_string ('/') + string (*s);
259 dirs.push_back (path);
262 dirs.push_back (lilypond_datadir + "/fonts/otf/");
263 dirs.push_back (lilypond_datadir + "/fonts/type1/");
264 dirs.push_back (lilypond_datadir + "/fonts/svg/");
266 for (vsize i = 0; i < dirs.size (); i++)
267 global_path.prepend (dirs[i]);
271 expand_environment_variables (string orig)
273 const char *start_ptr = orig.c_str ();
274 const char *ptr = orig.c_str ();
275 size_t len = orig.length ();
278 while (ptr < start_ptr + len)
280 char *dollar = strchr (ptr, '$');
284 char *start_var = dollar + 1;
285 char *end_var = start_var;
286 char *start_next = end_var;
288 out += string (ptr, dollar - ptr);
291 if (*start_var == '{')
295 end_var = strchr (start_var, '}');
299 end_var = start_var + len;
300 start_next = end_var;
304 start_next = end_var + 1;
310 Hmm. what to do for $1 , $~ etc.?
316 while (isalnum (*end_var) || *end_var == '_');
317 start_next = end_var;
320 if (start_var < end_var)
322 string var_name (start_var, end_var - start_var);
323 const char *value = getenv (var_name.c_str ());
325 out += string (value);
347 while ((c = fgetc (f)) != EOF && c != '\n')
354 read_relocation_file (string filename)
356 if (be_verbose_global)
357 progress_indication (_f ("Relocation file: %s", filename.c_str ())
360 char const *cname = filename.c_str ();
361 FILE *f = fopen (cname, "r");
363 error (_f ("cannot open file: `%s'", cname));
367 string line = read_line (f);
368 size_t idx = line.find (' ');
372 string command = line.substr (0, idx);
373 line = line.substr (idx + 1);
377 idx = line.find ('=');
379 string variable = line.substr (0, idx);
380 string value = line.substr (idx + 1);
382 value = expand_environment_variables (value);
384 if (command == "set")
385 sane_putenv (variable.c_str (), value, true);
386 else if (command == "setdir")
387 set_env_dir (variable.c_str (), value);
388 else if (command == "setfile")
389 set_env_file (variable.c_str (), value);
390 else if (command == "prependdir")
391 prepend_env_path (variable.c_str (), value);
393 error (_f ("Unknown relocation command %s", command));
400 read_relocation_dir (string dirname)
402 if (DIR *dir = opendir (dirname.c_str ()))
403 while (struct dirent *ent = readdir (dir))
405 File_name name (ent->d_name);
406 if (name.ext_ == "reloc")
407 read_relocation_file (dirname + "/" + name.to_string ());