]> git.lyx.org Git - features.git/blob - development/scons/SConstruct
Scons: handle the case when qt4 is in system directories
[features.git] / development / scons / SConstruct
1 # vi:filetype=python:expandtab:tabstop=4:shiftwidth=4
2 #
3 # file SConstruct
4 #
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
7 #
8 # \author Bo Peng
9 # Full author contact details are available in file CREDITS.
10 #
11 # This is a scons based building system for lyx, please refer
12 # to INSTALL.scons for detailed instructions.
13 #
14
15 import os, sys, copy, cPickle, glob, time
16
17 # scons_utils.py defines a few utility function
18 sys.path.append('config')
19 import scons_utils as utils
20 # import all file lists
21 from scons_manifest import *
22
23 #----------------------------------------------------------
24 # Required runtime environment
25 #----------------------------------------------------------
26
27 # scons asks for 1.5.2, lyx requires 2.3
28 EnsurePythonVersion(2, 3)
29 # Please use at least 0.96.92 (not 0.96.1)
30 EnsureSConsVersion(0, 96)
31 # also check for minor version number for scons 0.96
32 from SCons import __version__
33 version = map(int, __version__.split('.'))
34 if version[0] == 0 and version[1] == 96 and version[2] < 92:
35     print "Scons >= 0.96.92 is required."
36     Exit(1)
37
38 # determine where I am ...
39 #
40 from SCons.Node.FS import default_fs
41 # default_fs.SConstruct_dir is where SConstruct file is located.
42 scons_dir = default_fs.SConstruct_dir.path
43 # get the ../.. of scons_dir
44 top_src_dir = os.path.split(os.path.split(default_fs.SConstruct_dir.abspath)[0])[0]
45
46
47 #----------------------------------------------------------
48 # Global definitions
49 #----------------------------------------------------------
50
51 # some global settings
52 #
53 # get version number from configure.ac so that JMarc does
54 # not have to change SConstruct during lyx release
55 package_version = utils.getVerFromConfigure(top_src_dir)
56 package_cygwin_version = '%s-1' % package_version
57 boost_version = ['1_34']
58
59 if 'svn' in package_version:
60     devel_version = True
61     default_build_mode = 'debug'
62 else:
63     devel_version = False
64     default_build_mode = 'release'
65
66 package = 'lyx'
67 package_bugreport = 'lyx-devel@lists.lyx.org'
68 package_name = 'LyX'
69 package_tarname = 'lyx'
70 package_string = '%s %s' % (package_name, package_version)
71
72 # various cache/log files
73 default_log_file = 'scons_lyx.log'
74 opt_cache_file = 'opt.cache'
75
76
77 #----------------------------------------------------------
78 # platform dependent settings
79 #----------------------------------------------------------
80
81 if os.name == 'nt':
82     platform_name = 'win32'
83     default_frontend = 'qt4'
84     default_prefix = 'c:/program files/lyx'
85     default_with_x = False
86     default_packaging_method = 'windows'
87 elif os.name == 'posix' and sys.platform != 'cygwin':
88     platform_name = sys.platform
89     default_frontend = 'qt4'
90     default_prefix = '/usr/local'
91     default_with_x = True
92     default_packaging_method = 'posix'
93 elif os.name == 'posix' and sys.platform == 'cygwin':
94     platform_name = 'cygwin'
95     default_frontend = 'qt4'
96     default_prefix = '/usr'
97     default_with_x = True
98     default_packaging_method = 'posix'
99 elif os.name == 'darwin':
100     platform_name = 'macosx'
101     default_frontend = 'qt4'
102     # FIXME: macOSX default prefix?
103     default_prefix = '.'
104     default_with_x = False
105     default_packaging_method = 'macosx'
106 else:  # unsupported system, assume posix behavior
107     platform_name = 'others'
108     default_frontend = 'qt4'
109     default_prefix = '.'
110     default_with_x = True
111     default_packaging_method = 'posix'
112
113 #---------------------------------------------------------
114 # Handling options
115 #----------------------------------------------------------
116 #
117 # You can set perminant default values in config.py
118 if os.path.isfile('config.py'):
119     print "Getting options from config.py..."
120     print open('config.py').read()
121
122 opts = Options(['config.py'])
123 opts.AddOptions(
124     # frontend
125     EnumOption('frontend', 'Main GUI', default_frontend,
126         allowed_values = ('qt4',) ),
127     # debug or release build
128     EnumOption('mode', 'Building method', default_build_mode,
129         allowed_values = ('debug', 'release') ),
130     # boost libraries
131     EnumOption('boost',
132         'Use included, system boost library, or try sytem boost first.',
133         'auto', allowed_values = (
134             'auto',       # detect boost, if not found, use included
135             'included',   # always use included boost
136             'system',     # always use system boost, fail if can not find
137             ) ),
138     #
139     EnumOption('gettext',
140         'Use included, system gettext library, or try sytem gettext first',
141         'auto', allowed_values = (
142             'auto',       # detect gettext, if not found, use included
143             'included',   # always use included gettext
144             'system',     # always use system gettext, fail if can not find
145             ) ),
146     #
147     EnumOption('spell', 'Choose spell checker to use.', 'auto',
148         allowed_values = ('aspell', 'pspell', 'ispell', 'auto', 'no') ),
149     # packaging method
150     EnumOption('packaging', 'Packaging method to use.', default_packaging_method,
151         allowed_values = ('windows', 'posix', 'macosx')),
152     #
153     BoolOption('fast_start', 'This option is obsolete.', False),
154     # No precompiled header support (too troublesome to make it work for msvc)
155     # BoolOption('pch', 'Whether or not use pch', False),
156     # enable assertion, (config.h has ENABLE_ASSERTIOS
157     BoolOption('assertions', 'Use assertions', True),
158     # enable warning, (config.h has WITH_WARNINGS)
159     # default to False since MSVC does not have #warning
160     BoolOption('warnings', 'Use warnings', False),
161     # config.h define _GLIBCXX_CONCEPT_CHECKS
162     # Note: for earlier version of gcc (3.3) define _GLIBCPP_CONCEPT_CHECKS
163     BoolOption('concept_checks', 'Enable concept checks', True),
164     #
165     BoolOption('nls', 'Whether or not use native language support', True),
166     #
167     BoolOption('profiling', 'Whether or not enable profiling', False),
168     # config.h define _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC
169     BoolOption('stdlib_debug', 'Whether or not turn on stdlib debug', False),
170     # using x11?
171     BoolOption('X11', 'Use x11 windows system', default_with_x),
172     # use MS VC++ to build lyx
173     BoolOption('use_vc', 'Use MS VC++ to build lyx (cl.exe will be probed)', None),
174     #
175     PathOption('qt_dir', 'Path to qt directory', None),
176     #
177     PathOption('qt_inc_path', 'Path to qt include directory', None),
178     #
179     PathOption('qt_lib_path', 'Path to qt library directory', None),
180     # extra include and libpath
181     PathOption('extra_inc_path', 'Extra include path', None),
182     #
183     PathOption('extra_lib_path', 'Extra library path', None),
184     #
185     PathOption('extra_bin_path', 'A convenient way to add a path to $PATH', None),
186     #
187     PathOption('extra_inc_path1', 'Extra include path', None),
188     #
189     PathOption('extra_lib_path1', 'Extra library path', None),
190     # rebuild only specifed, comma separated targets
191     ('rebuild', '''rebuild only specifed, comma separated targets.
192         yes or all (default): rebuild everything
193         no or none: rebuild nothing (usually used for installation)
194         comp1,comp2,...: rebuild specified targets''', None),
195     # can be set to a non-existing directory
196     ('prefix', 'install architecture-independent files in PREFIX', default_prefix),
197     # build directory, will use $mode if not set
198     ('build_dir', 'Build directory', None),
199     # version suffix
200     ('version_suffix', 'install lyx as lyx-suffix', None),
201     # how to load options
202     ('load_option', '''load option from previous scons run. option can be
203         yes (default): load all options
204         no: do not load any option
205         opt1,opt2: load specified options
206         -opt1,opt2: load all options other than specified ones''', 'yes'),
207     #
208     ('optimization', 'optimization CCFLAGS option.', None),
209     #
210     PathOption('exec_prefix', 'install architecture-independent executable files in PREFIX', None),
211     # log file
212     ('logfile', 'save commands (not outputs) to logfile', default_log_file),
213     # provided for backward compatibility
214     ('dest_dir', 'install to DESTDIR. (Provided for backward compatibility only)', None),
215     # environment variable can be set as options.
216     ('DESTDIR', 'install to DESTDIR', None),
217     ('CC', 'replace default $CC', None),
218     ('LINK', 'replace default $LINK', None),
219     ('CPP', 'replace default $CPP', None),
220     ('CXX', 'replace default $CXX', None),
221     ('CXXCPP', 'replace default $CXXCPP', None),
222     ('CCFLAGS', 'replace default $CCFLAGS', None),
223     ('CPPFLAGS', 'replace default $CPPFLAGS', None),
224     ('LINKFLAGS', 'replace default $LINKFLAGS', None),
225 )
226
227 # allowed options
228 all_options = [x.key for x in opts.options]
229
230 # copied from SCons/Options/BoolOption.py
231 # We need to use them before a boolean ARGUMENTS option is available
232 # in env as bool.
233 true_strings  = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
234 false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none')
235
236 if ARGUMENTS.has_key('fast_start'):
237     print 'fast_start option is obsolete'
238
239 # if load_option=yes (default), load saved comand line options
240 #
241 # This option can take value yes/no/opt1,opt2/-opt1,opt2
242 # and tries to be clever in choosing options to load
243 if (not ARGUMENTS.has_key('load_option') or \
244     ARGUMENTS['load_option'] not in false_strings) \
245     and os.path.isfile(opt_cache_file):
246     cache_file = open(opt_cache_file)
247     opt_cache = cPickle.load(cache_file)
248     cache_file.close()
249     # import cached options, but we should ignore qt_dir when frontend changes
250     if ARGUMENTS.has_key('frontend') and opt_cache.has_key('frontend') \
251         and ARGUMENTS['frontend'] != opt_cache['frontend'] \
252         and opt_cache.has_key('qt_dir'):
253         opt_cache.pop('qt_dir')
254     # and we do not cache some options (dest_dir is obsolete)
255     for arg in ['load_option', 'dest_dir']:
256         if opt_cache.has_key(arg):
257             opt_cache.pop(arg)
258     # remove obsolete cached keys (well, SConstruct is evolving. :-)
259     for arg in opt_cache.keys():
260         if arg not in all_options:
261             print 'Option %s is obsolete, do not load it' % arg
262             opt_cache.pop(arg)
263     # now, if load_option=opt1,opt2 or -opt1,opt2
264     if ARGUMENTS.has_key('load_option') and \
265         ARGUMENTS['load_option'] not in true_strings + false_strings:
266         # if -opt1,opt2 is specified, do not load these options
267         if ARGUMENTS['load_option'][0] == '-':
268             for arg in ARGUMENTS['load_option'][1:].split(','):
269                 if opt_cache.has_key(arg):
270                     opt_cache.pop(arg)
271         # if opt1,opt2 is specified, only load specified options
272         else:
273             args = ARGUMENTS['load_option'].split(',')
274             for arg in opt_cache.keys():
275                 if arg not in args:
276                     opt_cache.pop(arg)
277     # now restore options as if entered from command line
278     for key in opt_cache.keys():
279         if not ARGUMENTS.has_key(key):
280             ARGUMENTS[key] = opt_cache[key]
281             print "Restoring cached option  %s=%s" % (key, ARGUMENTS[key])
282     print
283
284 # check if there is unused (or misspelled) argument
285 for arg in ARGUMENTS.keys():
286     if arg not in all_options:
287         import textwrap
288         print "Unknown option '%s'... exiting." % arg
289         print
290         print "Available options are (check 'scons -help' for details):"
291         print '    ' + '\n    '.join(textwrap.wrap(',  '.join(all_options)))
292         Exit(1)
293
294 # save options used
295 cache_file = open(opt_cache_file, 'w')
296 cPickle.dump(ARGUMENTS, cache_file)
297 cache_file.close()
298
299 #---------------------------------------------------------
300 # Setting up environment
301 #---------------------------------------------------------
302
303 # I do not really like ENV=os.environ, but you may add it
304 # here if you experience some environment related problem
305 env = Environment(options = opts)
306
307 # set individual variables since I do not really like ENV = os.environ
308 env['ENV']['PATH'] = os.environ.get('PATH')
309 env['ENV']['HOME'] = os.environ.get('HOME')
310 # these are defined for MSVC
311 env['ENV']['LIB'] = os.environ.get('LIB')
312 env['ENV']['INCLUDE'] = os.environ.get('INCLUDE')
313
314 # for simplicity, use var instead of env[var]
315 frontend = env['frontend']
316 prefix = env['prefix']
317 mode = env['mode']
318
319 if platform_name == 'win32':
320     if env.has_key('use_vc'):
321         use_vc = env['use_vc']
322         if WhereIs('cl.exe') is None:
323             print "cl.exe is not found. Are you using the MSVC environment?"
324             Exit(2)
325     elif WhereIs('cl.exe') is not None:
326         use_vc = True
327     else:
328         use_vc = False
329 else:
330     use_vc = False
331
332 # lyx will be built to $build/build_dir so it is possible
333 # to build multiple build_dirs using the same source
334 # $mode can be debug or release
335 if env.has_key('build_dir') and env['build_dir'] is not None:
336     # create the directory if needed
337     if not os.path.isdir(env['build_dir']):
338         try:
339             os.makedirs(env['build_dir'])
340         except:
341             pass
342         if not os.path.isdir(env['build_dir']):
343             print 'Can not create directory', env['build_dir']
344             Exit(3)
345     env['BUILDDIR'] = env['build_dir']
346 else:
347     # Determine the name of the build $mode
348     env['BUILDDIR'] = '#' + mode
349
350 # all built libraries will go to build_dir/libs
351 # (This is different from the make file approach)
352 env['LOCALLIBPATH'] = '$BUILDDIR/libs'
353 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
354
355
356 # Here is a summary of variables defined in env
357 # 1. defined options
358 # 2. undefined options with a non-None default value
359 # 3. compiler commands and flags like CCFLAGS.
360 #     MSGFMT used to process po files
361 # 4. Variables that will be used to replace variables in some_file.in
362 #     src/support/package.C.in:
363 #       TOP_SRCDIR, LOCALEDIR, LYX_DIR, PROGRAM_SUFFIX
364 #     lib/lyx2lyx/lyx2lyx_version.py.in
365 #       PACKAGE_VERSION
366 #     src/version.C.in
367 #       PACKAGE_VERSION, LYX_DATE, VERSION_INFO
368
369 # full path name is used to build msvs project files
370 # and to replace TOP_SRCDIR in package.C
371 env['TOP_SRCDIR'] = Dir(top_src_dir).abspath
372 # needed by src/version.C.in => src/version.C
373 env['PACKAGE_VERSION'] = package_version
374 env['LYX_DATE'] = time.asctime()
375
376 # determine share_dir etc
377 packaging_method = env.get('packaging')
378 if packaging_method == 'windows':
379     share_dir = 'Resources'
380     man_dir = 'Resources/man/man1'
381     locale_dir = 'Resources/locale'
382 else:
383     share_dir = 'share/lyx'
384     locale_dir = 'share/locale'
385     if platform_name == 'cygwin':
386         man_dir = 'share/man/man1'
387     else:
388         man_dir = 'man/man1'
389
390 # program suffix: can be yes, or a string
391 if env.has_key('version_suffix'):
392     if env['version_suffix'] in true_strings:
393         program_suffix = package_version
394     elif env['version_suffix'] in false_strings:
395         program_suffix = ''
396     else:
397         program_suffix = env['version_suffix']
398 else:
399     program_suffix = ''
400 # used by package.C.in
401 env['PROGRAM_SUFFIX'] = program_suffix
402
403 # whether or not add suffix to file and directory names
404 add_suffix = packaging_method != 'windows'
405 # LYX_DIR are different (used in package.C.in)
406 if add_suffix:
407     env['LYX_DIR'] = Dir(os.path.join(prefix, share_dir + program_suffix)).abspath
408 else:
409     env['LYX_DIR'] = Dir(os.path.join(prefix, share_dir)).abspath
410 # we need absolute path for package.C
411 env['LOCALEDIR'] = Dir(os.path.join(prefix, locale_dir)).abspath
412
413
414 #---------------------------------------------------------
415 # Setting building environment (Tools, compiler flags etc)
416 #---------------------------------------------------------
417
418 # Since Tool('mingw') will reset CCFLAGS etc, this should be
419 # done before getEnvVariable
420 if platform_name == 'win32':
421     if use_vc:
422         env.Tool('msvc')
423         env.Tool('mslink')
424     else:
425         env.Tool('mingw')
426         env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
427
428 # we differentiate between hard-coded options and default options
429 # hard-coded options are required and will always be there
430 # default options can be replaced by enviromental variables or command line options
431 CCFLAGS_required = []
432 LINKFLAGS_required = []
433 CCFLAGS_default = []
434
435 # under windows, scons is confused by .C/.c and uses gcc instead of
436 # g++. I am forcing the use of g++ here. This is expected to change
437 # after lyx renames all .C files to .cpp
438 #
439 # save the old c compiler and CCFLAGS (used by libintl)
440 C_COMPILER = env.subst('$CC')
441 C_CCFLAGS = env.subst('$CCFLAGS').split()
442 # if we use ms vc, the commands are fine (cl.exe and link.exe)
443 if use_vc:
444     # /TP treat all source code as C++
445     # C4819: The file contains a character that cannot be represented
446     #   in the current code page (number)
447     # C4996: foo was decleared deprecated
448     CCFLAGS_required.extend(['/TP', '/EHsc'])
449     if mode == 'debug':
450         CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MDd'])
451         # the flags are also needed in C mode (for intl lib)
452         C_CCFLAGS.extend(['/wd4819', '/wd4996', '/nologo', '/MDd'])
453     else:
454         CCFLAGS_default.extend(['/wd4819', '/wd4996', '/nologo', '/MD'])
455         C_CCFLAGS.extend(['/wd4819', '/wd4996', '/nologo', '/MD'])
456 else:
457     if env.has_key('CXX') and env['CXX']:
458         env['CC'] = env.subst('$CXX')
459         env['LINK'] = env.subst('$CXX')
460     else:
461         env['CC'] = 'g++'
462         env['LINK'] = 'g++'
463
464 # for debug/release mode
465 if env.has_key('optimization') and env['optimization'] is not None:
466     # if user supplies optimization flags, use it anyway
467     CCFLAGS_required.extend(env['optimization'].split())
468     # and do not use default
469     set_default_optimization_flags = False
470 else:
471     set_default_optimization_flags = True
472
473 if mode == 'debug':
474     if use_vc:
475         CCFLAGS_required.append('/Zi')
476         LINKFLAGS_required.extend(['/debug', '/map'])
477     else:
478         CCFLAGS_required.append('-g')
479         CCFLAGS_default.append('-O')
480 elif mode == 'release' and set_default_optimization_flags:
481     if use_vc:
482         CCFLAGS_default.append('/O2')
483     else:
484         CCFLAGS_default.append('-O2')
485
486 # msvc uses separate tools for profiling
487 if env.has_key('profiling') and env['profiling']:
488     if use_vc:
489         print 'Visual C++ does not use profiling options'
490     else:
491         CCFLAGS_required.append('-pg')
492         LINKFLAGS_required.append('-pg')
493
494 if env.has_key('warnings') and env['warnings']:
495     if use_vc:
496         CCFLAGS_default.append('/W2')
497     else:
498         # Note: autotools detect gxx version and pass -W for 3.x
499         # and -Wextra for other versions of gcc
500         CCFLAGS_default.append('-Wall')
501
502 # Now, set the variables as follows:
503 # 1. if command line option exists: replace default
504 # 2. then if s envronment variable exists: replace default
505 # 3. set variable to required + default
506 def setEnvVariable(env, name, required = None, default = None, split = True):
507     ''' env: environment to set variable
508             name: variable
509             required: hardcoded options
510             default: default options that can be replaced by command line or
511                 environment variables
512             split: whether or not split obtained variable like '-02 -g'
513     '''
514     # 1. ARGUMENTS is already set to env[name], override default.
515     if ARGUMENTS.has_key(name):
516         # env[name] may be rewritten when building tools are reloaded
517         # if that is the case, commandline option will override it.
518         env[name] = ARGUMENTS[name]
519         default = None
520     # then use environment default
521     elif os.environ.has_key(name):
522         print "Acquiring variable %s from system environment: %s" % (name, os.environ[name])
523         default = os.environ[name]
524         if split:
525             default = default.split()
526     # the real value should be env[name] + default + required
527     if split:
528         value = []
529         if env.has_key(name):
530             value = str(env[name]).split()
531         if required is not None:
532             value += required
533         if default is not None:
534             value += default
535     else:
536         value = ""
537         if env.has_key(name):
538             value = str(env[name])
539         if required is not None:
540             value += " " + required
541         if default is not None:
542             value += " " + default
543     env[name] = value
544     # print name, env[name]
545
546 setEnvVariable(env, 'DESTDIR', split=False)
547 setEnvVariable(env, 'CC')
548 setEnvVariable(env, 'LINK')
549 setEnvVariable(env, 'CPP')
550 setEnvVariable(env, 'CXX')
551 setEnvVariable(env, 'CXXCPP')
552 setEnvVariable(env, 'CCFLAGS', CCFLAGS_required, CCFLAGS_default)
553 setEnvVariable(env, 'CXXFLAGS')
554 setEnvVariable(env, 'CPPFLAGS')
555 setEnvVariable(env, 'LINKFLAGS', LINKFLAGS_required)
556
557 # if DESTDIR is not set...
558 if env.has_key('dest_dir'):
559     print "This option is obsolete. Please use DESTDIR instead."
560     env['DESTDIR'] = env['dest_dir']
561
562
563 #---------------------------------------------------------
564 # Frontend related variables (QTDIR etc)
565 #---------------------------------------------------------
566
567 if env.has_key('qt_dir') and env['qt_dir']:
568     env['QTDIR'] = env['qt_dir']
569
570 # if there is a valid QTDIR, set path for lib and bin directories
571 if env.has_key('QTDIR'):
572     # add path to the qt tools
573     if os.path.isdir(os.path.join(env['QTDIR'], 'lib')):
574         env.AppendUnique(LIBPATH = [os.path.join(env['QTDIR'], 'lib')])
575     # set environment so that moc etc can be found even if its path is not set properly
576     if os.path.isdir(os.path.join(env['QTDIR'], 'bin')):
577         os.environ['PATH'] += os.pathsep + os.path.join(env['QTDIR'], 'bin')
578         env.PrependENVPath('PATH', os.path.join(env['QTDIR'], 'bin'))
579
580 if env.has_key('qt_lib_path') and env['qt_lib_path']:
581     qt_lib_path = env.subst('$qt_lib_path')
582 elif env.has_key('QTDIR') and os.path.isdir(os.path.join(env.subst('$QTDIR'), 'lib')):
583     qt_lib_path = env.subst('$QTDIR/lib')
584 # this is the path for cygwin.
585 elif os.path.isdir(os.path.join('/usr/lib/', frontend, 'lib')):
586     qt_lib_path = '/usr/lib/%s/lib' % frontend
587 else:
588     # in system directory? (No need to specify)
589     qt_lib_path = None
590
591 if qt_lib_path is not None:
592     env.AppendUnique(LIBPATH = [qt_lib_path])
593     # qt4 seems to be using pkg_config
594     env.PrependENVPath('PKG_CONFIG_PATH', qt_lib_path)
595
596 if env.has_key('qt_inc_path') and env['qt_inc_path']:
597     qt_inc_path = env['qt_inc_path']
598 elif env.has_key('QTDIR') and os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
599     qt_inc_path = '$QTDIR/include'
600 # this is the path for cygwin.
601 elif os.path.isdir('/usr/include/' + frontend):
602     qt_inc_path = '/usr/include/' + frontend
603 else:
604     qt_inc_path = None
605
606 # Note that this CPPPATH is for testing only
607 # it will be removed before calling SConscript
608 if qt_inc_path is not None:
609     env['CPPPATH'] = [qt_inc_path]
610
611 #
612 # extra_inc_path and extra_lib_path
613 #
614 extra_inc_paths = []
615 if env.has_key('extra_inc_path') and env['extra_inc_path']:
616     extra_inc_paths.append(env['extra_inc_path'])
617 if env.has_key('extra_lib_path') and env['extra_lib_path']:
618     env.AppendUnique(LIBPATH = [env['extra_lib_path']])
619 if env.has_key('extra_inc_path1') and env['extra_inc_path1']:
620     extra_inc_paths.append(env['extra_inc_path1'])
621 if env.has_key('extra_lib_path1') and env['extra_lib_path1']:
622     env.AppendUnique(LIBPATH = [env['extra_lib_path1']])
623 if env.has_key('extra_bin_path') and env['extra_bin_path']:
624     # only the first one is needed (a scons bug?)
625     os.environ['PATH'] += os.pathsep + env['extra_bin_path']
626     env.PrependENVPath('PATH', env['extra_bin_path'])
627 # extra_inc_paths will be used later by intlenv etc
628 env.AppendUnique(CPPPATH = extra_inc_paths)
629
630
631 #----------------------------------------------------------
632 # Autoconf business
633 #----------------------------------------------------------
634
635 conf = Configure(env,
636     custom_tests = {
637         'CheckPkgConfig' : utils.checkPkgConfig,
638         'CheckPackage' : utils.checkPackage,
639         'CheckMkdirOneArg' : utils.checkMkdirOneArg,
640         'CheckSelectArgType' : utils.checkSelectArgType,
641         'CheckBoostLibraries' : utils.checkBoostLibraries,
642         'CheckCommand' : utils.checkCommand,
643         'CheckCXXGlobalCstd' : utils.checkCXXGlobalCstd,
644         'CheckLC_MESSAGES' : utils.checkLC_MESSAGES,
645         'CheckIconvConst' : utils.checkIconvConst,
646         'CheckSizeOfWChar' : utils.checkSizeOfWChar,
647     }
648 )
649
650 # pkg-config? (if not, we use hard-coded options)
651 if conf.CheckPkgConfig('0.15.0'):
652     env['HAS_PKG_CONFIG'] = True
653 else:
654     print 'pkg-config >= 0.1.50 is not found'
655     env['HAS_PKG_CONFIG'] = False
656
657 # zlib? This is required.
658 if (not use_vc and not conf.CheckLibWithHeader('z', 'zlib.h', 'C')) \
659     or (use_vc and not conf.CheckLibWithHeader('zdll', 'zlib.h', 'C')):
660     print 'Did not find zdll.lib or zlib.h, exiting!'
661     Exit(1)
662 if conf.CheckLib('iconv'):
663     env['ICONV_LIB'] = 'iconv'
664 elif conf.CheckLib('libiconv'):
665     env['ICONV_LIB'] = 'libiconv'
666 elif conf.CheckFunc('iconv_open'):
667     env['ICONV_LIB'] = None
668 else:
669     print 'Did not find iconv or libiconv, exiting!'
670     Exit(1)
671
672
673 # qt libraries?
674 #
675 if frontend == 'qt4':
676     succ = False
677     # first: try pkg_config
678     if env['HAS_PKG_CONFIG']:
679         succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
680         # FIXME: use pkg_config information?
681         #env['QT4_PKG_CONFIG'] = succ
682     # second: try to link to it
683     if not succ:
684         # Under linux, I can test the following perfectly
685         # Under windows, lib names need to passed as libXXX4.a ...
686         if platform_name == 'win32' and use_vc:
687             succ = conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
688         else:
689             succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
690     # still can not find it
691     if not succ:
692         print 'Did not find qt libraries, exiting!'
693         Exit(1)
694     #
695     # Now, determine the correct suffix:
696     qt_libs = ['QtCore', 'QtGui']
697     if platform_name == 'win32':
698         if mode == 'debug' and use_vc and \
699             conf.CheckLibWithHeader('QtCored4', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
700             qt_lib_suffix = 'd4'
701             use_qt_debug_libs = True
702         else:
703             qt_lib_suffix = '4'
704             use_qt_debug_libs = False
705     else:
706         if mode == 'debug' and conf.CheckLibWithHeader('QtCore_debug', 'QtGui/QApplication', 'c++', 'QApplication qapp();'):
707             qt_lib_suffix = '_debug'
708             use_qt_debug_libs = True
709         else:
710             qt_lib_suffix = ''
711             use_qt_debug_libs = False
712     frontend_libs = [x + qt_lib_suffix for x in qt_libs]
713     qtcore_lib = ['QtCore' + qt_lib_suffix]
714     
715
716 # now, if msvc2005 is used, we will need that QT_LIB_PATH/QT_LIB.manifest file
717 if use_vc:
718     if frontend == 'qt4':
719         if mode == 'debug':
720             if qt_lib_path is not None:
721                 manifest = os.path.join(qt_lib_path, 'QtGuid4.dll.manifest')
722             else:
723                 manifest = 'QtGuid4.dll.manifest'
724         else:
725             if qt_lib_path is not None:
726                 manifest = os.path.join(qt_lib_path, 'QtGui4.dll.manifest')
727             else:
728                 manifest = 'QtGui4.dll.manifest'
729     if os.path.isfile(manifest):
730         env['LINKCOM'] = [env['LINKCOM'], 'mt.exe /MANIFEST %s /outputresource:$TARGET;1' % manifest]
731
732 # check socket libs
733 socket_libs = []
734 if conf.CheckLib('socket'):
735     socket_libs.append('socket')
736 # nsl is the network services library and provides a
737 # transport-level interface to networking services.
738 if conf.CheckLib('nsl'):
739     socket_libs.append('nsl')
740
741 # check available boost libs (since lyx1.4 does not use iostream)
742 boost_libs = []
743 for lib in ['signals', 'regex', 'filesystem', 'iostreams']:
744     if os.path.isdir(os.path.join(top_src_dir, 'boost', 'libs', lib)):
745         boost_libs.append(lib)
746
747 # check boost libraries
748 boost_opt = ARGUMENTS.get('boost', 'auto')
749 # check for system boost
750 lib_paths = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
751 inc_paths = env['CPPPATH'] + ['/usr/include', '/usr/local/include']
752 # default to $BUILDDIR/libs (use None since this path will be added anyway)
753 boost_libpath = None
754 # here I assume that all libraries are in the same directory
755 if boost_opt == 'included':
756     boost_libraries = ['included_boost_%s' % x for x in boost_libs]
757     included_boost = True
758     env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
759 elif boost_opt == 'auto':
760     res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
761     # if not found, use local boost
762     if res[0] is None:
763         boost_libraries = ['included_boost_%s' % x for x in boost_libs]
764         included_boost = True
765         env['BOOST_INC_PATH'] = '$TOP_SRCDIR/boost'
766     else:
767         included_boost = False
768         (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
769 elif boost_opt == 'system':
770     res = conf.CheckBoostLibraries(boost_libs, lib_paths, inc_paths, boost_version, mode == 'debug')
771     if res[0] is None:
772         print "Can not find system boost libraries with version %s " % boost_version
773         print "Please supply a path through extra_lib_path and try again."
774         print "Or use boost=included to use included boost libraries."
775         Exit(2)
776     else:
777         included_boost = False
778         (boost_libraries, boost_libpath, env['BOOST_INC_PATH']) = res
779
780
781 if boost_libpath is not None:
782     env.AppendUnique(LIBPATH = [boost_libpath])
783
784
785 env['ENABLE_NLS'] = env['nls']
786
787 if not env['ENABLE_NLS']:
788     intl_libs = []
789     included_gettext = False
790 else:
791     # check gettext libraries
792     gettext_opt = ARGUMENTS.get('gettext', 'auto')
793     # check for system gettext
794     succ = False
795     if gettext_opt in ['auto', 'system']:
796         if conf.CheckFunc('gettext'):
797             included_gettext = False
798             intl_libs = []
799             succ = True
800         elif conf.CheckLib('intl'):
801             included_gettext = False
802             intl_libs = ['intl']
803             succ = True
804         else: # no found
805             if gettext_opt == 'system':
806                 print "Can not find system gettext library"
807                 print "Please supply a path through extra_lib_path and try again."
808                 print "Or use gettext=included to use included gettext libraries."
809                 Exit(2)
810     # now, auto and succ = false, or gettext=included
811     if not succ:
812         # we do not need to set LIBPATH now.
813         included_gettext = True
814         intl_libs = ['included_intl']
815
816
817 #
818 # check for msgfmt command
819 env['MSGFMT'] = conf.CheckCommand('msgfmt')
820
821 # cygwin packaging requires the binaries to be stripped
822 if platform_name == 'cygwin':
823     env['STRIP'] = conf.CheckCommand('strip')
824
825 # check uic and moc commands for qt frontends
826 if frontend[:2] == 'qt' and (conf.CheckCommand('uic') == None \
827     or conf.CheckCommand('moc') == None):
828     print 'uic or moc command is not found for frontend', frontend
829     Exit(1)
830
831 #
832 # Customized builders
833 #
834 # install customized builders
835 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
836
837
838 #----------------------------------------------------------
839 # Generating config.h
840 #----------------------------------------------------------
841 aspell_lib = 'aspell'
842 # assume that we use aspell, aspelld compiled for msvc
843 if platform_name == 'win32' and mode == 'debug' and use_vc:
844     aspell_lib = 'aspelld'
845
846 # check the existence of config.h
847 config_h = os.path.join(env.Dir('$BUILDDIR/common').path, 'config.h')
848 boost_config_h = os.path.join(env.Dir('$BUILDDIR/boost').path, 'config.h')
849 #
850 print "Creating %s..." % boost_config_h
851 #
852 utils.createConfigFile(conf,
853     config_file = boost_config_h,
854     config_pre = '''/* boost/config.h.  Generated by SCons.  */
855
856 /* -*- C++ -*- */
857 /*
858 * \file config.h
859 * This file is part of LyX, the document processor.
860 * Licence details can be found in the file COPYING.
861 *
862 * This is the compilation configuration file for LyX.
863 * It was generated by scon.
864 * You might want to change some of the defaults if something goes wrong
865 * during the compilation.
866 */
867
868 #ifndef _BOOST_CONFIG_H
869 #define _BOOST_CONFIG_H
870 ''',
871     headers = [
872         ('ostream', 'HAVE_OSTREAM', 'cxx'),
873         ('locale', 'HAVE_LOCALE', 'cxx'),
874         ('sstream', 'HAVE_SSTREAM', 'cxx'),
875         #('newapis.h', 'HAVE_NEWAPIS_H', 'c'),
876     ],
877     custom_tests = [
878         (env.has_key('assertions') and env['assertions'],
879             'ENABLE_ASSERTIONS',
880             'Define if you want assertions to be enabled in the code'
881         ),
882     ],
883     types = [
884         ('wchar_t', 'HAVE_WCHAR_T', None),
885     ],
886     config_post = '''
887
888 #if defined(HAVE_OSTREAM) && defined(HAVE_LOCALE) && defined(HAVE_SSTREAM)
889 #  define USE_BOOST_FORMAT 1
890 #else
891 #  define USE_BOOST_FORMAT 0
892 #endif
893
894 #if !defined(ENABLE_ASSERTIONS)
895 #  define BOOST_DISABLE_ASSERTS 1
896 #endif
897 #define BOOST_ENABLE_ASSERT_HANDLER 1
898
899 #define BOOST_DISABLE_THREADS 1
900 #define BOOST_NO_WSTRING 1
901
902 #ifdef __CYGWIN__
903 #  define BOOST_POSIX 1
904 #  define BOOST_POSIX_API 1
905 #  define BOOST_POSIX_PATH 1
906 #endif
907
908 #define BOOST_ALL_NO_LIB 1
909
910 #if defined(HAVE_NEWAPIS_H)
911 #  define WANT_GETFILEATTRIBUTESEX_WRAPPER 1
912 #endif
913
914 #if defined(HAVE_WCHAR_T) && SIZEOF_WCHAR_T == 4
915 #  define LIBC_WCTYPE_USES_UCS4
916 #endif
917
918 #endif
919 '''
920 )
921 #
922 print "\nGenerating %s..." % config_h
923
924 # AIKSAURUS_H_LOCATION
925 if (conf.CheckCXXHeader("Aiksaurus.h")):
926     aik_location = '<Aiksaurus.h>'
927 elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
928     aik_location = '<Aiksaurus/Aiksaurus.h>'
929 else:
930     aik_location = ''
931
932 # determine headers to use
933 spell_opt = ARGUMENTS.get('spell', 'auto')
934 env['USE_ASPELL'] = False
935 env['USE_PSPELL'] = False
936 env['USE_ISPELL'] = False
937 if spell_opt in ['auto', 'aspell'] and conf.CheckLib(aspell_lib):
938     spell_engine = 'USE_ASPELL'
939 elif spell_opt in ['auto', 'pspell'] and conf.CheckLib('pspell'):
940     spell_engine = 'USE_PSPELL'
941 elif spell_opt in ['auto', 'ispell'] and conf.CheckLib('ispell'):
942     spell_engine = 'USE_ISPELL'
943 else:
944     spell_engine = None
945
946 if spell_engine is not None:
947     env[spell_engine] = True
948 else:
949     if spell_opt == 'auto':
950         print "Warning: Can not locate any spell checker"
951     elif spell_opt != 'no':
952         print "Warning: Can not locate specified spell checker:", spell_opt
953         Exit(1)
954
955 # check arg types of select function
956 (select_arg1, select_arg234, select_arg5) = conf.CheckSelectArgType()
957
958 # check the size of wchar_t
959 sizeof_wchar_t = conf.CheckSizeOfWChar()
960 # something wrong
961 if sizeof_wchar_t == 0:
962     print 'Error: Can not determine the size of wchar_t.'
963     Exit(1)
964
965 #
966 # create config.h
967 result = utils.createConfigFile(conf,
968     config_file = config_h,
969     config_pre = '''/* config.h.  Generated by SCons.  */
970
971 /* -*- C++ -*- */
972 /*
973 * \file config.h
974 * This file is part of LyX, the document processor.
975 * Licence details can be found in the file COPYING.
976 *
977 * This is the compilation configuration file for LyX.
978 * It was generated by scon.
979 * You might want to change some of the defaults if something goes wrong
980 * during the compilation.
981 */
982
983 #ifndef _CONFIG_H
984 #define _CONFIG_H
985 ''',
986     headers = [
987         ('io.h', 'HAVE_IO_H', 'c'),
988         ('limits.h', 'HAVE_LIMITS_H', 'c'),
989         ('locale.h', 'HAVE_LOCALE_H', 'c'),
990         ('process.h', 'HAVE_PROCESS_H', 'c'),
991         ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
992         ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
993         ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
994         ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
995         ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
996         ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
997         ('unistd.h', 'HAVE_UNISTD_H', 'c'),
998         ('utime.h', 'HAVE_UTIME_H', 'c'),
999         ('direct.h', 'HAVE_DIRECT_H', 'c'),
1000         ('istream', 'HAVE_ISTREAM', 'cxx'),
1001         ('ios', 'HAVE_IOS', 'cxx'),
1002     ],
1003     functions = [
1004         ('open', 'HAVE_OPEN', None),
1005         ('chmod', 'HAVE_CHMOD', None),
1006         ('close', 'HAVE_CLOSE', None),
1007         ('popen', 'HAVE_POPEN', None),
1008         ('pclose', 'HAVE_PCLOSE', None),
1009         ('_open', 'HAVE__OPEN', None),
1010         ('_close', 'HAVE__CLOSE', None),
1011         ('_popen', 'HAVE__POPEN', None),
1012         ('_pclose', 'HAVE__PCLOSE', None),
1013         ('getpid', 'HAVE_GETPID', None),
1014         ('_getpid', 'HAVE__GETPID', None),
1015         ('mkdir', 'HAVE_MKDIR', None),
1016         ('_mkdir', 'HAVE__MKDIR', None),
1017         ('mktemp', 'HAVE_MKTEMP', None),
1018         ('mkstemp', 'HAVE_MKSTEMP', None),
1019         ('strerror', 'HAVE_STRERROR', None),
1020         ('count', 'HAVE_STD_COUNT', '''
1021 #include <algorithm>
1022 int count()
1023 {
1024 char a[] = "hello";
1025 return std::count(a, a+5, 'l');
1026 }
1027 '''),
1028         ('getcwd', 'HAVE_GETCWD', None),
1029         ('setenv', 'HAVE_SETENV', None),
1030         ('putenv', 'HAVE_PUTENV', None),
1031         ('fcntl', 'HAVE_FCNTL', None),
1032     ],
1033     types = [
1034         ('std::istreambuf_iterator<std::istream>', 'HAVE_DECL_ISTREAMBUF_ITERATOR',
1035             '#include <streambuf>\n#include <istream>'),
1036         ('wchar_t', 'HAVE_WCHAR_T', None),
1037         ('mode_t', 'HAVE_MODE_T', "#include <sys/types.h>"),
1038     ],
1039     libs = [
1040         ('gdi32', 'HAVE_LIBGDI32'),
1041         (('Aiksaurus', 'libAiksaurus'), 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB'),
1042     ],
1043     custom_tests = [
1044         (conf.CheckType('pid_t', includes='#include <sys/types.h>'),
1045             'HAVE_PID_T',
1046             'Define is sys/types.h does not have pid_t',
1047             '',
1048             '#define pid_t int',
1049         ),
1050         (conf.CheckCXXGlobalCstd(),
1051             'CXX_GLOBAL_CSTD',
1052             'Define if your C++ compiler puts C library functions in the global namespace'
1053         ),
1054         (conf.CheckMkdirOneArg(),
1055             'MKDIR_TAKES_ONE_ARG',
1056             'Define if mkdir takes only one argument.'
1057         ),
1058         (conf.CheckIconvConst(),
1059             'ICONV_CONST',
1060             'Define as const if the declaration of iconv() needs const.',
1061             '#define ICONV_CONST const',
1062             '#define ICONV_CONST',
1063         ),
1064         (conf.CheckLC_MESSAGES(),
1065             'HAVE_LC_MESSAGES',
1066             'Define if your <locale.h> file defines LC_MESSAGES.'
1067         ),
1068         (devel_version, 'DEVEL_VERSION', 'Whether or not a development version'),
1069         (env['nls'],
1070             'ENABLE_NLS',
1071             "Define to 1 if translation of program messages to the user's native anguage is requested.",
1072         ),
1073         (env['nls'] and not included_gettext,
1074             'HAVE_GETTEXT',
1075             'Define to 1 if using system gettext library'
1076         ),
1077         (env.has_key('warnings') and env['warnings'],
1078             'WITH_WARNINGS',
1079             'Define this if you want to see the warning directives put here and there by the developpers to get attention'
1080         ),
1081         (env.has_key('concept_checks') and env['concept_checks'],
1082             '_GLIBCXX_CONCEPT_CHECKS',
1083             'libstdc++ concept checking'
1084         ),
1085         (env.has_key('stdlib_debug') and env['stdlib_debug'],
1086             '_GLIBCXX_DEBUG',
1087             'libstdc++ debug mode'
1088         ),
1089         (env.has_key('stdlib_debug') and env['stdlib_debug'],
1090             '_GLIBCXX_DEBUG_PEDANTIC',
1091             'libstdc++ pedantic debug mode'
1092         ),
1093         (os.name != 'nt', 'BOOST_POSIX',
1094             'Indicates to boost < 1.34 which API to use (posix or windows).'
1095         ),
1096         (os.name != 'nt', 'BOOST_POSIX_API',
1097             'Indicates to boost 1.34 which API to use (posix or windows).'
1098         ),
1099         (os.name != 'nt', 'BOOST_POSIX_PATH',
1100             'Indicates to boost 1.34 which path style to use (posix or windows).'
1101         ),
1102         (spell_engine is not None, spell_engine,
1103             'Spell engine to use'
1104         ),
1105         # we need to know the byte order for unicode conversions
1106         (sys.byteorder == 'big', 'WORDS_BIGENDIAN',
1107             'Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX).'
1108         ),
1109     ],
1110     extra_items = [
1111         ('#define PACKAGE "%s%s"' % (package, program_suffix),
1112             'Name of package'),
1113         ('#define PACKAGE_BUGREPORT "%s"' % package_bugreport,
1114             'Define to the address where bug reports for this package should be sent.'),
1115         ('#define PACKAGE_NAME "%s"' % package_name,
1116             'Define to the full name of this package.'),
1117         ('#define PACKAGE_STRING "%s"' % package_string,
1118             'Define to the full name and version of this package.'),
1119         ('#define PACKAGE_TARNAME "%s"' % package_tarname,
1120             'Define to the one symbol short name of this package.'),
1121         ('#define PACKAGE_VERSION "%s"' % package_version,
1122             'Define to the version of this package.'),
1123         ('#define BOOST_ALL_NO_LIB 1',
1124             'disable automatic linking of boost libraries.'),
1125         ('#define USE_%s_PACKAGING 1' % packaging_method.upper(),
1126             'Packaging method'),
1127         ('#define AIKSAURUS_H_LOCATION ' + aik_location,
1128             'Aiksaurus include file'),
1129         ('#define SELECT_TYPE_ARG1 %s' % select_arg1,
1130             "Define to the type of arg 1 for `select'."),
1131         ('#define SELECT_TYPE_ARG234 %s' % select_arg234,
1132             "Define to the type of arg 2, 3, 4 for `select'."),
1133         ('#define SELECT_TYPE_ARG5 %s' % select_arg5,
1134             "Define to the type of arg 5 for `select'."),
1135         ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1136             'Define to be the size of type wchar_t'),
1137     ],
1138     config_post = '''/************************************************************
1139 ** You should not need to change anything beyond this point */
1140
1141 #ifndef HAVE_STRERROR
1142 #if defined(__cplusplus)
1143 extern "C"
1144 #endif
1145 char * strerror(int n);
1146 #endif
1147
1148 #ifdef HAVE_MKSTEMP
1149 #ifndef HAVE_DECL_MKSTEMP
1150 #if defined(__cplusplus)
1151 extern "C"
1152 #endif
1153 int mkstemp(char*);
1154 #endif
1155 #endif
1156
1157 #include <../boost/config.h>
1158
1159 #endif
1160 '''
1161 )
1162
1163 # these keys are needed in env
1164 for key in ['USE_ASPELL', 'USE_PSPELL', 'USE_ISPELL', 'HAVE_FCNTL',\
1165     'HAVE_LIBGDI32', 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB']:
1166     # USE_ASPELL etc does not go through result
1167     if result.has_key(key):
1168         env[key] = result[key]
1169
1170 #
1171 # if nls=yes and gettext=included, create intl/config.h
1172 # intl/libintl.h etc
1173 #
1174 intl_config_h = os.path.join(env.Dir('$BUILDDIR/intl').path, 'config.h')
1175 if env['nls'] and included_gettext:
1176     #
1177     print "Creating %s..." % intl_config_h
1178     #
1179     # create intl/config.h
1180     result = utils.createConfigFile(conf,
1181         config_file = intl_config_h,
1182         config_pre = '''/* intl/config.h.  Generated by SCons.  */
1183
1184 /* -*- C++ -*- */
1185 /*
1186 * \file config.h
1187 * This file is part of LyX, the document processor.
1188 * Licence details can be found in the file COPYING.
1189 *
1190 * This is the compilation configuration file for LyX.
1191 * It was generated by scon.
1192 * You might want to change some of the defaults if something goes wrong
1193 * during the compilation.
1194 */
1195
1196 #ifndef _CONFIG_H
1197 #define _CONFIG_H
1198 ''',
1199         headers = [
1200             ('unistd.h', 'HAVE_UNISTD_H', 'c'),
1201             ('inttypes.h', 'HAVE_INTTYPES_H', 'c'),
1202             ('string.h', 'HAVE_STRING_H', 'c'),
1203             ('strings.h', 'HAVE_STRINGS_H', 'c'),
1204             ('argz.h', 'HAVE_ARGZ_H', 'c'),
1205             ('limits.h', 'HAVE_LIMITS_H', 'c'),
1206             ('alloca.h', 'HAVE_ALLOCA_H', 'c'),
1207             ('stddef.h', 'HAVE_STDDEF_H', 'c'),
1208             ('stdint.h', 'HAVE_STDINT_H', 'c'),
1209             ('sys/param.h', 'HAVE_SYS_PARAM_H', 'c'),
1210         ],
1211         functions = [
1212             ('getcwd', 'HAVE_GETCWD', None),
1213             ('stpcpy', 'HAVE_STPCPY', None),
1214             ('strcasecmp', 'HAVE_STRCASECMP', None),
1215             ('strdup', 'HAVE_STRDUP', None),
1216             ('strtoul', 'HAVE_STRTOUL', None),
1217             ('alloca', 'HAVE_ALLOCA', None),
1218             ('__fsetlocking', 'HAVE___FSETLOCKING', None),
1219             ('mempcpy', 'HAVE_MEMPCPY', None),
1220             ('__argz_count', 'HAVE___ARGZ_COUNT', None),
1221             ('__argz_next', 'HAVE___ARGZ_NEXT', None),
1222             ('__argz_stringify', 'HAVE___ARGZ_STRINGIFY', None),
1223             ('setlocale', 'HAVE_SETLOCALE', None),
1224             ('tsearch', 'HAVE_TSEARCH', None),
1225             ('getegid', 'HAVE_GETEGID', None),
1226             ('getgid', 'HAVE_GETGID', None),
1227             ('getuid', 'HAVE_GETUID', None),
1228             ('wcslen', 'HAVE_WCSLEN', None),
1229             ('asprintf', 'HAVE_ASPRINTF', None),
1230             ('wprintf', 'HAVE_WPRINTF', None),
1231             ('snprintf', 'HAVE_SNPRINTF', None),
1232             ('printf', 'HAVE_POSIX_PRINTF', None),
1233             ('fcntl', 'HAVE_FCNTL', None),
1234         ],
1235         types = [
1236             ('intmax_t', 'HAVE_INTMAX_T', None),
1237             ('long double', 'HAVE_LONG_DOUBLE', None),
1238             ('long long', 'HAVE_LONG_LONG', None),
1239             ('wchar_t', 'HAVE_WCHAR_T', None),
1240             ('wint_t', 'HAVE_WINT_T', None),
1241             ('uintmax_t', 'HAVE_INTTYPES_H_WITH_UINTMAX', '#include <inttypes.h>'),
1242             ('uintmax_t', 'HAVE_STDINT_H_WITH_UINTMAX', '#include <stdint.h>'),
1243         ],
1244         libs = [
1245             ('c', 'HAVE_LIBC'),
1246         ],
1247         custom_tests = [
1248             (conf.CheckLC_MESSAGES(),
1249                 'HAVE_LC_MESSAGES',
1250                 'Define if your <locale.h> file defines LC_MESSAGES.'
1251             ),
1252             (conf.CheckIconvConst(),
1253                 'ICONV_CONST',
1254                 'Define as const if the declaration of iconv() needs const.',
1255                 '#define ICONV_CONST const',
1256                 '#define ICONV_CONST',
1257             ),
1258             (conf.CheckType('intmax_t', includes='#include <stdint.h>') or \
1259             conf.CheckType('intmax_t', includes='#include <inttypes.h>'),
1260                 'HAVE_INTMAX_T',
1261                 "Define to 1 if you have the `intmax_t' type."
1262             ),
1263             (env.has_key('nls') and env['nls'],
1264                 'ENABLE_NLS',
1265                 "Define to 1 if translation of program messages to the user's native anguage is requested.",
1266             ),
1267         ],
1268         extra_items = [
1269             ('#define HAVE_ICONV 1', 'Define if iconv or libiconv is found'),
1270             ('#define SIZEOF_WCHAR_T %d' % sizeof_wchar_t,
1271                 'Define to be the size of type wchar_t'),
1272         ],
1273         config_post = '#endif'
1274     )
1275
1276     # these keys are needed in env
1277     for key in ['HAVE_ASPRINTF', 'HAVE_WPRINTF', 'HAVE_SNPRINTF', \
1278         'HAVE_POSIX_PRINTF', 'HAVE_LIBC']:
1279         # USE_ASPELL etc does not go through result
1280         if result.has_key(key):
1281             env[key] = result[key]
1282
1283
1284 # this looks misplaced, but intl/libintl.h is needed by src/message.C
1285 if env['nls'] and included_gettext:
1286     # libgnuintl.h.in => libintl.h
1287     env.Depends('$TOP_SRCDIR/intl/libintl.h', '$BUILDDIR/intl/config.h')
1288     env.substFile('$BUILDDIR/intl/libintl.h', '$TOP_SRCDIR/intl/libgnuintl.h.in')
1289     env.Command('$BUILDDIR/intl/libgnuintl.h', '$BUILDDIR/intl/libintl.h',
1290         [Copy('$TARGET', '$SOURCE')])
1291
1292 #
1293 # Finish auto-configuration
1294 env = conf.Finish()
1295
1296 #----------------------------------------------------------
1297 # Now set up our build process accordingly
1298 #----------------------------------------------------------
1299
1300
1301
1302 if env['ICONV_LIB'] is None:
1303     system_libs = []
1304 else:
1305     system_libs = [env['ICONV_LIB']]
1306 if platform_name in ['win32', 'cygwin']:
1307     # the final link step needs stdc++ to succeed under mingw
1308     # FIXME: shouldn't g++ automatically link to stdc++?
1309     if use_vc:
1310         system_libs += ['ole32', 'shlwapi', 'shell32', 'advapi32', 'zdll']
1311     else:
1312         system_libs += ['shlwapi', 'stdc++', 'z']
1313 elif platform_name == 'cygwin' and env['X11']:
1314     system_libs += ['GL',  'Xmu', 'Xi', 'Xrender', 'Xrandr',
1315         'Xcursor', 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 
1316         'resolv', 'pthread', 'z']
1317 else:
1318     system_libs += ['z']
1319
1320 libs = [
1321     ('HAVE_LIBGDI32', 'gdi32'),
1322     ('HAVE_LIBAIKSAURUS', env['AIKSAURUS_LIB']),
1323     ('USE_ASPELL', aspell_lib),
1324     ('USE_ISPELL', 'ispell'),
1325     ('USE_PSPELL', 'pspell'),
1326 ]
1327
1328 for lib in libs:
1329     if env[lib[0]]:
1330         system_libs.append(lib[1])
1331
1332 #
1333 # Build parameters CPPPATH etc
1334 #
1335 if env['X11']:
1336     env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
1337
1338 #
1339 # boost: for boost header files
1340 # BUILDDIR/common: for config.h
1341 # TOP_SRCDIR/src: for support/* etc
1342 #
1343 env['CPPPATH'] += ['$BUILDDIR/common', '$TOP_SRCDIR/src']
1344 #
1345 # Separating boost directories from CPPPATH stops scons from building
1346 # the dependency tree for boost header files, and effectively reduce
1347 # the null build time of lyx from 29s to 16s. Since lyx may tweak local
1348 # boost headers, this is only done for system boost headers.
1349 if included_boost:
1350     env.AppendUnique(CPPPATH = ['$BOOST_INC_PATH'])
1351 else:
1352     if use_vc:
1353         env.PrependUnique(CCFLAGS = ['/I$BOOST_INC_PATH'])
1354     else:
1355         env.PrependUnique(CCFLAGS = ['-I$BOOST_INC_PATH'])
1356
1357 # for intl/config.h, intl/libintl.h and intl/libgnuintl.h
1358 if env['nls'] and included_gettext:
1359     env['CPPPATH'].append('$BUILDDIR/intl')
1360 #
1361 # QT_INC_PATH is not needed for *every* source file
1362 if qt_inc_path is not None:
1363     env['CPPPATH'].remove(qt_inc_path)
1364
1365 #
1366 # A Link script for cygwin see
1367 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
1368 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
1369 # for details
1370 #
1371 if platform_name == 'cygwin':
1372     ld_script_path = '/tmp'
1373     ld_script = utils.installCygwinLDScript(ld_script_path)
1374     env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc',
1375         '-Wl,--script,%s' % ld_script, '-Wl,-s'])
1376
1377 #
1378 # Report results
1379 #
1380 # fill in the version info
1381 env['VERSION_INFO'] = '''Configuration
1382   Host type:                      %s
1383   Special build flags:            %s
1384   C   Compiler:                   %s
1385   C   Compiler flags:             %s %s
1386   C++ Compiler:                   %s
1387   C++ Compiler LyX flags:         %s
1388   C++ Compiler flags:             %s %s
1389   Linker flags:                   %s
1390   Linker user flags:              %s
1391 Build info:
1392   Builing directory:              %s
1393   Local library directory:        %s
1394   Libraries paths:                %s
1395   Boost libraries:                %s
1396   Frontend libraries:             %s
1397   System libraries:               %s
1398   include search path:            %s
1399 Frontend:
1400   Frontend:                       %s
1401   Packaging:                      %s
1402   LyX dir:                        %s
1403   LyX files dir:                  %s
1404 ''' % (platform_name,
1405     env.subst('$CCFLAGS'), env.subst('$CC'),
1406     env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
1407     env.subst('$CXX'), env.subst('$CXXFLAGS'),
1408     env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
1409     env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
1410     env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
1411     str(env['LIBPATH']), str(boost_libraries),
1412     str(frontend_libs), str(system_libs), str(env['CPPPATH']),
1413     frontend, packaging_method,
1414     prefix, env['LYX_DIR'])
1415
1416 if frontend in ['qt4']:
1417     env['VERSION_INFO'] += '''  include dir:                    %s
1418   library dir:                    %s
1419   X11:                            %s
1420 ''' % (qt_inc_path, qt_lib_path, env['X11'])
1421
1422 print env['VERSION_INFO']
1423
1424 #
1425 # Mingw command line may be too short for our link usage,
1426 # Here we use a trick from scons wiki
1427 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
1428 #
1429 # I also would like to add logging (commands only) capacity to the
1430 # spawn system.
1431 logfile = env.get('logfile', default_log_file)
1432 if logfile != '' or platform_name == 'win32':
1433     import time
1434     utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
1435         info = '''# This is a log of commands used by scons to build lyx
1436 # Time: %s
1437 # Command: %s
1438 # Info: %s
1439 ''' % (time.asctime(), ' '.join(sys.argv),
1440     env['VERSION_INFO'].replace('\n','\n# ')) )
1441
1442
1443 # Cleanup stuff
1444 #
1445 # -h will print out help info
1446 Help(opts.GenerateHelpText(env))
1447
1448
1449
1450 #----------------------------------------------------------
1451 # Start building
1452 #----------------------------------------------------------
1453 # this has been the source of problems on some platforms...
1454 # I find that I need to supply it with full path name
1455 env.SConsignFile(os.path.join(Dir(env['BUILDDIR']).abspath, '.sconsign'))
1456 # this usage needs further investigation.
1457 #env.CacheDir('%s/Cache/%s' % (env['BUILDDIR'], frontend))
1458
1459 print "Building all targets recursively"
1460
1461 if env.has_key('rebuild'):
1462     rebuild_targets = env['rebuild'].split(',')
1463     if 'none' in rebuild_targets or 'no' in rebuild_targets:
1464         rebuild_targets = []
1465     elif 'all' in rebuild_targets or 'yes' in rebuild_targets:
1466         # None: let scons decide which components to build
1467         # Forcing all components to be rebuilt is in theory not necessary
1468         rebuild_targets = None    
1469 else:
1470     rebuild_targets = None
1471
1472 def libExists(libname):
1473     ''' Check whether or not lib $LOCALLIBNAME/libname already exists'''
1474     return os.path.isfile(File(env.subst('$LOCALLIBPATH/${LIBPREFIX}%s$LIBSUFFIX'%libname)).abspath)
1475
1476 def appExists(apppath, appname):
1477     ''' Check whether or not application already exists'''
1478     return os.path.isfile(File(env.subst('$BUILDDIR/common/%s/${PROGPREFIX}%s$PROGSUFFIX' % (apppath, appname))).abspath)
1479
1480 targets = BUILD_TARGETS
1481 # msvc need to pass full target name, so I have to look for path/lyx etc
1482 build_lyx = targets == [] or True in ['lyx' in x for x in targets] \
1483     or 'install' in targets or 'all' in targets
1484 build_boost = (included_boost and not libExists('boost_regex')) or 'boost' in targets
1485 build_intl = (included_gettext and not libExists('included_intl')) or 'intl' in targets
1486 build_support = build_lyx or True in [x in targets for x in ['support', 'client', 'tex2lyx']]
1487 build_mathed = build_lyx or 'mathed' in targets
1488 build_insets = build_lyx or 'insets' in targets
1489 build_frontends = build_lyx or 'frontends' in targets
1490 build_graphics = build_lyx or 'graphics' in targets
1491 build_controllers = build_lyx or 'controllers' in targets
1492 build_client = True in ['client' in x for x in targets] \
1493     or 'install' in targets or 'all' in targets
1494 build_tex2lyx = True in ['tex2lyx' in x for x in targets] \
1495     or 'install' in targets or 'all' in targets
1496 build_lyxbase = build_lyx or 'lyxbase' in targets
1497 build_po = 'po' in targets or 'install' in targets or 'all' in targets
1498 build_qt4 = (build_lyx and frontend == 'qt4') or 'qt4' in targets
1499 build_msvs_projects = use_vc and 'msvs_projects' in targets
1500
1501
1502 # now, if rebuild_targets is specified, do not rebuild some targets
1503 if rebuild_targets is not None:
1504     #
1505     def ifBuildLib(name, libname, old_value):
1506         # explicitly asked to rebuild
1507         if name in rebuild_targets:
1508             return True
1509         # else if not rebuild, and if the library already exists
1510         elif libExists(libname):
1511             return False
1512         # do not change the original value
1513         else:
1514             return old_value
1515     build_boost = ifBuildLib('boost', 'included_boost_filesystem', build_boost)
1516     build_intl = ifBuildLib('intl', 'included_intl', build_intl)
1517     build_support = ifBuildLib('support', 'support', build_support)
1518     build_mathed = ifBuildLib('mathed', 'mathed', build_mathed)
1519     build_insets = ifBuildLib('insets', 'insets', build_insets)
1520     build_frontends = ifBuildLib('frontends', 'frontends', build_frontends)
1521     build_graphics = ifBuildLib('graphics', 'graphics', build_graphics)
1522     build_controllers = ifBuildLib('controllers', 'controllers', build_controllers)
1523     build_lyxbase = ifBuildLib('lyxbase', 'lyxbase_pre', build_lyxbase)
1524     build_qt4 = ifBuildLib('qt4', 'qt4', build_qt4)
1525     #
1526     def ifBuildApp(name, appname, old_value):
1527         # explicitly asked to rebuild
1528         if name in rebuild_targets:
1529             return True
1530         # else if not rebuild, and if the library already exists
1531         elif appExists(name, appname):
1532             return False
1533         # do not change the original value
1534         else:
1535             return old_value
1536     build_tex2lyx = ifBuildApp('tex2lyx', 'tex2lyx', build_tex2lyx)
1537     build_client = ifBuildApp('client', 'lyxclient', build_client)
1538
1539 # sync frontend and frontend (?)
1540 if build_qt4:
1541     frontend = 'qt4'
1542
1543
1544 if build_boost:
1545     #
1546     # boost libraries
1547     #
1548     # special builddir
1549     env.BuildDir('$BUILDDIR/boost', '$TOP_SRCDIR/boost/libs', duplicate = 0)
1550
1551     boostenv = env.Copy()
1552     #
1553     # boost use its own config.h
1554     boostenv['CPPPATH'] = ['$TOP_SRCDIR/boost', '$BUILDDIR/boost'] + extra_inc_paths
1555     boostenv.AppendUnique(CCFLAGS = ['-DBOOST_USER_CONFIG="<config.h>"'])
1556
1557     for lib in boost_libs:
1558         print 'Processing files in boost/libs/%s/src...' % lib
1559         boostlib = boostenv.StaticLibrary(
1560             target = '$LOCALLIBPATH/included_boost_%s' % lib,
1561             source = ['$BUILDDIR/boost/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)]
1562         )
1563         Alias('boost', boostlib)
1564
1565
1566 if build_intl:
1567     #
1568     # intl
1569     #
1570     intlenv = env.Copy()
1571
1572     print "Processing files in intl..."
1573
1574     env.BuildDir('$BUILDDIR/intl', '$TOP_SRCDIR/intl', duplicate = 0)
1575
1576     # we need the original C compiler for these files
1577     intlenv['CC'] = C_COMPILER
1578     intlenv['CCFLAGS'] = C_CCFLAGS
1579     if use_vc:
1580         intlenv.Append(CCFLAGS=['/Dinline#', '/D__attribute__(x)#', '/Duintmax_t=UINT_MAX'])
1581     # intl does not use global config.h
1582     intlenv['CPPPATH'] = ['$BUILDDIR/intl'] + extra_inc_paths
1583
1584     intlenv.Append(CCFLAGS = [
1585         r'-DLOCALEDIR=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1586         r'-DLOCALE_ALIAS_PATH=\"' + env['LOCALEDIR'].replace('\\', '\\\\') + r'\"',
1587         r'-DLIBDIR=\"' + env['TOP_SRCDIR'].replace('\\', '\\\\') + r'/lib\"',
1588         '-DIN_LIBINTL',
1589         '-DENABLE_RELOCATABLE=1',
1590         '-DIN_LIBRARY',
1591         r'-DINSTALLDIR=\"' + prefix.replace('\\', '\\\\') + r'/lib\"',
1592         '-DNO_XMALLOC',
1593         '-Dset_relocation_prefix=libintl_set_relocation_prefix',
1594         '-Drelocate=libintl_relocate',
1595         '-DDEPENDS_ON_LIBICONV=1',
1596         '-DHAVE_CONFIG_H'
1597         ]
1598     )
1599
1600     intl = intlenv.StaticLibrary(
1601         target = '$LOCALLIBPATH/included_intl',
1602         LIBS = ['c'],
1603         source = ['$BUILDDIR/intl/%s' % x for x in intl_files]
1604     )
1605     Alias('intl', intl)
1606
1607
1608 #
1609 # Now, src code under src/
1610 #
1611 env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1612
1613
1614 if build_support:
1615     #
1616     # src/support
1617     #
1618     print "Processing files in src/support..."
1619
1620     env.Depends('$BUILDDIR/common/support/package.C', '$BUILDDIR/common/config.h')
1621     env.substFile('$BUILDDIR/common/support/package.C', '$TOP_SRCDIR/src/support/package.C.in')
1622
1623     if qt_inc_path is None:
1624         qt_CPPPATH = ['QtCore']
1625     else:
1626         qt_CPPPATH = [qt_inc_path, os.path.join(qt_inc_path, 'QtCore')]
1627
1628     support = env.StaticLibrary(
1629         target = '$LOCALLIBPATH/support',
1630         source = ['$BUILDDIR/common/support/%s' % x for x in src_support_files],
1631         CPPPATH = ['$CPPPATH'] + qt_CPPPATH
1632     )
1633     Alias('support', support)
1634
1635
1636 if build_mathed:
1637     #
1638     # src/mathed
1639     #
1640     print "Processing files in src/mathed..."
1641     #
1642     mathed = env.StaticLibrary(
1643         target = '$LOCALLIBPATH/mathed',
1644         source = ['$BUILDDIR/common/mathed/%s' % x for x in src_mathed_files]
1645     )
1646     Alias('mathed', mathed)
1647
1648
1649 if build_insets:
1650     #
1651     # src/insets
1652     #
1653     print "Processing files in src/insets..."
1654     #
1655     insets = env.StaticLibrary(
1656         target = '$LOCALLIBPATH/insets',
1657         source = ['$BUILDDIR/common/insets/%s' % x for x in src_insets_files]
1658     )
1659     Alias('insets', insets)
1660
1661
1662 if build_frontends:
1663     #
1664     # src/frontends
1665     #
1666     print "Processing files in src/frontends..."
1667
1668     frontends = env.StaticLibrary(
1669         target = '$LOCALLIBPATH/frontends',
1670         source = ['$BUILDDIR/common/frontends/%s' % x for x in src_frontends_files]
1671     )
1672     Alias('frontends', frontends)
1673
1674
1675 if build_graphics:
1676     #
1677     # src/graphics
1678     #
1679     print "Processing files in src/graphics..."
1680
1681     graphics = env.StaticLibrary(
1682         target = '$LOCALLIBPATH/graphics',
1683         source = ['$BUILDDIR/common/graphics/%s' % x for x in src_graphics_files]
1684     )
1685     Alias('graphics', graphics)
1686
1687
1688 if build_controllers:
1689     #
1690     # src/frontends/controllers
1691     #
1692     print "Processing files in src/frontends/controllers..."
1693
1694     controllers = env.StaticLibrary(
1695         target = '$LOCALLIBPATH/controllers',
1696         source = ['$BUILDDIR/common/frontends/controllers/%s' % x for x in src_frontends_controllers_files]
1697     )
1698     Alias('controllers', controllers)
1699
1700
1701 #
1702 # src/frontend/qt4
1703 #
1704 if build_qt4:
1705     env.BuildDir('$BUILDDIR/$frontend', '$TOP_SRCDIR/src/frontend/$frontend', duplicate = 0)
1706
1707     print "Processing files in src/frontends/qt4..."
1708
1709     qt4env = env.Copy()
1710     qt4env['QT_AUTOSCAN'] = 0
1711
1712     # local qt4 toolset from
1713     # http://www.iua.upf.es/~dgarcia/Codders/sconstools.html
1714     #
1715     # NOTE: I have to patch qt4.py since it does not automatically
1716     # process .C file!!! (add to cxx_suffixes )
1717     #
1718     qt4env.Tool('qt4', [scons_dir])
1719     qt4env.EnableQt4Modules(qt_libs, debug = (mode == 'debug' and use_qt_debug_libs))
1720     qt4env['QT4_AUTOSCAN'] = 0
1721     qt4env['QT4_UICDECLFLAGS'] = '-tr lyx::qt_'
1722
1723     qt4env.AppendUnique(CPPPATH = [
1724         '$BUILDDIR/common',
1725         '$BUILDDIR/common/images',
1726         '$BUILDDIR/common/frontends',
1727         '$BUILDDIR/common/frontends/qt4',
1728         '$BUILDDIR/common/frontends/controllers',
1729         qt_inc_path
1730         ]
1731     )
1732
1733     # FIXME: replace by something from pkg_config
1734     qt4env.Append(CCFLAGS = [
1735         '-DHAVE_CONFIG_H',
1736         '-DQT_CLEAN_NAMESPACE',
1737         '-DQT_GENUINE_STR',
1738         '-DQT_NO_STL',
1739         '-DQT_NO_KEYWORDS',
1740         ]
1741     )
1742
1743
1744     qt4_moc_files = ["$BUILDDIR/common/frontends/qt4/%s" % x for x in src_frontends_qt4_moc_files]
1745
1746     #
1747     # Compile resources
1748     #
1749     resources = [qt4env.Uic4(x.split('.')[0]) for x in \
1750         ["$BUILDDIR/common/frontends/qt4/ui/%s" % x for x in src_frontends_qt4_ui_files]]
1751
1752     #
1753     # moc qt4_moc_files, the moced files are included in the original files
1754     #
1755     qt4_moced_files = [qt4env.Moc4(x.replace('.C', '_moc.cpp'), x.replace('.C', '.h')) for x in qt4_moc_files]
1756
1757     qt4 = qt4env.StaticLibrary(
1758         target = '$LOCALLIBPATH/qt4',
1759         source = ['$BUILDDIR/common/frontends/qt4/%s' % x for x in src_frontends_qt4_files]
1760     )
1761     Alias('qt4', qt4)
1762
1763
1764 if build_client:
1765     #
1766     # src/client
1767     #
1768     env.BuildDir('$BUILDDIR/common', '$TOP_SRCDIR/src', duplicate = 0)
1769
1770     print "Processing files in src/client..."
1771
1772     if env['HAVE_FCNTL']:
1773         client = env.Program(
1774             target = '$BUILDDIR/common/client/lyxclient',
1775             LIBS = ['support'] + intl_libs + system_libs +
1776                 socket_libs + boost_libraries + qtcore_lib,
1777             source = ['$BUILDDIR/common/client/%s' % x for x in src_client_files]
1778         )
1779         Alias('client', env.Command(os.path.join('$BUILDDIR', os.path.split(str(client[0]))[1]),
1780             client, [Copy('$TARGET', '$SOURCE')]))
1781     else:
1782         client = None
1783     Alias('client', client)
1784 else:
1785     if env['HAVE_FCNTL']:
1786         # define client even if lyxclient is not built with rebuild=no
1787         client = [env.subst('$BUILDDIR/common/client/${PROGPREFIX}lyxclient$PROGSUFFIX')]
1788     else:
1789         client = None
1790
1791
1792 if build_tex2lyx:
1793     #
1794     # tex2lyx
1795     #
1796     print "Processing files in src/tex2lyx..."
1797
1798     tex2lyx_env = env.Copy()
1799     #
1800     tex2lyx_env.Prepend(CPPPATH = ['$BUILDDIR/common/tex2lyx'])
1801     tex2lyx_env.AppendUnique(LIBPATH = ['#$LOCALLIBPATH'])
1802
1803     for file in ['FloatList.C', 'Floating.C', 'counters.C', 'lyxlayout.h', 'lyxlayout.C', 
1804         'lyxtextclass.h', 'lyxtextclass.C', 'lyxlex.C', 'lyxlex_pimpl.C']:
1805         env.Command('$BUILDDIR/common/tex2lyx/'+file, '$TOP_SRCDIR/src/'+file,
1806             [Copy('$TARGET', '$SOURCE')])
1807
1808     tex2lyx = tex2lyx_env.Program(
1809         target = '$BUILDDIR/common/tex2lyx/tex2lyx',
1810         LIBS = ['support'] + boost_libraries + intl_libs + system_libs + qtcore_lib,
1811         source = ['$BUILDDIR/common/tex2lyx/%s' % x for x in src_tex2lyx_files]
1812     )
1813     Alias('tex2lyx', env.Command(os.path.join('$BUILDDIR', os.path.split(str(tex2lyx[0]))[1]),
1814         tex2lyx, [Copy('$TARGET', '$SOURCE')]))
1815     Alias('tex2lyx', tex2lyx)
1816 else:
1817     # define tex2lyx even if tex2lyx is not built with rebuild=no
1818     tex2lyx = [env.subst('$BUILDDIR/common/tex2lyx/${PROGPREFIX}tex2lyx$PROGSUFFIX')]
1819
1820
1821 if build_lyxbase:
1822     #
1823     # src/
1824     #
1825     print "Processing files in src..."
1826
1827     env.Depends('$BUILDDIR/common/version.C', '$BUILDDIR/common/config.h')
1828     env.substFile('$BUILDDIR/common/version.C', '$TOP_SRCDIR/src/version.C.in')
1829
1830     if env.has_key('USE_ASPELL') and env['USE_ASPELL']:
1831         src_post_files.append('aspell.C')
1832     elif env.has_key('USE_PSPELL') and env['USE_PSPELL']:
1833         src_post_files.append('pspell.C')
1834     elif env.has_key('USE_ISPELL') and env['USE_ISPELL']:
1835         src_post_files.append('ispell.C')
1836
1837     # msvc requires at least one source file with main()
1838     # so I exclude main.C from lyxbase
1839     lyxbase_pre = env.StaticLibrary(
1840         target = '$LOCALLIBPATH/lyxbase_pre',
1841         source = ['$BUILDDIR/common/%s' % x for x in src_pre_files]
1842     )
1843     lyxbase_post = env.StaticLibrary(
1844         target = '$LOCALLIBPATH/lyxbase_post',
1845         source = ["$BUILDDIR/common/%s" % x for x in src_post_files]
1846     )
1847     Alias('lyxbase', lyxbase_pre)
1848     Alias('lyxbase', lyxbase_post)
1849
1850
1851 if build_lyx:
1852     #
1853     # Build lyx with given frontend
1854     #
1855     lyx = env.Program(
1856         target = '$BUILDDIR/lyx',
1857         source = ['$BUILDDIR/common/main.C'],
1858         LIBS = [
1859             'lyxbase_pre',
1860             'mathed',
1861             'insets',
1862             'frontends',
1863             frontend,
1864             'controllers',
1865             'graphics',
1866             'support',
1867             'lyxbase_post',
1868             ] +
1869             boost_libraries +
1870             frontend_libs +
1871             intl_libs +
1872             socket_libs +
1873             system_libs
1874     )
1875     Alias('lyx', lyx)
1876 else:
1877     # define lyx even if lyx is not built with rebuild=no
1878     lyx = [env.subst('$BUILDDIR/${PROGPREFIX}lyx$PROGSUFFIX')]
1879
1880
1881 if build_msvs_projects:
1882     def build_project(target, full_target = None,
1883         src = [], inc = [], res = [], rebuildTargetOnly = True):
1884         ''' build mavs project files
1885             target:      alias (correspond to directory name)
1886             full_target: full path/filename of the target
1887             src:         source files
1888             inc:         include files
1889             res:         resource files
1890             rebuildTargetOnly:     whether or not only rebuild this target
1891
1892         For non-debug-able targets like static libraries, target (alias) is
1893         enough to build the target. For executable targets, msvs need to know
1894         the full path to start debug them.
1895         '''
1896         if rebuildTargetOnly:
1897             cmds = 'rebuild='+target
1898         else:
1899             cmds = ''
1900         if full_target is None:
1901             build_target = target
1902         else:
1903             build_target = full_target
1904         # project
1905         proj = env.MSVSProject(
1906             target = target + env['MSVSPROJECTSUFFIX'],
1907             # this allows easy access to header files (along with source)
1908             srcs = [env.subst(x) for x in src + inc],
1909             incs = [env.subst('$TOP_SRCDIR/src/config.h')],
1910             localincs = [env.subst(x) for x in inc],
1911             resources = [env.subst(x) for x in res],
1912             buildtarget = build_target,
1913             cmdargs = cmds,
1914             variant = 'Debug'
1915         )
1916         Alias('msvs_projects', proj)
1917     #
1918     boost_src = []
1919     for lib in boost_libs:
1920         boost_src += ['$TOP_SRCDIR/boost/libs/%s/src/%s' % (lib, x) for x in eval('boost_libs_%s_src_files' % lib)]
1921     build_project('boost', src = boost_src)
1922     #
1923     build_project('intl', src = ['$TOP_SRCDIR/intl/%s' % x for x in intl_files], 
1924         inc = ['$TOP_SRCDIR/intl/%s' % x for x in intl_header_files])
1925     #
1926     build_project('support', src = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files], 
1927         inc = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files])
1928     #
1929     build_project('mathed', src = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files], 
1930         inc = ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files])
1931     #
1932     build_project('insets', src = ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files], 
1933         inc = ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files])
1934     #
1935     build_project('frontends', src = ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files], 
1936         inc = ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files])
1937     #
1938     build_project('graphics', src = ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files], 
1939         inc = ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files])
1940     #
1941     build_project('controllers', src = ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_files], 
1942         inc = ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files])
1943     #
1944     build_project('qt4', src = ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files + src_frontends_qt4_moc_files],
1945         inc = ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1946         res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files])
1947     #
1948     build_project('client', src = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_files],
1949         inc = ['$TOP_SRCDIR/src/client/%s' % x for x in src_client_header_files],
1950         rebuildTargetOnly = False,
1951         full_target = File(env.subst('$BUILDDIR/common/client/lyxclient$PROGSUFFIX')).abspath)
1952     #
1953     build_project('tex2lyx', src = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_files],
1954         inc = ['$TOP_SRCDIR/src/tex2lyx/%s' % x for x in src_tex2lyx_header_files],
1955         rebuildTargetOnly = False,
1956         full_target = File(env.subst('$BUILDDIR/common/tex2lyx/tex2lyx$PROGSUFFIX')).abspath)
1957     #
1958     build_project('lyxbase', src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files],
1959         inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files])
1960     build_project('lyx', 
1961         src = ['$TOP_SRCDIR/src/%s' % x for x in src_pre_files + src_post_files] + \
1962             ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_files] + \
1963             ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_files] + \
1964             ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_files] + \
1965             ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_files] + \
1966             ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_files] + \
1967             ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_files] + \
1968             ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_files + src_frontends_qt4_moc_files],
1969         inc = ['$TOP_SRCDIR/src/%s' % x for x in src_header_files] + \
1970             ['$TOP_SRCDIR/src/support/%s' % x for x in src_support_header_files] + \
1971             ['$TOP_SRCDIR/src/mathed/%s' % x for x in src_mathed_header_files] + \
1972             ['$TOP_SRCDIR/src/insets/%s' % x for x in src_insets_header_files] + \
1973             ['$TOP_SRCDIR/src/frontends/%s' % x for x in src_frontends_header_files] + \
1974             ['$TOP_SRCDIR/src/graphics/%s' % x for x in src_graphics_header_files] + \
1975             ['$TOP_SRCDIR/src/frontends/controllers/%s' % x for x in src_frontends_controllers_header_files] + \
1976             ['$TOP_SRCDIR/src/frontends/qt4/%s' % x for x in src_frontends_qt4_header_files],
1977         res = ['$TOP_SRCDIR/src/frontends/qt4/ui/%s' % x for x in src_frontends_qt4_ui_files],
1978         rebuildTargetOnly = False,
1979         full_target = File(env.subst('$BUILDDIR/lyx$PROGSUFFIX')).abspath)
1980
1981
1982 if build_po:
1983     #
1984     # po/
1985     #
1986     print 'Processing files in po...'
1987
1988     import glob
1989     # handle po files
1990     #
1991     # files to translate
1992     transfiles = glob.glob(os.path.join(env.subst('$TOP_SRCDIR'), 'po', '*.po'))
1993     # possibly *only* handle these languages
1994     languages = None
1995     if env.has_key('languages'):
1996         languages = env.make_list(env['lanauges'])
1997     # use defulat msgfmt
1998     gmo_files = []
1999     if not env['MSGFMT']:
2000         print 'msgfmt does not exist. Can not process po files'
2001     else:
2002         # create a builder
2003         env['BUILDERS']['Transfiles'] = Builder(action='$MSGFMT $SOURCE -o $TARGET',suffix='.gmo',src_suffix='.po')
2004         #
2005         for f in transfiles:
2006             # get filename
2007             fname = os.path.split(f)[1]
2008             # country code
2009             country = fname.split('.')[0]
2010             #
2011             if not languages or country in languages:
2012                 gmo_files.extend(env.Transfiles(f))
2013
2014
2015 if 'install' in targets:
2016     #
2017     # this part is a bit messy right now. Since scons will provide
2018     # --DESTDIR option soon, at least the dest_dir handling can be 
2019     # removed later.
2020     #
2021     # how to join dest_dir and prefix
2022     def joinPaths(path1, path2):
2023         ''' join path1 and path2, do not use os.path.join because
2024             under window, c:\destdir\d:\program is invalid '''
2025         if path1 == '':
2026             return os.path.normpath(path2)
2027         # separate drive letter
2028         (drive, path) = os.path.splitdrive(os.path.normpath(path2))
2029         # ignore drive letter, so c:\destdir + c:\program = c:\destdir\program
2030         return os.path.join(os.path.normpath(path1), path[1:])
2031     #
2032     # install to dest_dir/prefix
2033     dest_dir = env.get('DESTDIR', '')
2034     dest_prefix_dir = joinPaths(dest_dir, env.Dir(prefix).abspath)
2035     # create the directory if needed
2036     if not os.path.isdir(dest_prefix_dir):
2037         try:
2038             os.makedirs(dest_prefix_dir)
2039         except:
2040             pass
2041         if not os.path.isdir(dest_prefix_dir):
2042             print 'Can not create directory', dest_prefix_dir
2043             Exit(3)
2044     #
2045     if env.has_key('exec_prefix'):
2046         bin_dest_dir = joinPaths(dest_dir, Dir(env['exec_prefix']).abspath)
2047     else:
2048         bin_dest_dir = os.path.join(dest_prefix_dir, 'bin')
2049     if add_suffix:
2050         share_dest_dir = os.path.join(dest_prefix_dir, share_dir + program_suffix)
2051     else:
2052         share_dest_dir = os.path.join(dest_prefix_dir, share_dir)
2053     man_dest_dir = os.path.join(dest_prefix_dir, man_dir)
2054     locale_dest_dir = os.path.join(dest_prefix_dir, locale_dir)
2055     #
2056     import glob
2057     #
2058     # install executables (lyxclient may be None)
2059     #
2060     if add_suffix:
2061         version_suffix = program_suffix
2062     else:
2063         version_suffix = ''
2064     #
2065     # install lyx, if in release mode, try to strip the binary
2066     if env.has_key('STRIP') and env['STRIP'] is not None and mode != 'debug':
2067         # create a builder to strip and install
2068         env['BUILDERS']['StripInstallAs'] = Builder(action='$STRIP $SOURCE -o $TARGET')
2069
2070     # install executables
2071     for (name, obj) in (('lyx', lyx), ('tex2lyx', tex2lyx), ('client', client)):
2072         if obj is None:
2073             continue
2074         target_name = os.path.split(str(obj[0]))[1].replace(name, '%s%s' % (name, version_suffix))
2075         target = os.path.join(bin_dest_dir, target_name)
2076         if env['BUILDERS'].has_key('StripInstallAs'):
2077             env.StripInstallAs(target, obj)
2078         else:
2079             env.InstallAs(target, obj)
2080         Alias('install', target)
2081
2082     # share/lyx
2083     dirs = []
2084     for (dir,files) in [
2085             ('.', lib_files),  
2086             ('clipart', lib_clipart_files),
2087             ('examples', lib_examples_files),
2088             ('images', lib_images_files),
2089             ('images/math', lib_images_math_files),
2090             ('bind', lib_bind_files),
2091             ('kbd', lib_kbd_files),
2092             ('layouts', lib_layouts_files),
2093             ('scripts', lib_scripts_files),
2094             ('templates', lib_templates_files),
2095             ('tex', lib_tex_files),
2096             ('ui', lib_ui_files),
2097             ('doc', lib_doc_files),
2098             ('lyx2lyx', lib_lyx2lyx_files)]:
2099         dirs.append(env.Install(os.path.join(share_dest_dir, dir),
2100             [env.subst('$TOP_SRCDIR/lib/%s/%s' % (dir, file)) for file in files]))
2101     Alias('install', dirs)
2102     
2103     if platform_name == 'cygwin':
2104         # cygwin packaging requires a file /usr/share/doc/Cygwin/foot-vendor-suffix.README
2105         Cygwin_README = os.path.join(dest_prefix_dir, 'share', 'doc', 'Cygwin', 
2106             '%s-%s.README' % (package, package_cygwin_version))
2107         env.InstallAs(Cygwin_README,
2108             os.path.join(env.subst('$TOP_SRCDIR'), 'README.cygwin'))
2109         Alias('install', Cygwin_README)
2110         # also a directory /usr/share/doc/lyx for README etc
2111         Cygwin_Doc = os.path.join(dest_prefix_dir, 'share', 'doc', package)
2112         env.Install(Cygwin_Doc, [os.path.join(env.subst('$TOP_SRCDIR'), x) for x in \
2113             ['INSTALL', 'README', 'README.Cygwin', 'RELEASE-NOTES', 'COPYING', 'ANNOUNCE']])
2114         Alias('install', Cygwin_Doc)
2115         # cygwin fonts also need to be installed
2116         Cygwin_fonts = os.path.join(share_dest_dir, 'fonts')
2117         env.Install(Cygwin_fonts, 
2118             [env.subst('$TOP_SRCDIR/development/Win32/packaging/bakoma/%s' % file) \
2119                   for file in win32_bakoma_fonts])
2120         Alias('install', Cygwin_fonts)
2121         # we also need a post installation script
2122         tmp_script = utils.installCygwinPostinstallScript('/tmp')
2123         postinstall_path = os.path.join(dest_dir, 'etc', 'postinstall')
2124         env.Install(postinstall_path, tmp_script)
2125         Alias('install', postinstall_path)
2126
2127     # subst and install lyx2lyx_version.py which is not in scons_manifest.py
2128     env.Depends(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py', '$BUILDDIR/common/config.h')
2129     env.substFile(share_dest_dir + '/lyx2lyx/lyx2lyx_version.py',
2130         '$TOP_SRCDIR/lib/lyx2lyx/lyx2lyx_version.py.in')
2131     Alias('install', share_dest_dir + '/lyx2lyx/lyx2lyx_version.py')
2132
2133     # man
2134     env.InstallAs(os.path.join(man_dest_dir, 'lyx' + version_suffix + '.1'),
2135         env.subst('$TOP_SRCDIR/lyx.man'))
2136     env.InstallAs(os.path.join(man_dest_dir, 'tex2lyx' + version_suffix + '.1'),
2137         env.subst('$TOP_SRCDIR/src/tex2lyx/tex2lyx.man'))
2138     env.InstallAs(os.path.join(man_dest_dir, 'lyxclient' + version_suffix + '.1'),
2139         env.subst('$TOP_SRCDIR/src/client/lyxclient.man'))
2140     Alias('install', [os.path.join(man_dest_dir, x + version_suffix + '.1') for
2141         x in ['lyx', 'tex2lyx', 'lyxclient']])
2142     # locale files?
2143     # ru.gmo ==> ru/LC_MESSAGES/lyxSUFFIX.mo
2144     for gmo in gmo_files:
2145         lan = os.path.split(str(gmo))[1].split('.')[0]
2146         dest_file = os.path.join(locale_dest_dir, lan, 'LC_MESSAGES', 'lyx' + program_suffix + '.mo')
2147         env.InstallAs(dest_file, gmo)
2148         Alias('install', dest_file)
2149
2150
2151 Default('lyx')
2152 Alias('all', ['lyx', 'client', 'tex2lyx'])