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