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 #----------------------------------------------------------
40 # Required runtime environment
41 #----------------------------------------------------------
43 # scons asks for 1.5.2, lyx requires 2.3
44 EnsurePythonVersion(2, 3)
45 # Please use at least 0.96.92 (not 0.96.1)
46 EnsureSConsVersion(0, 96)
47 # also check for minor version number for scons 0.96
48 from SCons import __version__
49 # allow the use of snapshot version of scons
50 __version__ = __version__.split('d')[0]
51 version = map(int, __version__.split('.'))
52 if version[0] == 0 and version[1] == 96 and version[2] < 92:
53 print "Scons >= 0.96.92 is required."
57 #----------------------------------------------------------
59 #----------------------------------------------------------
61 # some global settings
63 # get version number from configure.ac so that JMarc does
64 # not have to change SConstruct during lyx release
65 package_version, lyx_date = utils.getVerFromConfigure(top_src_dir)
66 package_cygwin_version = '%s-1' % package_version
67 boost_version = ['1_34']
69 if 'svn' in package_version:
71 default_build_mode = 'debug'
74 default_build_mode = 'release'
77 package_bugreport = 'lyx-devel@lists.lyx.org'
79 package_tarname = 'lyx'
80 package_string = '%s %s' % (package_name, package_version)
82 # various cache/log files
83 default_log_file = 'scons_lyx.log'
84 opt_cache_file = 'opt.cache'
87 #----------------------------------------------------------
88 # platform dependent settings
89 #----------------------------------------------------------
92 platform_name = 'win32'
93 default_prefix = 'c:/program files/lyx'
94 default_with_x = False
95 default_packaging_method = 'windows'
96 elif os.name == 'posix' and sys.platform != 'cygwin':
97 platform_name = sys.platform
98 default_prefix = '/usr/local'
100 default_packaging_method = 'posix'
101 elif os.name == 'posix' and sys.platform == 'cygwin':
102 platform_name = 'cygwin'
103 default_prefix = '/usr'
104 default_with_x = True
105 default_packaging_method = 'posix'
106 elif os.name == 'darwin':
107 platform_name = 'macosx'
108 # FIXME: macOSX default prefix?
110 default_with_x = False
111 default_packaging_method = 'macosx'
112 else: # unsupported system, assume posix behavior
113 platform_name = 'others'
115 default_with_x = True
116 default_packaging_method = 'posix'
118 #---------------------------------------------------------
120 #----------------------------------------------------------
122 # You can set perminant default values in config.py
123 if os.path.isfile('config.py'):
124 print "Getting options from config.py..."
125 print open('config.py').read()
127 opts = Options(['config.py'])
130 EnumOption('frontend', 'Main GUI', 'qt4',
131 allowed_values = ('qt4',) ),
132 # debug or release build
133 EnumOption('mode', 'Building method', default_build_mode,
134 allowed_values = ('debug', 'release') ),
137 'Use included, system boost library, or try sytem boost first.',
138 'auto', allowed_values = (
139 'auto', # detect boost, if not found, use included
140 'included', # always use included boost
141 'system', # always use system boost, fail if can not find
144 EnumOption('gettext',
145 'Use included, system gettext library, or try sytem gettext first',
146 'auto', allowed_values = (
147 'auto', # detect gettext, if not found, use included
148 'included', # always use included gettext
149 'system', # always use system gettext, fail if can not find
152 EnumOption('spell', 'Choose spell checker to use.', 'auto',
153 allowed_values = ('aspell', 'pspell', 'ispell', 'auto', 'no') ),
155 EnumOption('packaging', 'Packaging method to use.', default_packaging_method,
156 allowed_values = ('windows', 'posix', 'macosx')),
158 BoolOption('fast_start', 'This option is obsolete.', False),
159 # No precompiled header support (too troublesome to make it work for msvc)
160 # BoolOption('pch', 'Whether or not use pch', False),
161 # enable assertion, (config.h has ENABLE_ASSERTIOS
162 BoolOption('assertions', 'Use assertions', True),
163 # config.h define _GLIBCXX_CONCEPT_CHECKS
164 # Note: for earlier version of gcc (3.3) define _GLIBCPP_CONCEPT_CHECKS
165 BoolOption('concept_checks', 'Enable concept checks', True),
167 BoolOption('nls', 'Whether or not use native language support', True),
169 BoolOption('profiling', 'Whether or not enable profiling', False),
170 # config.h define _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC
171 BoolOption('stdlib_debug', 'Whether or not turn on stdlib debug', False),
173 BoolOption('X11', 'Use x11 windows system', default_with_x),
174 # use MS VC++ to build lyx
175 BoolOption('use_vc', 'Use MS VC++ to build lyx (cl.exe will be probed)', None),
177 PathOption('qt_dir', 'Path to qt directory', None),
179 PathOption('qt_inc_path', 'Path to qt include directory', None),
181 PathOption('qt_lib_path', 'Path to qt library directory', None),
182 # extra include and libpath
183 PathOption('extra_inc_path', 'Extra include path', None),
185 PathOption('extra_lib_path', 'Extra library path', None),
187 PathOption('extra_bin_path', 'A convenient way to add a path to $PATH', None),
189 PathOption('extra_inc_path1', 'Extra include path', None),
191 PathOption('extra_lib_path1', 'Extra library path', None),
192 # rebuild only specifed, comma separated targets
193 ('rebuild', '''rebuild only specifed, comma separated targets.
194 yes or all (default): rebuild everything
195 no or none: rebuild nothing (usually used for installation)
196 comp1,comp2,...: rebuild specified targets''', None),
197 # can be set to a non-existing directory
198 ('prefix', 'install architecture-independent files in PREFIX', default_prefix),
199 # replace the default name and location of the windows installer
200 ('win_installer', 'name or full path to the windows installer', None),
201 # the deps package used to create minimal installer (qt and other libraries)
202 ('deps_dir', 'path to the development depedency packages with zlib, iconv, zlib and qt libraries', None),
203 # whether or not build bundle installer
204 BoolOption('bundle', 'Whether or not build bundle installer', False),
205 # the bundle directory, containing bundled applications
206 PathOption('bundle_dir', 'path to the bundle dependency package with miktex setup.exe etc', None),
207 # build directory, will use $mode if not set
208 ('build_dir', 'Build directory', None),
210 ('version_suffix', 'install lyx as lyx-suffix', None),
211 # how to load options
212 ('load_option', '''load option from previous scons run. option can be
213 yes (default): load all options
214 no: do not load any option
215 opt1,opt2: load specified options
216 -opt1,opt2: load all options other than specified ones''', 'yes'),
218 ('optimization', 'optimization CCFLAGS option.', None),
220 PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
222 ('logfile', 'save commands (not outputs) to logfile', default_log_file),
223 # provided for backward compatibility
224 ('dest_dir', 'install to DESTDIR. (Provided for backward compatibility only)', None),
225 # environment variable can be set as options.
226 ('DESTDIR', 'install to DESTDIR', None),
227 ('CC', 'replace default $CC', None),
228 ('LINK', 'replace default $LINK', None),
229 ('CPP', 'replace default $CPP', None),
230 ('CXX', 'replace default $CXX', None),
231 ('CXXCPP', 'replace default $CXXCPP', None),
232 ('CCFLAGS', 'replace default $CCFLAGS', None),
233 ('CPPFLAGS', 'replace default $CPPFLAGS', None),
234 ('LINKFLAGS', 'replace default $LINKFLAGS', None),
238 all_options = [x.key for x in opts.options]
240 # copied from SCons/Options/BoolOption.py
241 # We need to use them before a boolean ARGUMENTS option is available
243 true_strings = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
244 false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none')
246 if ARGUMENTS.has_key('fast_start'):
247 print 'fast_start option is obsolete'
249 # if load_option=yes (default), load saved comand line options
251 # This option can take value yes/no/opt1,opt2/-opt1,opt2
252 # and tries to be clever in choosing options to load
253 if (not ARGUMENTS.has_key('load_option') or \
254 ARGUMENTS['load_option'] not in false_strings) \
255 and os.path.isfile(opt_cache_file):
256 cache_file = open(opt_cache_file)
257 opt_cache = cPickle.load(cache_file)
259 # import cached options, but we should ignore qt_dir when frontend changes
260 if ARGUMENTS.has_key('frontend') and opt_cache.has_key('frontend') \
261 and ARGUMENTS['frontend'] != opt_cache['frontend'] \
262 and opt_cache.has_key('qt_dir'):
263 opt_cache.pop('qt_dir')
264 # and we do not cache some options (dest_dir is obsolete)
265 for arg in ['load_option', 'dest_dir', 'bundle']:
266 if opt_cache.has_key(arg):
268 # remove obsolete cached keys (well, SConstruct is evolving. :-)
269 for arg in opt_cache.keys():
270 if arg not in all_options:
271 print 'Option %s is obsolete, do not load it' % arg
273 # now, if load_option=opt1,opt2 or -opt1,opt2
274 if ARGUMENTS.has_key('load_option') and \
275 ARGUMENTS['load_option'] not in true_strings + false_strings:
276 # if -opt1,opt2 is specified, do not load these options
277 if ARGUMENTS['load_option'][0] == '-':
278 for arg in ARGUMENTS['load_option'][1:].split(','):
279 if opt_cache.has_key(arg):
281 # if opt1,opt2 is specified, only load specified options
283 args = ARGUMENTS['load_option'].split(',')
284 for arg in opt_cache.keys():
287 # now restore options as if entered from command line
288 for key in opt_cache.keys():
289 if not ARGUMENTS.has_key(key):
290 ARGUMENTS[key] = opt_cache[key]
291 print "Restoring cached option %s=%s" % (key, ARGUMENTS[key])
294 # check if there is unused (or misspelled) argument
295 for arg in ARGUMENTS.keys():
296 if arg not in all_options:
298 print "Unknown option '%s'... exiting." % arg
300 print "Available options are (check 'scons -help' for details):"
301 print ' ' + '\n '.join(textwrap.wrap(', '.join(all_options)))
305 cache_file = open(opt_cache_file, 'w')
306 cPickle.dump(ARGUMENTS, cache_file)
309 #---------------------------------------------------------
310 # Setting up environment
311 #---------------------------------------------------------
313 # I do not really like ENV=os.environ, but you may add it
314 # here if you experience some environment related problem
315 env = Environment(options = opts)
317 # set individual variables since I do not really like ENV = os.environ
318 env['ENV']['PATH'] = os.environ.get('PATH')
319 env['ENV']['HOME'] = os.environ.get('HOME')
320 # these are defined for MSVC
321 env['ENV']['LIB'] = os.environ.get('LIB')
322 env['ENV']['INCLUDE'] = os.environ.get('INCLUDE')
324 # for simplicity, use var instead of env[var]
325 frontend = env['frontend']
326 prefix = env['prefix']
329 if platform_name == 'win32':
330 if env.has_key('use_vc'):
331 use_vc = env['use_vc']
332 if WhereIs('cl.exe') is None:
333 print "cl.exe is not found. Are you using the MSVC environment?"
335 elif WhereIs('cl.exe') is not None:
342 # lyx will be built to $build/build_dir so it is possible
343 # to build multiple build_dirs using the same source
344 # $mode can be debug or release
345 if env.has_key('build_dir') and env['build_dir'] is not None:
346 # create the directory if needed
347 if not os.path.isdir(env['build_dir']):
349 os.makedirs(env['build_dir'])
352 if not os.path.isdir(env['build_dir']):
353 print 'Can not create directory', env['build_dir']
355 env['BUILDDIR'] = env['build_dir']
357 # Determine the name of the build $mode
358 env['BUILDDIR'] = '#' + mode
360 # all built libraries will go to build_dir/libs
361 # (This is different from the make file approach)
362 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
363 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
366 # Here is a summary of variables defined in env
368 # 2. undefined options with a non-None default value
369 # 3. compiler commands and flags like CCFLAGS.
370 # MSGFMT used to process po files
371 # 4. Variables that will be used to replace variables in some_file.in
372 # src/support/Package.cpp.in:
373 # TOP_SRCDIR, LOCALEDIR, LYX_DIR, PROGRAM_SUFFIX
374 # lib/lyx2lyx/lyx2lyx_version.py.in
377 # full path name is used to build msvs project files
378 # and to replace TOP_SRCDIR in package.C
379 env['TOP_SRCDIR'] = Dir(top_src_dir).abspath
381 # determine share_dir etc
382 packaging_method = env.get('packaging')
383 if packaging_method == 'windows':
384 share_dir = 'Resources'
385 man_dir = 'Resources/man/man1'
386 locale_dir = 'Resources/locale'
388 share_dir = 'share/lyx'
389 locale_dir = 'share/locale'
390 if platform_name == 'cygwin':
391 man_dir = 'share/man/man1'
395 # program suffix: can be yes, or a string
396 if env.has_key('version_suffix'):
397 if env['version_suffix'] in true_strings:
398 program_suffix = package_version
399 elif env['version_suffix'] in false_strings:
402 program_suffix = env['version_suffix']
405 # used by Package.cpp.in
406 env['PROGRAM_SUFFIX'] = program_suffix
408 # whether or not add suffix to file and directory names
409 add_suffix = packaging_method != 'windows'
410 # LYX_DIR are different (used in Package.cpp.in)
412 env['LYX_DIR'] = Dir(os.path.join(prefix, share_dir + program_suffix)).abspath
414 env['LYX_DIR'] = Dir(os.path.join(prefix, share_dir)).abspath
415 # we need absolute path for package.C
416 env['LOCALEDIR'] = Dir(os.path.join(prefix, locale_dir)).abspath
419 #---------------------------------------------------------
420 # Setting building environment (Tools, compiler flags etc)
421 #---------------------------------------------------------
423 # Since Tool('mingw') will reset CCFLAGS etc, this should be
424 # done before getEnvVariable
425 if platform_name == 'win32':
431 env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
432 # fix a scons winres bug (there is a missing space between ${RCINCPREFIX} and ${SOURCE.dir}
434 env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
437 # we differentiate between hard-coded options and default options
438 # hard-coded options are required and will always be there
439 # default options can be replaced by enviromental variables or command line options
440 CCFLAGS_required = []
441 LINKFLAGS_required = []
444 # under windows, scons is confused by .C/.c and uses gcc instead of
445 # g++. I am forcing the use of g++ here. This is expected to change
446 # after lyx renames all .C files to .cpp
448 # save the old c compiler and CCFLAGS (used by libintl)
449 C_COMPILER = env.subst('$CC')
450 C_CCFLAGS = env.subst('$CCFLAGS').split()
451 # if we use ms vc, the commands are fine (cl.exe and link.exe)
453 # C4819: The file contains a character that cannot be represented
454 # in the current code page (number)
455 # C4996: foo was decleared deprecated
456 CCFLAGS_required.append('/EHsc')
458 CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MDd'])
459 # the flags are also needed in C mode (for intl lib)
460 C_CCFLAGS.extend(['/wd4819', '/wd4996', '/nologo', '/MDd'])
462 CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MD'])
463 C_CCFLAGS.extend(['/wd4819', '/wd4996', '/nologo', '/MD'])
465 if env.has_key('CXX') and env['CXX']:
466 env['CC'] = env.subst('$CXX')
467 env['LINK'] = env.subst('$CXX')
472 # for debug/release mode
473 if env.has_key('optimization') and env['optimization'] is not None:
474 # if user supplies optimization flags, use it anyway
475 CCFLAGS_required.extend(env['optimization'].split())
476 # and do not use default
477 set_default_optimization_flags = False
479 set_default_optimization_flags = True
483 CCFLAGS_required.append('/Zi')
484 LINKFLAGS_required.extend(['/debug', '/map'])
486 CCFLAGS_required.append('-g')
487 CCFLAGS_default.append('-O')
488 elif mode == 'release' and set_default_optimization_flags:
490 CCFLAGS_default.append('/O2')
492 CCFLAGS_default.append('-O2')
494 # msvc uses separate tools for profiling
495 if env.has_key('profiling') and env['profiling']:
497 print 'Visual C++ does not use profiling options'
499 CCFLAGS_required.append('-pg')
500 LINKFLAGS_required.append('-pg')
502 if env.has_key('warnings') and env['warnings']:
504 CCFLAGS_default.append('/W2')
506 # Note: autotools detect gxx version and pass -W for 3.x
507 # and -Wextra for other versions of gcc
508 CCFLAGS_default.append('-Wall')
510 # Now, set the variables as follows:
511 # 1. if command line option exists: replace default
512 # 2. then if s envronment variable exists: replace default
513 # 3. set variable to required + default
514 def setEnvVariable(env, name, required = None, default = None, split = True):
515 ''' env: environment to set variable
517 required: hardcoded options
518 default: default options that can be replaced by command line or
519 environment variables
520 split: whether or not split obtained variable like '-02 -g'
522 # 1. ARGUMENTS is already set to env[name], override default.
523 if ARGUMENTS.has_key(name):
524 # env[name] may be rewritten when building tools are reloaded
525 # if that is the case, commandline option will override it.
526 env[name] = ARGUMENTS[name]
528 # then use environment default
529 elif os.environ.has_key(name):
530 print "Acquiring variable %s from system environment: %s" % (name, os.environ[name])
531 default = os.environ[name]
533 default = default.split()
534 # the real value should be env[name] + default + required
537 if env.has_key(name):
538 value = str(env[name]).split()
539 if required is not None:
541 if default is not None:
545 if env.has_key(name):
546 value = str(env[name])
547 if required is not None:
548 value += " " + required
549 if default is not None:
550 value += " " + default
552 # print name, env[name]
554 setEnvVariable(env, 'DESTDIR', split=False)
555 setEnvVariable(env, 'CC')
556 setEnvVariable(env, 'LINK')
557 setEnvVariable(env, 'CPP')
558 setEnvVariable(env, 'CXX')
559 setEnvVariable(env, 'CXXCPP')
560 setEnvVariable(env, 'CCFLAGS', CCFLAGS_required, CCFLAGS_default)
561 setEnvVariable(env, 'CXXFLAGS')
562 setEnvVariable(env, 'CPPFLAGS')
563 setEnvVariable(env, 'LINKFLAGS', LINKFLAGS_required)
565 # if DESTDIR is not set...
566 if env.has_key('dest_dir'):
567 print "This option is obsolete. Please use DESTDIR instead."
568 env['DESTDIR'] = env['dest_dir']
571 # extra_inc_path and extra_lib_path
574 if env.has_key('extra_inc_path') and env['extra_inc_path']:
575 extra_inc_paths.append(env['extra_inc_path'])
576 if env.has_key('extra_lib_path') and env['extra_lib_path']:
577 env.AppendUnique(LIBPATH = [env['extra_lib_path']])
578 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
579 extra_inc_paths.append(env['extra_inc_path1'])
580 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
581 env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
582 if env.has_key('extra_bin_path') and env['extra_bin_path']:
583 # only the first one is needed (a scons bug?)
584 os.environ['PATH'] += os.pathsep + env['extra_bin_path']
585 env.PrependENVPath('PATH', env['extra_bin_path'])
586 # extra_inc_paths will be used later by intlenv etc
587 env.AppendUnique(CPPPATH = extra_inc_paths)
590 #----------------------------------------------------------
592 #----------------------------------------------------------
594 conf = Configure(env,
596 'CheckPkgConfig' : utils.checkPkgConfig,
597 'CheckPackage' : utils.checkPackage,
598 'CheckMkdirOneArg' : utils.checkMkdirOneArg,
599 'CheckSelectArgType' : utils.checkSelectArgType,
600 'CheckBoostLibraries' : utils.checkBoostLibraries,
601 'CheckCommand' : utils.checkCommand,
602 'CheckNSIS' : utils.checkNSIS,
603 'CheckCXXGlobalCstd' : utils.checkCXXGlobalCstd,
604 'CheckLC_MESSAGES' : utils.checkLC_MESSAGES,
605 'CheckIconvConst' : utils.checkIconvConst,
606 'CheckSizeOfWChar' : utils.checkSizeOfWChar,
607 'CheckDeclaration' : utils.checkDeclaration,
611 # When using msvc, windows.h is required
612 if use_vc and not conf.CheckCHeader('windows.h'):
613 print 'Windows.h is not found. Please install Windows Platform SDK.'
614 print 'Please check config.log for more information.'
617 # pkg-config? (if not, we use hard-coded options)
618 if conf.CheckPkgConfig('0.15.0'):
619 env['HAS_PKG_CONFIG'] = True
621 print 'pkg-config >= 0.1.50 is not found'
622 env['HAS_PKG_CONFIG'] = False
624 # zlib? This is required.
625 if (not use_vc and not conf.CheckLibWithHeader('z', 'zlib.h', 'C')) \
626 or (use_vc and not conf.CheckLibWithHeader('zdll', 'zlib.h', 'C')):
627 print 'Did not find zdll.lib or zlib.h, exiting!'
628 print 'Please check config.log for more information.'
630 if conf.CheckLib('iconv'):
631 env['ICONV_LIB'] = 'iconv'
632 elif conf.CheckLib('libiconv'):
633 env['ICONV_LIB'] = 'libiconv'
634 elif conf.CheckFunc('iconv_open'):
635 env['ICONV_LIB'] = None
637 print 'Did not find iconv or libiconv, exiting!'
638 print 'Please check config.log for more information.'
643 if conf.CheckLib('socket'):
644 socket_libs.append('socket')
645 # nsl is the network services library and provides a
646 # transport-level interface to networking services.
647 if conf.CheckLib('nsl'):
648 socket_libs.append('nsl')
650 # check available boost libs (since lyx1.4 does not use iostream)
652 for lib in ['signals', 'regex', 'filesystem', 'iostreams']:
653 if os.path.isdir(os.path.join(top_src_dir, 'boost', 'libs', lib)):
654 boost_libs.append(lib)
656 # check boost libraries
657 boost_opt = ARGUMENTS.get('boost', 'auto')
658 # check for system boost
659 lib_paths = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
660 inc_paths = env['CPPPATH'] + ['/usr/include', '/usr/local/include']
661 # default to $BUILDDIR/libs (use None since this path will be added anyway)
663 # here I assume that all libraries are in the same directory
664 if boost_opt == 'included':
665 boost_libraries = ['included_boost_%s' % x for x in boost_libs]
666 included_boost = True
667 env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
668 elif boost_opt == 'auto':
669 res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
670 # if not found, use local boost
672 boost_libraries = ['included_boost_%s' % x for x in boost_libs]
673 included_boost = True
674 env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
676 included_boost = False
677 (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
678 elif boost_opt == 'system':
679 res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
681 print "Can not find system boost libraries with version %s " % boost_version
682 print "Please supply a path through extra_lib_path and try again."
683 print "Or use boost=included to use included boost libraries."
686 included_boost = False
687 (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
690 if boost_libpath is not None:
691 env.AppendUnique(LIBPATH = [boost_libpath])
694 env['ENABLE_NLS'] = env['nls']
696 if not env['ENABLE_NLS']:
698 included_gettext = False
700 # check gettext libraries
701 gettext_opt = ARGUMENTS.get('gettext', 'auto')
702 # check for system gettext
704 if gettext_opt in ['auto', 'system']:
705 if conf.CheckFunc('gettext'):
706 included_gettext = False
709 elif conf.CheckLib('intl'):
710 included_gettext = False
714 if gettext_opt == 'system':
715 print "Can not find system gettext library"
716 print "Please supply a path through extra_lib_path and try again."
717 print "Or use gettext=included to use included gettext libraries."
719 # now, auto and succ = false, or gettext=included
721 # we do not need to set LIBPATH now.
722 included_gettext = True
723 intl_libs = ['included_intl']
727 # check for msgfmt command
728 env['MSGFMT'] = conf.CheckCommand('msgfmt')
729 env['MSGMERGE'] = conf.CheckCommand('msgmerge')
730 env['XGETTEXT'] = conf.CheckCommand('xgettext')
731 env['MSGUNIQ'] = conf.CheckCommand('msguniq')
733 # if under windows, check the nsis compiler
734 if platform_name == 'win32':
735 env['NSIS'] = conf.CheckNSIS()
737 # cygwin packaging requires the binaries to be stripped
738 if platform_name == 'cygwin':
739 env['STRIP'] = conf.CheckCommand('strip')
742 # Customized builders
744 # install customized builders
745 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
746 env['BUILDERS']['installTOC'] = Builder(action = utils.env_toc)
747 env['BUILDERS']['potfiles'] = Builder(action = utils.env_potfiles)
750 #----------------------------------------------------------
751 # Generating config.h
752 #----------------------------------------------------------
753 aspell_lib = 'aspell'
754 # assume that we use aspell, aspelld compiled for msvc
755 if platform_name == 'win32' and mode == 'debug' and use_vc:
756 aspell_lib = 'aspelld'
758 # check the existence of config.h
759 config_h = os.path.join(env.Dir('$BUILDDIR/common').path, 'config.h')
760 boost_config_h = os.path.join(env.Dir('$BUILDDIR/boost').path, 'config.h')
762 print "Creating %s..." % boost_config_h
764 utils.createConfigFile(conf,
765 config_file = boost_config_h,
766 config_pre = '''/* boost/config.h. Generated by SCons. */
771 * This file is part of LyX, the document processor.
772 * Licence details can be found in the file COPYING.
774 * This is the compilation configuration file for LyX.
775 * It was generated by scon.
776 * You might want to change some of the defaults if something goes wrong
777 * during the compilation.
780 #ifndef _BOOST_CONFIG_H
781 #define _BOOST_CONFIG_H
784 ('ostream', 'HAVE_OSTREAM', 'cxx'),
785 ('locale', 'HAVE_LOCALE', 'cxx'),
786 ('sstream', 'HAVE_SSTREAM', 'cxx'),
787 #('newapis.h', 'HAVE_NEWAPIS_H', 'c'),
790 (env.has_key('assertions') and env['assertions'],
792 'Define if you want assertions to be enabled in the code'
796 ('wchar_t', 'HAVE_WCHAR_T', None),
800 #if defined(HAVE_OSTREAM) && defined(HAVE_LOCALE) && defined(HAVE_SSTREAM)
801 # define USE_BOOST_FORMAT 1
803 # define USE_BOOST_FORMAT 0
806 #if !defined(ENABLE_ASSERTIONS)
807 # define BOOST_DISABLE_ASSERTS 1
809 #define BOOST_ENABLE_ASSERT_HANDLER 1
811 #define BOOST_DISABLE_THREADS 1
812 #define BOOST_NO_WSTRING 1
815 # define BOOST_POSIX 1
816 # define BOOST_POSIX_API 1
817 # define BOOST_POSIX_PATH 1
820 #define BOOST_ALL_NO_LIB 1
822 #if defined(HAVE_NEWAPIS_H)
823 # define WANT_GETFILEATTRIBUTESEX_WRAPPER 1
827 * the FreeBSD libc uses UCS4, but libstdc++ has no proper wchar_t
828 * support compiled in:
829 * http://gcc.gnu.org/onlinedocs/libstdc++/faq/index.html#3_9
830 * And we are not interested at all what libc
831 * does: What we need is a 32bit wide wchar_t, and a libstdc++ that
832 * has the needed wchar_t support and uses UCS4. Whether it
833 * implements this with the help of libc, or whether it has own code
834 * does not matter for us, because we don't use libc directly (Georg)
836 #if defined(HAVE_WCHAR_T) && SIZEOF_WCHAR_T == 4 && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
844 print "\nGenerating %s..." % config_h
846 # AIKSAURUS_H_LOCATION
847 if (conf.CheckCXXHeader("Aiksaurus.h")):
848 aik_location = '<Aiksaurus.h>'
849 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
850 aik_location = '<Aiksaurus/Aiksaurus.h>'
854 # determine headers to use
855 spell_opt = ARGUMENTS.get('spell', 'auto')
856 env['USE_ASPELL'] = False
857 env['USE_PSPELL'] = False
858 env['USE_ISPELL'] = False
859 if spell_opt in ['auto', 'aspell'] and conf.CheckLib(aspell_lib):
860 spell_engine = 'USE_ASPELL'
861 elif spell_opt in ['auto', 'pspell'] and conf.CheckLib('pspell'):
862 spell_engine = 'USE_PSPELL'
863 elif spell_opt in ['auto', 'ispell'] and conf.CheckLib('ispell'):
864 spell_engine = 'USE_ISPELL'
868 if spell_engine is not None:
869 env[spell_engine] = True
871 if spell_opt == 'auto':
872 print "Warning: Can not locate any spell checker"
873 elif spell_opt != 'no':
874 print "Warning: Can not locate specified spell checker:", spell_opt
875 print 'Please check config.log for more information.'
878 # check arg types of select function
879 (select_arg1, select_arg234, select_arg5) = conf.CheckSelectArgType()
881 # check the size of wchar_t
882 sizeof_wchar_t = conf.CheckSizeOfWChar()
884 if sizeof_wchar_t == 0:
885 print 'Error: Can not determine the size of wchar_t.'
886 print 'Please check config.log for more information.'
890 # fill in the version info
891 env['VERSION_INFO'] = '''Configuration
893 Special build flags: %s
895 C Compiler flags: %s %s
897 C++ Compiler LyX flags: %s
898 C++ Compiler flags: %s %s
900 Linker user flags: %s
902 Builing directory: %s
903 Local library directory: %s
906 include search path: %s
912 ''' % (platform_name,
913 env.subst('$CCFLAGS'), env.subst('$CC'),
914 env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
915 env.subst('$CXX'), env.subst('$CXXFLAGS'),
916 env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
917 env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
918 env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
919 str(env['LIBPATH']), str(boost_libraries),
921 frontend, packaging_method,
922 prefix, env['LYX_DIR'])
926 result = utils.createConfigFile(conf,
927 config_file = config_h,
928 config_pre = '''/* config.h. Generated by SCons. */
933 * This file is part of LyX, the document processor.
934 * Licence details can be found in the file COPYING.
936 * This is the compilation configuration file for LyX.
937 * It was generated by scon.
938 * You might want to change some of the defaults if something goes wrong
939 * during the compilation.
946 ('io.h', 'HAVE_IO_H', 'c'),
947 ('limits.h', 'HAVE_LIMITS_H', 'c'),
948 ('locale.h', 'HAVE_LOCALE_H', 'c'),
949 ('process.h', 'HAVE_PROCESS_H', 'c'),
950 ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
951 ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
952 ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
953 ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
954 ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
955 ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
956 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
957 ('utime.h', 'HAVE_UTIME_H', 'c'),
958 ('direct.h', 'HAVE_DIRECT_H', 'c'),
959 ('istream', 'HAVE_ISTREAM', 'cxx'),
960 ('ios', 'HAVE_IOS', 'cxx'),
963 ('open', 'HAVE_OPEN', None),
964 ('chmod', 'HAVE_CHMOD', None),
965 ('close', 'HAVE_CLOSE', None),
966 ('popen', 'HAVE_POPEN', None),
967 ('pclose', 'HAVE_PCLOSE', None),
968 ('_open', 'HAVE__OPEN', None),
969 ('_close', 'HAVE__CLOSE', None),
970 ('_popen', 'HAVE__POPEN', None),
971 ('_pclose', 'HAVE__PCLOSE', None),
972 ('getpid', 'HAVE_GETPID', None),
973 ('_getpid', 'HAVE__GETPID', None),
974 ('mkdir', 'HAVE_MKDIR', None),
975 ('_mkdir', 'HAVE__MKDIR', None),
976 ('mktemp', 'HAVE_MKTEMP', None),
977 ('mkstemp', 'HAVE_MKSTEMP', None),
978 ('strerror', 'HAVE_STRERROR', None),
979 ('getcwd', 'HAVE_GETCWD', None),
980 ('setenv', 'HAVE_SETENV', None),
981 ('putenv', 'HAVE_PUTENV', None),
982 ('fcntl', 'HAVE_FCNTL', None),
983 ('mkfifo', 'HAVE_MKFIFO', None),
986 ('mkstemp', 'HAVE_DECL_MKSTEMP', ['unistd.h', 'stdlib.h']),
989 ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
990 '#include <streambuf>\n#include <istream>'),
991 ('wchar_t', 'HAVE_WCHAR_T', None),
992 ('mode_t', 'HAVE_MODE_T', "#include <sys/types.h>"),
995 ('gdi32', 'HAVE_LIBGDI32'),
996 (('Aiksaurus', 'libAiksaurus'), 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB'),
999 (conf.CheckType('pid_t', includes='#include <sys/types.h>'),
1001 'Define is sys/types.h does not have pid_t',
1003 '#define pid_t int',
1005 (conf.CheckCXXGlobalCstd(),
1007 'Define if your C++ compiler puts C library functions in the global namespace'
1009 (conf.CheckMkdirOneArg(),
1010 'MKDIR_TAKES_ONE_ARG',
1011 'Define if mkdir takes only one argument.'
1013 (conf.CheckIconvConst(),
1015 'Define as const if the declaration of iconv() needs const.',
1016 '#define ICONV_CONST const',
1017 '#define ICONV_CONST',
1019 (conf.CheckLC_MESSAGES(),
1021 'Define if your <locale.h> file defines LC_MESSAGES.'
1023 (devel_version, 'DEVEL_VERSION', 'Whether or not a development version'),
1026 "Define to 1 if translation of program messages to the user's native anguage is requested.",
1028 (env['nls'] and not included_gettext,
1030 'Define to 1 if using system gettext library'
1032 (env.has_key('concept_checks') and env['concept_checks'],
1033 '_GLIBCXX_CONCEPT_CHECKS',
1034 'libstdc++ concept checking'
1036 (env.has_key('stdlib_debug') and env['stdlib_debug'],
1038 'libstdc++ debug mode'
1040 (env.has_key('stdlib_debug') and env['stdlib_debug'],
1041 '_GLIBCXX_DEBUG_PEDANTIC',
1042 'libstdc++ pedantic debug mode'
1044 (os.name != 'nt', 'BOOST_POSIX',
1045 'Indicates to boost < 1.34 which API to use (posix or windows).'
1047 (os.name != 'nt', 'BOOST_POSIX_API',
1048 'Indicates to boost 1.34 which API to use (posix or windows).'
1050 (os.name != 'nt', 'BOOST_POSIX_PATH',
1051 'Indicates to boost 1.34 which path style to use (posix or windows).'
1053 (spell_engine is not None, spell_engine,
1054 'Spell engine to use'
1056 # we need to know the byte order for unicode conversions
1057 (sys.byteorder == 'big', 'WORDS_BIGENDIAN',
1058 'Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX).'
1062 ('#define PACKAGE "%s%s"' % (package, program_suffix),
1064 ('#define PACKAGE_BUGREPORT "%s"' % package_bugreport,
1065 'Define to the address where bug reports for this package should be sent.'),
1066 ('#define PACKAGE_NAME "%s"' % package_name,
1067 'Define to the full name of this package.'),
1068 ('#define PACKAGE_STRING "%s"' % package_string,
1069 'Define to the full name and version of this package.'),
1070 ('#define PACKAGE_TARNAME "%s"' % package_tarname,
1071 'Define to the one symbol short name of this package.'),
1072 ('#define PACKAGE_VERSION "%s"' % package_version,
1073 'Define to the version of this package.'),
1074 ('#define VERSION_INFO "%s"' % env['VERSION_INFO'].replace('\n', '\\n'),
1075 'Full version info'),
1076 ('#define LYX_DATE "%s"' % lyx_date,
1078 ('#define BOOST_ALL_NO_LIB 1',
1079 'disable automatic linking of boost libraries.'),
1080 ('#define USE_%s_PACKAGING 1' % packaging_method.upper(),
1081 'Packaging method'),
1082 ('#define AIKSAURUS_H_LOCATION ' + aik_location,
1083 'Aiksaurus include file'),
1084 ('#define SELECT_TYPE_ARG1 %s' % select_arg1,
1085 "Define to the type of arg 1 for `select'."),
1086 ('#define SELECT_TYPE_ARG234 %s' % select_arg234,
1087 "Define to the type of arg 2, 3, 4 for `select'."),
1088 ('#define SELECT_TYPE_ARG5 %s' % select_arg5,
1089 "Define to the type of arg 5 for `select'."),
1090 ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1091 'Define to be the size of type wchar_t'),
1093 config_post = '''/************************************************************
1094 ** You should not need to change anything beyond this point */
1096 #ifndef HAVE_STRERROR
1097 #if defined(__cplusplus)
1100 char * strerror(int n);
1103 #include <../boost/config.h>
1109 # these keys are needed in env
1110 for key in ['USE_ASPELL', 'USE_PSPELL', 'USE_ISPELL', 'HAVE_FCNTL',\
1111 'HAVE_LIBGDI32', 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB']:
1112 # USE_ASPELL etc does not go through result
1113 if result.has_key(key):
1114 env[key] = result[key]
1117 # if nls=yes and gettext=included, create intl/config.h
1118 # intl/libintl.h etc
1120 intl_config_h = os.path.join(env.Dir('$BUILDDIR/intl').path, 'config.h')
1121 if env['nls'] and included_gettext:
1123 print "Creating %s..." % intl_config_h
1125 # create intl/config.h
1126 result = utils.createConfigFile(conf,
1127 config_file = intl_config_h,
1128 config_pre = '''/* intl/config.h. Generated by SCons. */
1133 * This file is part of LyX, the document processor.
1134 * Licence details can be found in the file COPYING.
1136 * This is the compilation configuration file for LyX.
1137 * It was generated by scon.
1138 * You might want to change some of the defaults if something goes wrong
1139 * during the compilation.
1146 ('unistd.h', 'HAVE_UNISTD_H', 'c'),
1147 ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
1148 ('string.h', 'HAVE_STRING_H', 'c'),
1149 ('strings.h', 'HAVE_STRINGS_H', 'c'),
1150 ('argz.h', 'HAVE_ARGZ_H', 'c'),
1151 ('limits.h', 'HAVE_LIMITS_H', 'c'),
1152 ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
1153 ('stddef.h', 'HAVE_STDDEF_H', 'c'),
1154 ('stdint.h', 'HAVE_STDINT_H', 'c'),
1155 ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c'),
1158 ('getcwd', 'HAVE_GETCWD', None),
1159 ('stpcpy', 'HAVE_STPCPY', None),
1160 ('strcasecmp', 'HAVE_STRCASECMP', None),
1161 ('strdup', 'HAVE_STRDUP', None),
1162 ('strtoul', 'HAVE_STRTOUL', None),
1163 ('alloca', 'HAVE_ALLOCA', None),
1164 ('__fsetlocking', 'HAVE___FSETLOCKING', None),
1165 ('mempcpy', 'HAVE_MEMPCPY', None),
1166 ('__argz_count', 'HAVE___ARGZ_COUNT', None),
1167 ('__argz_next', 'HAVE___ARGZ_NEXT', None),
1168 ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
1169 ('setlocale', 'HAVE_SETLOCALE', None),
1170 ('tsearch', 'HAVE_TSEARCH', None),
1171 ('getegid', 'HAVE_GETEGID', None),
1172 ('getgid', 'HAVE_GETGID', None),
1173 ('getuid', 'HAVE_GETUID', None),
1174 ('wcslen', 'HAVE_WCSLEN', None),
1175 ('asprintf', 'HAVE_ASPRINTF', None),
1176 ('wprintf', 'HAVE_WPRINTF', None),
1177 ('snprintf', 'HAVE_SNPRINTF', None),
1178 ('printf', 'HAVE_POSIX_PRINTF', None),
1179 ('fcntl', 'HAVE_FCNTL', None),
1182 ('intmax_t', 'HAVE_INTMAX_T', None),
1183 ('long double', 'HAVE_LONG_DOUBLE', None),
1184 ('long long', 'HAVE_LONG_LONG', None),
1185 ('wchar_t', 'HAVE_WCHAR_T', None),
1186 ('wint_t', 'HAVE_WINT_T', None),
1187 ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
1188 ('uintmax_t', 'HAVE_STDINT_H_WITH_UINTMAX', '#include <stdint.h>'),
1194 (conf.CheckLC_MESSAGES(),
1196 'Define if your <locale.h> file defines LC_MESSAGES.'
1198 (conf.CheckIconvConst(),
1200 'Define as const if the declaration of iconv() needs const.',
1201 '#define ICONV_CONST const',
1202 '#define ICONV_CONST',
1204 (conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
1205 conf.CheckType('intmax_t', includes='#include <inttypes.h>'),
1207 "Define to 1 if you have the `intmax_t' type."
1209 (env.has_key('nls') and env['nls'],
1211 "Define to 1 if translation of program messages to the user's native anguage is requested.",
1215 ('#define HAVE_ICONV 1', 'Define if iconv or libiconv is found'),
1216 ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1217 'Define to be the size of type wchar_t'),
1219 config_post = '#endif'
1222 # these keys are needed in env
1223 for key in ['HAVE_ASPRINTF', 'HAVE_WPRINTF', 'HAVE_SNPRINTF', \
1224 'HAVE_POSIX_PRINTF', 'HAVE_LIBC']:
1225 # USE_ASPELL etc does not go through result
1226 if result.has_key(key):
1227 env[key] = result[key]
1230 # this looks misplaced, but intl/libintl.h is needed by src/message.C
1231 if env['nls'] and included_gettext:
1232 # libgnuintl.h.in => libintl.h
1233 env.Depends('$TOP_SRCDIR/intl/libintl.h', '$BUILDDIR/intl/config.h')
1234 env.substFile('$BUILDDIR/intl/libintl.h', '$TOP_SRCDIR/intl/libgnuintl.h.in')
1235 env.Command('$BUILDDIR/intl/libgnuintl.h', '$BUILDDIR/intl/libintl.h',
1236 [Copy('$TARGET', '$SOURCE')])
1239 # Finish auto-configuration
1242 #----------------------------------------------------------
1243 # Now set up our build process accordingly
1244 #----------------------------------------------------------
1246 if env['ICONV_LIB'] is None:
1249 system_libs = [env['ICONV_LIB']]
1250 if platform_name in ['win32', 'cygwin']:
1251 # the final link step needs stdc++ to succeed under mingw
1252 # FIXME: shouldn't g++ automatically link to stdc++?
1254 system_libs += ['ole32', 'shlwapi', 'shell32', 'advapi32', 'zdll']
1256 system_libs += ['shlwapi', 'stdc++', 'z']
1257 elif platform_name == 'cygwin' and env['X11']:
1258 system_libs += ['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr',
1259 'Xcursor', 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE',
1260 'resolv', 'pthread', 'z']
1262 system_libs += ['z']
1265 ('HAVE_LIBGDI32', 'gdi32'),
1266 ('HAVE_LIBAIKSAURUS', env['AIKSAURUS_LIB']),
1267 ('USE_ASPELL', aspell_lib),
1268 ('USE_ISPELL', 'ispell'),
1269 ('USE_PSPELL', 'pspell'),
1274 system_libs.append(lib[1])
1277 # Build parameters CPPPATH etc
1280 env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1283 # boost: for boost header files
1284 # BUILDDIR/common: for config.h
1285 # TOP_SRCDIR/src: for support/* etc
1287 env['CPPPATH'] += ['$BUILDDIR/common', '$TOP_SRCDIR/src']
1289 # Separating boost directories from CPPPATH stops scons from building
1290 # the dependency tree for boost header files, and effectively reduce
1291 # the null build time of lyx from 29s to 16s. Since lyx may tweak local
1292 # boost headers, the following is not 100% safe.
1293 # env.AppendUnique(CPPPATH = ['$BOOST_INC_PATH'])
1294 env.PrependUnique(CCFLAGS = ['$INCPREFIX$BOOST_INC_PATH'])
1296 # for intl/config.h, intl/libintl.h and intl/libgnuintl.h
1297 if env['nls'] and included_gettext:
1298 env['CPPPATH'].append('$BUILDDIR/intl')
1302 # A Link script for cygwin see
1303 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1304 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1307 if platform_name == 'cygwin':
1308 ld_script_path = '/tmp'
1309 ld_script = utils.installCygwinLDScript(ld_script_path)
1310 env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1311 '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1314 #---------------------------------------------------------
1315 # Frontend related variables (QTDIR etc)
1316 #---------------------------------------------------------
1319 # create a separate environment so that other files do not have
1320 # to be built with all the include directories etc
1322 if frontend == 'qt4':
1323 frontend_env = env.Copy()
1325 # handle qt related user specified paths
1326 # set environment so that moc etc can be found even if its path is not set properly
1327 if frontend_env.has_key('qt_dir') and frontend_env['qt_dir']:
1328 frontend_env['QTDIR'] = frontend_env['qt_dir']
1329 if os.path.isdir(os.path.join(frontend_env['qt_dir'], 'bin')):
1330 os.environ['PATH'] += os.pathsep + os.path.join(frontend_env['qt_dir'], 'bin')
1331 frontend_env.PrependENVPath('PATH', os.path.join(frontend_env['qt_dir'], 'bin'))
1332 if os.path.isdir(os.path.join(frontend_env['qt_dir'], 'lib')):
1333 frontend_env.PrependENVPath('PKG_CONFIG_PATH', os.path.join(frontend_env['qt_dir'], 'lib'))
1335 # if separate qt_lib_path is given
1336 if frontend_env.has_key('qt_lib_path') and frontend_env['qt_lib_path']:
1337 qt_lib_path = frontend_env.subst('$qt_lib_path')
1338 frontend_env.AppendUnique(LIBPATH = [qt_lib_path])
1339 frontend_env.PrependENVPath('PKG_CONFIG_PATH', qt_lib_path)
1343 # if separate qt_inc_path is given
1344 if frontend_env.has_key('qt_inc_path') and frontend_env['qt_inc_path']:
1345 qt_inc_path = frontend_env['qt_inc_path']
1349 # local qt4 toolset from
1350 # http://www.iua.upf.es/~dgarcia/Codders/sconstools.html
1352 # NOTE: I have to patch qt4.py since it does not automatically
1353 # process .C file!!! (add to cxx_suffixes )
1355 frontend_env.Tool('qt4', [scons_dir])
1356 frontend_env['QT_AUTOSCAN'] = 0
1357 frontend_env['QT4_AUTOSCAN'] = 0
1358 frontend_env['QT4_UICDECLFLAGS'] = '-tr lyx::qt_'
1360 if qt_lib_path is None:
1361 qt_lib_path = os.path.join(frontend_env.subst('$QTDIR'), 'lib')
1362 if qt_inc_path is None:
1363 qt_inc_path = os.path.join(frontend_env.subst('$QTDIR'), 'include')
1366 conf = Configure(frontend_env,
1368 'CheckPackage' : utils.checkPackage,
1369 'CheckCommand' : utils.checkCommand,
1374 # first: try pkg_config
1375 if frontend_env['HAS_PKG_CONFIG']:
1376 succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
1377 # FIXME: use pkg_config information?
1378 #frontend_env['QT4_PKG_CONFIG'] = succ
1379 # second: try to link to it
1381 # Under linux, I can test the following perfectly
1382 # Under windows, lib names need to passed as libXXX4.a ...
1383 if platform_name == 'win32':
1384 succ = conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
1386 succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
1387 # still can not find it
1389 print 'Did not find qt libraries, exiting!'
1390 print 'Please check config.log for more information.'
1393 # Now, determine the correct suffix:
1394 qt_libs = ['QtCore', 'QtGui']
1395 if platform_name == 'win32':
1396 if mode == 'debug' and use_vc and \
1397 conf.CheckLibWithHeader('QtCored4', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
1398 qt_lib_suffix = 'd4'
1399 use_qt_debug_libs = True
1402 use_qt_debug_libs = False
1404 if mode == 'debug' and conf.CheckLibWithHeader('QtCore_debug', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
1405 qt_lib_suffix = '_debug'
1406 use_qt_debug_libs = True
1409 use_qt_debug_libs = False
1410 frontend_env.EnableQt4Modules(qt_libs, debug = (mode == 'debug' and use_qt_debug_libs))
1411 frontend_libs = [x + qt_lib_suffix for x in qt_libs]
1412 qtcore_lib = ['QtCore' + qt_lib_suffix]
1414 # check uic and moc commands for qt frontends
1415 if conf.CheckCommand('uic') == None or conf.CheckCommand('moc') == None:
1416 print 'uic or moc command is not found for frontend', frontend
1419 # now, if msvc2005 is used, we will need to embed lyx.exe.manifest to lyx.exe
1420 # NOTE: previously, lyx.exe had to be linked to some qt manifest to work.
1421 # For some unknown changes in msvc or qt, this is no longer needed.
1423 frontend_env['LINKCOM'] = [frontend_env['LINKCOM'], \
1424 'mt.exe /MANIFEST %s /outputresource:$TARGET;1' % \
1425 env.File('$BUILDDIR/lyx.exe.manifest').path]
1427 frontend_env = conf.Finish()
1434 print env['VERSION_INFO']
1437 # Mingw command line may be too short for our link usage,
1438 # Here we use a trick from scons wiki
1439 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1441 # I also would like to add logging (commands only) capacity to the
1443 logfile = env.get('logfile', default_log_file)
1444 if logfile != '' or platform_name == 'win32':
1446 utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1447 info = '''# This is a log of commands used by scons to build lyx
1451 ''' % (time.asctime(), ' '.join(sys.argv),
1452 env['VERSION_INFO'].replace('\n','\n# ')) )
1457 # -h will print out help info
1458 Help(opts.GenerateHelpText(env))
1462 #----------------------------------------------------------
1464 #----------------------------------------------------------
1465 # this has been the source of problems on some platforms...
1466 # I find that I need to supply it with full path name
1467 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1468 # this usage needs further investigation.
1469 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1471 print "Building all targets recursively"
1473 if env.has_key('rebuild'):
1474 rebuild_targets = env['rebuild'].split(',')
1475 if 'none' in rebuild_targets or 'no' in rebuild_targets:
1476 rebuild_targets = []
1477 elif 'all' in rebuild_targets or 'yes' in rebuild_targets:
1478 # None: let scons decide which components to build
1479 # Forcing all components to be rebuilt is in theory not necessary
1480 rebuild_targets = None
1482 rebuild_targets = None
1484 def libExists(libname):
1485 ''' Check whether or not lib $LOCALLIBNAME/libname already exists'''
1486 return os.path.isfile(File(env.subst('$LOCALLIBPATH/${LIBPREFIX}%s$LIBSUFFIX'%libname)).abspath)
1488 def appExists(apppath, appname):
1489 ''' Check whether or not application already exists'''
1490 return os.path.isfile(File(env.subst('$BUILDDIR/common/%s/${PROGPREFIX}%s$PROGSUFFIX' % (apppath, appname))).abspath)
1492 targets = BUILD_TARGETS
1493 build_install = 'install' in targets or 'installer' in targets
1494 build_installer = 'installer' in targets
1495 # msvc need to pass full target name, so I have to look for path/lyx etc
1496 build_lyx = build_installer or targets == [] or True in ['lyx' in x for x in targets] \
1497 or build_install or 'all' in targets
1498 build_boost = (included_boost and not libExists('boost_regex')) or 'boost' in targets
1499 build_intl = (included_gettext and not libExists('included_intl')) or 'intl' in targets
1500 build_support = build_lyx or True in [x in targets for x in ['support', 'client', 'tex2lyx']]
1501 build_mathed = build_lyx or 'mathed' in targets
1502 build_insets = build_lyx or 'insets' in targets
1503 build_frontends = build_lyx or 'frontends' in targets
1504 build_graphics = build_lyx or 'graphics' in targets
1505 build_controllers = build_lyx or 'controllers' in targets
1506 build_client = True in ['client' in x for x in targets] \
1507 or build_install or 'all' in targets or build_installer
1508 build_tex2lyx = True in ['tex2lyx' in x for x in targets] \
1509 or build_install or 'all' in targets or build_installer
1510 build_lyxbase = build_lyx or 'lyxbase' in targets
1511 update_po = 'update_po' in targets
1512 update_manifest = 'update_manifest' in targets
1513 build_po = 'po' in targets or build_install or 'all' in targets
1514 build_qt4 = (build_lyx and frontend == 'qt4') or 'qt4' in targets
1515 build_msvs_projects = use_vc and 'msvs_projects' in targets
1518 # now, if rebuild_targets is specified, do not rebuild some targets
1519 if rebuild_targets is not None:
1521 def ifBuildLib(name, libname, old_value):
1522 # explicitly asked to rebuild
1523 if name in rebuild_targets:
1525 # else if not rebuild, and if the library already exists
1526 elif libExists(libname):
1528 # do not change the original value
1531 build_boost = ifBuildLib('boost', 'included_boost_filesystem', build_boost)
1532 build_intl = ifBuildLib('intl', 'included_intl', build_intl)
1533 build_support = ifBuildLib('support', 'support', build_support)
1534 build_mathed = ifBuildLib('mathed', 'mathed', build_mathed)
1535 build_insets = ifBuildLib('insets', 'insets', build_insets)
1536 build_frontends = ifBuildLib('frontends', 'frontends', build_frontends)
1537 build_graphics = ifBuildLib('graphics', 'graphics', build_graphics)
1538 build_controllers = ifBuildLib('controllers', 'controllers', build_controllers)
1539 build_lyxbase = ifBuildLib('lyxbase', 'lyxbase_pre', build_lyxbase)
1540 build_qt4 = ifBuildLib('qt4', 'qt4', build_qt4)
1542 def ifBuildApp(name, appname, old_value):
1543 # explicitly asked to rebuild
1544 if name in rebuild_targets:
1546 # else if not rebuild, and if the library already exists
1547 elif appExists(name, appname):
1549 # do not change the original value
1552 build_tex2lyx = ifBuildApp('tex2lyx', 'tex2lyx', build_tex2lyx)
1553 build_client = ifBuildApp('client', 'lyxclient', build_client)
1555 # sync frontend and frontend (?)
1565 env.BuildDir('$BUILDDIR/boost', '$TOP_SRCDIR/boost/libs', duplicate = 0)
1567 boostenv = env.Copy()
1569 # boost use its own config.h
1570 boostenv['CPPPATH'] = ['$BUILDDIR/boost'] + extra_inc_paths
1571 boostenv['CCFLAGS'] = ['$INCPREFIX$TOP_SRCDIR/boost']
1572 boostenv.AppendUnique(CCFLAGS = ['-DBOOST_USER_CONFIG="<config.h>"'])
1574 for lib in boost_libs:
1575 print 'Processing files in boost/libs/%s/src...' % lib
1576 boostlib = boostenv.StaticLibrary(
1577 target = '$LOCALLIBPATH/included_boost_%s' % lib,
1578 source = ['$BUILDDIR/boost/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)]
1580 Alias('boost', boostlib)
1587 intlenv = env.Copy()
1589 print "Processing files in intl..."
1591 env.BuildDir('$BUILDDIR/intl', '$TOP_SRCDIR/intl', duplicate = 0)
1593 # we need the original C compiler for these files
1594 intlenv['CC'] = C_COMPILER
1595 intlenv['CCFLAGS'] = C_CCFLAGS
1597 intlenv.Append(CCFLAGS=['/Dinline#', '/D__attribute__(x)#', '/Duintmax_t=UINT_MAX'])
1598 # intl does not use global config.h
1599 intlenv['CPPPATH'] = ['$BUILDDIR/intl'] + extra_inc_paths
1601 intlenv.Append(CCFLAGS = [
1602 r'-DLOCALEDIR=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1603 r'-DLOCALE_ALIAS_PATH=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1604 r'-DLIBDIR=\"' + env['TOP_SRCDIR'].replace('\\', '\\\\') + r'/lib\"',
1606 '-DENABLE_RELOCATABLE=1',
1608 r'-DINSTALLDIR=\"' + prefix.replace('\\', '\\\\') + r'/lib\"',
1610 '-Dset_relocation_prefix=libintl_set_relocation_prefix',
1611 '-Drelocate=libintl_relocate',
1612 '-DDEPENDS_ON_LIBICONV=1',
1617 intl = intlenv.StaticLibrary(
1618 target = '$LOCALLIBPATH/included_intl',
1620 source = ['$BUILDDIR/intl/%s' % x for x in intl_files]
1626 # Now, src code under src/
1628 env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1635 print "Processing files in src/support..."
1637 frontend_env.Depends('$BUILDDIR/common/support/Package.cpp', '$BUILDDIR/common/config.h')
1638 Package_cpp = env.substFile('$BUILDDIR/common/support/Package.cpp', '$TOP_SRCDIR/src/support/Package.cpp.in')
1640 support = frontend_env.StaticLibrary(
1641 target = '$LOCALLIBPATH/support',
1642 source = ['$BUILDDIR/common/support/%s' % x for x in src_support_files] + Package_cpp + \
1643 ['$BUILDDIR/common/support/minizip/%s' % x for x in src_support_minizip_files] + \
1644 ['$BUILDDIR/common/support/minizip/%s' % x for x in src_support_minizip_windows_files if platform_name == 'win32'],
1648 '-DQT_CLEAN_NAMESPACE',
1653 CPPPATH = ['$CPPPATH', '$TOP_SRCDIR/src/support/minizip']
1655 Alias('support', support)
1662 print "Processing files in src/mathed..."
1664 mathed = env.StaticLibrary(
1665 target = '$LOCALLIBPATH/mathed',
1666 source = ['$BUILDDIR/common/mathed/%s' % x for x in src_mathed_files]
1668 Alias('mathed', mathed)
1675 print "Processing files in src/insets..."
1677 insets = env.StaticLibrary(
1678 target = '$LOCALLIBPATH/insets',
1679 source = ['$BUILDDIR/common/insets/%s' % x for x in src_insets_files]
1681 Alias('insets', insets)
1688 print "Processing files in src/frontends..."
1690 frontends = env.StaticLibrary(
1691 target = '$LOCALLIBPATH/frontends',
1692 source = ['$BUILDDIR/common/frontends/%s' % x for x in src_frontends_files]
1694 Alias('frontends', frontends)
1701 print "Processing files in src/graphics..."
1703 graphics = env.StaticLibrary(
1704 target = '$LOCALLIBPATH/graphics',
1705 source = ['$BUILDDIR/common/graphics/%s' % x for x in src_graphics_files]
1707 Alias('graphics', graphics)
1710 if build_controllers:
1712 # src/frontends/controllers
1714 print "Processing files in src/frontends/controllers..."
1716 controllers = env.StaticLibrary(
1717 target = '$LOCALLIBPATH/controllers',
1718 source = ['$BUILDDIR/common/frontends/controllers/%s' % x for x in src_frontends_controllers_files]
1720 Alias('controllers', controllers)
1726 env.BuildDir('$BUILDDIR/$frontend', '$TOP_SRCDIR/src/frontend/$frontend', duplicate = 0)
1728 print "Processing files in src/frontends/qt4..."
1729 frontend_env['QT4_MOCHPREFIX'] = ''
1730 frontend_env['QT4_MOCHSUFFIX'] = '_moc.cpp'
1732 # tells scons how to get these moced files, although not all moced files are needed
1733 # (or are actually generated).
1734 qt4_moced_files = [frontend_env.Moc4('$BUILDDIR/common/frontends/qt4/%s' % x)
1735 for x in src_frontends_qt4_header_files ]
1736 resources = [frontend_env.Uic4('$BUILDDIR/common/frontends/qt4/ui/%s' % x.split('.')[0])
1737 for x in src_frontends_qt4_ui_files]
1740 # moc qt4_moc_files, the moced files are included in the original files
1742 qt4 = frontend_env.StaticLibrary(
1743 target = '$LOCALLIBPATH/qt4',
1744 source = ['$BUILDDIR/common/frontends/qt4/%s' % x for x in src_frontends_qt4_files],
1748 '$BUILDDIR/common/images',
1749 '$BUILDDIR/common/frontends',
1750 '$BUILDDIR/common/frontends/qt4',
1751 '$BUILDDIR/common/frontends/qt4/ui',
1752 '$BUILDDIR/common/frontends/controllers'
1757 '-DQT_CLEAN_NAMESPACE',
1770 frontend_env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1772 print "Processing files in src/client..."
1774 if env['HAVE_FCNTL']:
1775 client = frontend_env.Program(
1776 target = '$BUILDDIR/common/client/lyxclient',
1777 LIBS = ['support'] + intl_libs + system_libs +
1778 socket_libs + boost_libraries + qtcore_lib,
1779 source = ['$BUILDDIR/common/client/%s' % x for x in src_client_files] + \
1780 utils.createResFromIcon(frontend_env, 'lyx_32x32.ico', '$LOCALLIBPATH/client.rc')
1782 Alias('client', frontend_env.Command(os.path.join('$BUILDDIR', os.path.split(str(client[0]))[1]),
1783 client, [Copy('$TARGET', '$SOURCE')]))
1786 Alias('client', client)
1788 if env['HAVE_FCNTL']:
1789 # define client even if lyxclient is not built with rebuild=no
1790 client = [env.subst('$BUILDDIR/common/client/${PROGPREFIX}lyxclient$PROGSUFFIX')]
1799 print "Processing files in src/tex2lyx..."
1802 for file in src_tex2lyx_copied_files + src_tex2lyx_copied_header_files:
1803 frontend_env.Command('$BUILDDIR/common/tex2lyx/'+file, '$TOP_SRCDIR/src/'+file,
1804 [Copy('$TARGET', '$SOURCE')])
1806 tex2lyx = frontend_env.Program(
1807 target = '$BUILDDIR/common/tex2lyx/tex2lyx',
1808 LIBS = ['support'] + boost_libraries + intl_libs + system_libs + qtcore_lib,
1809 source = ['$BUILDDIR/common/tex2lyx/%s' % x for x in src_tex2lyx_files + src_tex2lyx_copied_files] + \
1810 utils.createResFromIcon(frontend_env, 'lyx_32x32.ico', '$LOCALLIBPATH/tex2lyx.rc'),
1811 CPPPATH = ['$BUILDDIR/common/tex2lyx', '$CPPPATH'],
1812 LIBPATH = ['#$LOCALLIBPATH', '$LIBPATH'],
1814 Alias('tex2lyx', frontend_env.Command(os.path.join('$BUILDDIR', os.path.split(str(tex2lyx[0]))[1]),
1815 tex2lyx, [Copy('$TARGET', '$SOURCE')]))
1816 Alias('tex2lyx', tex2lyx)
1818 # define tex2lyx even if tex2lyx is not built with rebuild=no
1819 tex2lyx = [frontend_env.subst('$BUILDDIR/common/tex2lyx/${PROGPREFIX}tex2lyx$PROGSUFFIX')]
1826 print "Processing files in src..."
1828 if env.has_key('USE_ASPELL') and env['USE_ASPELL']:
1829 src_post_files.append('ASpell.cpp')
1830 elif env.has_key('USE_PSPELL') and env['USE_PSPELL']:
1831 src_post_files.append('PSpell.cpp')
1832 elif env.has_key('USE_ISPELL') and env['USE_ISPELL']:
1833 src_post_files.append('ISpell.cpp')
1835 # msvc requires at least one source file with main()
1836 # so I exclude main.cpp from lyxbase
1837 lyxbase_pre = env.StaticLibrary(
1838 target = '$LOCALLIBPATH/lyxbase_pre',
1839 source = ['$BUILDDIR/common/%s' % x for x in src_pre_files]
1841 lyxbase_post = env.StaticLibrary(
1842 target = '$LOCALLIBPATH/lyxbase_post',
1843 source = ["$BUILDDIR/common/%s" % x for x in src_post_files]
1845 Alias('lyxbase', lyxbase_pre)
1846 Alias('lyxbase', lyxbase_post)
1851 # Build lyx with given frontend
1853 lyx = frontend_env.Program(
1854 target = '$BUILDDIR/lyx',
1855 source = ['$BUILDDIR/common/main.cpp'] + \
1856 utils.createResFromIcon(frontend_env, 'lyx_32x32.ico', '$LOCALLIBPATH/lyx.rc'),
1876 # define lyx even if lyx is not built with rebuild=no
1877 lyx = [frontend_env.subst('$BUILDDIR/${PROGPREFIX}lyx$PROGSUFFIX')]
1880 if build_msvs_projects:
1881 def build_project(target, full_target = None,
1882 src = [], inc = [], res = [], rebuildTargetOnly = True):
1883 ''' build mavs project files
1884 target: alias (correspond to directory name)
1885 full_target: full path/filename of the target
1889 rebuildTargetOnly: whether or not only rebuild this target
1891 For non-debug-able targets like static libraries, target (alias) is
1892 enough to build the target. For executable targets, msvs need to know
1893 the full path to start debug them.
1895 if rebuildTargetOnly:
1896 cmds = 'rebuild='+target
1899 if full_target is None:
1900 build_target = target
1902 build_target = full_target
1904 proj = env.MSVSProject(
1905 target = target + env['MSVSPROJECTSUFFIX'],
1906 # this allows easy access to header files (along with source)
1907 srcs = [env.subst(x) for x in src + inc],
1908 incs = [env.subst('$TOP_SRCDIR/src/config.h')],
1909 localincs = [env.subst(x) for x in inc],
1910 resources = [env.subst(x) for x in res],
1911 buildtarget = build_target,
1915 Alias('msvs_projects', proj)
1917 build_project('client', src = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_files],
1918 inc = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_header_files],
1919 rebuildTargetOnly = False,
1920 full_target = File(env.subst('$BUILDDIR/common/client/lyxclient$PROGSUFFIX')).abspath)
1922 build_project('tex2lyx', src = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_files],
1923 inc = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_header_files],
1924 rebuildTargetOnly = False,
1925 full_target = File(env.subst('$BUILDDIR/common/tex2lyx/tex2lyx$PROGSUFFIX')).abspath)
1927 build_project('lyx',
1928 src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files + ['version.cpp']] + \
1929 ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files + ['Package.cpp'] ] + \
1930 ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_files] + \
1931 ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files] + \
1932 ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files] + \
1933 ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files] + \
1934 ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_files] + \
1935 ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files + src_frontends_qt4_moc_files],
1936 inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files] + \
1937 ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files] + \
1938 ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_header_files] + \
1939 ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files] + \
1940 ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files] + \
1941 ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files] + \
1942 ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files] + \
1943 ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1944 res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files],
1945 rebuildTargetOnly = False,
1946 full_target = File(env.subst('$BUILDDIR/lyx$PROGSUFFIX')).abspath)
1951 # update scons_manifest.py
1953 # When you run 'scons update_manifest', it tells you which files are missing
1954 # and which files are not in the source tree. It also generates a
1955 # scons_manifest.py.new file with all the missing files added to
1956 # XXX_extra_files. It will *not* change other sections of existing
1959 print 'Validating development/scons/scons_manifest.py...'
1961 manifest = open(env.File('$TOP_SRCDIR/development/scons/scons_manifest.py.new').abspath, 'w')
1962 print >> manifest, 'from SCons.Util import Split\n'
1964 ignore_dirs = ['boost/boost', 'm4', 'development',
1965 utils.relativePath(env.Dir('$BUILDDIR').abspath, env.Dir('$TOP_SRCDIR').abspath)]
1966 ignore_types = ['.svn', '.deps', '.cache', '.tmp', '.bak', '.gmo', '.pot',
1967 '.pyc', '.pyo', '.o', '_moc.cpp', 'Makefile.in', 'config.h.in',
1968 'LaTeXConfig.lyx', 'version.cpp', 'Package.cpp']
1969 ext_types = ['_header_files', '_files', '_pre_files', '_post_files', '_moc_files', '_inc_files',
1970 '_copied_files', '_copied_header_files', '_extra_header_files', '_extra_src_files', '_extra_files']
1971 for root,path,files in os.walk(env.Dir('$TOP_SRCDIR').abspath):
1972 if os.path.split(root)[-1][0] == '.' \
1973 or True in [x in root for x in ignore_types] \
1974 or True in [utils.isSubDir(root, x) for x in ignore_dirs]:
1976 dirname = utils.relativePath(root, env.subst('$TOP_SRCDIR')).replace(os.sep, '_')
1979 # files in the current manifest.py
1981 for ext in ext_types:
1982 if 'copied' not in ext and dirname + ext in locals():
1983 cur_files.extend(eval(dirname + ext))
1985 # compare files with cur_files
1986 files = [x for x in files if x[0] != '.' and True not in [len(x) >= len(y) and x[-len(y):] == y for y in ignore_types]]
1988 if cur_files != files:
1991 if f not in cur_files:
1997 if len(missing) > 0:
1998 print 'Missing: %s in %s' % (', '.join(missing), root)
1999 if dirname + '_extra_files' in locals():
2000 exec('%s_extra_files.extend(missing)' % dirname)
2002 exec('%s_extra_files = missing' % dirname)
2004 print 'Extra: %s in %s' % (', '.join(extra), root)
2005 # write to a new manifest file
2006 for ext in ext_types:
2007 if dirname + ext in locals():
2008 exec('%s%s.sort()' % (dirname, ext))
2009 print >> manifest, "%s%s = Split('''\n " % (dirname, ext),
2010 print >> manifest, eval(r"'\n '.join(%s%s)" % (dirname, ext))
2011 print >> manifest, "''')\n\n"
2013 Alias('update_manifest', None)
2020 print 'Updating po/*.po files...'
2022 # whether or not update po files
2023 if not env['XGETTEXT'] or not env['MSGMERGE'] or not env['MSGUNIQ']:
2024 print 'xgettext or msgmerge does not exist. Cannot merge po files'
2026 # rebuild POTFILES.in
2027 POTFILES_in = env.potfiles('$TOP_SRCDIR/po/POTFILES.in',
2028 ['$TOP_SRCDIR/src/%s' % x for x in src_header_files + src_pre_files + src_post_files + \
2029 src_extra_src_files] + \
2030 ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files + src_support_files + \
2031 src_support_extra_header_files + src_support_extra_src_files] + \
2032 ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_header_files + src_mathed_files] + \
2033 ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files + src_insets_files] + \
2034 ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files + src_frontends_files] + \
2035 ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files + src_graphics_files] + \
2036 ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files + src_frontends_controllers_files] + \
2037 ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files + src_frontends_qt4_files + src_frontends_qt4_moc_files] + \
2038 ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_header_files + src_client_files ] + \
2039 ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_header_files + src_tex2lyx_files ]
2041 Alias('update_po', POTFILES_in)
2042 # build language_l10n.pot, ui_l10n.pot, layouts_l10n.pot, qt4_l10n.pot, external_l10n
2043 # and combine them to lyx.po
2044 env['LYX_POT'] = 'python $TOP_SRCDIR/po/lyx_pot.py'
2045 lyx_po = env.Command('$BUILDDIR/po/lyx.po',
2046 env.Command('$BUILDDIR/po/all.po',
2047 [env.Command('$BUILDDIR/po/qt4_l10n.pot',
2048 ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files],
2049 '$LYX_POT -b $TOP_SRCDIR -t qt4 -o $TARGET $SOURCES'),
2050 env.Command('$BUILDDIR/po/layouts_l10n.pot',
2051 ['$TOP_SRCDIR/lib/layouts/%s' % x for x in lib_layouts_files + lib_layouts_inc_files],
2052 '$LYX_POT -b $TOP_SRCDIR -t layouts -o $TARGET $SOURCES'),
2053 env.Command('$BUILDDIR/po/languages_l10n.pot', '$TOP_SRCDIR/lib/languages',
2054 '$LYX_POT -b $TOP_SRCDIR -t languages -o $TARGET $SOURCES'),
2055 env.Command('$BUILDDIR/po/ui_l10n.pot',
2056 ['$TOP_SRCDIR/lib/ui/%s' % x for x in lib_ui_files],
2057 '$LYX_POT -b $TOP_SRCDIR -t ui -o $TARGET $SOURCES'),
2058 env.Command('$BUILDDIR/po/external_l10n.pot', '$TOP_SRCDIR/lib/external_templates',
2059 '$LYX_POT -b $TOP_SRCDIR -t external -o $TARGET $SOURCES'),
2061 ['$MSGUNIQ -o $TARGET $SOURCE',
2062 '''$XGETTEXT --default-domain=${TARGET.base} \
2063 --directory=$TOP_SRCDIR --add-comments=TRANSLATORS: \
2064 --language=C++ --join-existing \
2065 --keyword=_ --keyword=N_ --keyword=B_ --keyword=qt_ \
2066 --files-from=$TOP_SRCDIR/po/POTFILES.in \
2067 --copyright-holder="LyX Developers" \
2068 --msgid-bugs-address="lyx-devel@lists.lyx.org" ''']
2070 env.Depends(lyx_po, POTFILES_in)
2071 # copy lyx.po to lyx.pot
2072 lyx_pot = env.Command('$BUILDDIR/po/lyx.pot', lyx_po,
2073 Copy('$TARGET', '$SOURCE'))
2076 # files to translate
2077 transfiles = glob.glob(os.path.join(env.Dir('$TOP_SRCDIR/po').abspath, '*.po'))
2078 # possibly *only* handle these languages
2080 if env.has_key('languages'):
2081 languages = env.make_list(env['languages'])
2082 # merge. if I use lan.po as $TARGET, it will be removed
2083 # before it is merged. In this builder,
2084 # $BUILDDIR/po/lang.po is merged from po/lang.po and $BUILDDIR/po/lyx.pot
2085 # and is copied to po/lang.po
2086 env['BUILDERS']['msgmerge'] = Builder(action=[
2087 '$MSGMERGE $TOP_SRCDIR/po/${TARGET.filebase}.po $SOURCE -o $TARGET',
2088 Copy('$TOP_SRCDIR/po/${TARGET.filebase}.po', '$TARGET')]
2090 # for each po file, generate pot
2091 for po_file in transfiles:
2093 fname = os.path.split(po_file)[1]
2095 country = fname.split('.')[0]
2097 if not languages or country in languages:
2098 # merge po files, the generated lan.po_new file is copied to lan.po file.
2099 po = env.msgmerge('$BUILDDIR/po/%s.po' % country, lyx_pot)
2100 env.Depends(po, POTFILES_in)
2101 Alias('update_po', po)
2108 print 'Processing files in po...'
2113 # files to translate
2114 transfiles = glob.glob(os.path.join(env.subst('$TOP_SRCDIR'), 'po', '*.po'))
2115 # possibly *only* handle these languages
2117 if env.has_key('languages'):
2118 languages = env.make_list(env['lanauges'])
2119 # use defulat msgfmt
2121 if not env['MSGFMT']:
2122 print 'msgfmt does not exist. Can not process po files'
2125 env['BUILDERS']['Transfiles'] = Builder(action='$MSGFMT $SOURCE -c --statistics -o $TARGET',suffix='.gmo',src_suffix='.po')
2127 for f in transfiles:
2129 fname = os.path.split(f)[1]
2131 country = fname.split('.')[0]
2133 if not languages or country in languages:
2134 gmo_files.extend(env.Transfiles(f))
2139 # this part is a bit messy right now. Since scons will provide
2140 # --DESTDIR option soon, at least the dest_dir handling can be
2143 # how to join dest_dir and prefix
2144 def joinPaths(path1, path2):
2145 ''' join path1 and path2, do not use os.path.join because
2146 under window, c:\destdir\d:\program is invalid '''
2148 return os.path.normpath(path2)
2149 # separate drive letter
2150 (drive, path) = os.path.splitdrive(os.path.normpath(path2))
2151 # ignore drive letter, so c:\destdir + c:\program = c:\destdir\program
2152 return os.path.join(os.path.normpath(path1), path[1:])
2154 # install to dest_dir/prefix
2155 dest_dir = env.get('DESTDIR', '')
2156 dest_prefix_dir = joinPaths(dest_dir, env.Dir(prefix).abspath)
2157 # create the directory if needed
2158 if not os.path.isdir(dest_prefix_dir):
2160 os.makedirs(dest_prefix_dir)
2163 if not os.path.isdir(dest_prefix_dir):
2164 print 'Can not create directory', dest_prefix_dir
2167 if env.has_key('exec_prefix'):
2168 bin_dest_dir = joinPaths(dest_dir, Dir(env['exec_prefix']).abspath)
2170 bin_dest_dir = os.path.join(dest_prefix_dir, 'bin')
2172 share_dest_dir = os.path.join(dest_prefix_dir, share_dir + program_suffix)
2174 share_dest_dir = os.path.join(dest_prefix_dir, share_dir)
2175 man_dest_dir = os.path.join(dest_prefix_dir, man_dir)
2176 locale_dest_dir = os.path.join(dest_prefix_dir, locale_dir)
2177 env['LYX2LYX_DEST'] = os.path.join(share_dest_dir, 'lyx2lyx')
2181 # install executables (lyxclient may be None)
2184 version_suffix = program_suffix
2188 # install lyx, if in release mode, try to strip the binary
2189 if env.has_key('STRIP') and env['STRIP'] is not None and mode != 'debug':
2190 # create a builder to strip and install
2191 env['BUILDERS']['StripInstallAs'] = Builder(action='$STRIP $SOURCE -o $TARGET')
2193 # install executables
2194 for (name, obj) in (('lyx', lyx), ('tex2lyx', tex2lyx), ('client', client)):
2197 target_name = os.path.split(str(obj[0]))[1].replace(name, '%s%s' % (name, version_suffix))
2198 target = os.path.join(bin_dest_dir, target_name)
2199 if env['BUILDERS'].has_key('StripInstallAs'):
2200 env.StripInstallAs(target, obj)
2202 env.InstallAs(target, obj)
2203 Alias('install', target)
2207 for (dir,files) in [
2209 ('bind', lib_bind_files),
2210 ('bind/de', lib_bind_de_files),
2211 ('bind/fi', lib_bind_fi_files),
2212 ('bind/pt', lib_bind_pt_files),
2213 ('bind/sv', lib_bind_sv_files),
2214 ('doc', lib_doc_files),
2215 ('doc/biblio', lib_doc_biblio_files),
2216 ('doc/clipart', lib_doc_clipart_files),
2217 ('doc/cs', lib_doc_cs_files),
2218 ('doc/da', lib_doc_da_files),
2219 ('doc/de', lib_doc_de_files),
2220 ('doc/de/clipart', lib_doc_de_clipart_files),
2221 ('doc/es', lib_doc_es_files),
2222 ('doc/es/clipart', lib_doc_es_clipart_files),
2223 ('doc/eu', lib_doc_eu_files),
2224 ('doc/fr', lib_doc_fr_files),
2225 ('doc/he', lib_doc_he_files),
2226 ('doc/hu', lib_doc_hu_files),
2227 ('doc/it', lib_doc_it_files),
2228 ('doc/nl', lib_doc_nl_files),
2229 ('doc/nb', lib_doc_nb_files),
2230 ('doc/pl', lib_doc_pl_files),
2231 ('doc/pt', lib_doc_pt_files),
2232 ('doc/ro', lib_doc_ro_files),
2233 ('doc/ru', lib_doc_ru_files),
2234 ('doc/sk', lib_doc_sk_files),
2235 ('doc/sl', lib_doc_sl_files),
2236 ('doc/sv', lib_doc_sv_files),
2237 ('examples', lib_examples_files),
2238 ('examples/ca', lib_examples_ca_files),
2239 ('examples/cs', lib_examples_cs_files),
2240 ('examples/da', lib_examples_da_files),
2241 ('examples/de', lib_examples_de_files),
2242 ('examples/es', lib_examples_es_files),
2243 ('examples/eu', lib_examples_eu_files),
2244 ('examples/fa', lib_examples_fa_files),
2245 ('examples/fr', lib_examples_fr_files),
2246 ('examples/he', lib_examples_he_files),
2247 ('examples/hu', lib_examples_hu_files),
2248 ('examples/it', lib_examples_it_files),
2249 ('examples/nl', lib_examples_nl_files),
2250 ('examples/pl', lib_examples_pl_files),
2251 ('examples/pt', lib_examples_pt_files),
2252 ('examples/ru', lib_examples_ru_files),
2253 ('examples/sl', lib_examples_sl_files),
2254 ('examples/ro', lib_examples_ro_files),
2255 ('fonts', lib_fonts_files),
2256 ('images', lib_images_files),
2257 ('images/math', lib_images_math_files),
2258 ('kbd', lib_kbd_files),
2259 ('layouts', lib_layouts_files + lib_layouts_inc_files),
2260 ('lyx2lyx', lib_lyx2lyx_files),
2261 ('scripts', lib_scripts_files),
2262 ('templates', lib_templates_files),
2263 ('tex', lib_tex_files),
2264 ('ui', lib_ui_files)]:
2265 dirs.append(env.Install(os.path.join(share_dest_dir, dir),
2266 [env.subst('$TOP_SRCDIR/lib/%s/%s' % (dir, file)) for file in files]))
2267 Alias('install', dirs)
2269 # subst and install lyx2lyx_version.py which is not in scons_manifest.py
2270 env.Depends(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py', '$BUILDDIR/common/config.h')
2271 env.substFile(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py',
2272 '$TOP_SRCDIR/lib/lyx2lyx/lyx2lyx_version.py.in')
2273 Alias('install', share_dest_dir + '/lyx2lyx/lyx2lyx_version.py')
2274 sys.path.append(share_dest_dir + '/lyx2lyx')
2276 # generate TOC files for each doc
2277 languages = depend.all_documents(env.Dir('$TOP_SRCDIR/lib/doc').abspath)
2279 for lang in languages.keys():
2280 if os.path.isdir(os.path.join(env.Dir('$TOP_SRCDIR/lib/doc').abspath, lang)):
2281 toc = env.installTOC(os.path.join(share_dest_dir, 'doc', lang, 'TOC.lyx'),
2284 # doc_toc.build_toc needs a installed version of lyx2lyx to execute
2285 env.Depends(toc, share_dest_dir + '/lyx2lyx/lyx2lyx_version.py')
2287 # this is for English
2288 toc = env.installTOC(os.path.join(share_dest_dir, 'doc', 'TOC.lyx'),
2291 env.Depends(toc, share_dest_dir + '/lyx2lyx/lyx2lyx_version.py')
2292 Alias('install', tocs)
2294 if platform_name == 'cygwin':
2295 # cygwin packaging requires a file /usr/share/doc/Cygwin/foot-vendor-suffix.README
2296 Cygwin_README = os.path.join(dest_prefix_dir, 'share', 'doc', 'Cygwin',
2297 '%s-%s.README' % (package, package_cygwin_version))
2298 env.InstallAs(Cygwin_README,
2299 os.path.join(env.subst('$TOP_SRCDIR'), 'README.cygwin'))
2300 Alias('install', Cygwin_README)
2301 # also a directory /usr/share/doc/lyx for README etc
2302 Cygwin_Doc = os.path.join(dest_prefix_dir, 'share', 'doc', package)
2303 env.Install(Cygwin_Doc, [os.path.join(env.subst('$TOP_SRCDIR'), x) for x in \
2304 ['INSTALL', 'README', 'README.Cygwin', 'RELEASE-NOTES', 'COPYING', 'ANNOUNCE']])
2305 Alias('install', Cygwin_Doc)
2306 # cygwin fonts also need to be installed
2307 Cygwin_fonts = os.path.join(share_dest_dir, 'fonts')
2308 env.Install(Cygwin_fonts,
2309 [env.subst('$TOP_SRCDIR/development/Win32/packaging/bakoma/%s' % file) \
2310 for file in win32_bakoma_fonts])
2311 Alias('install', Cygwin_fonts)
2312 # we also need a post installation script
2313 tmp_script = utils.installCygwinPostinstallScript('/tmp')
2314 postinstall_path = os.path.join(dest_dir, 'etc', 'postinstall')
2315 env.Install(postinstall_path, tmp_script)
2316 Alias('install', postinstall_path)
2320 env.InstallAs(os.path.join(man_dest_dir, 'lyx' + version_suffix + '.1'),
2321 env.subst('$TOP_SRCDIR/lyx.man'))
2322 env.InstallAs(os.path.join(man_dest_dir, 'tex2lyx' + version_suffix + '.1'),
2323 env.subst('$TOP_SRCDIR/src/tex2lyx/tex2lyx.man'))
2324 env.InstallAs(os.path.join(man_dest_dir, 'lyxclient' + version_suffix + '.1'),
2325 env.subst('$TOP_SRCDIR/src/client/lyxclient.man'))
2326 Alias('install', [os.path.join(man_dest_dir, x + version_suffix + '.1') for
2327 x in ['lyx', 'tex2lyx', 'lyxclient']])
2329 # ru.gmo ==> ru/LC_MESSAGES/lyxSUFFIX.mo
2330 for gmo in gmo_files:
2331 lan = os.path.split(str(gmo))[1].split('.')[0]
2332 dest_file = os.path.join(locale_dest_dir, lan, 'LC_MESSAGES', 'lyx' + program_suffix + '.mo')
2333 env.InstallAs(dest_file, gmo)
2334 Alias('install', dest_file)
2339 # build windows installer using NSIS
2342 # There is a nsis builder on scons wiki but it does not work with
2343 # our lyx.nsi because it does not dig through all the include directives
2344 # and find the dependencies automatically. Also, it can not parse
2345 # OutFile in lyx.nsi since it is defined as SETUP_EXE which is in turn
2346 # something rely on date.
2347 # Because of this, I am doing a simple nsis builder here.
2348 if platform_name != 'win32':
2349 print 'installer target is only available for windows platform'
2351 if mode != 'release':
2352 print 'installer has to be built in release mode (use option mode=release)'
2354 installer_files = ['$TOP_SRCDIR/development/Win32/packaging/installer/%s' \
2355 % x for x in development_Win32_packaging_installer] + \
2356 ['$TOP_SRCDIR/development/Win32/packaging/installer/components/%s' \
2357 % x for x in development_Win32_packaging_installer_components] + \
2358 ['$TOP_SRCDIR/development/Win32/packaging/installer/dialogs/%s' \
2359 % x for x in development_Win32_packaging_installer_dialogs] + \
2360 ['$TOP_SRCDIR/development/Win32/packaging/installer/graphics/%s' \
2361 % x for x in development_Win32_packaging_installer_graphics] + \
2362 ['$TOP_SRCDIR/development/Win32/packaging/installer/include/%s' \
2363 % x for x in development_Win32_packaging_installer_include] + \
2364 ['$TOP_SRCDIR/development/Win32/packaging/installer/lang/%s' \
2365 % x for x in development_Win32_packaging_installer_lang]
2366 if env.has_key('NSIS') and env['NSIS'] is not None:
2367 # create a builder to strip and install
2368 env['BUILDERS']['installer'] = Builder(generator=utils.env_nsis)
2370 print 'No nsis compiler is found. Existing...'
2372 if not env.has_key('win_installer') or env['win_installer'] is None:
2374 env['win_installer'] = '%s-%s-%s-Installer.exe' % (package_name, package_version, time.strftime('%Y-%m-%d'))
2376 env['win_installer'] = '%s-%s-Installer.exe' % (package_name, package_version)
2377 # provide default setting
2378 if not env.has_key('deps_dir') or env['deps_dir'] is None:
2379 env['deps_dir'] = os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'lyx-windows-deps-msvc-qt4')
2380 if not os.path.isdir(env.Dir('$deps_dir').abspath):
2381 print 'Development dependency package is not found.'
2384 env['deps_dir'] = env.Dir('$deps_dir').abspath
2386 if env.has_key('bundle_dir') and os.path.isdir(env.Dir('$bundle_dir').abspath):
2387 env['bundle_dir'] = env.Dir('$bundle_dir').abspath
2388 elif os.path.isdir(os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'lyx-windows-bundle-deps')):
2389 env['bundle_dir'] = os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'lyx-windows-bundle-deps')
2391 env['bundle_dir'] = None
2392 # if absolute path is given, use it, otherwise, write to current directory
2393 if not (':' in env['win_installer'] or '/' in env['win_installer'] or '\\' in env['win_installer']):
2394 env['win_installer'] = os.path.join(env.Dir('$BUILDDIR').abspath, env['win_installer'])
2395 env.Append(NSISDEFINES={
2396 'ExeFile':env['win_installer'],
2397 'BundleExeFile':env['win_installer'].replace('.exe', '-bundle.exe'),
2398 'FilesLyx':env.Dir(dest_prefix_dir).abspath,
2399 'FilesDeps':env['deps_dir'],
2400 'FilesBundle':env['bundle_dir'],
2402 installer = env.installer(env['win_installer'],
2403 '$TOP_SRCDIR/development/Win32/packaging/installer/lyx.nsi')
2404 # since I can not use a scanner, explicit dependent is required
2405 env.Depends(installer, 'install')
2406 env.Depends(installer, installer_files)
2407 env.Alias('installer', installer)
2408 # also generate bundle?
2409 if env.has_key('bundle') and env['bundle']:
2410 if env['bundle_dir'] is None or not os.path.isdir(env['bundle_dir']):
2411 print 'Bundle directory does not exist (default to %s\lyx-windows-bundle-deps.' % env.Dir('$TOP_SRCDIR').abspath
2412 print 'Use bundle_dir option to specify'
2414 # generator of the builder will add bundle stuff depending on output name
2415 bundle_installer = env.installer(env['win_installer'].replace('.exe', '-bundle.exe'),
2416 '$TOP_SRCDIR/development/Win32/packaging/installer/lyx.nsi')
2417 env.Depends(bundle_installer, 'install')
2418 env.Depends(bundle_installer, installer_files)
2419 env.Alias('installer', bundle_installer)
2422 Alias('all', ['lyx', 'client', 'tex2lyx'])