]> git.donarmstrong.com Git - lilypond.git/blob - lily/main.cc
Run grand-replace (issue 3765)
[lilypond.git] / lily / main.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "main.hh"
21
22 #include <cassert>
23 #include <clocale>
24 #include <cstring>
25 #include <cerrno>
26 #include <cstdio>
27 using namespace std;
28
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include "config.hh"
32
33 #if HAVE_GRP_H
34 #include <grp.h>
35 #endif
36 #if HAVE_PWD_H
37 #include <pwd.h>
38 #endif
39 #if HAVE_GETTEXT
40 #include <libintl.h>
41 #endif
42
43 #include "all-font-metrics.hh"
44 #include "file-name.hh"
45 #include "freetype.hh"
46 #include "getopt-long.hh"
47 #include "global-ctor.hh"
48 #include "international.hh"
49 #include "lily-version.hh"
50 #include "misc.hh"
51 #include "output-def.hh"
52 #include "program-option.hh"
53 #include "relocate.hh"
54 #include "string-convert.hh"
55 #include "version.hh"
56 #include "warn.hh"
57
58 /*
59  * Global options that can be overridden through command line.
60  */
61
62 /* Names of header fields to be dumped to a separate file. */
63 //vector<string> dump_header_fieldnames_global; // moved to global-data.cc
64
65 /* Name of initialisation file. */
66 //string init_name_global; // moved to global-data.cc
67
68 /* Output formats to generate.  */
69 //string output_format_global = ""; // moved to global-data.cc
70
71 /* Current output name. */
72 //string output_name_global; // moved to global-data.cc
73
74 /* Run in safe mode? */
75 //bool be_safe_global = false; // moved to global-data.cc
76
77 /* Provide URI links to the original file */
78 bool point_and_click_global = true;
79
80 /* Scheme code to execute before parsing, after .scm init.
81    This is where -e arguments are appended to.  */
82 //string init_scheme_code_global; // moved to global-data.cc
83 //string init_scheme_variables_global; // moved to global-data.cc
84
85 //bool relocate_binary = true; // moved to global-data.cc
86
87 /*
88  * Miscellaneous global stuff.
89  */
90 //File_path global_path; // moved to global-data.cc
91
92 /*
93  * File globals.
94  */
95
96 static char const *AUTHORS
97   = "  Han-Wen Nienhuys <hanwen@xs4all.nl>\n"
98     "  Jan Nieuwenhuizen <janneke@gnu.org>\n";
99
100 static char const *PROGRAM_NAME = "lilypond";
101 static char const *PROGRAM_URL = "http://lilypond.org";
102
103 static char const *NOTICE
104   = _i ("This program is free software.  It is covered by the GNU General Public\n"
105         "License and you are welcome to change it and/or distribute copies of it\n"
106         "under certain conditions.  Invoke as `%s --warranty' for more\n"
107         "information.\n");
108
109 static char const *WARRANTY
110   = _i ("    This program is free software; you can redistribute it and/or\n"
111         "modify it under the terms of the GNU General Public License as \n"
112         "published by the Free Software Foundation, either version 3 of\n"
113         "the License, or (at your option) any later version.\n"
114         "\n"
115         "    This program is distributed in the hope that it will be useful,\n"
116         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
117         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
118         "General Public License for more details.\n"
119         "\n"
120         "    You should have received a copy of the\n"
121         "GNU General Public License along with this program; if not, write to\n"
122         "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
123         "Boston, MA 02111-1307, USA.\n");
124
125 /* Where the init files live.  Typically:
126    LILYPOND_DATADIR = /usr/share/lilypond
127 */
128 //string lilypond_datadir; // moved to global-data.cc
129
130 /* The jail specification: USER, GROUP, JAIL, DIR. */
131 string jail_spec;
132
133 /*  The option parser */
134 static Getopt_long *option_parser = 0;
135
136 /* Internationalisation kludge in two steps:
137  * use _i () to get entry in POT file
138  * call gettext () explicitly for actual "translation"  */
139
140 /*
141   Data to be used to display when
142   -h command line option is detected.
143 */
144 static Long_option_init options_static[]
145 =
146 {
147   {
148     _i ("SYM[=VAL]"), "define-default", 'd',
149     _i ("set Scheme option SYM to VAL (default: #t).\n"
150     "Use -dhelp for help.")
151   },
152
153   {_i ("EXPR"), "evaluate", 'e', _i ("evaluate scheme code")},
154   /* Bug in option parser: --output =foe is taken as an abbreviation
155      for --output-format.  */
156   {_i ("FORMATs"), "formats", 'f', _i ("dump FORMAT,...  Also as separate options:")},
157   {0, "pdf", 0, _i ("generate PDF (default)")},
158   {0, "png", 0, _i ("generate PNG")},
159   {0, "ps", 0, _i ("generate PostScript")},
160   {0, "help", 'h', _i ("show this help and exit")},
161   {
162     _i ("FIELD"), "header", 'H', _i ("dump header field FIELD to file\n"
163     "named BASENAME.FIELD")
164   },
165   {_i ("DIR"), "include", 'I', _i ("add DIR to search path")},
166   {_i ("FILE"), "init", 'i', _i ("use FILE as init file")},
167 #if HAVE_CHROOT
168   {
169     _i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
170     "and cd into DIR")
171   },
172 #endif
173   {
174     _i ("LOGLEVEL"), "loglevel", 'l', _i ("print log messages according to"
175     " LOGLEVEL.  Possible values are:\n"
176     "NONE, ERROR, WARNING, BASIC, PROGRESS, INFO (default) and DEBUG.")
177   },
178   {_i ("FILE"), "output", 'o', _i ("write output to FILE (suffix will be added)")},
179   {0, "relocate", 0, _i ("relocate using directory of lilypond program")},
180   {0, "silent", 's', _i ("no progress, only error messages (equivalent to loglevel=ERROR)")},
181   {0, "version", 'v', _i ("show version number and exit")},
182   {0, "verbose", 'V', _i ("be verbose (equivalent to loglevel=DEBUG)")},
183   {0, "warranty", 'w', _i ("show warranty and copyright")},
184   {0, 0, 0, 0}
185 };
186
187 char const *LILYPOND_DATADIR = PACKAGE_DATADIR "/" TOPLEVEL_VERSION;
188
189 /* x86 defaults to using 80-bit extended precision arithmetic. This can cause
190    problems because the truncation from 80 bits to 64 bits can occur in
191    unpredictable places. To get around this, we tell the x87 FPU to use only
192    double precision. Note that this is not needed for x86_64 because that uses
193    the SSE unit by default instead of the x87 FPU. */
194 #if ((defined (__x86__) || defined (__i386__)) \
195   && defined (HAVE_FPU_CONTROL_H) && (HAVE_FPU_CONTROL_H == 1))
196
197 #include <fpu_control.h>
198 static void
199 configure_fpu ()
200 {
201   fpu_control_t fpu_control = 0x027f;
202   _FPU_SETCW (fpu_control);
203 }
204
205 #else
206
207 static void
208 configure_fpu ()
209 {
210 }
211
212 #endif /* defined(__x86__) || defined(__i386__) */
213
214 static void
215 env_var_info (FILE *out, char const *key)
216 /*
217  * Retrieve value of an OS environment variable.
218  * Parameter:
219  *  key, the name of an environment variable.
220  */
221 {
222   if (char const *value = getenv (key))
223     fprintf (out, "%s=\"%s\"\n", key, value);
224 }
225
226 static void
227 dir_info (FILE *out)
228 /*
229  * Print out information re directories being used by LilyPond
230  * for this session.
231  */
232 {
233   fputs ("\n", out);
234   fprintf (out, "LILYPOND_DATADIR=\"%s\"\n", LILYPOND_DATADIR);
235   env_var_info (out, "LILYPONDPREFIX");
236   env_var_info (out, "LILYPOND_DATADIR");
237   fprintf (out, "LOCALEDIR=\"%s\"\n", LOCALEDIR);
238
239   fprintf (out, "\nEffective prefix: \"%s\"\n", lilypond_datadir.c_str ());
240
241   if (relocate_binary)
242     {
243       env_var_info (out, "FONTCONFIG_FILE");
244       env_var_info (out, "FONTCONFIG_PATH");
245       env_var_info (out, "GS_FONTPATH");
246       env_var_info (out, "GS_LIB");
247       env_var_info (out, "GUILE_LOAD_PATH");
248       env_var_info (out, "PANGO_RC_FILE");
249       env_var_info (out, "PANGO_PREFIX");
250       env_var_info (out, "PATH");
251     }
252 }
253
254 static void
255 copyright ()
256 /*
257  * Print out LilyPond copyright info.
258  */
259 {
260   /* Do not update the copyright years here, run `make grand-replace'  */
261   printf ("%s", (_f ("Copyright (c) %s by\n%s  and others.", "1996--2014",
262                      AUTHORS).c_str ()));
263   printf ("\n");
264 }
265
266 static void
267 identify (FILE *out)
268 /*
269  * Print out LilyPond version string.
270  */
271 {
272   fputs (gnu_lilypond_version_string ().c_str (), out);
273   fputs ("\n", out);
274 }
275
276 static void
277 /*
278  * Print copyright and program name
279  */
280 notice ()
281 {
282   identify (stdout);
283   printf ("\n");
284   copyright ();
285   printf ("\n");
286   puts (_f (NOTICE, PROGRAM_NAME).c_str ());
287 }
288
289 LY_DEFINE (ly_usage, "ly:usage",
290            0, 0, 0, (),
291            "Print usage message.")
292 /*
293  * ly_usage: Routine to output standard information when LilyPond is run without a
294  * source file to compile.
295  * Also callable as ly:usage from Scheme.
296  */
297 {
298   /* No version number or newline here.  It confuses help2man.  */
299   printf ("%s", (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME).c_str ()));
300   printf ("\n\n");
301   printf ("%s", (_ ("Typeset music and/or produce MIDI from FILE.").c_str ()));
302   printf ("\n\n");
303   printf ("%s", (_ ("LilyPond produces beautiful music notation.").c_str ()));
304   printf ("\n");
305   printf ("%s", (_f ("For more information, see %s", PROGRAM_URL).c_str ()));
306   printf ("\n\n");
307   printf ("%s", (_ ("Options:").c_str ()));
308   printf ("\n");
309   printf ("%s", Long_option_init::table_string (options_static).c_str ());
310   printf ("\n");
311   /* Translators, please translate this string as
312      "Report bugs in English via %s",
313      or if there is a LilyPond users list or forum in your language
314      "Report bugs in English via %s or in YOUR_LANG via URI"  */
315   printf ("%s", (_f ("Report bugs via %s",
316                      "http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs"
317                     ).c_str ()));
318   printf ("\n");
319   printf ("\n");
320   return SCM_UNSPECIFIED;
321 }
322
323 static void
324 warranty ()
325 /*
326  * Prints out LilyPond warranty information
327  */
328 {
329   identify (stdout);
330   printf ("\n");
331   copyright ();
332   printf ("\n");
333   printf ("%s", (_ (WARRANTY).c_str ()));
334 }
335
336 static void
337 prepend_scheme_list (const string &dir, const string &scmlist)
338 /*
339  *  Inserts an item at the front of a Scheme list, e.g. %load-path
340  *  Parameters:
341  *    dir:     The directory to add to the front of the list
342  *    scmlist: The Scheme list onto which to prepend the directory
343  */
344 {
345   SCM var = scm_c_lookup (scmlist.c_str());
346   scm_variable_set_x (var, scm_cons (scm_from_locale_string (dir.c_str()),
347                                      scm_variable_ref (var)));
348   /*  string setcmd =
349              "(set! " + scmlist + " (cons \"" + dir + "\" " + scmlist +"))";
350              scm_c_eval_string (setcmd.c_str());*/
351 }
352
353 void init_global_tweak_registry ();
354 void init_fontconfig ();
355
356 #if HAVE_CHROOT
357 static void
358 do_chroot_jail ()
359 {
360   /* Now we chroot, setuid/setgrp and chdir.  If something goes wrong,
361      we exit (this is a security-sensitive area).  First we split
362      jail_spec into its components, then we retrieve the user/group id
363      (necessarily *before* chroot'ing) and finally we perform the
364      actual actions.  */
365
366   enum Jail
367   {
368     USER_NAME, GROUP_NAME, JAIL, DIR, JAIL_MAX
369   };
370
371   vector<string> components = string_split (jail_spec, ',');
372   if (components.size () != JAIL_MAX)
373     {
374       error (_f ("expected %d arguments with jail, found: %u", JAIL_MAX,
375                  (unsigned) components.size ()));
376       exit (2);
377     }
378
379   /* Hmm.  */
380   errno = 0;
381
382   int uid;
383   if (passwd *passwd = getpwnam (components[USER_NAME].c_str ()))
384     uid = passwd->pw_uid;
385   else
386     {
387       if (errno == 0)
388         error (_f ("no such user: %s", components[USER_NAME]));
389       else
390         error (_f ("cannot get user id from user name: %s: %s",
391                    components[USER_NAME],
392                    strerror (errno)));
393       exit (3);
394     }
395
396   /* Hmm.  */
397   errno = 0;
398
399   int gid;
400   if (group *group = getgrnam (components[GROUP_NAME].c_str ()))
401     gid = group->gr_gid;
402   else
403     {
404       if (errno == 0)
405         error (_f ("no such group: %s", components[GROUP_NAME]));
406       else
407         error (_f ("cannot get group id from group name: %s: %s",
408                    components[GROUP_NAME],
409                    strerror (errno)));
410       exit (3);
411     }
412
413   if (chroot (components[JAIL].c_str ()))
414     {
415       error (_f ("cannot chroot to: %s: %s", components[JAIL],
416                  strerror (errno)));
417       exit (3);
418     }
419
420   if (setgid (gid))
421     {
422       error (_f ("cannot change group id to: %d: %s", gid, strerror (errno)));
423       exit (3);
424     }
425
426   if (setuid (uid))
427     {
428       error (_f ("cannot change user id to: %d: %s", uid, strerror (errno)));
429       exit (3);
430     }
431
432   if (chdir (components[DIR].c_str ()))
433     {
434       error (_f ("cannot change working directory to: %s: %s", components[DIR],
435                  strerror (errno)));
436       exit (3);
437     }
438 }
439 #endif
440
441 static void
442 main_with_guile (void *, int, char **)
443 /*
444  * main-with-guile is invoked as a callback via scm_boot_guile from
445  * main.
446  * scm_boot_guile will have passed its data, argc and argv parameters
447  * to main_with_guile.
448  */
449 {
450   /* Engravers use lily.scm contents, so we need to make Guile find it.
451      Prepend onto GUILE %load-path.
452       %load-path is the symbol Guile searches for .scm files
453       %load-compiled-path is the symbol Guile V2 searches for .go files
454    */
455    string scm_pct_load_path = "%load-path";
456    string scm_pct_load_compiled_path = "%load-compiled-path";
457
458    prepend_scheme_list (lilypond_datadir, scm_pct_load_path );
459    prepend_scheme_list (lilypond_datadir + "/scm", scm_pct_load_path);
460
461 #if (GUILE2)
462    /*
463      Just as ughy - prepend "/scm/out" onto GUILE V2+ %load-compiled-path
464      and set %compile-fallback-path to our scm/out directory
465    */
466    /*
467      %load-compiled-path is the symbol Guile V2 searches for .go files
468    */
469    prepend_scheme_list (lilypond_datadir + "/scm/out",
470                           scm_pct_load_compiled_path);
471    /*
472      %compile-fallback-path is the guile cache root for auto-compiled files
473    */
474
475    string scm_pct_fallback_path = "%compile-fallback-path";
476    string ly_scm_go_dir = lilypond_datadir + "/scm/out";
477    //string scm_pct_set_fallback = "(set! " + scm_pct_fallback_path +
478    //  " \"" + lilypond_datadir + "/scm/out\")";
479    //scm_c_eval_string (scm_pct_set_fallback.c_str() );
480    scm_primitive_eval
481      (scm_list_3 (scm_from_locale_symbol ("set!"),
482                   scm_from_locale_symbol ("%compile-fallback-path"),
483                   scm_from_locale_string (ly_scm_go_dir.c_str())));
484 #endif
485
486   if (is_loglevel (LOG_DEBUG))
487     dir_info (stderr);
488
489   init_scheme_variables_global = "(list " + init_scheme_variables_global + ")";
490   init_scheme_code_global = "(begin " + init_scheme_code_global + ")";
491
492   ly_c_init_guile ();
493   call_constructors ();
494   init_fontconfig ();
495
496   init_freetype ();
497   ly_reset_all_fonts ();
498
499   /*
500      We accept multiple independent music files on the command line to
501      reduce compile time when processing lots of small files.
502      This way we don't have to start the Guile/Scheme interpreter more than once, as
503      starting the GUILE engine is very time consuming.
504   */
505
506   SCM files = SCM_EOL;
507   SCM *tail = &files;
508   while (char const *arg = option_parser->get_next_arg ())
509     {
510       *tail = scm_cons (scm_from_locale_string (arg), SCM_EOL);
511       tail = SCM_CDRLOC (*tail);
512     }
513
514   delete option_parser;
515   option_parser = 0;
516
517 #if HAVE_CHROOT
518   if (!jail_spec.empty ())
519     do_chroot_jail ();
520 #endif
521   /*
522     Now execute the Scheme entry-point declared in
523     lily.scm (lilypond-main)
524   */
525   // These commands moved to lily_guile_v2.scm
526   // SCM rep_mod = scm_c_resolve_module ("system repl repl");
527   // scm_c_use_module ("system repl repl");
528   // SCM err_handling_mod = scm_c_resolve_module ("system repl error-handling");
529   // SCM call_with_error_handling = scm_c_module_lookup (err_handling_mod, "call-with-error-handling");
530   // SCM result = scm_call_1 (
531   //                       scm_variable_ref (call_with_error_handling),
532   //                       scm_call_1 (ly_lily_module_constant ("lilypond-main"), files));
533   SCM result = scm_call_1 (ly_lily_module_constant ("lilypond-main"), files);
534   (void) result;
535
536   /* Unreachable.  */
537   exit (0);
538 }
539
540 static void
541 setup_localisation ()
542 /*
543  *  Set up local language text locale (if available from configure)
544  *  Implicit inputs:
545  *  HAVE_GETTEXT: Internationalization available for a local language.
546  */
547 {
548 #if HAVE_GETTEXT
549   /* Enable locales */
550   setlocale (LC_ALL, "");
551
552   /* FIXME: check if this is still true.
553      Disable localisation of float values. */
554   setlocale (LC_NUMERIC, "C");
555
556   string localedir = LOCALEDIR;
557   if (char const *env = getenv ("LILYPOND_LOCALEDIR"))
558     localedir = env;
559
560   bindtextdomain ("lilypond", localedir.c_str ());
561   textdomain ("lilypond");
562 #endif
563 }
564
565 static void
566 add_output_format (const string &format)
567 /*
568  * Capture information internally from command-line options
569  * re output format.
570  *
571  */
572 {
573   if (output_format_global != "")
574     output_format_global += ",";
575   output_format_global += format;
576 }
577
578 static void
579 parse_argv (int argc, char **argv)
580 /*
581  *  Parse command-line options
582  *  also, if -h (help), -v (version) or  -w (warranty) is detected,
583  *  output the usage information and exit.
584  */
585 {
586   bool show_help = false;
587   option_parser = new Getopt_long (argc, argv, options_static);
588   while (Long_option_init const *opt = (*option_parser) ())
589     {
590       switch (opt->shortname_char_)
591         {
592         case 0:
593           if (string (opt->longname_str0_) == "pdf"
594               || string (opt->longname_str0_) == "png"
595               || string (opt->longname_str0_) == "ps")
596             add_output_format (opt->longname_str0_);
597           else if (string (opt->longname_str0_) == "relocate")
598             relocate_binary = true;
599           break;
600
601         case 'd':
602           {
603             string arg (option_parser->optional_argument_str0_);
604             ssize eq = arg.find ('=');
605
606             string key = arg;
607             string val = "#t";
608
609             if (eq != NPOS)
610               {
611                 key = arg.substr (0, eq);
612                 val = arg.substr (eq + 1, arg.length () - 1);
613               }
614
615             init_scheme_variables_global
616             += "(cons \'" + key + " '" + val + ")\n";
617           }
618           break;
619
620         case 'v':
621           notice ();
622           exit (0);
623           break;
624         case 'o':
625           {
626             string s = option_parser->optional_argument_str0_;
627             File_name file_name (s);
628             output_name_global = file_name.to_string ();
629           }
630           break;
631         case 'j':
632           jail_spec = option_parser->optional_argument_str0_;
633           break;
634
635         case 'e':
636           init_scheme_code_global
637           += option_parser->optional_argument_str0_ + string (" ");
638           break;
639         case 'w':
640           warranty ();
641           exit (0);
642           break;
643
644         case 'f':
645           {
646             vector<string> components
647               = string_split (option_parser->optional_argument_str0_, ',');
648             for (vsize i = 0; i < components.size (); i++)
649               add_output_format (components[i]);
650           }
651           break;
652
653         case 'H':
654           dump_header_fieldnames_global
655           .push_back (option_parser->optional_argument_str0_);
656           break;
657         case 'I':
658           global_path.append (option_parser->optional_argument_str0_);
659           break;
660         case 'i':
661           init_name_global = option_parser->optional_argument_str0_;
662           break;
663         case 'h':
664           show_help = true;
665           break;
666         case 'V':
667           set_loglevel (LOGLEVEL_DEBUG);
668           break;
669         case 's':
670           set_loglevel (LOGLEVEL_ERROR);
671           break;
672         case 'l':
673           set_loglevel (option_parser->optional_argument_str0_);
674           break;
675         default:
676           programming_error (to_string ("unhandled short option: %c",
677                                         opt->shortname_char_));
678           assert (false);
679           break;
680         }
681     }
682
683   if (output_format_global == "")
684     output_format_global = "pdf";
685
686   if (show_help)
687     {
688       ly_usage ();
689       if (is_loglevel (LOG_DEBUG))
690         dir_info (stdout);
691       exit (0);
692     }
693 }
694
695 /*
696   T1686 Add two new routines called by setup_guile_env
697 */
698
699 void
700 setup_guile_gc_env ()
701 /*
702  * Set up environment variables relevant to the
703  * Garbage Collector
704  */
705 {
706   char const *yield = getenv ("LILYPOND_GC_YIELD");
707   bool overwrite = true;
708   if (!yield)
709     {
710       yield = "65";
711       overwrite = false;
712     }
713
714   sane_putenv ("GUILE_MIN_YIELD_1", yield, overwrite);
715   sane_putenv ("GUILE_MIN_YIELD_2", yield, overwrite);
716   sane_putenv ("GUILE_MIN_YIELD_MALLOC", yield, overwrite);
717
718   sane_putenv ("GUILE_INIT_SEGMENT_SIZE_1",
719                "10485760", overwrite);
720   sane_putenv ("GUILE_MAX_SEGMENT_SIZE",
721                "104857600", overwrite);
722 }
723
724
725 void
726 setup_guile_v2_env ()
727 /*
728  * Set up environment variables relevant to compiling
729  * Scheme files for Guile V2.
730  */
731 {
732      sane_putenv("GUILE_AUTO_COMPILE", "0", true);  // disable auto-compile
733      sane_putenv("GUILE_WARN_DEPRECATED",
734                   "detailed", "true");   // set Guile to info re deprecation
735      /*
736         Set root for Guile %compile-fallback to
737         Lilypond root for its data.
738       */
739      sane_putenv("XDG_CACHE_HOME",
740                   lilypond_datadir, true);
741 }
742
743 void
744 setup_guile_env ()
745 /*
746  * Set up environment variables relevant to Scheme
747  */
748 {
749
750   setup_guile_gc_env ();  // configure garbage collector
751 #if (GUILEV2)
752   setup_guile_v2_env ();  // configure Guile V2 behaviour
753 #endif
754 }
755
756 //vector<string> start_environment_global;
757
758 int
759 main (int argc, char **argv, char **envp)
760 /*
761  * Main entry-point for LilyPond executable image
762  * Parameters:
763  * argc:   Count of arguments on the command line
764  * argv:   Vector of string arguments on command line
765  * envp:   Point to vector of OS environment variables
766  */
767 {
768   configure_fpu ();
769   /*
770     Process environment variables
771   */
772   for (char **p = envp; *p; p++)
773     start_environment_global.push_back (*p);
774   /*
775     Handle old-style environment equivalent to
776     old-style -V or --verbose command arguments.
777     Set it to the equivalent for --loglevel-DEBUG
778    */
779   if (getenv ("LILYPOND_VERBOSE"))
780     set_loglevel (LOGLEVEL_DEBUG);
781   if (getenv ("LILYPOND_LOGLEVEL"))
782     set_loglevel (getenv ("LILYPOND_LOGLEVEL"));
783
784   setup_localisation ();
785   parse_argv (argc, argv);
786   if (isatty (STDIN_FILENO) && (is_loglevel (LOG_BASIC)))
787     identify (stderr);
788
789   setup_paths (argv[0]);
790   setup_guile_env ();  // set up environment variables to pass into Guile API
791   /*
792    * Start up Guile API using main_with_guile as a callback.
793    */
794 #if (GUILEV2)
795  /* Debugging aid.
796     Set it on by default for Guile V2
797     while migration in progress.
798  */
799   try
800     {
801       scm_boot_guile (argc, argv, main_with_guile, 0);
802     }
803   catch (exception e)
804     {
805       error (_f ("exception caught: %s", e.what ()));
806     };
807 #else
808   scm_boot_guile (argc, argv, main_with_guile, 0);
809 #endif
810
811   /* Only reachable if GUILE exits.  That is an error.  */
812   return 1;
813 }