2 relocate.cc -- implement relocation based on argv0
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
10 #include "relocate.hh"
15 /* TODO: autoconf support */
18 #include <sys/types.h>
26 #include "file-name.hh"
27 #include "file-path.hh"
28 #include "international.hh"
29 #include "lily-guile.hh"
30 #include "lily-version.hh"
35 #define FRAMEWORKDIR ".."
38 sane_putenv (char const *key, string value, bool overwrite)
40 if (overwrite || !getenv (key))
42 string combine = string (key) + "=" + value;
43 char *s = strdup (combine.c_str ());
45 if (be_verbose_global)
46 progress_indication (_f ("Setting %s to %s" , key, value.c_str ())
49 int retval = putenv (s);
51 unfortunately, we can't portably free S here,
52 due to various bugs in glibc prior to 2.1.1
61 set_env_file (char const *key, string value, bool overwrite = false)
64 return sane_putenv (key, value, overwrite);
65 else if (be_verbose_global)
66 warning (_f ("no such file: %s for %s", value, key));
71 set_env_dir (char const *key, string value)
74 return sane_putenv (key, value, false);
75 else if (be_verbose_global)
76 warning (_f ("no such directory: %s for %s", value, key));
81 prepend_env_path (char const *key, string value)
85 if (be_verbose_global)
86 progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ()));
88 if (char const *cur = getenv (key))
89 value += to_string (PATHSEP) + cur;
91 return sane_putenv (key, value.c_str (), true);
93 else if (be_verbose_global)
94 warning (_f ("no such directory: %s for %s", value, key));
103 prefix_relocation (string prefix)
105 string bindir = prefix + "/bin";
106 string datadir = prefix + "/share";
107 string localedir = datadir + "/locale";
108 string package_datadir = datadir + "/lilypond/";
109 string old_lilypond_datadir = lilypond_datadir;
111 if (is_dir (package_datadir + "/" + TOPLEVEL_VERSION))
112 lilypond_datadir = package_datadir + "/" + TOPLEVEL_VERSION;
113 else if (is_dir (package_datadir + "/current"))
114 lilypond_datadir = package_datadir + "/current";
116 warning (_f ("not relocating, no %s/ or current/ found under %s",
117 TOPLEVEL_VERSION, package_datadir.c_str ()));
120 if (is_dir (localedir))
121 bindtextdomain ("lilypond", localedir.c_str ());
124 prepend_env_path ("PATH", bindir);
126 if (be_verbose_global)
127 warning (_f ("Relocation: compile datadir=%s, new datadir=%s",
128 old_lilypond_datadir.c_str (),
129 lilypond_datadir.c_str ()));
133 UGH : this is a complete mess.
137 framework_relocation (string prefix)
139 if (be_verbose_global)
140 warning (_f ("Relocation: framework_prefix=%s", prefix));
142 sane_putenv ("INSTALLER_PREFIX", prefix, true);
144 read_relocation_dir (prefix + "/etc/relocate/");
146 string bindir = prefix + "/bin";
148 prepend_env_path ("PATH", bindir);
152 UGH : this is a complete mess.
155 setup_paths (char const *argv0_ptr)
157 File_name argv0_filename (argv0_ptr);
161 string prefix_directory;
162 if (getenv ("LILYPOND_RELOCATE_PREFIX"))
164 prefix_directory = getenv ("LILYPOND_RELOCATE_PREFIX");
166 /* Normalize file name. */
167 prefix_directory = File_name (prefix_directory).to_string ();
168 #endif /* __MINGW32__ */
170 prefix_relocation (prefix_directory);
171 string bindir = prefix_directory + "/bin";
172 framework_relocation (bindir);
174 else if (relocate_binary)
177 if (argv0_filename.is_absolute ())
179 argv0_abs = argv0_filename.to_string ();
180 if (be_verbose_global)
181 warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
183 else if (argv0_filename.dir_.length ())
185 argv0_abs = get_working_directory ()
186 + "/" + string (argv0_filename.to_string ());
187 if (be_verbose_global)
188 warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
192 /* Find absolute ARGV0 name, using PATH. */
194 path.parse_path (getenv ("PATH"));
196 if (be_verbose_global)
197 warning (_f ("Relocation: from PATH=%s\nargv0=%s",
198 path.to_string ().c_str (), argv0_ptr));
201 argv0_abs = path.find (argv0_filename.to_string ());
202 #else /* __MINGW32__ */
203 char const *ext[] = {"exe", "", 0 };
204 argv0_abs = path.find (argv0_filename.to_string (), ext);
205 #endif /* __MINGW32__ */
207 if (argv0_abs.empty ())
208 programming_error ("cannot find absolute argv0");
211 string bindir = dir_name (argv0_abs);
212 string argv0_prefix = dir_name (bindir);
213 string compile_prefix = dir_name (dir_name (dir_name (lilypond_datadir)));
214 if (argv0_prefix != compile_prefix)
216 prefix_relocation (argv0_prefix);
217 prefix_directory = argv0_prefix;
219 if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
221 framework_relocation (bindir + "/" + FRAMEWORKDIR);
222 prefix_directory = bindir + "/" + FRAMEWORKDIR;
226 lilypond_datadir = prefix_directory
227 + "/share/lilypond/" TOPLEVEL_VERSION;
230 if (getenv ("LILYPONDPREFIX"))
231 error (_ ("LILYPONDPREFIX is obsolete, use LILYPOND_DATADIR"));
233 if (char const *env = getenv ("LILYPOND_DATADIR"))
235 /* Normalize file name. */
236 lilypond_datadir = File_name (env).to_string ();
239 /* When running from build dir, a full LILYPOND_DATADIR is set-up at
240 $(OUTBASE)/{share, lib}/lilypond/current. Configure lily using
241 ./configure --prefix=$(pwd)/out */
242 string build_datadir_current = dir_name (lilypond_datadir) + "/current";
243 if (!is_dir (lilypond_datadir.c_str ())
244 && is_dir (build_datadir_current.c_str ()))
245 lilypond_datadir = build_datadir_current;
248 lilypond_datadir = File_name (lilypond_datadir).canonicalized().to_string();
250 global_path.append ("");
252 /* Adding mf/out make lilypond unchanged source directory, when setting
253 LILYPONDPREFIX to lilypond-x.y.z */
254 char const *suffixes[] = {"ly", "ps", "scm", 0 };
257 for (char const **s = suffixes; *s; s++)
259 string path = lilypond_datadir + to_string ('/') + string (*s);
260 dirs.push_back (path);
263 dirs.push_back (lilypond_datadir + "/fonts/otf/");
264 dirs.push_back (lilypond_datadir + "/fonts/type1/");
265 dirs.push_back (lilypond_datadir + "/fonts/svg/");
267 for (vsize i = 0; i < dirs.size (); i++)
268 global_path.prepend (dirs[i]);
272 expand_environment_variables (string orig)
274 char const *start_ptr = orig.c_str ();
275 char const *ptr = orig.c_str ();
276 size_t len = orig.length ();
279 while (ptr < start_ptr + len)
281 char const *dollar = strchr (ptr, '$');
285 char const *start_var = dollar + 1;
286 char const *end_var = start_var;
287 char const *start_next = end_var;
289 out += string (ptr, dollar - ptr);
292 if (*start_var == '{')
296 end_var = strchr (start_var, '}');
300 end_var = start_var + len;
301 start_next = end_var;
305 start_next = end_var + 1;
311 Hmm. what to do for $1 , $~ etc.?
317 while (isalnum (*end_var) || *end_var == '_');
318 start_next = end_var;
321 if (start_var < end_var)
323 string var_name (start_var, end_var - start_var);
324 char const *value = getenv (var_name.c_str ());
326 out += string (value);
341 // Ugh - very inefficient, but safer than fgets.
348 while ((c = fgetc (f)) != EOF && c != '\n')
355 read_relocation_file (string filename)
357 if (be_verbose_global)
358 progress_indication (_f ("Relocation file: %s", filename.c_str ())
361 char const *cname = filename.c_str ();
362 FILE *f = fopen (cname, "r");
364 error (_f ("cannot open file: `%s'", cname));
368 string line = read_line (f);
369 size_t idx = line.find (' ');
373 string command = line.substr (0, idx);
374 line = line.substr (idx + 1);
378 idx = line.find ('=');
380 string variable = line.substr (0, idx);
381 string value = line.substr (idx + 1);
383 value = expand_environment_variables (value);
385 if (command == "set")
386 sane_putenv (variable.c_str (), value, true);
387 else if (command == "setdir")
388 set_env_dir (variable.c_str (), value);
389 else if (command == "setfile")
390 set_env_file (variable.c_str (), value);
391 else if (command == "prependdir")
392 prepend_env_path (variable.c_str (), value);
394 error (_f ("Unknown relocation command %s", command));
401 read_relocation_dir (string dirname)
403 if (DIR *dir = opendir (dirname.c_str ()))
404 while (struct dirent *ent = readdir (dir))
406 File_name name (ent->d_name);
407 if (name.ext_ == "reloc")
408 read_relocation_file (dirname + "/" + name.to_string ());