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