1 # vi:filetype=python:expandtab:tabstop=4:shiftwidth=4
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
9 # Full author contact details are available in file CREDITS.
11 # This is a scons based building system for lyx, please refer
12 # to INSTALL.scons for detailed instructions.
15 import os, sys, copy, cPickle, glob, time
17 # determine where I am ...
19 from SCons.Node.FS import default_fs
20 # default_fs.SConstruct_dir is where SConstruct file is located.
21 scons_dir = default_fs.SConstruct_dir.path
22 scons_absdir = default_fs.SConstruct_dir.abspath
24 # if SConstruct is copied to the top source directory
25 if os.path.exists(os.path.join(scons_dir, 'development', 'scons', 'scons_manifest.py')):
26 scons_dir = os.path.join(scons_dir, 'development', 'scons')
27 scons_absdir = os.path.join(scons_absdir, 'development', 'scons')
28 # get the ../.. of scons_dir
29 top_src_dir = os.path.split(os.path.split(scons_absdir)[0])[0]
31 sys.path.extend([scons_absdir, os.path.join(top_src_dir, 'lib', 'doc')])
34 # scons_utils.py defines a few utility function
35 import scons_utils as utils
36 # import all file lists
37 from scons_manifest import *
39 # scons asks for 1.5.2, lyx requires 2.3
40 EnsurePythonVersion(2, 3)
41 # Please use at least version 0.97
42 EnsureSConsVersion(0, 97)
44 #----------------------------------------------------------
46 #----------------------------------------------------------
48 # some global settings
50 # get version number from configure.ac so that JMarc does
51 # not have to change SConstruct during lyx release
52 package_version, majmin_ver, lyx_date = utils.getVerFromConfigure(top_src_dir)
53 package_cygwin_version = '%s-1' % package_version
54 boost_version = ['1_34']
56 if 'svn' in package_version:
58 default_build_mode = 'debug'
61 default_build_mode = 'release'
64 package_bugreport = 'lyx-devel@lists.lyx.org'
66 package_tarname = 'lyx'
67 package_string = '%s %s' % (package_name, package_version)
69 # various cache/log files
70 default_log_file = 'scons_lyx.log'
71 opt_cache_file = 'opt.cache'
74 #----------------------------------------------------------
75 # platform dependent settings
76 #----------------------------------------------------------
79 platform_name = 'win32'
80 default_prefix = 'c:/program files/lyx'
81 default_with_x = False
82 default_packaging_method = 'windows'
83 elif os.name == 'posix' and sys.platform != 'cygwin':
84 platform_name = sys.platform
85 default_prefix = '/usr/local'
87 default_packaging_method = 'posix'
88 elif os.name == 'posix' and sys.platform == 'cygwin':
89 platform_name = 'cygwin'
90 default_prefix = '/usr'
92 default_packaging_method = 'posix'
93 elif os.name == 'darwin':
94 platform_name = 'macosx'
95 # FIXME: macOSX default prefix?
97 default_with_x = False
98 default_packaging_method = 'macosx'
99 else: # unsupported system, assume posix behavior
100 platform_name = 'others'
102 default_with_x = True
103 default_packaging_method = 'posix'
105 #---------------------------------------------------------
107 #----------------------------------------------------------
109 # You can set perminant default values in config.py
110 if os.path.isfile('config.py'):
111 print "Getting options from config.py..."
112 print open('config.py').read()
114 opts = Options(['config.py'])
117 EnumOption('frontend', 'Main GUI', 'qt4',
118 allowed_values = ('qt4',) ),
119 # debug or release build
120 EnumOption('mode', 'Building method', default_build_mode,
121 allowed_values = ('debug', 'release') ),
124 'Use included, system boost library, or try sytem boost first.',
125 'auto', allowed_values = (
126 'auto', # detect boost, if not found, use included
127 'included', # always use included boost
128 'system', # always use system boost, fail if can not find
131 EnumOption('gettext',
132 'Use included, system gettext library, or try sytem gettext first',
133 'auto', allowed_values = (
134 'auto', # detect gettext, if not found, use included
135 'included', # always use included gettext
136 'system', # always use system gettext, fail if can not find
139 EnumOption('spell', 'Choose spell checker to use.', 'auto',
140 allowed_values = ('aspell', 'pspell', 'ispell', 'auto', 'no') ),
142 EnumOption('packaging', 'Packaging method to use.', default_packaging_method,
143 allowed_values = ('windows', 'posix', 'macosx')),
145 BoolOption('fast_start', 'This option is obsolete.', False),
146 # No precompiled header support (too troublesome to make it work for msvc)
147 # BoolOption('pch', 'Whether or not use pch', False),
148 # enable assertion, (config.h has ENABLE_ASSERTIOS
149 BoolOption('assertions', 'Use assertions', True),
150 # config.h define _GLIBCXX_CONCEPT_CHECKS
151 # Note: for earlier version of gcc (3.3) define _GLIBCPP_CONCEPT_CHECKS
152 BoolOption('concept_checks', 'Enable concept checks', True),
154 BoolOption('nls', 'Whether or not use native language support', True),
156 BoolOption('profiling', 'Whether or not enable profiling', False),
157 # config.h define _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC
158 BoolOption('stdlib_debug', 'Whether or not turn on stdlib debug', False),
160 BoolOption('X11', 'Use x11 windows system', default_with_x),
161 # use MS VC++ to build lyx
162 BoolOption('use_vc', 'Use MS VC++ to build lyx (cl.exe will be probed)', None),
164 PathOption('qt_dir', 'Path to qt directory', None),
166 PathOption('qt_inc_path', 'Path to qt include directory', None),
168 PathOption('qt_lib_path', 'Path to qt library directory', None),
169 # extra include and libpath
170 PathOption('extra_inc_path', 'Extra include path', None),
172 PathOption('extra_lib_path', 'Extra library path', None),
174 PathOption('extra_bin_path', 'A convenient way to add a path to $PATH', None),
176 PathOption('extra_inc_path1', 'Extra include path', None),
178 PathOption('extra_lib_path1', 'Extra library path', None),
180 ('rebuild', 'Obsolete option', None),
181 # can be set to a non-existing directory
182 ('prefix', 'install architecture-independent files in PREFIX', default_prefix),
183 # replace the default name and location of the windows installer
184 ('win_installer', 'name or full path to the windows installer', None),
185 # the deps package used to create minimal installer (qt and other libraries)
186 ('deps_dir', 'path to the development depedency packages with zlib, iconv, zlib and qt libraries', None),
187 # whether or not build bundle installer
188 BoolOption('bundle', 'Whether or not build bundle installer', False),
189 # the bundle directory, containing bundled applications
190 PathOption('bundle_dir', 'path to the bundle dependency package with miktex setup.exe etc', None),
191 # build directory, will use $mode if not set
192 ('build_dir', 'Build directory', None),
194 ('version_suffix', 'install lyx as lyx-suffix', None),
195 # how to load options
196 ('load_option', '''load option from previous scons run. option can be
197 yes (default): load all options
198 no: do not load any option
199 opt1,opt2: load specified options
200 -opt1,opt2: load all options other than specified ones''', 'yes'),
202 ('optimization', 'optimization CCFLAGS option.', None),
204 PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
206 ('logfile', 'save commands (not outputs) to logfile', default_log_file),
207 # provided for backward compatibility
208 ('dest_dir', 'install to DESTDIR. (Provided for backward compatibility only)', None),
209 # environment variable can be set as options.
210 ('DESTDIR', 'install to DESTDIR', None),
211 ('CC', 'replace default $CC', None),
212 ('LINK', 'replace default $LINK', None),
213 ('CPP', 'replace default $CPP', None),
214 ('CXX', 'replace default $CXX', None),
215 ('CXXCPP', 'replace default $CXXCPP', None),
216 ('CCFLAGS', 'replace default $CCFLAGS', None),
217 ('CPPFLAGS', 'replace default $CPPFLAGS', None),
218 ('LINKFLAGS', 'replace default $LINKFLAGS', None),
222 all_options = [x.key for x in opts.options]
224 # copied from SCons/Options/BoolOption.py
225 # We need to use them before a boolean ARGUMENTS option is available
227 true_strings = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
228 false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none')
230 if ARGUMENTS.has_key('fast_start'):
231 print 'fast_start option is obsolete'
233 # if load_option=yes (default), load saved comand line options
235 # This option can take value yes/no/opt1,opt2/-opt1,opt2
236 # and tries to be clever in choosing options to load
237 if (not ARGUMENTS.has_key('load_option') or \
238 ARGUMENTS['load_option'] not in false_strings) \
239 and os.path.isfile(opt_cache_file):
240 cache_file = open(opt_cache_file)
241 opt_cache = cPickle.load(cache_file)
243 # import cached options, but we should ignore qt_dir when frontend changes
244 if ARGUMENTS.has_key('frontend') and opt_cache.has_key('frontend') \
245 and ARGUMENTS['frontend'] != opt_cache['frontend'] \
246 and opt_cache.has_key('qt_dir'):
247 opt_cache.pop('qt_dir')
248 # and we do not cache some options (dest_dir is obsolete)
249 for arg in ['load_option', 'dest_dir', 'bundle']:
250 if opt_cache.has_key(arg):
252 # remove obsolete cached keys (well, SConstruct is evolving. :-)
253 for arg in opt_cache.keys():
254 if arg not in all_options:
255 print 'Option %s is obsolete, do not load it' % arg
257 # now, if load_option=opt1,opt2 or -opt1,opt2
258 if ARGUMENTS.has_key('load_option') and \
259 ARGUMENTS['load_option'] not in true_strings + false_strings:
260 # if -opt1,opt2 is specified, do not load these options
261 if ARGUMENTS['load_option'][0] == '-':
262 for arg in ARGUMENTS['load_option'][1:].split(','):
263 if opt_cache.has_key(arg):
265 # if opt1,opt2 is specified, only load specified options
267 args = ARGUMENTS['load_option'].split(',')
268 for arg in opt_cache.keys():
271 # now restore options as if entered from command line
272 for key in opt_cache.keys():
273 if not ARGUMENTS.has_key(key):
274 ARGUMENTS[key] = opt_cache[key]
275 print "Restoring cached option %s=%s" % (key, ARGUMENTS[key])
278 # check if there is unused (or misspelled) argument
279 for arg in ARGUMENTS.keys():
280 if arg not in all_options:
282 print "Unknown option '%s'... exiting." % arg
284 print "Available options are (check 'scons -help' for details):"
285 print ' ' + '\n '.join(textwrap.wrap(', '.join(all_options)))
289 cache_file = open(opt_cache_file, 'w')
290 cPickle.dump(ARGUMENTS, cache_file)
293 #---------------------------------------------------------
294 # Setting up environment
295 #---------------------------------------------------------
297 # I do not really like ENV=os.environ, but you may add it
298 # here if you experience some environment related problem
299 env = Environment(options = opts)
301 # set individual variables since I do not really like ENV = os.environ
302 env['ENV']['PATH'] = os.environ.get('PATH')
303 env['ENV']['HOME'] = os.environ.get('HOME')
304 # these are defined for MSVC
305 env['ENV']['LIB'] = os.environ.get('LIB')
306 env['ENV']['INCLUDE'] = os.environ.get('INCLUDE')
308 # for simplicity, use var instead of env[var]
309 frontend = env['frontend']
310 prefix = env['prefix']
313 if platform_name == 'win32':
314 if env.has_key('use_vc'):
315 use_vc = env['use_vc']
316 if WhereIs('cl.exe') is None:
317 print "cl.exe is not found. Are you using the MSVC environment?"
319 elif WhereIs('cl.exe') is not None:
326 if env.has_key('build_dir') and env['build_dir'] is not None:
327 env['BUILDDIR'] = env['build_dir']
329 # Determine the name of the build $mode
330 env['BUILDDIR'] = '#' + mode
332 # all built libraries will go to build_dir/libs
333 # (This is different from the make file approach)
334 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
335 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
338 # Here is a summary of variables defined in env
340 # 2. undefined options with a non-None default value
341 # 3. compiler commands and flags like CCFLAGS.
342 # MSGFMT used to process po files
343 # 4. Variables that will be used to replace variables in some_file.in
344 # lib/lyx2lyx/lyx2lyx_version.py.in
347 # full path name is used to build msvs project files
348 # and to replace TOP_SRCDIR in package.C
349 env['TOP_SRCDIR'] = Dir(top_src_dir).abspath
351 # determine share_dir etc
352 packaging_method = env.get('packaging')
353 if packaging_method == 'windows':
354 share_dir = 'Resources'
355 man_dir = 'Resources/man/man1'
356 locale_dir = 'Resources/locale'
358 share_dir = 'share/lyx'
359 locale_dir = 'share/locale'
360 if platform_name == 'cygwin':
361 man_dir = 'share/man/man1'
365 # program suffix: can be yes, or a string
366 if env.has_key('version_suffix'):
367 if env['version_suffix'] in true_strings:
368 program_suffix = package_version
369 elif env['version_suffix'] in false_strings:
372 program_suffix = env['version_suffix']
377 # whether or not add suffix to file and directory names
378 add_suffix = packaging_method != 'windows'
379 # Absolute data directory
380 if mode == 'release':
382 env['LYX_DATA_DIR'] = Dir(os.path.join(prefix, share_dir + program_suffix)).abspath
384 env['LYX_DATA_DIR'] = Dir(os.path.join(prefix, share_dir)).abspath
386 # in the debug mode, use $TOP_SRCDIR/lib to make sure lyx can be started from anyway
387 # by using this directory as data directory
388 env['LYX_DATA_DIR'] = os.path.join(env.subst('$TOP_SRCDIR'), 'lib')
389 # we need absolute path for package.C
390 env['LOCALEDIR'] = Dir(os.path.join(prefix, locale_dir)).abspath
393 #---------------------------------------------------------
394 # Setting building environment (Tools, compiler flags etc)
395 #---------------------------------------------------------
397 # Since Tool('mingw') will reset CCFLAGS etc, this should be
398 # done before getEnvVariable
399 if platform_name == 'win32':
405 env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
406 # fix a scons winres bug (there is a missing space between ${RCINCPREFIX} and ${SOURCE.dir}
408 env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
411 # we differentiate between hard-coded options and default options
412 # hard-coded options are required and will always be there
413 # default options can be replaced by enviromental variables or command line options
414 CCFLAGS_required = []
415 LINKFLAGS_required = []
418 # if we use ms vc, the commands are fine (cl.exe and link.exe)
420 # C4819: The file contains a character that cannot be represented
421 # in the current code page (number)
422 # C4996: foo was decleared deprecated
423 CCFLAGS_required.append('/EHsc')
425 CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MDd'])
427 CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MD'])
429 # for debug/release mode
430 if env.has_key('optimization') and env['optimization'] is not None:
431 # if user supplies optimization flags, use it anyway
432 CCFLAGS_required.extend(env['optimization'].split())
433 # and do not use default
434 set_default_optimization_flags = False
436 set_default_optimization_flags = True
440 CCFLAGS_required.append('/Zi')
441 LINKFLAGS_required.extend(['/debug', '/map'])
443 CCFLAGS_required.append('-g')
444 CCFLAGS_default.append('-O')
445 elif mode == 'release' and set_default_optimization_flags:
447 CCFLAGS_default.append('/O2')
449 CCFLAGS_default.append('-O2')
451 # msvc uses separate tools for profiling
452 if env.has_key('profiling') and env['profiling']:
454 print 'Visual C++ does not use profiling options'
456 CCFLAGS_required.append('-pg')
457 LINKFLAGS_required.append('-pg')
459 if env.has_key('warnings') and env['warnings']:
461 CCFLAGS_default.append('/W2')
463 # Note: autotools detect gxx version and pass -W for 3.x
464 # and -Wextra for other versions of gcc
465 CCFLAGS_default.append('-Wall')
467 # Now, set the variables as follows:
468 # 1. if command line option exists: replace default
469 # 2. then if s envronment variable exists: replace default
470 # 3. set variable to required + default
471 def setEnvVariable(env, name, required = None, default = None, split = True):
472 ''' env: environment to set variable
474 required: hardcoded options
475 default: default options that can be replaced by command line or
476 environment variables
477 split: whether or not split obtained variable like '-02 -g'
479 # 1. ARGUMENTS is already set to env[name], override default.
480 if ARGUMENTS.has_key(name):
481 # env[name] may be rewritten when building tools are reloaded
482 # if that is the case, commandline option will override it.
483 env[name] = ARGUMENTS[name]
485 # then use environment default
486 elif os.environ.has_key(name):
487 print "Acquiring variable %s from system environment: %s" % (name, os.environ[name])
488 default = os.environ[name]
490 default = default.split()
491 # the real value should be env[name] + default + required
494 if env.has_key(name):
495 value = str(env[name]).split()
496 if required is not None:
498 if default is not None:
502 if env.has_key(name):
503 value = str(env[name])
504 if required is not None:
505 value += " " + required
506 if default is not None:
507 value += " " + default
509 # print name, env[name]
511 setEnvVariable(env, 'DESTDIR', split=False)
512 setEnvVariable(env, 'CC')
513 setEnvVariable(env, 'LINK')
514 setEnvVariable(env, 'CPP')
515 setEnvVariable(env, 'CXX')
516 setEnvVariable(env, 'CXXCPP')
517 setEnvVariable(env, 'CCFLAGS', CCFLAGS_required, CCFLAGS_default)
518 setEnvVariable(env, 'CXXFLAGS')
519 setEnvVariable(env, 'CPPFLAGS')
520 setEnvVariable(env, 'LINKFLAGS', LINKFLAGS_required)
522 # if DESTDIR is not set...
523 if env.has_key('dest_dir'):
524 print "This option is obsolete. Please use DESTDIR instead."
525 env['DESTDIR'] = env['dest_dir']
528 # extra_inc_path and extra_lib_path
531 if env.has_key('extra_inc_path') and env['extra_inc_path']:
532 extra_inc_paths.append(env['extra_inc_path'])
533 if env.has_key('extra_lib_path') and env['extra_lib_path']:
534 env.AppendUnique(LIBPATH = [env['extra_lib_path']])
535 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
536 extra_inc_paths.append(env['extra_inc_path1'])
537 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
538 env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
539 if env.has_key('extra_bin_path') and env['extra_bin_path']:
540 # only the first one is needed (a scons bug?)
541 os.environ['PATH'] += os.pathsep + env['extra_bin_path']
542 env.PrependENVPath('PATH', env['extra_bin_path'])
543 # extra_inc_paths will be used later by intlenv etc
544 env.AppendUnique(CPPPATH = extra_inc_paths)
547 #----------------------------------------------------------
549 #----------------------------------------------------------
551 conf = Configure(env,
553 'CheckPkgConfig' : utils.checkPkgConfig,
554 'CheckPackage' : utils.checkPackage,
555 'CheckMkdirOneArg' : utils.checkMkdirOneArg,
556 'CheckSelectArgType' : utils.checkSelectArgType,
557 'CheckBoostLibraries' : utils.checkBoostLibraries,
558 'CheckCommand' : utils.checkCommand,
559 'CheckNSIS' : utils.checkNSIS,
560 'CheckCXXGlobalCstd' : utils.checkCXXGlobalCstd,
561 'CheckLC_MESSAGES' : utils.checkLC_MESSAGES,
562 'CheckIconvConst' : utils.checkIconvConst,
563 'CheckSizeOfWChar' : utils.checkSizeOfWChar,
564 'CheckDeclaration' : utils.checkDeclaration,
568 # When using msvc, windows.h is required
569 if use_vc and not conf.CheckCHeader('windows.h'):
570 print 'Windows.h is not found. Please install Windows Platform SDK.'
571 print 'Please check config.log for more information.'
574 # pkg-config? (if not, we use hard-coded options)
575 if conf.CheckPkgConfig('0.15.0'):
576 env['HAS_PKG_CONFIG'] = True
578 print 'pkg-config >= 0.1.50 is not found'
579 env['HAS_PKG_CONFIG'] = False
581 # zlib? This is required.
582 if (not use_vc and not conf.CheckLibWithHeader('z', 'zlib.h', 'C')) \
583 or (use_vc and not conf.CheckLibWithHeader('zdll', 'zlib.h', 'C')):
584 print 'Did not find zdll.lib or zlib.h, exiting!'
585 print 'Please check config.log for more information.'
587 if conf.CheckLib('iconv'):
588 env['ICONV_LIB'] = 'iconv'
589 elif conf.CheckLib('libiconv'):
590 env['ICONV_LIB'] = 'libiconv'
591 elif conf.CheckFunc('iconv_open'):
592 env['ICONV_LIB'] = None
594 print 'Did not find iconv or libiconv, exiting!'
595 print 'Please check config.log for more information.'
600 if conf.CheckLib('socket'):
601 socket_libs.append('socket')
602 # nsl is the network services library and provides a
603 # transport-level interface to networking services.
604 if conf.CheckLib('nsl'):
605 socket_libs.append('nsl')
607 # check available boost libs (since lyx1.4 does not use iostream)
609 for lib in ['signals', 'regex']:
610 if os.path.isdir(os.path.join(top_src_dir, 'boost', 'libs', lib)):
611 boost_libs.append(lib)
613 # check boost libraries
614 boost_opt = ARGUMENTS.get('boost', 'auto')
615 # check for system boost
616 lib_paths = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
617 inc_paths = env['CPPPATH'] + ['/usr/include', '/usr/local/include']
618 # default to $BUILDDIR/libs (use None since this path will be added anyway)
620 # here I assume that all libraries are in the same directory
621 if boost_opt == 'included':
622 boost_libraries = ['included_boost_%s' % x for x in boost_libs]
623 included_boost = True
624 env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
625 elif boost_opt == 'auto':
626 res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
627 # if not found, use local boost
629 boost_libraries = ['included_boost_%s' % x for x in boost_libs]
630 included_boost = True
631 env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
633 included_boost = False
634 (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
635 elif boost_opt == 'system':
636 res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
638 print "Can not find system boost libraries with version %s " % boost_version
639 print "Please supply a path through extra_lib_path and try again."
640 print "Or use boost=included to use included boost libraries."
643 included_boost = False
644 (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
647 if boost_libpath is not None:
648 env.AppendUnique(LIBPATH = [boost_libpath])
651 env['ENABLE_NLS'] = env['nls']
653 if not env['ENABLE_NLS']:
655 included_gettext = False
657 # check gettext libraries
658 gettext_opt = ARGUMENTS.get('gettext', 'auto')
659 # check for system gettext
661 if gettext_opt in ['auto', 'system']:
662 if conf.CheckFunc('gettext'):
663 included_gettext = False
666 elif conf.CheckLib('intl'):
667 included_gettext = False
671 if gettext_opt == 'system':
672 print "Can not find system gettext library"
673 print "Please supply a path through extra_lib_path and try again."
674 print "Or use gettext=included to use included gettext libraries."
676 # now, auto and succ = false, or gettext=included
678 # we do not need to set LIBPATH now.
679 included_gettext = True
680 intl_libs = ['included_intl']
684 # check for msgfmt command
685 env['MSGFMT'] = conf.CheckCommand('msgfmt')
686 env['MSGMERGE'] = conf.CheckCommand('msgmerge')
687 env['XGETTEXT'] = conf.CheckCommand('xgettext')
688 env['MSGUNIQ'] = conf.CheckCommand('msguniq')
690 # if under windows, check the nsis compiler
691 if platform_name == 'win32':
692 env['NSIS'] = conf.CheckNSIS()
694 # cygwin packaging requires the binaries to be stripped
695 if platform_name == 'cygwin':
696 env['STRIP'] = conf.CheckCommand('strip')
699 # Customized builders
701 # install customized builders
702 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
703 #env['BUILDERS']['installTOC'] = Builder(action = utils.env_toc)
704 env['BUILDERS']['potfiles'] = Builder(action = utils.env_potfiles)
707 #----------------------------------------------------------
708 # Generating config.h
709 #----------------------------------------------------------
710 aspell_lib = 'aspell'
711 # assume that we use aspell, aspelld compiled for msvc
712 if platform_name == 'win32' and mode == 'debug' and use_vc:
713 aspell_lib = 'aspelld'
715 # check the existence of config.h
716 config_h = os.path.join(env.Dir('$BUILDDIR/src').path, 'config.h')
717 boost_config_h = os.path.join(env.Dir('$BUILDDIR/boost').path, 'config.h')
719 print "Creating %s..." % boost_config_h
721 utils.createConfigFile(conf,
722 config_file = boost_config_h,
723 config_pre = r'''/* boost/config.h. Generated by SCons. */
728 * This file is part of LyX, the document processor.
729 * Licence details can be found in the file COPYING.
731 * This is the compilation configuration file for LyX.
732 * It was generated by scon.
733 * You might want to change some of the defaults if something goes wrong
734 * during the compilation.
737 #ifndef _BOOST_CONFIG_H
738 #define _BOOST_CONFIG_H
741 ('ostream', 'HAVE_OSTREAM', 'cxx'),
742 ('locale', 'HAVE_LOCALE', 'cxx'),
743 ('sstream', 'HAVE_SSTREAM', 'cxx'),
744 #('newapis.h', 'HAVE_NEWAPIS_H', 'c'),
747 (env.has_key('assertions') and env['assertions'] and devel_version,
749 'Define if you want assertions to be enabled in the code'
753 ('wchar_t', 'HAVE_WCHAR_T', None),
757 #if defined(HAVE_OSTREAM) && defined(HAVE_LOCALE) && defined(HAVE_SSTREAM)
758 # define USE_BOOST_FORMAT 1
760 # define USE_BOOST_FORMAT 0
763 #if !defined(ENABLE_ASSERTIONS)
764 # define BOOST_DISABLE_ASSERTS 1
766 #define BOOST_ENABLE_ASSERT_HANDLER 1
768 #define BOOST_DISABLE_THREADS 1
769 #define BOOST_NO_WSTRING 1
772 # define BOOST_POSIX 1
773 # define BOOST_POSIX_API 1
774 # define BOOST_POSIX_PATH 1
777 #define BOOST_ALL_NO_LIB 1
779 #if defined(HAVE_NEWAPIS_H)
780 # define WANT_GETFILEATTRIBUTESEX_WRAPPER 1
784 * the FreeBSD libc uses UCS4, but libstdc++ has no proper wchar_t
785 * support compiled in:
786 * http://gcc.gnu.org/onlinedocs/libstdc++/faq/index.html#3_9
787 * And we are not interested at all what libc
788 * does: What we need is a 32bit wide wchar_t, and a libstdc++ that
789 * has the needed wchar_t support and uses UCS4. Whether it
790 * implements this with the help of libc, or whether it has own code
791 * does not matter for us, because we don't use libc directly (Georg)
793 #if defined(HAVE_WCHAR_T) && SIZEOF_WCHAR_T == 4 && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
801 print "\nGenerating %s..." % config_h
803 # AIKSAURUS_H_LOCATION
804 if (conf.CheckCXXHeader("Aiksaurus.h")):
805 aik_location = '<Aiksaurus.h>'
806 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
807 aik_location = '<Aiksaurus/Aiksaurus.h>'
811 # determine headers to use
812 spell_opt = ARGUMENTS.get('spell', 'auto')
813 env['USE_ASPELL'] = False
814 env['USE_PSPELL'] = False
815 env['USE_ISPELL'] = False
816 if spell_opt in ['auto', 'aspell'] and conf.CheckLib(aspell_lib):
817 spell_engine = 'USE_ASPELL'
818 elif spell_opt in ['auto', 'pspell'] and conf.CheckLib('pspell'):
819 spell_engine = 'USE_PSPELL'
820 elif spell_opt in ['auto', 'ispell'] and conf.CheckLib('ispell'):
821 spell_engine = 'USE_ISPELL'
825 if spell_engine is not None:
826 env[spell_engine] = True
828 if spell_opt == 'auto':
829 print "Warning: Can not locate any spell checker"
830 elif spell_opt != 'no':
831 print "Warning: Can not locate specified spell checker:", spell_opt
832 print 'Please check config.log for more information.'
835 # check arg types of select function
836 (select_arg1, select_arg234, select_arg5) = conf.CheckSelectArgType()
838 # check the size of wchar_t
839 sizeof_wchar_t = conf.CheckSizeOfWChar()
841 if sizeof_wchar_t == 0:
842 print 'Error: Can not determine the size of wchar_t.'
843 print 'Please check config.log for more information.'
847 # fill in the version info
848 env['VERSION_INFO'] = '''Configuration
850 Special build flags: %s
852 C Compiler flags: %s %s
854 C++ Compiler LyX flags: %s
855 C++ Compiler flags: %s %s
857 Linker user flags: %s
859 Builing directory: %s
862 include search path: %s
868 ''' % (platform_name,
869 env.subst('$CCFLAGS'), env.subst('$CC'),
870 env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
871 env.subst('$CXX'), env.subst('$CXXFLAGS'),
872 env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
873 env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
874 env.subst('$LOCALLIBPATH'),
875 env.subst('$LIBPATH'), str(boost_libraries),
876 env.subst('$CPPPATH'),
877 frontend, packaging_method,
878 prefix, env['LYX_DATA_DIR'])
882 result = utils.createConfigFile(conf,
883 config_file = config_h,
884 config_pre = r'''/* config.h. Generated by SCons. */
889 * This file is part of LyX, the document processor.
890 * Licence details can be found in the file COPYING.
892 * This is the compilation configuration file for LyX.
893 * It was generated by scon.
894 * You might want to change some of the defaults if something goes wrong
895 * during the compilation.
902 ('io.h', 'HAVE_IO_H', 'c'),
903 ('limits.h', 'HAVE_LIMITS_H', 'c'),
904 ('locale.h', 'HAVE_LOCALE_H', 'c'),
905 ('process.h', 'HAVE_PROCESS_H', 'c'),
906 ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
907 ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
908 ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
909 ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
910 ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
911 ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
912 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
913 ('utime.h', 'HAVE_UTIME_H', 'c'),
914 ('direct.h', 'HAVE_DIRECT_H', 'c'),
915 ('istream', 'HAVE_ISTREAM', 'cxx'),
916 ('ios', 'HAVE_IOS', 'cxx'),
919 ('open', 'HAVE_OPEN', None),
920 ('chmod', 'HAVE_CHMOD', None),
921 ('close', 'HAVE_CLOSE', None),
922 ('popen', 'HAVE_POPEN', None),
923 ('pclose', 'HAVE_PCLOSE', None),
924 ('_open', 'HAVE__OPEN', None),
925 ('_close', 'HAVE__CLOSE', None),
926 ('_popen', 'HAVE__POPEN', None),
927 ('_pclose', 'HAVE__PCLOSE', None),
928 ('getpid', 'HAVE_GETPID', None),
929 ('_getpid', 'HAVE__GETPID', None),
930 ('mkdir', 'HAVE_MKDIR', None),
931 ('_mkdir', 'HAVE__MKDIR', None),
932 ('mktemp', 'HAVE_MKTEMP', None),
933 ('mkstemp', 'HAVE_MKSTEMP', None),
934 ('strerror', 'HAVE_STRERROR', None),
935 ('getcwd', 'HAVE_GETCWD', None),
936 ('setenv', 'HAVE_SETENV', None),
937 ('putenv', 'HAVE_PUTENV', None),
938 ('fcntl', 'HAVE_FCNTL', None),
939 ('mkfifo', 'HAVE_MKFIFO', None),
942 ('mkstemp', 'HAVE_DECL_MKSTEMP', ['unistd.h', 'stdlib.h']),
945 ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
946 '#include <streambuf>\n#include <istream>'),
947 ('wchar_t', 'HAVE_WCHAR_T', None),
948 ('mode_t', 'HAVE_MODE_T', "#include <sys/types.h>"),
951 ('gdi32', 'HAVE_LIBGDI32'),
952 (('Aiksaurus', 'libAiksaurus'), 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB'),
955 (conf.CheckType('pid_t', includes='#include <sys/types.h>'),
957 'Define is sys/types.h does not have pid_t',
961 (conf.CheckCXXGlobalCstd(),
963 'Define if your C++ compiler puts C library functions in the global namespace'
965 (conf.CheckMkdirOneArg(),
966 'MKDIR_TAKES_ONE_ARG',
967 'Define if mkdir takes only one argument.'
969 (conf.CheckIconvConst(),
971 'Define as const if the declaration of iconv() needs const.',
972 '#define ICONV_CONST const',
973 '#define ICONV_CONST',
975 (conf.CheckLC_MESSAGES(),
977 'Define if your <locale.h> file defines LC_MESSAGES.'
979 (devel_version, 'DEVEL_VERSION', 'Whether or not a development version'),
982 "Define to 1 if translation of program messages to the user's native anguage is requested.",
984 (env['nls'] and not included_gettext,
986 'Define to 1 if using system gettext library'
988 (env.has_key('concept_checks') and env['concept_checks'],
989 '_GLIBCXX_CONCEPT_CHECKS',
990 'libstdc++ concept checking'
992 (env.has_key('stdlib_debug') and env['stdlib_debug'],
994 'libstdc++ debug mode'
996 (env.has_key('stdlib_debug') and env['stdlib_debug'],
997 '_GLIBCXX_DEBUG_PEDANTIC',
998 'libstdc++ pedantic debug mode'
1000 (os.name != 'nt', 'BOOST_POSIX',
1001 'Indicates to boost < 1.34 which API to use (posix or windows).'
1003 (os.name != 'nt', 'BOOST_POSIX_API',
1004 'Indicates to boost 1.34 which API to use (posix or windows).'
1006 (os.name != 'nt', 'BOOST_POSIX_PATH',
1007 'Indicates to boost 1.34 which path style to use (posix or windows).'
1009 (spell_engine is not None, spell_engine,
1010 'Spell engine to use'
1012 # we need to know the byte order for unicode conversions
1013 (sys.byteorder == 'big', 'WORDS_BIGENDIAN',
1014 'Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX).'
1018 ('#define PACKAGE "%s%s"' % (package, program_suffix),
1020 ('#define PACKAGE_BUGREPORT "%s"' % package_bugreport,
1021 'Define to the address where bug reports for this package should be sent.'),
1022 ('#define PACKAGE_NAME "%s"' % package_name,
1023 'Define to the full name of this package.'),
1024 ('#define PACKAGE_STRING "%s"' % package_string,
1025 'Define to the full name and version of this package.'),
1026 ('#define PACKAGE_TARNAME "%s"' % package_tarname,
1027 'Define to the one symbol short name of this package.'),
1028 ('#define PACKAGE_VERSION "%s"' % package_version,
1029 'Define to the version of this package.'),
1030 ('#define VERSION_INFO "%s"' % env['VERSION_INFO'].replace('\n', '\\n'),
1031 'Full version info'),
1032 ('#define LYX_DIR_VER "LYX_DIR_%sx"' % majmin_ver,
1033 'Versioned env var for system dir'),
1034 ('#define LYX_USERDIR_VER "LYX_USERDIR_%sx"' % majmin_ver,
1035 'Versioned env var for user dir'),
1036 ('#define LYX_DATE "%s"' % lyx_date,
1038 ('#define PROGRAM_SUFFIX "%s"' % program_suffix,
1039 'Program version suffix'),
1040 ('#define LYX_ABS_INSTALLED_DATADIR "%s"' % env.subst('$LYX_DATA_DIR').replace('\\', '/'),
1041 'Hard coded system support directory'),
1042 ('#define LYX_ABS_INSTALLED_LOCALEDIR "%s"' % env.subst('$LOCALEDIR').replace('\\', '/'),
1043 'Hard coded locale directory'),
1044 ('#define LYX_ABS_TOP_SRCDIR "%s"' % env.subst('$TOP_SRCDIR').replace('\\', '/'),
1045 'Top source directory'),
1046 ('#define BOOST_ALL_NO_LIB 1',
1047 'disable automatic linking of boost libraries.'),
1048 ('#define USE_%s_PACKAGING 1' % packaging_method.upper(),
1049 'Packaging method'),
1050 ('#define AIKSAURUS_H_LOCATION ' + aik_location,
1051 'Aiksaurus include file'),
1052 ('#define SELECT_TYPE_ARG1 %s' % select_arg1,
1053 "Define to the type of arg 1 for `select'."),
1054 ('#define SELECT_TYPE_ARG234 %s' % select_arg234,
1055 "Define to the type of arg 2, 3, 4 for `select'."),
1056 ('#define SELECT_TYPE_ARG5 %s' % select_arg5,
1057 "Define to the type of arg 5 for `select'."),
1058 ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1059 'Define to be the size of type wchar_t'),
1061 config_post = '''/************************************************************
1062 ** You should not need to change anything beyond this point */
1064 #ifndef HAVE_STRERROR
1065 #if defined(__cplusplus)
1068 char * strerror(int n);
1071 #include <../boost/config.h>
1077 # these keys are needed in env
1078 for key in ['USE_ASPELL', 'USE_PSPELL', 'USE_ISPELL', 'HAVE_FCNTL',\
1079 'HAVE_LIBGDI32', 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB']:
1080 # USE_ASPELL etc does not go through result
1081 if result.has_key(key):
1082 env[key] = result[key]
1085 # if nls=yes and gettext=included, create intl/config.h
1086 # intl/libintl.h etc
1088 intl_config_h = os.path.join(env.Dir('$BUILDDIR/intl').path, 'config.h')
1089 if env['nls'] and included_gettext:
1091 print "Creating %s..." % intl_config_h
1093 # create intl/config.h
1094 result = utils.createConfigFile(conf,
1095 config_file = intl_config_h,
1096 config_pre = r'''/* intl/config.h. Generated by SCons. */
1101 * This file is part of LyX, the document processor.
1102 * Licence details can be found in the file COPYING.
1104 * This is the compilation configuration file for LyX.
1105 * It was generated by scon.
1106 * You might want to change some of the defaults if something goes wrong
1107 * during the compilation.
1110 #ifndef _INTL_CONFIG_H
1111 #define _INTL_CONFIG_H
1114 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
1115 ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
1116 ('string.h', 'HAVE_STRING_H', 'c'),
1117 ('strings.h', 'HAVE_STRINGS_H', 'c'),
1118 ('argz.h', 'HAVE_ARGZ_H', 'c'),
1119 ('limits.h', 'HAVE_LIMITS_H', 'c'),
1120 ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
1121 ('stddef.h', 'HAVE_STDDEF_H', 'c'),
1122 ('stdint.h', 'HAVE_STDINT_H', 'c'),
1123 ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c'),
1126 ('getcwd', 'HAVE_GETCWD', None),
1127 ('stpcpy', 'HAVE_STPCPY', None),
1128 ('strcasecmp', 'HAVE_STRCASECMP', None),
1129 ('strdup', 'HAVE_STRDUP', None),
1130 ('strtoul', 'HAVE_STRTOUL', None),
1131 ('alloca', 'HAVE_ALLOCA', None),
1132 ('__fsetlocking', 'HAVE___FSETLOCKING', None),
1133 ('mempcpy', 'HAVE_MEMPCPY', None),
1134 ('__argz_count', 'HAVE___ARGZ_COUNT', None),
1135 ('__argz_next', 'HAVE___ARGZ_NEXT', None),
1136 ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
1137 ('setlocale', 'HAVE_SETLOCALE', None),
1138 ('tsearch', 'HAVE_TSEARCH', None),
1139 ('getegid', 'HAVE_GETEGID', None),
1140 ('getgid', 'HAVE_GETGID', None),
1141 ('getuid', 'HAVE_GETUID', None),
1142 ('wcslen', 'HAVE_WCSLEN', None),
1143 ('asprintf', 'HAVE_ASPRINTF', None),
1144 ('wprintf', 'HAVE_WPRINTF', None),
1145 ('snprintf', 'HAVE_SNPRINTF', None),
1146 ('printf', 'HAVE_POSIX_PRINTF', None),
1147 ('fcntl', 'HAVE_FCNTL', None),
1150 ('intmax_t', 'HAVE_INTMAX_T', None),
1151 ('long double', 'HAVE_LONG_DOUBLE', None),
1152 ('long long', 'HAVE_LONG_LONG', None),
1153 ('wchar_t', 'HAVE_WCHAR_T', None),
1154 ('wint_t', 'HAVE_WINT_T', None),
1155 ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
1156 ('uintmax_t', 'HAVE_STDINT_H_WITH_UINTMAX', '#include <stdint.h>'),
1162 (conf.CheckLC_MESSAGES(),
1164 'Define if your <locale.h> file defines LC_MESSAGES.'
1166 (conf.CheckIconvConst(),
1168 'Define as const if the declaration of iconv() needs const.',
1169 '#define ICONV_CONST const',
1170 '#define ICONV_CONST',
1172 (conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
1173 conf.CheckType('intmax_t', includes='#include <inttypes.h>'),
1175 "Define to 1 if you have the `intmax_t' type."
1177 (env.has_key('nls') and env['nls'],
1179 "Define to 1 if translation of program messages to the user's native anguage is requested.",
1183 ('#define HAVE_ICONV 1', 'Define if iconv or libiconv is found'),
1184 ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1185 'Define to be the size of type wchar_t'),
1187 config_post = '#endif'
1190 # these keys are needed in env
1191 for key in ['HAVE_ASPRINTF', 'HAVE_WPRINTF', 'HAVE_SNPRINTF', \
1192 'HAVE_POSIX_PRINTF', 'HAVE_LIBC']:
1193 # USE_ASPELL etc does not go through result
1194 if result.has_key(key):
1195 env[key] = result[key]
1198 # this looks misplaced, but intl/libintl.h is needed by src/message.C
1199 if env['nls'] and included_gettext:
1200 # libgnuintl.h.in => libintl.h
1201 env.Depends('$TOP_SRCDIR/intl/libintl.h', '$BUILDDIR/intl/config.h')
1202 env.substFile('$BUILDDIR/intl/libintl.h', '$TOP_SRCDIR/intl/libgnuintl.h.in')
1203 env.Command('$BUILDDIR/intl/libgnuintl.h', '$BUILDDIR/intl/libintl.h',
1204 [Copy('$TARGET', '$SOURCE')])
1207 # Finish auto-configuration
1210 #----------------------------------------------------------
1211 # Now set up our build process accordingly
1212 #----------------------------------------------------------
1214 if env['ICONV_LIB'] is None:
1217 system_libs = [env['ICONV_LIB']]
1218 if platform_name in ['win32', 'cygwin']:
1219 # the final link step needs stdc++ to succeed under mingw
1220 # FIXME: shouldn't g++ automatically link to stdc++?
1222 system_libs += ['ole32', 'shlwapi', 'shell32', 'advapi32', 'zdll']
1224 system_libs += ['shlwapi', 'stdc++', 'z']
1225 elif platform_name == 'cygwin' and env['X11']:
1226 system_libs += ['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr',
1227 'Xcursor', 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE',
1228 'resolv', 'pthread', 'z']
1230 system_libs += ['z']
1233 ('HAVE_LIBGDI32', 'gdi32'),
1234 ('HAVE_LIBAIKSAURUS', env['AIKSAURUS_LIB']),
1235 ('USE_ASPELL', aspell_lib),
1236 ('USE_ISPELL', 'ispell'),
1237 ('USE_PSPELL', 'pspell'),
1242 system_libs.append(lib[1])
1245 # Build parameters CPPPATH etc
1248 env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1251 # boost: for boost header files
1252 # BUILDDIR/src: for config.h
1253 # TOP_SRCDIR/src: for support/* etc
1255 env['CPPPATH'] += ['$BUILDDIR/src', '$TOP_SRCDIR/src']
1257 # Separating boost directories from CPPPATH stops scons from building
1258 # the dependency tree for boost header files, and effectively reduce
1259 # the null build time of lyx from 29s to 16s. Since lyx may tweak local
1260 # boost headers, the following is not 100% safe.
1261 # env.AppendUnique(CPPPATH = ['$BOOST_INC_PATH'])
1262 env.PrependUnique(CCFLAGS = ['$INCPREFIX$BOOST_INC_PATH'])
1264 # for intl/config.h, intl/libintl.h and intl/libgnuintl.h
1265 if env['nls'] and included_gettext:
1266 env['CPPPATH'].append('$BUILDDIR/intl')
1270 # A Link script for cygwin see
1271 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1272 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1275 if platform_name == 'cygwin':
1276 ld_script_path = '/tmp'
1277 ld_script = utils.installCygwinLDScript(ld_script_path)
1278 env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1279 '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1282 #---------------------------------------------------------
1283 # Frontend related variables (QTDIR etc)
1284 #---------------------------------------------------------
1287 # create a separate environment so that other files do not have
1288 # to be built with all the include directories etc
1290 if frontend == 'qt4':
1291 frontend_env = env.Clone()
1292 frontend_env['BUILDERS']['qtResource'] = Builder(action = utils.env_qtResource)
1294 # handle qt related user specified paths
1295 # set environment so that moc etc can be found even if its path is not set properly
1296 if frontend_env.has_key('qt_dir') and frontend_env['qt_dir']:
1297 frontend_env['QTDIR'] = frontend_env['qt_dir']
1298 if os.path.isdir(os.path.join(frontend_env['qt_dir'], 'bin')):
1299 os.environ['PATH'] += os.pathsep + os.path.join(frontend_env['qt_dir'], 'bin')
1300 frontend_env.PrependENVPath('PATH', os.path.join(frontend_env['qt_dir'], 'bin'))
1301 if os.path.isdir(os.path.join(frontend_env['qt_dir'], 'lib')):
1302 frontend_env.PrependENVPath('PKG_CONFIG_PATH', os.path.join(frontend_env['qt_dir'], 'lib'))
1304 # if separate qt_lib_path is given
1305 if frontend_env.has_key('qt_lib_path') and frontend_env['qt_lib_path']:
1306 qt_lib_path = frontend_env.subst('$qt_lib_path')
1307 frontend_env.AppendUnique(LIBPATH = [qt_lib_path])
1308 frontend_env.PrependENVPath('PKG_CONFIG_PATH', qt_lib_path)
1312 # if separate qt_inc_path is given
1313 if frontend_env.has_key('qt_inc_path') and frontend_env['qt_inc_path']:
1314 qt_inc_path = frontend_env['qt_inc_path']
1318 # local qt4 toolset from
1319 # http://www.iua.upf.es/~dgarcia/Codders/sconstools.html
1321 # NOTE: I have to patch qt4.py since it does not automatically
1322 # process .C file!!! (add to cxx_suffixes )
1324 frontend_env.Tool('qt4', [scons_dir])
1325 frontend_env['QT_AUTOSCAN'] = 0
1326 frontend_env['QT4_AUTOSCAN'] = 0
1327 frontend_env['QT4_UICDECLFLAGS'] = '-tr lyx::qt_'
1329 if qt_lib_path is None:
1330 qt_lib_path = os.path.join(frontend_env.subst('$QTDIR'), 'lib')
1331 if qt_inc_path is None:
1332 qt_inc_path = os.path.join(frontend_env.subst('$QTDIR'), 'include')
1335 conf = Configure(frontend_env,
1337 'CheckPackage' : utils.checkPackage,
1338 'CheckCommand' : utils.checkCommand,
1343 # first: try pkg_config
1344 if frontend_env['HAS_PKG_CONFIG']:
1345 succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
1346 # FIXME: use pkg_config information?
1347 #frontend_env['QT4_PKG_CONFIG'] = succ
1348 # second: try to link to it
1350 # Under linux, I can test the following perfectly
1351 # Under windows, lib names need to passed as libXXX4.a ...
1352 if platform_name == 'win32':
1353 succ = conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
1355 succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
1356 # still can not find it
1358 print 'Did not find qt libraries, exiting!'
1359 print 'Please check config.log for more information.'
1362 # Now, determine the correct suffix:
1363 qt_libs = ['QtCore', 'QtGui']
1364 if platform_name == 'win32':
1365 if mode == 'debug' and use_vc and \
1366 conf.CheckLibWithHeader('QtCored4', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
1367 qt_lib_suffix = 'd4'
1368 use_qt_debug_libs = True
1371 use_qt_debug_libs = False
1373 if mode == 'debug' and conf.CheckLibWithHeader('QtCore_debug', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
1374 qt_lib_suffix = '_debug'
1375 use_qt_debug_libs = True
1378 use_qt_debug_libs = False
1379 frontend_env.EnableQt4Modules(qt_libs, debug = (mode == 'debug' and use_qt_debug_libs))
1380 frontend_libs = [x + qt_lib_suffix for x in qt_libs]
1381 qtcore_lib = ['QtCore' + qt_lib_suffix]
1383 # check uic and moc commands for qt frontends
1384 if conf.CheckCommand('uic') == None or conf.CheckCommand('moc') == None:
1385 print 'uic or moc command is not found for frontend', frontend
1388 # now, if msvc2005 is used, we will need to embed lyx.exe.manifest to lyx.exe
1389 # NOTE: previously, lyx.exe had to be linked to some qt manifest to work.
1390 # For some unknown changes in msvc or qt, this is no longer needed.
1392 frontend_env['LINKCOM'] = [frontend_env['LINKCOM'], \
1393 'mt.exe /MANIFEST %s /outputresource:$TARGET;1' % \
1394 env.File('$BUILDDIR/lyx.exe.manifest').path]
1396 frontend_env = conf.Finish()
1401 print env['VERSION_INFO']
1404 # Mingw command line may be too short for our link usage,
1405 # Here we use a trick from scons wiki
1406 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1408 # I also would like to add logging (commands only) capacity to the
1410 logfile = env.get('logfile', default_log_file)
1411 if logfile != '' or platform_name == 'win32':
1413 utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1414 info = '''# This is a log of commands used by scons to build lyx
1418 ''' % (time.asctime(), ' '.join(sys.argv),
1419 env['VERSION_INFO'].replace('\n','\n# ')) )
1424 # -h will print out help info
1425 Help(opts.GenerateHelpText(env))
1428 #----------------------------------------------------------
1430 #----------------------------------------------------------
1431 # this has been the source of problems on some platforms...
1432 # I find that I need to supply it with full path name
1433 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1434 # this usage needs further investigation.
1435 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1436 env.BuildDir('$BUILDDIR/boost', '$TOP_SRCDIR/boost/libs', duplicate = 0)
1437 env.BuildDir('$BUILDDIR/intl', '$TOP_SRCDIR/intl', duplicate = 0)
1438 env.BuildDir('$BUILDDIR/src', '$TOP_SRCDIR/src', duplicate = 0)
1439 frontend_env.BuildDir('$BUILDDIR/src', '$TOP_SRCDIR/src', duplicate = 0)
1441 print "Building all targets recursively"
1443 def libExists(libname):
1444 ''' Check whether or not lib $LOCALLIBNAME/libname already exists'''
1445 return os.path.isfile(File(env.subst('$LOCALLIBPATH/${LIBPREFIX}%s$LIBSUFFIX'%libname)).abspath)
1448 if (included_boost and not libExists('included_boost_regex')) or 'boost' in BUILD_TARGETS:
1452 for lib in boost_libs:
1453 boostlib = env.StaticLibrary(
1454 target = '$LOCALLIBPATH/included_boost_%s' % lib,
1455 source = ['$BUILDDIR/boost/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)],
1456 # do not use global CPPPATH because src/config.h will mess up with boost/config.h
1457 CPPPATH = ['$BUILDDIR/boost'] + extra_inc_paths,
1458 CCFLAGS = ['$CCFLAGS', '$INCPREFIX$TOP_SRCDIR/boost', '-DBOOST_USER_CONFIG="<config.h>"']
1460 Alias('boost', boostlib)
1463 if (included_gettext and not libExists('included_intl')) or 'intl' in BUILD_TARGETS:
1468 r'-DLOCALEDIR=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1469 r'-DLOCALE_ALIAS_PATH=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1470 r'-DLIBDIR=\"' + env['TOP_SRCDIR'].replace('\\', '\\\\') + r'/lib\"',
1472 '-DENABLE_RELOCATABLE=1',
1474 r'-DINSTALLDIR=\"' + prefix.replace('\\', '\\\\') + r'/lib\"',
1476 '-Dset_relocation_prefix=libintl_set_relocation_prefix',
1477 '-Drelocate=libintl_relocate',
1478 '-DDEPENDS_ON_LIBICONV=1',
1482 INTL_CCFLAGS.extend(['/Dinline#', '/D__attribute__(x)#', '/Duintmax_t=UINT_MAX'])
1484 intl = env.StaticLibrary(
1485 target = '$LOCALLIBPATH/included_intl',
1487 CCFLAGS = INTL_CCFLAGS,
1488 # do not use global CPPPATH because src/config.h will mess up with intl/config.h
1489 CPPPATH = ['$BUILDDIR/intl'] + extra_inc_paths,
1490 source = ['$BUILDDIR/intl/%s' % x for x in intl_files]
1497 frontend_env['QT4_MOCHPREFIX'] = ''
1498 frontend_env['QT4_MOCHSUFFIX'] = '_moc.cpp'
1500 support_moced_files = [frontend_env.Moc4('$BUILDDIR/src/support/%s' % x)
1501 for x in src_support_header_files ]
1502 support = frontend_env.StaticLibrary(
1503 target = '$LOCALLIBPATH/support',
1504 source = ['$BUILDDIR/src/support/%s' % x for x in src_support_files],
1511 CPPPATH = ['$CPPPATH', '$BUILDDIR/src/support']
1513 Alias('support', support)
1519 mathed = env.StaticLibrary(
1520 target = '$LOCALLIBPATH/mathed',
1521 source = ['$BUILDDIR/src/mathed/%s' % x for x in src_mathed_files]
1523 Alias('mathed', mathed)
1529 insets = env.StaticLibrary(
1530 target = '$LOCALLIBPATH/insets',
1531 source = ['$BUILDDIR/src/insets/%s' % x for x in src_insets_files]
1533 Alias('insets', insets)
1539 frontends = env.StaticLibrary(
1540 target = '$LOCALLIBPATH/frontends',
1541 source = ['$BUILDDIR/src/frontends/%s' % x for x in src_frontends_files]
1543 Alias('frontends', frontends)
1549 graphics = env.StaticLibrary(
1550 target = '$LOCALLIBPATH/graphics',
1551 source = ['$BUILDDIR/src/graphics/%s' % x for x in src_graphics_files]
1553 Alias('graphics', graphics)
1559 # tells scons how to get these moced files, although not all moced files are needed
1560 # (or are actually generated).
1561 qt4_moced_files = [frontend_env.Moc4('$BUILDDIR/src/frontends/qt4/%s' % x)
1562 for x in src_frontends_qt4_header_files ]
1563 ui_files = [frontend_env.Uic4('$BUILDDIR/src/frontends/qt4/ui/%s' % x.split('.')[0])
1564 for x in src_frontends_qt4_ui_files]
1565 resource = frontend_env.Qrc(frontend_env.qtResource(
1566 '$BUILDDIR/src/frontends/qt4/Resource.qrc',
1567 ['$TOP_SRCDIR/lib/images/%s' % x for x in lib_images_files] +
1568 ['$TOP_SRCDIR/lib/images/math/%s' % x for x in lib_images_math_files] +
1569 ['$TOP_SRCDIR/lib/images/commands/%s' % x for x in lib_images_commands_files]))
1571 # moc qt4_moc_files, the moced files are included in the original files
1573 qt4 = frontend_env.StaticLibrary(
1574 target = '$LOCALLIBPATH/qt4',
1575 source = ['$BUILDDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files] + resource,
1579 '$BUILDDIR/src/images',
1580 '$BUILDDIR/src/frontends',
1581 '$BUILDDIR/src/frontends/qt4',
1582 '$BUILDDIR/src/frontends/qt4/ui',
1597 if env['HAVE_FCNTL']:
1598 client = frontend_env.Program(
1599 target = '$BUILDDIR/src/client/lyxclient',
1600 LIBS = ['support'] + intl_libs + system_libs +
1601 socket_libs + boost_libraries + qtcore_lib,
1602 source = ['$BUILDDIR/src/client/%s' % x for x in src_client_files] + \
1603 utils.createResFromIcon(frontend_env, 'lyx.ico', '$LOCALLIBPATH/client.rc')
1605 Alias('client', frontend_env.Command(os.path.join('$BUILDDIR', os.path.split(str(client[0]))[1]),
1606 client, [Copy('$TARGET', '$SOURCE')]))
1609 Alias('client', client)
1615 for file in src_tex2lyx_copied_files + src_tex2lyx_copied_header_files:
1616 frontend_env.Command('$BUILDDIR/src/tex2lyx/'+file, '$TOP_SRCDIR/src/'+file,
1617 [Copy('$TARGET', '$SOURCE')])
1619 tex2lyx = frontend_env.Program(
1620 target = '$BUILDDIR/src/tex2lyx/tex2lyx',
1621 LIBS = ['support'] + boost_libraries + intl_libs + system_libs + qtcore_lib,
1622 source = ['$BUILDDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_files + src_tex2lyx_copied_files] + \
1623 utils.createResFromIcon(frontend_env, 'lyx.ico', '$LOCALLIBPATH/tex2lyx.rc'),
1624 CPPPATH = ['$BUILDDIR/src/tex2lyx', '$BUILDDIR/src', '$CPPPATH'],
1625 LIBPATH = ['#$LOCALLIBPATH', '$LIBPATH'],
1626 CCFLAGS = ['$CCFLAGS', '-DTEX2LYX'],
1628 Alias('tex2lyx', frontend_env.Command(os.path.join('$BUILDDIR', os.path.split(str(tex2lyx[0]))[1]),
1629 tex2lyx, [Copy('$TARGET', '$SOURCE')]))
1630 Alias('tex2lyx', tex2lyx)
1636 if env.has_key('USE_ASPELL') and env['USE_ASPELL']:
1637 src_post_files.append('ASpell.cpp')
1638 elif env.has_key('USE_PSPELL') and env['USE_PSPELL']:
1639 src_post_files.append('PSpell.cpp')
1640 elif env.has_key('USE_ISPELL') and env['USE_ISPELL']:
1641 src_post_files.append('ISpell.cpp')
1643 # msvc requires at least one source file with main()
1644 # so I exclude main.cpp from lyxbase
1645 lyxbase_pre = env.StaticLibrary(
1646 target = '$LOCALLIBPATH/lyxbase_pre',
1647 source = ['$BUILDDIR/src/%s' % x for x in src_pre_files]
1649 lyxbase_post = env.StaticLibrary(
1650 target = '$LOCALLIBPATH/lyxbase_post',
1651 source = ["$BUILDDIR/src/%s" % x for x in src_post_files]
1653 Alias('lyxbase', lyxbase_pre)
1654 Alias('lyxbase', lyxbase_post)
1658 # Build lyx with given frontend
1660 lyx = frontend_env.Program(
1661 target = '$BUILDDIR/lyx',
1662 source = ['$BUILDDIR/src/main.cpp'] + \
1663 utils.createResFromIcon(frontend_env, 'lyx.ico', '$LOCALLIBPATH/lyx.rc'),
1673 boost_libraries + ['lyxbase_post'] +
1682 if use_vc and 'msvs_projects' in BUILD_TARGETS:
1683 def build_project(target, full_target = None, src = [], inc = [], res = []):
1684 ''' build mavs project files
1685 target: alias (correspond to directory name)
1686 full_target: full path/filename of the target
1691 For non-debug-able targets like static libraries, target (alias) is
1692 enough to build the target. For executable targets, msvs need to know
1693 the full path to start debug them.
1696 proj = env.MSVSProject(
1697 target = target + env['MSVSPROJECTSUFFIX'],
1698 # this allows easy access to header files (along with source)
1699 srcs = [env.subst(x) for x in src + inc],
1700 incs = [env.subst('$TOP_SRCDIR/src/config.h')],
1701 localincs = [env.subst(x) for x in inc],
1702 resources = [env.subst(x) for x in res],
1703 buildtarget = full_target,
1706 Alias('msvs_projects', proj)
1708 build_project('client', src = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_files],
1709 inc = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_header_files],
1710 full_target = File(env.subst('$BUILDDIR/src/client/lyxclient$PROGSUFFIX')).abspath)
1712 build_project('tex2lyx', src = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_files],
1713 inc = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_header_files],
1714 full_target = File(env.subst('$BUILDDIR/src/tex2lyx/tex2lyx$PROGSUFFIX')).abspath)
1716 build_project('lyx',
1717 src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files + ['version.cpp']] + \
1718 ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files + ['Package.cpp'] ] + \
1719 ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_files] + \
1720 ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files] + \
1721 ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files] + \
1722 ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files] + \
1723 ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files],
1724 inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files] + \
1725 ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files] + \
1726 ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_header_files] + \
1727 ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files] + \
1728 ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files] + \
1729 ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files] + \
1730 ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1731 res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files],
1732 full_target = File(env.subst('$BUILDDIR/lyx$PROGSUFFIX')).abspath)
1735 if 'update_po' in BUILD_TARGETS:
1739 print 'Updating po/*.po files...'
1741 # whether or not update po files
1742 if not env['XGETTEXT'] or not env['MSGMERGE'] or not env['MSGUNIQ']:
1743 print 'xgettext or msgmerge does not exist. Cannot merge po files'
1745 # rebuild POTFILES.in
1746 POTFILES_in = env.potfiles('$TOP_SRCDIR/po/POTFILES.in',
1747 ['$TOP_SRCDIR/src/%s' % x for x in src_header_files + src_pre_files + src_post_files + \
1748 src_extra_src_files] + \
1749 ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files + src_support_files + \
1750 src_support_extra_header_files + src_support_extra_src_files] + \
1751 ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_header_files + src_mathed_files] + \
1752 ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files + src_insets_files] + \
1753 ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files + src_frontends_files] + \
1754 ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files + src_graphics_files] + \
1755 ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files + src_frontends_qt4_files] + \
1756 ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_header_files + src_client_files ] + \
1757 ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_header_files + src_tex2lyx_files ]
1759 Alias('update_po', POTFILES_in)
1760 # build language_l10n.pot, encodings_10n.pot, ui_l10n.pot, layouts_l10n.pot, qt4_l10n.pot, external_l10n, formats_l10n
1761 # and combine them to lyx.po
1762 env['LYX_POT'] = 'python $TOP_SRCDIR/po/lyx_pot.py'
1763 lyx_po = env.Command('$BUILDDIR/po/lyx.po',
1764 env.Command('$BUILDDIR/po/all.po',
1765 [env.Command('$BUILDDIR/po/qt4_l10n.pot',
1766 ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files],
1767 '$LYX_POT -b $TOP_SRCDIR -t qt4 -o $TARGET $SOURCES'),
1768 env.Command('$BUILDDIR/po/layouts_l10n.pot',
1769 ['$TOP_SRCDIR/lib/layouts/%s' % x for x in lib_layouts_files + lib_layouts_inc_files + lib_layouts_module_files],
1770 '$LYX_POT -b $TOP_SRCDIR -t layouts -o $TARGET $SOURCES'),
1771 env.Command('$BUILDDIR/po/languages_l10n.pot', '$TOP_SRCDIR/lib/languages',
1772 '$LYX_POT -b $TOP_SRCDIR -t languages -o $TARGET $SOURCES'),
1773 env.Command('$BUILDDIR/po/encodings_l10n.pot', '$TOP_SRCDIR/lib/encodings',
1774 '$LYX_POT -b $TOP_SRCDIR -t encodings -o $TARGET $SOURCES'),
1775 env.Command('$BUILDDIR/po/ui_l10n.pot',
1776 ['$TOP_SRCDIR/lib/ui/%s' % x for x in lib_ui_files],
1777 '$LYX_POT -b $TOP_SRCDIR -t ui -o $TARGET $SOURCES'),
1778 env.Command('$BUILDDIR/po/external_l10n.pot', '$TOP_SRCDIR/lib/external_templates',
1779 '$LYX_POT -b $TOP_SRCDIR -t external -o $TARGET $SOURCES'),
1780 env.Command('$BUILDDIR/po/formats_l10n.pot', '$TOP_SRCDIR/lib/configure.py',
1781 '$LYX_POT -b $TOP_SRCDIR -t formats -o $TARGET $SOURCES'),
1783 ['$MSGUNIQ -o $TARGET $SOURCE',
1784 '''$XGETTEXT --default-domain=${TARGET.base} \
1785 --directory=$TOP_SRCDIR --add-comments=TRANSLATORS: \
1786 --language=C++ --join-existing \
1787 --keyword=_ --keyword=N_ --keyword=B_ --keyword=qt_ \
1788 --files-from=$TOP_SRCDIR/po/POTFILES.in \
1789 --copyright-holder="LyX Developers" \
1790 --msgid-bugs-address="lyx-devel@lists.lyx.org" ''']
1792 env.Depends(lyx_po, POTFILES_in)
1793 # copy lyx.po to lyx.pot
1794 lyx_pot = env.Command('$BUILDDIR/po/lyx.pot', lyx_po,
1795 Copy('$TARGET', '$SOURCE'))
1798 # files to translate
1799 transfiles = glob.glob(os.path.join(env.Dir('$TOP_SRCDIR/po').abspath, '*.po'))
1800 # possibly *only* handle these languages
1802 if env.has_key('languages'):
1803 languages = env.make_list(env['languages'])
1804 # merge. if I use lan.po as $TARGET, it will be removed
1805 # before it is merged. In this builder,
1806 # $BUILDDIR/po/lang.po is merged from po/lang.po and $BUILDDIR/po/lyx.pot
1807 # and is copied to po/lang.po
1808 env['BUILDERS']['msgmerge'] = Builder(action=[
1809 '$MSGMERGE $TOP_SRCDIR/po/${TARGET.filebase}.po $SOURCE -o $TARGET',
1810 Copy('$TOP_SRCDIR/po/${TARGET.filebase}.po', '$TARGET')]
1812 # for each po file, generate pot
1813 for po_file in transfiles:
1815 fname = os.path.split(po_file)[1]
1817 country = fname.split('.')[0]
1819 if not languages or country in languages:
1820 # merge po files, the generated lan.po_new file is copied to lan.po file.
1821 po = env.msgmerge('$BUILDDIR/po/%s.po' % country, lyx_pot)
1822 env.Depends(po, POTFILES_in)
1823 Alias('update_po', po)
1826 # if 'install' is not in the target, do not process this
1827 if 'install' in BUILD_TARGETS or 'installer' in BUILD_TARGETS:
1829 # this part is a bit messy right now. Since scons will provide
1830 # --DESTDIR option soon, at least the dest_dir handling can be
1839 # files to translate
1840 transfiles = glob.glob(os.path.join(env.subst('$TOP_SRCDIR'), 'po', '*.po'))
1841 # possibly *only* handle these languages
1843 if env.has_key('languages'):
1844 languages = env.make_list(env['lanauges'])
1845 # use defulat msgfmt
1847 if not env['MSGFMT']:
1848 print 'msgfmt does not exist. Can not process po files'
1851 env['BUILDERS']['Transfiles'] = Builder(action='$MSGFMT $SOURCE -c --statistics -o $TARGET',suffix='.gmo',src_suffix='.po')
1853 for f in transfiles:
1855 fname = os.path.split(f)[1]
1857 country = fname.split('.')[0]
1859 if not languages or country in languages:
1860 gmo_files.extend(env.Transfiles(f))
1861 # how to join dest_dir and prefix
1862 def joinPaths(path1, path2):
1863 ''' join path1 and path2, do not use os.path.join because
1864 under window, c:\destdir\d:\program is invalid '''
1866 return os.path.normpath(path2)
1867 # separate drive letter
1868 (drive, path) = os.path.splitdrive(os.path.normpath(path2))
1869 # ignore drive letter, so c:\destdir + c:\program = c:\destdir\program
1870 return os.path.join(os.path.normpath(path1), path[1:])
1872 # install to dest_dir/prefix
1873 dest_dir = env.get('DESTDIR', '')
1874 dest_prefix_dir = joinPaths(dest_dir, env.Dir(prefix).abspath)
1875 # create the directory if needed
1876 if not os.path.isdir(dest_prefix_dir):
1878 os.makedirs(dest_prefix_dir)
1881 if not os.path.isdir(dest_prefix_dir):
1882 print 'Can not create directory', dest_prefix_dir
1885 if env.has_key('exec_prefix'):
1886 bin_dest_dir = joinPaths(dest_dir, Dir(env['exec_prefix']).abspath)
1888 bin_dest_dir = os.path.join(dest_prefix_dir, 'bin')
1890 share_dest_dir = os.path.join(dest_prefix_dir, share_dir + program_suffix)
1892 share_dest_dir = os.path.join(dest_prefix_dir, share_dir)
1893 man_dest_dir = os.path.join(dest_prefix_dir, man_dir)
1894 locale_dest_dir = os.path.join(dest_prefix_dir, locale_dir)
1895 env['LYX2LYX_DEST'] = os.path.join(share_dest_dir, 'lyx2lyx')
1899 # install executables (lyxclient may be None)
1902 version_suffix = program_suffix
1906 # install lyx, if in release mode, try to strip the binary
1907 if env.has_key('STRIP') and env['STRIP'] is not None and mode != 'debug':
1908 # create a builder to strip and install
1909 env['BUILDERS']['StripInstallAs'] = Builder(action='$STRIP $SOURCE -o $TARGET')
1911 # install executables
1912 for (name, obj) in (('lyx', lyx), ('tex2lyx', tex2lyx), ('client', client)):
1915 target_name = os.path.split(str(obj[0]))[1].replace(name, '%s%s' % (name, version_suffix))
1916 target = os.path.join(bin_dest_dir, target_name)
1917 if env['BUILDERS'].has_key('StripInstallAs'):
1918 env.StripInstallAs(target, obj)
1920 env.InstallAs(target, obj)
1921 Alias('install', target)
1925 for (dir,files) in [
1927 ('bind', lib_bind_files),
1928 ('bind/de', lib_bind_de_files),
1929 ('bind/fi', lib_bind_fi_files),
1930 ('bind/pt', lib_bind_pt_files),
1931 ('bind/sv', lib_bind_sv_files),
1932 ('commands', lib_commands_files),
1933 ('doc', lib_doc_files),
1934 ('doc/biblio', lib_doc_biblio_files),
1935 ('doc/clipart', lib_doc_clipart_files),
1936 ('doc/ca', lib_doc_ca_files),
1937 ('doc/cs', lib_doc_cs_files),
1938 ('doc/da', lib_doc_da_files),
1939 ('doc/de', lib_doc_de_files),
1940 ('doc/de/clipart', lib_doc_de_clipart_files),
1941 ('doc/es', lib_doc_es_files),
1942 ('doc/es/clipart', lib_doc_es_clipart_files),
1943 ('doc/eu', lib_doc_eu_files),
1944 ('doc/fr', lib_doc_fr_files),
1945 ('doc/fr/clipart', lib_doc_fr_clipart_files),
1946 ('doc/he', lib_doc_he_files),
1947 ('doc/hu', lib_doc_hu_files),
1948 ('doc/it', lib_doc_it_files),
1949 ('doc/it/clipart', lib_doc_it_clipart_files),
1950 ('doc/ja', lib_doc_ja_files),
1951 ('doc/ja/clipart', lib_doc_ja_clipart_files),
1952 ('doc/nl', lib_doc_nl_files),
1953 ('doc/nb', lib_doc_nb_files),
1954 ('doc/pl', lib_doc_pl_files),
1955 ('doc/pt', lib_doc_pt_files),
1956 ('doc/ro', lib_doc_ro_files),
1957 ('doc/ru', lib_doc_ru_files),
1958 ('doc/sk', lib_doc_sk_files),
1959 ('doc/sl', lib_doc_sl_files),
1960 ('doc/sv', lib_doc_sv_files),
1961 ('doc/uk', lib_doc_uk_files),
1962 ('doc/uk/clipart', lib_doc_uk_clipart_files),
1963 ('examples', lib_examples_files),
1964 ('examples/ca', lib_examples_ca_files),
1965 ('examples/cs', lib_examples_cs_files),
1966 ('examples/da', lib_examples_da_files),
1967 ('examples/de', lib_examples_de_files),
1968 ('examples/es', lib_examples_es_files),
1969 ('examples/eu', lib_examples_eu_files),
1970 ('examples/fa', lib_examples_fa_files),
1971 ('examples/fr', lib_examples_fr_files),
1972 ('examples/he', lib_examples_he_files),
1973 ('examples/hu', lib_examples_hu_files),
1974 ('examples/it', lib_examples_it_files),
1975 ('examples/ja', lib_examples_ja_files),
1976 ('examples/nl', lib_examples_nl_files),
1977 ('examples/pl', lib_examples_pl_files),
1978 ('examples/pt', lib_examples_pt_files),
1979 ('examples/ru', lib_examples_ru_files),
1980 ('examples/sl', lib_examples_sl_files),
1981 ('examples/ro', lib_examples_ro_files),
1982 ('fonts', lib_fonts_files),
1983 ('images', lib_images_files),
1984 ('images/math', lib_images_math_files),
1985 ('images/commands', lib_images_commands_files),
1986 ('kbd', lib_kbd_files),
1987 ('layouts', lib_layouts_files + lib_layouts_inc_files + lib_layouts_module_files),
1988 ('lyx2lyx', lib_lyx2lyx_files),
1989 ('scripts', lib_scripts_files),
1990 ('templates', lib_templates_files),
1991 ('tex', lib_tex_files),
1992 ('ui', lib_ui_files)]:
1993 dirs.append(env.Install(os.path.join(share_dest_dir, dir),
1994 [env.subst('$TOP_SRCDIR/lib/%s/%s' % (dir, file)) for file in files]))
1995 Alias('install', dirs)
1997 # subst and install lyx2lyx_version.py which is not in scons_manifest.py
1998 env.Depends(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py', '$BUILDDIR/src/config.h')
1999 env.substFile(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py',
2000 '$TOP_SRCDIR/lib/lyx2lyx/lyx2lyx_version.py.in')
2001 Alias('install', share_dest_dir + '/lyx2lyx/lyx2lyx_version.py')
2002 sys.path.append(share_dest_dir + '/lyx2lyx')
2004 if platform_name == 'cygwin':
2005 # cygwin packaging requires a file /usr/share/doc/Cygwin/foot-vendor-suffix.README
2006 Cygwin_README = os.path.join(dest_prefix_dir, 'share', 'doc', 'Cygwin',
2007 '%s-%s.README' % (package, package_cygwin_version))
2008 env.InstallAs(Cygwin_README,
2009 os.path.join(env.subst('$TOP_SRCDIR'), 'README.cygwin'))
2010 Alias('install', Cygwin_README)
2011 # also a directory /usr/share/doc/lyx for README etc
2012 Cygwin_Doc = os.path.join(dest_prefix_dir, 'share', 'doc', package)
2013 env.Install(Cygwin_Doc, [os.path.join(env.subst('$TOP_SRCDIR'), x) for x in \
2014 ['INSTALL', 'README', 'README.Cygwin', 'RELEASE-NOTES', 'COPYING', 'ANNOUNCE']])
2015 Alias('install', Cygwin_Doc)
2016 # cygwin fonts also need to be installed
2017 Cygwin_fonts = os.path.join(share_dest_dir, 'fonts')
2018 env.Install(Cygwin_fonts,
2019 [env.subst('$TOP_SRCDIR/development/Win32/packaging/bakoma/%s' % file) \
2020 for file in win32_bakoma_fonts])
2021 Alias('install', Cygwin_fonts)
2022 # we also need a post installation script
2023 tmp_script = utils.installCygwinPostinstallScript('/tmp')
2024 postinstall_path = os.path.join(dest_dir, 'etc', 'postinstall')
2025 env.Install(postinstall_path, tmp_script)
2026 Alias('install', postinstall_path)
2028 env.InstallAs(os.path.join(man_dest_dir, 'lyx' + version_suffix + '.1'),
2029 env.subst('$TOP_SRCDIR/lyx.1in'))
2030 env.InstallAs(os.path.join(man_dest_dir, 'tex2lyx' + version_suffix + '.1'),
2031 env.subst('$TOP_SRCDIR/src/tex2lyx/tex2lyx.man'))
2032 env.InstallAs(os.path.join(man_dest_dir, 'lyxclient' + version_suffix + '.1'),
2033 env.subst('$TOP_SRCDIR/src/client/lyxclient.man'))
2034 Alias('install', [os.path.join(man_dest_dir, x + version_suffix + '.1') for
2035 x in ['lyx', 'tex2lyx', 'lyxclient']])
2037 # ru.gmo ==> ru/LC_MESSAGES/lyxSUFFIX.mo
2038 for gmo in gmo_files:
2039 lan = os.path.split(str(gmo))[1].split('.')[0]
2040 dest_file = os.path.join(locale_dest_dir, lan, 'LC_MESSAGES', 'lyx' + program_suffix + '.mo')
2041 env.InstallAs(dest_file, gmo)
2042 Alias('install', dest_file)
2045 if 'installer' in BUILD_TARGETS:
2047 # build windows installer using NSIS
2050 # There is a nsis builder on scons wiki but it does not work with
2051 # our lyx.nsi because it does not dig through all the include directives
2052 # and find the dependencies automatically. Also, it can not parse
2053 # OutFile in lyx.nsi since it is defined as SETUP_EXE which is in turn
2054 # something rely on date.
2055 # Because of this, I am doing a simple nsis builder here.
2056 if platform_name != 'win32':
2057 print 'installer target is only available for windows platform'
2059 if mode != 'release':
2060 print 'installer has to be built in release mode (use option mode=release)'
2062 installer_files = ['$TOP_SRCDIR/development/Win32/packaging/installer/%s' \
2063 % x for x in development_Win32_packaging_installer] + \
2064 ['$TOP_SRCDIR/development/Win32/packaging/installer/graphics/%s' \
2065 % x for x in development_Win32_packaging_installer_graphics] + \
2066 ['$TOP_SRCDIR/development/Win32/packaging/installer/gui/%s' \
2067 % x for x in development_Win32_packaging_installer_gui] + \
2068 ['$TOP_SRCDIR/development/Win32/packaging/installer/include/%s' \
2069 % x for x in development_Win32_packaging_installer_include] + \
2070 ['$TOP_SRCDIR/development/Win32/packaging/installer/lang/%s' \
2071 % x for x in development_Win32_packaging_installer_lang] + \
2072 ['$TOP_SRCDIR/development/Win32/packaging/installer/setup/%s' \
2073 % x for x in development_Win32_packaging_installer_setup]
2074 if env.has_key('NSIS') and env['NSIS'] is not None:
2075 # create a builder to strip and install
2076 env['BUILDERS']['installer'] = Builder(generator=utils.env_nsis)
2078 print 'No nsis compiler is found. Existing...'
2080 if not env.has_key('win_installer') or env['win_installer'] is None:
2082 env['win_installer'] = '%s-%s-%s-Installer.exe' % (package_name, package_version, time.strftime('%Y-%m-%d'))
2084 env['win_installer'] = '%s-%s-Installer.exe' % (package_name, package_version)
2085 # provide default setting
2086 if not env.has_key('deps_dir') or env['deps_dir'] is None:
2087 env['deps_dir'] = os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'lyx-windows-deps-msvc-qt4')
2088 if not os.path.isdir(env.Dir('$deps_dir').abspath):
2089 print 'Development dependency package is not found.'
2092 env['deps_dir'] = env.Dir('$deps_dir').abspath
2094 if env.has_key('bundle_dir') and os.path.isdir(env.Dir('$bundle_dir').abspath):
2095 env['bundle_dir'] = env.Dir('$bundle_dir').abspath
2096 elif os.path.isdir(os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'lyx-windows-bundle-deps')):
2097 env['bundle_dir'] = os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'lyx-windows-bundle-deps')
2099 env['bundle_dir'] = None
2100 # if absolute path is given, use it, otherwise, write to current directory
2101 if not (':' in env['win_installer'] or '/' in env['win_installer'] or '\\' in env['win_installer']):
2102 env['win_installer'] = os.path.join(env.Dir('$BUILDDIR').abspath, env['win_installer'])
2103 env.Append(NSISDEFINES={
2104 'ExeFile':env['win_installer'],
2105 'BundleExeFile':env['win_installer'].replace('.exe', '-bundle.exe'),
2106 'FilesLyx':env.Dir(dest_prefix_dir).abspath,
2107 'FilesDeps':env['deps_dir'],
2108 'FilesBundle':env['bundle_dir'],
2110 installer = env.installer(env['win_installer'],
2111 '$TOP_SRCDIR/development/Win32/packaging/installer/lyx.nsi')
2112 # since I can not use a scanner, explicit dependent is required
2113 env.Depends(installer, 'install')
2114 env.Depends(installer, installer_files)
2115 env.Alias('installer', installer)
2116 # also generate bundle?
2117 if env.has_key('bundle') and env['bundle']:
2118 if env['bundle_dir'] is None or not os.path.isdir(env['bundle_dir']):
2119 print 'Bundle directory does not exist (default to %s\lyx-windows-bundle-deps.' % env.Dir('$TOP_SRCDIR').abspath
2120 print 'Use bundle_dir option to specify'
2122 # generator of the builder will add bundle stuff depending on output name
2123 bundle_installer = env.installer(env['win_installer'].replace('.exe', '-bundle.exe'),
2124 '$TOP_SRCDIR/development/Win32/packaging/installer/lyx.nsi')
2125 env.Depends(bundle_installer, 'install')
2126 env.Depends(bundle_installer, installer_files)
2127 env.Alias('installer', bundle_installer)
2130 Alias('all', ['lyx', 'client', 'tex2lyx'])