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