]> git.donarmstrong.com Git - lilypond.git/blob - lily/relocate.cc
(framework_relocation): use INSTALLER_PREFIX.
[lilypond.git] / lily / relocate.cc
1 /*
2   relocate.cc -- implement relocation based on argv0
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8 */
9
10 #include "relocate.hh"
11
12 #include "config.hh"
13
14
15 /* TODO: autoconf support */
16
17 #include <sys/types.h>
18 #include <dirent.h>
19
20 #if HAVE_GETTEXT
21 #include <libintl.h>
22 #endif
23
24 #include "file-name.hh"
25 #include "file-path.hh"
26 #include "international.hh"
27 #include "lily-guile.hh"
28 #include "lily-version.hh"
29 #include "main.hh"
30 #include "version.hh"
31 #include "warn.hh"
32
33 #define FRAMEWORKDIR ".."
34
35
36 int
37 sane_putenv (char const *key, string value, bool overwrite)
38 {
39   if (overwrite || !getenv (key))
40     {
41       string combine = string (key) + "=" + value;
42       char *s = strdup (combine.c_str ());
43       return putenv (s);
44     }
45   
46   return -1;
47 }
48
49 static int
50 set_env_file (char const *key, string value, bool overwrite = false)
51 {
52   if (is_file (value))
53     return sane_putenv (key, value, overwrite);
54   else if (be_verbose_global)
55     warning (_f ("no such file: %s for %s", value, key));
56   return -1;
57 }
58
59 static int
60 set_env_dir (char const *key, string value)
61 {
62   if (is_dir (value))
63     return sane_putenv (key, value, false);
64   else if (be_verbose_global)
65     warning (_f ("no such directory: %s for %s", value, key));
66   return -1;
67 }
68
69 static int
70 prepend_env_path (char const *key, string value)
71 {
72   if (is_dir (value))
73     {
74       if (be_verbose_global)
75         progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ())); 
76
77       if (char const *cur = getenv (key))
78         value += to_string (PATHSEP) + cur;
79
80       return sane_putenv (key, value.c_str (), true);
81     }
82   else if (be_verbose_global)
83     warning (_f ("no such directory: %s for %s", value, key));
84   return -1;
85 }
86
87 #ifdef __MINGW32__
88 #include <winbase.h>
89 #endif
90
91 void
92 prefix_relocation (string prefix)
93 {
94   if (be_verbose_global)
95     warning (_f ("Relocation: compile prefix=%s, new prefix=%s",
96                  prefix_directory,
97                  prefix.c_str ()));
98   
99   string bindir = prefix + "/bin";
100   string datadir = prefix + "/share";
101   string localedir = datadir + "/locale";
102   string lilypond_datadir = datadir + "/lilypond/";
103
104   if (is_dir (lilypond_datadir + "/" + TOPLEVEL_VERSION))
105     prefix_directory = lilypond_datadir + "/" + TOPLEVEL_VERSION;
106   else if (is_dir (lilypond_datadir + "/current"))
107     prefix_directory = lilypond_datadir + "/current";
108
109 #if HAVE_GETTEXT
110   if (is_dir (localedir))
111     bindtextdomain ("lilypond", localedir.c_str ());
112 #endif
113
114   prepend_env_path ("PATH", bindir);
115 }
116
117 void
118 framework_relocation (string prefix)
119 {
120   if (be_verbose_global)
121     warning (_f ("Relocation: framework_prefix=%s", prefix));
122
123   sane_putenv ("INSTALLER_PREFIX", prefix, true);
124                
125   read_relocation_dir (prefix + "/etc/relocate/");
126
127   string bindir = prefix + "/bin";
128
129 #ifdef OLD_RELOCATION
130   string datadir = prefix + "/share";
131   string libdir = prefix + "/lib";
132   string sysconfdir = prefix + "/etc";
133   
134   /* need otherwise dynamic .so's aren't found.   */
135   prepend_env_path ("DYLD_LIBRARY_PATH", libdir);
136   
137   set_env_file ("FONTCONFIG_FILE", sysconfdir + "/fonts/fonts.conf", true);
138   set_env_dir ("FONTCONFIG_PATH", sysconfdir + "/fonts");
139
140 #ifdef __MINGW32__
141   char font_dir[PATH_MAX];
142   ExpandEnvironmentStrings ("%windir%/fonts", font_dir, sizeof (font_dir));
143   prepend_env_path ("GS_FONTPATH", font_dir);
144 #endif
145
146   string gs_version =
147 #ifdef GHOSTSCRIPT_VERSION
148     GHOSTSCRIPT_VERSION
149 #else
150     "ghostscript-version-undefined"
151 #endif
152     ;
153   
154   if (char const *cur = getenv ("LILYPOND_GS_VERSION"))
155     gs_version = cur;
156   
157   prepend_env_path ("GS_FONTPATH", datadir + "/ghostscript/" + gs_version + "/fonts");
158   prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/Resource");
159   prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/lib");
160
161   prepend_env_path ("GS_FONTPATH", datadir + "/gs/fonts");
162   prepend_env_path ("GS_LIB", datadir + "/gs/Resource");
163   prepend_env_path ("GS_LIB", datadir + "/gs/lib");
164   
165   prepend_env_path ("GUILE_LOAD_PATH", datadir
166                     + to_string ("/guile/%d.%d",
167                                  SCM_MAJOR_VERSION, SCM_MINOR_VERSION));
168   set_env_file ("PANGO_RC_FILE", sysconfdir + "/pango/pangorc");
169   set_env_dir ("PANGO_PREFIX", prefix);
170
171 #endif
172   
173   
174   prepend_env_path ("PATH", bindir);
175 }
176
177 void
178 setup_paths (char const *argv0_ptr)
179 {
180   File_name argv0_filename (argv0_ptr);
181   
182   prefix_directory = LILYPOND_DATADIR;
183   if (relocate_binary
184       && getenv ("LILYPOND_RELOCATE_PREFIX"))
185     {
186       string prefix = getenv ("LILYPOND_RELOCATE_PREFIX");
187 #ifdef __MINGW32__
188       /* Normalize file name.  */
189       prefix = File_name (prefix).to_string ();
190 #endif /* __MINGW32__ */
191       prefix_relocation (prefix);
192       string bindir = prefix + "/bin";
193       framework_relocation (bindir);
194     }
195   else if (relocate_binary)
196     {
197       string argv0_abs;
198       if (argv0_filename.is_absolute ())
199         {
200           argv0_abs = argv0_filename.to_string ();
201           if (be_verbose_global)
202             warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
203         }
204       else if (argv0_filename.dir_.length ())
205         {
206           argv0_abs = get_working_directory ()
207             + "/" + string (argv0_filename.to_string ());
208           if (be_verbose_global)
209             warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
210         }
211       else
212         {
213           /* Find absolute ARGV0 name, using PATH.  */
214           File_path path;
215           path.parse_path (getenv ("PATH"));
216
217           if (be_verbose_global)
218             warning (_f ("Relocation: from PATH=%s\nargv0=%s",
219                          path.to_string ().c_str (), argv0_ptr));
220
221 #ifndef __MINGW32__
222           argv0_abs = path.find (argv0_filename.to_string ());
223 #else /* __MINGW32__ */
224           char const *ext[] = {"exe", "", 0 };
225           argv0_abs = path.find (argv0_filename.to_string (), ext);
226 #endif /* __MINGW32__ */
227
228           if (argv0_abs.empty ())
229             programming_error ("can't find absolute argv0.");
230         }
231
232       string bindir = dir_name (argv0_abs);
233       string argv0_prefix = dir_name (bindir);
234       string compile_prefix = dir_name (dir_name (dir_name (prefix_directory)));
235       if (argv0_prefix != compile_prefix)
236         prefix_relocation (argv0_prefix);
237       if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
238         framework_relocation (bindir + "/" + FRAMEWORKDIR);
239     }
240
241   /* FIXME: use LILYPOND_DATADIR.  */
242   if (char const *env = getenv ("LILYPONDPREFIX"))
243     {
244
245 #ifdef __MINGW32__
246       /* Normalize file name.  */
247       prefix_directory = File_name (env).to_string ();
248 #else
249       prefix_directory = env;
250 #endif
251     }
252
253   global_path.append ("");
254
255
256   /*
257     When running from build dir, a full LILYPOND_PREFIX is set-up at
258
259         $(OUTBASE)/share/lilypond/TOPLEVEL_VERSION
260
261      This historical hack will allow the shorthand
262
263         LILYPONDPREFIX=out lily/out/lilypond ...
264
265   */
266   
267   string build_prefix_current = prefix_directory + "/share/lilypond/" "current";
268   string build_prefix_version = prefix_directory + "/share/lilypond/" TOPLEVEL_VERSION;
269   if (is_dir (build_prefix_version.c_str ()))
270     prefix_directory = build_prefix_version;
271   else if (is_dir (build_prefix_current.c_str ()))
272     prefix_directory = build_prefix_current;
273   
274   /* Adding mf/out make lilypond unchanged source directory, when setting
275      LILYPONDPREFIX to lilypond-x.y.z */
276   char const *suffixes[] = {"ly", "ps", "scm", 0 };
277   
278   vector<string> dirs;
279   for (char const **s = suffixes; *s; s++)
280     {
281       string path = prefix_directory + to_string ('/') + string (*s);
282       dirs.push_back (path);
283     }
284   
285   dirs.push_back (prefix_directory + "/fonts/otf/");
286   dirs.push_back (prefix_directory + "/fonts/type1/");
287   dirs.push_back (prefix_directory + "/fonts/svg/");
288   
289   for (vsize i = 0; i < dirs.size (); i++)
290     global_path.prepend (dirs[i]);
291 }
292
293
294
295 string
296 expand_environment_variables (string orig)
297 {
298   const char *start_ptr = orig.c_str();
299   const char *ptr = orig.c_str();
300   size_t len = orig.length();
301
302   string out;
303   while (ptr < start_ptr + len)
304     {
305       char *dollar = strchr (ptr, '$');
306       
307       if (dollar != NULL)
308         {
309           char *start_var = dollar + 1;
310           char *end_var = start_var;
311           char *start_next = end_var;
312           
313           out += string (ptr, dollar - ptr);
314           ptr = dollar;
315
316           if (*start_var == '{')
317             {
318               start_var ++;
319               
320               end_var = strchr (start_var, '}');
321               
322               if (end_var == NULL)
323                 {
324                   end_var = start_var + len;
325                   start_next = end_var;
326                 }
327               else
328                 {
329                   start_next = end_var + 1; 
330                 }
331             }
332           else 
333             {
334               /*
335                 Hmm. what to do for $1 , $~ etc.?
336                */
337               do
338                 {
339                   end_var ++;
340                 }
341               while (isalnum (*end_var) || *end_var == '_');
342               start_next = end_var;
343             }
344
345           if (start_var < end_var)
346             {
347               string var_name (start_var, end_var - start_var);
348               const char *value = getenv (var_name.c_str());
349               if (value != NULL)
350                 out += string (value);
351
352               ptr = start_next;
353             }
354         }
355       else
356         break;
357
358     }
359
360   out += ptr;
361
362   return out;
363 }
364
365
366 string
367 read_line (FILE *f)
368 {
369   string out;
370   
371   int c = 0;
372   while ((c = fgetc (f)) != EOF && c != '\n')
373     out += c;
374
375   return out;
376 }
377
378 void
379 read_relocation_file (string filename)
380 {
381   if (be_verbose_global)
382     progress_indication (_f ("Relocation file %s", filename.c_str ()));
383       
384   char const *cname = filename.c_str ();
385   FILE *f = fopen (cname, "r");
386   if (!f)
387     error (_f ("can't open file %s", cname));
388
389   while (!feof (f))
390     {
391       string line = read_line (f);
392       size_t idx = line.find (' ');
393       if (idx == NPOS)
394         continue;
395       
396       string command = line.substr (0, idx);
397       line = line.substr (idx + 1);
398       
399       if (idx == NPOS)
400         continue;
401       idx = line.find ('=');
402
403       string variable = line.substr (0, idx);
404       string value = line.substr (idx + 1);
405
406       value = expand_environment_variables (value);
407
408       if (command == "set")
409         sane_putenv (variable.c_str(), value, true);
410       else if (command == "setdir")
411         set_env_dir (variable.c_str(), value);
412       else if (command == "setfile")
413         set_env_file (variable.c_str(), value);
414       else if (command == "prependdir")
415         prepend_env_path (variable.c_str (), value);
416       else
417         error ( _f("Unknown relocation command %s", command));
418     }
419
420   fclose (f);
421 }
422
423 void
424 read_relocation_dir (string dirname)
425 {
426   DIR *dir = opendir  (dirname.c_str ());
427
428   while (struct dirent *ent = readdir (dir))
429     {
430       File_name name (ent->d_name);
431       if (name.ext_ == "reloc")
432         {
433           read_relocation_file (dirname + "/" + name.to_string ());
434         }
435     }
436 }