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