]> git.lyx.org Git - features.git/blob - SConstruct
Scons: various fixes from Enrico (aspell, aikasurus etc), and correct handling of...
[features.git] / SConstruct
1 # vi:filetype=python:expandtab:tabstop=2:shiftwidth=2
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 #
12 # This is a scons based building system for lyx, you can use it as follows:
13 # (after of course installation of scons from www.scons.org)
14 #  
15 #    scons [frontend=qt3|gt4] [boost=included|auto] ...
16 #
17 # Where:
18 #   * use scons -h for details about parameters
19 #   * qt3 is used by default on linux, cygwin and mac
20 #   * qt4 is used by default on win32
21 #
22 # File layouts (Important):
23 #   * Unless you specify builddir=dir, building will happen
24 #     in $BUILDDIR = $mode/$platform-$frontend. E.g., something like
25 #       debug/linux-qt3/
26 #   * All shared libs will be put in $BUILDDIR/libs, e.g.
27 #       debug/linux-qt3/libs
28 #   * lyx executable will be in directories like debug/linux-qt3
29 #  
30 # Hints:
31 #   * scons --config=force
32 #     force re-configuration (use scons -H for details)
33 #   
34 #   * check config.log to see why config has failed
35 #
36 #   * use extra_inc_path, extra_lib_path, qt_dir, qt_inc_path
37 #     qt_lib_path to help locate qt and other libraries
38 #     (there are extra_inc_path1, extra_lib_path1 for now)
39 #
40 #   * (Important) use scons logfile=logfile.log to enable command line
41 #     logging. (default is no logging)
42 #
43 # Notes:
44 #   * Currently, all scons does is building lyx in
45 #       $LYXROOT/$mode/$build_dir/
46 #     where $mode is debug or release, $build_dir is the build_dir name 
47 #     listed above
48 #
49 #   * scons install etc may be added later. Interested contributors can follow
50 #       http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/AccumulateBuilder
51 #     or
52 #       http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/DistTarBuilder
53 #     Please also see the commented out code in scons_utils.py
54 #       
55 #   * NSIS support can be found here.
56 #     http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/NsisSconsTool
57 #
58 #   * rpm support?
59 #     http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/RpmHonchoTemp
60 #
61 #   However, I decide to wait since scons seems to be standardizing these
62 #   features.
63 #
64
65 import os, sys
66
67 # config/scons_utils.py defines a few utility function
68 sys.path.append('config')
69 import scons_utils as utils
70
71 SetOption('implicit_cache', 1)
72
73 #----------------------------------------------------------
74 # Required runtime environment
75 #----------------------------------------------------------
76
77 # FIXME: I remember lyx requires higher version of python?
78 EnsurePythonVersion(1, 5)
79 # Please use at least 0.96.91 (not 0.96.1)
80 EnsureSConsVersion(0, 96)
81
82 #----------------------------------------------------------
83 # Global definitions
84 #----------------------------------------------------------
85
86 # some global settings
87 PACKAGE_VERSION = '1.5.0svn'
88 DEVEL_VERSION = True
89 default_build_mode = 'debug'
90
91 PACKAGE = 'lyx'
92 PACKAGE_BUGREPORT = 'lyx-devel@lists.lyx.org'
93 PACKAGE_NAME = 'LyX'
94 PACKAGE_TARNAME = 'lyx'
95 PACKAGE_STRING = '%s %s' % (PACKAGE_NAME, PACKAGE_VERSION)
96 PROGRAM_SUFFIX = ''
97 default_log_file = 'scons_lyx.log'
98
99 # FIXME: what is this? (They are used in src/support/package.C.in
100 LOCALEDIR = "../locale/"
101 LYX_DIR = "/usr/local/share/lyx"
102
103 # platform dependent default build_dir and other settings
104 #
105 # I know, somebody would say: 
106 #   This is TOTALLY wrong! Everything should be automatically
107 #   determined.
108 #
109 if os.name == 'nt':
110   platform_name = 'win32'
111   default_frontend = 'qt4'
112   # boost and gettext are unlikely to be installed already
113   default_boost_opt = 'included'
114   default_gettext_opt = 'included'
115   default_pch_opt = False
116   default_with_x = False
117   spell_checker = 'auto'
118   # FIXME: I need to know what exactly is boost_posix
119   # EF: It indicates to boost which API to use (posix or windows).
120   # If not specified, boost tries to figure out by itself, but it may fail.
121   boost_posix = False
122   packaging_method = 'windows'
123 elif os.name == 'posix' and sys.platform != 'cygwin':
124   platform_name = sys.platform
125   default_frontend = 'qt3'
126   # try to use system boost/gettext libraries
127   default_boost_opt = 'auto'
128   default_gettext_opt = 'auto'
129   default_pch_opt = False
130   default_with_x = True
131   boost_posix = True
132   packaging_method = 'posix'
133 elif os.name == 'posix' and sys.platform == 'cygwin':
134   platform_name = 'cygwin'
135   default_frontend = 'qt3'
136   # force the use of cygwin/boost/gettext
137   default_boost_opt = 'system'
138   default_gettext_opt = 'system'
139   default_pch_opt = False
140   default_with_x = True
141   boost_posix = True
142   packaging_method = 'posix'
143 elif os.name == 'darwin':
144   platform_name = 'mac'
145   default_frontend = 'qt3'
146   # to be safe
147   default_boost_opt = 'included'
148   default_gettext_opt = 'included'
149   default_pch_opt = False
150   default_with_x = False
151   boost_posix = True
152   packaging_method = 'msc'
153 else:  # unsupported system
154   platform_name = 'others'
155   default_frontend = 'qt3'
156   # to be safe
157   default_boost_opt = 'included'
158   default_gettext_opt = 'included'
159   default_pch_opt = False
160   default_with_x = True
161   boost_posix = False
162   packaging_method = 'posix'
163
164 #---------------------------------------------------------
165 # Handling options
166 #----------------------------------------------------------
167 # Note that if you set the options via the command line, 
168 # they will be remembered in the file 'options.cache'
169
170 # NOTE: the scons people are trying to fix scons so that
171 # options like --prefix will be accepted. Right now,
172 # we have to use the KEY=VALUE style of scons
173
174 if os.path.isfile('options.cache'):
175   print "Getting options from auto-saved options.cache..."
176   print open('options.cache').read()
177 if os.path.isfile('config.py'):
178   print "Getting options from config.py..."
179   print open('config.py').read()
180
181 opts = Options(['options.cache', 'config.py'])
182 opts.AddOptions(
183   # frontend, 
184   EnumOption('frontend', 'Main GUI', 
185     default_frontend,
186     allowed_values = ('xform', 'qt3', 'qt4', 'gtk') ),
187   # debug or release build
188   EnumOption('mode', 'Building method', default_build_mode,
189     allowed_values = ('debug', 'release') ),
190   # boost libraries
191   EnumOption('boost', 
192     'Use included, system boost library, or try sytem first.', 
193     default_boost_opt,
194     allowed_values = (
195       'auto',       # detect boost, if not found, use included
196       'included',   # always use included boost
197       'system',     # always use system boost, fail if can not find
198       ) ),
199   EnumOption('gettext', 
200     'Use included, system gettext library, or try sytem first', 
201     default_gettext_opt,
202     allowed_values = (
203       'auto',       # detect gettext, if not found, use included
204       'included',   # always use included gettext
205       'system',     # always use system gettext, fail if can not find
206       ) ),
207   # FIXME: I am not allowed to use '' as default, '.' is not good either.
208   PathOption('qt_dir', 'Path to qt directory', '.'),
209   PathOption('qt_include_path', 'Path to qt include directory', '.'),
210   PathOption('qt_lib_path', 'Path to qt library directory', '.'),
211   # FIXME: I do not know how pch is working. Ignore this option now.
212   BoolOption('pch', '(NA) Whether or not use pch', default_pch_opt),
213   # FIXME: Not implemented yet.
214   BoolOption('version_suffix', '(NA) Whether or not add version suffix', False),
215   # build directory, will replace build_dir if set
216   PathOption('build_dir', 'Build directory', '.'),
217   # extra include and libpath
218   PathOption('extra_inc_path', 'Extra include path', '.'),
219   PathOption('extra_lib_path', 'Extra library path', '.'),
220   PathOption('extra_inc_path1', 'Extra include path', '.'),
221   PathOption('extra_lib_path1', 'Extra library path', '.'),
222   # enable assertion, (config.h has  ENABLE_ASSERTIOS
223   BoolOption('assertions', 'Use assertions', True),
224   # enable warning, (config.h has  WITH_WARNINGS)
225   BoolOption('warnings', 'Use warnings', True),
226   # enable glib, (config.h has  _GLIBCXX_CONCEPT_CHECKS)
227   BoolOption('concept_checks', 'Enable concept checks', True),
228   # FIXME: I do not know what is nls
229   BoolOption('nls', '(NA) Whether or not use native language support', False),
230   # FIXME: not implemented
231   BoolOption('profile', '(NA) Whether or not enable profiling', False),
232   # FIXME: not implemented
233   PathOption('prefix', '(NA) install architecture-independent files in PREFIX', '.'),
234   # FIXME: not implemented
235   PathOption('exec_prefix', '(NA) install architecture-independent executable files in PREFIX', '.'),
236   # FIXME: not implemented
237   BoolOption('std_debug', '(NA) Whether or not turn on stdlib debug', False),
238   # using x11?
239   BoolOption('X11', 'Use x11 windows system', default_with_x),
240   # FIXME: not implemented
241   BoolOption('libintl', '(NA) Use libintl library', False),
242   # FIXME: not implemented
243   PathOption('intl_prefix', '(NA) Path to intl library', '.'),
244   # log file
245   ('logfile', 'save commands (not outputs) to logfile', default_log_file),
246   # Path to aikasurus
247   PathOption('aikasurus_path', 'Path to aikasurus library', '.'),
248   #
249   EnumOption('spell', 'Choose spell checker to use.', 'auto',
250     allowed_values = ('aspell', 'pspell', 'ispell', 'auto') ),
251   # environment variable can be set as options
252   ('CC', '$CC', 'gcc'),
253   ('CPP', '$CPP', 'gcc -E'),
254   ('CXX', '$CXX', 'g++'),
255   ('CXXCPP', '$CXXCPP', 'g++ -E'),
256   ('CCFLAGS', '$CCFLAGS', ''),
257   ('CPPFLAGS', '$CPPFLAGS', ''),
258   ('CPPPATH', '$CPPPATH', ''),
259   ('LDFLAGS', '$LDFLAGS', ''),
260 )  
261
262 # Determine the frontend to use
263 frontend = ARGUMENTS.get('frontend', default_frontend)
264 use_X11 = ARGUMENTS.get('X11', default_with_x)
265
266 #---------------------------------------------------------
267 # Setting up environment
268 #---------------------------------------------------------
269
270 env = Environment(
271   options = opts 
272 )
273
274 # set environment since I do not really like ENV = os.environ
275 env['ENV']['PATH'] = os.environ.get('PATH')
276 env['ENV']['HOME'] = os.environ.get('HOME')
277 # speed up source file processing
278 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
279 #env['CXXSUFFIX'] = ['.C']
280
281 def getEnvVariable(env, name):
282   # first try command line argument (override environment settings)
283   if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
284     env[name] = ARGUMENTS[name]
285   # then try environment variable  
286   elif os.environ.has_key(name) and os.environ[name].strip() != '':
287     env[name] = os.environ[name]
288     print "Acquiring varaible %s from system environment: %s" % (name, env[name])
289
290 getEnvVariable(env, 'CC')
291 getEnvVariable(env, 'CPP')
292 getEnvVariable(env, 'CXX')
293 getEnvVariable(env, 'CXXCPP')
294 getEnvVariable(env, 'CCFLAGS')
295 getEnvVariable(env, 'CXXFLAGS')
296 getEnvVariable(env, 'CPPFLAGS')
297 getEnvVariable(env, 'CPPPATH')
298 getEnvVariable(env, 'LDFLAGS')
299
300 env['TOP_SRC_DIR'] = Dir('.').abspath
301
302 # under windows, scons is confused by .C/.c and uses gcc instead of 
303 # g++. I am forcing the use of g++ here. This is expected to change
304 # after lyx renames all .C files to .cpp
305 if platform_name in ['win32', 'cygwin']:
306   env['CC'] = 'g++'
307   env['LINK'] = 'g++'
308
309 #
310 # frontend, mode, BUILDDIR and LOCALLIBPATH=BUILDDIR/libs
311
312 env['frontend'] = frontend
313 env['mode'] = ARGUMENTS.get('mode', default_build_mode)
314 # lyx will be built to $build/build_dir so it is possible
315 # to build multiple build_dirs using the same source 
316 # $mode can be debug or release
317 if ARGUMENTS.has_key('build_dir'):
318   build_dir = ARGUMENTS['build_dir']
319   env['BUILDDIR'] = build_dir
320 else:
321   # Determine the name of the build (platform+frontend
322   build_dir = '%s-%s' % (platform_name, frontend)
323   if use_X11 and platform_name == 'cygwin':
324     build_dir += '-X11'
325   env['BUILDDIR'] = os.path.join('$mode', build_dir)
326 # all built libraries will go to build_dir/libs
327 # (This is different from the make file approach)
328 env['LOCALLIBPATH'] = '#$BUILDDIR/libs'
329 env.AppendUnique(LIBPATH = ['$LOCALLIBPATH'])
330
331 #
332 # QTDIR, QT_LIB_PATH, QT_INC_PATH
333 #
334 if platform_name == 'win32':
335   env.Tool('mingw')
336
337 if ARGUMENTS.has_key('qt_dir'):
338   env['QTDIR'] = ARGUMENTS['qt_dir']
339   # add path to the qt tools
340   env.AppendUnique(LIBPATH = [os.path.join(ARGUMENTS['qt_dir'], 'lib')])
341   env.AppendUnique(CPPPATH = [os.path.join(ARGUMENTS['qt_dir'], 'include')])
342   # set environment so that moc etc can be found even if its path is not set properly
343   env.PrependENVPath('PATH', os.path.join(ARGUMENTS['qt_dir'], 'bin'))
344 else:
345   env['QTDIR'] = os.environ.get('QTDIR', '/usr/lib/qt-3.3')
346
347 if ARGUMENTS.has_key('qt_lib_path'):
348   env['QT_LIB_PATH'] = ARGUMENTS['qt_lib_path']
349 else:
350   env['QT_LIB_PATH'] = '$QTDIR/lib'
351 env.AppendUnique(LIBPATH = ['$QT_LIB_PATH'])
352 # qt4 seems to be using pkg_config
353 env.PrependENVPath('PKG_CONFIG_PATH', env.subst('$QT_LIB_PATH'))
354
355 if ARGUMENTS.has_key('qt_inc_path'):
356   env['QT_INC_PATH'] = ARGUMENTS['qt_inc_path']
357 elif os.path.isdir(os.path.join(env.subst('$QTDIR'), 'include')):
358   env['QT_INC_PATH'] = '$QTDIR/include'
359 else: # have to guess
360   env['QT_INC_PATH'] = '/usr/include/$frontend/'
361 env.AppendUnique(CPPPATH = env['QT_INC_PATH'])  
362
363 #
364 # extra_inc_path and extra_lib_path
365 #
366 if ARGUMENTS.has_key('extra_inc_path'):
367   env.AppendUnique(CPPPATH = [ARGUMENTS['extra_inc_path']])
368 if ARGUMENTS.has_key('extra_lib_path'):
369   env.AppendUnique(LIBPATH = [ARGUMENTS['extra_lib_path']])
370 if ARGUMENTS.has_key('extra_inc_path1'):
371   env.AppendUnique(CPPPATH = [ARGUMENTS['extra_inc_path1']])
372 if ARGUMENTS.has_key('extra_lib_path1'):
373   env.AppendUnique(LIBPATH = [ARGUMENTS['extra_lib_path1']])
374 if ARGUMENTS.has_key('aikasurus_path'):
375   env.AppendUnique(LIBPATH = [ARGUMENTS['aikasurus_path']])
376
377 #
378 # this is a bit out of place (after auto-configration)
379 # but it is required to do the tests.
380 if platform_name == 'win32':
381   env.AppendUnique(CPPPATH = ['#c:/MinGW/include'])
382
383 #----------------------------------------------------------
384 # Autoconf business 
385 #----------------------------------------------------------
386
387 conf = Configure(env,
388   custom_tests = {
389     'CheckPkgConfig' : utils.checkPkgConfig,
390     'CheckPackage' : utils.checkPackage,
391     'CheckPutenv' : utils.checkPutenv,
392     'CheckIstreambufIterator' : utils.checkIstreambufIterator,
393     'CheckMkdirOneArg' : utils.checkMkdirOneArg,
394     'CheckStdCount' : utils.checkStdCount,
395     'CheckSelectArgType' : utils.checkSelectArgType,
396     'CheckBoostLibraries' : utils.checkBoostLibraries,
397   }
398 )
399
400 # pkg-config? (if not, we use hard-coded options)
401 if conf.CheckPkgConfig('0.15.0'):
402   env['HAS_PKG_CONFIG'] = True
403 else:
404   print 'pkg-config >= 0.1.50 is not found'
405   env['HAS_PKG_CONFIG'] = False
406
407 # zlib? This is required.
408 if not conf.CheckLibWithHeader('z', 'zlib.h', 'C'): 
409   print 'Did not find libz or zlib.h, exiting!'
410   Exit(1)
411
412 # qt libraries?
413 #
414 # qt3 does not use pkg_config
415 if env['frontend'] == 'qt3':
416   if not conf.CheckLibWithHeader('qt-mt', 'qapp.h', 'c++', 'QApplication qapp();'):
417     print 'Did not find qt libraries, exiting!'
418     Exit(1)
419 elif env['frontend'] == 'qt4':
420   succ = False
421   # first: try pkg_config
422   if env['HAS_PKG_CONFIG']:
423     succ = conf.CheckPackage('QtCore') or conf.CheckPackage('QtCore4')
424     env['QT4_PKG_CONFIG'] = succ
425   # second: try to link to it
426   if not succ:
427     # FIXME: under linux, I can test the following perfectly
428     # However, under windows, lib names need to passed as libXXX4.a ...
429     succ = conf.CheckLibWithHeader('QtCore', 'QtGui/QApplication', 'c++', 'QApplication qapp();') or \
430       conf.CheckLibWithHeader('QtCore4', 'QtGui/QApplication', 'c++', 'QApplication qapp();')
431   # third: try to look up the path
432   if not succ:
433     succ = True
434     for lib in ['QtCore', 'QtGui', 'Qt3Support']:
435       # windows version has something like QtGui4 ...
436       if not (os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s.a' % lib)) or \
437         os.path.isfile(os.path.join(env.subst('$QT_LIB_PATH'), 'lib%s4.a' % lib))):
438         succ = False
439         break
440   # still can not find it
441   if succ:
442     print "Qt4 libraries are found."
443   else:
444     print 'Did not find qt libraries, exiting!'
445     Exit(1)
446
447 # check socket libs
448 env['socket_libs'] = []
449 if conf.CheckLib('socket'):
450   env.AppendUnique(socket_libs = ['socket'])
451
452 # FIXME: What is nsl, is it related to socket?
453 if conf.CheckLib('nsl'):
454   env.AppendUnique(socket_libs = ['nsl'])
455
456 # check boost libraries
457 boost_opt = ARGUMENTS.get('boost', default_boost_opt)
458 # check for system boost
459 succ = False
460 if boost_opt in ['auto', 'system']:
461   pathes = env['LIBPATH'] + ['/usr/lib', '/usr/local/lib']
462   sig = conf.CheckBoostLibraries('boost_signals', pathes)
463   reg = conf.CheckBoostLibraries('boost_regex', pathes)
464   fil = conf.CheckBoostLibraries('boost_filesystem', pathes)
465   ios = conf.CheckBoostLibraries('boost_iostreams', pathes)
466   # if any them is not found
467   if ('' in [sig[0], reg[0], fil[0], ios[0]]):
468     if boost_opt == 'system':
469       print "Can not find system boost libraries"
470       print "Please supply a path through extra_lib_path"
471       print "and try again."
472       Exit(2)
473   else:
474     env['BOOST_LIBRARIES'] = [sig[1], reg[1], fil[1], ios[1]]
475     # assume all boost libraries are in the same path...
476     env.AppendUnique(LIBPATH = sig[0])
477     env['INCLUDED_BOOST'] = False
478     succ = True
479 # now, auto and succ = false, or included
480 if not succ:
481   # we do not need to set LIBPATH now.
482   env['BOOST_LIBRARIES'] = ['boost_signals', 'boost_regex', 
483     'boost_filesystem', 'boost_iostreams']
484   env['INCLUDED_BOOST'] = True
485   
486 #
487 # Building config.h
488
489
490 print "Generating ", utils.config_h, "..."
491
492 # I do not handle all macros in src/config.h.in, rather I am following a list
493 # of *used-by-lyx* macros compiled by Abdelrazak Younes <younes.a@free.fr> 
494
495 # Note: addToConfig etc are defined in scons_util
496 utils.startConfigH()
497
498 # HAVE_IO_H
499 # HAVE_LIMITS_H
500 # HAVE_LOCALE_H
501 # HAVE_LOCALE
502 # HAVE_PROCESS_H
503 # HAVE_STDLIB_H
504 # HAVE_SYS_STAT_H
505 # HAVE_SYS_TIME_H
506 # HAVE_SYS_TYPES_H
507 # HAVE_SYS_UTIME_H
508 # HAVE_UNISTD_H
509 # HAVE_UTIME_H
510 # HAVE_ISTREAM
511 # HAVE_OSTREAM
512 # HAVE_IOS
513
514 # Check header files
515 headers = [
516   ('io.h', 'HAVE_IO_H', 'c'),
517   ('limits.h', 'HAVE_LIMITS_H', 'c'),
518   ('locale.h', 'HAVE_LOCALE_H', 'c'),
519   ('locale', 'HAVE_LOCALE', 'cxx'),
520   ('process.h', 'HAVE_PROCESS_H', 'c'),
521   ('stdlib.h', 'HAVE_STDLIB_H', 'c'),
522   ('sys/stat.h', 'HAVE_SYS_STAT_H', 'c'),
523   ('sys/time.h', 'HAVE_SYS_TIME_H', 'c'),
524   ('sys/types.h', 'HAVE_SYS_TYPES_H', 'c'),
525   ('sys/utime.h', 'HAVE_SYS_UTIME_H', 'c'),
526   ('sys/socket.h', 'HAVE_SYS_SOCKET_H', 'c'),
527   ('unistd.h', 'HAVE_UNISTD_H', 'c'),
528   ('utime.h', 'HAVE_UTIME_H', 'c'),
529   ('istream', 'HAVE_ISTREAM', 'cxx'),
530   ('ostream', 'HAVE_OSTREAM', 'cxx'),
531   ('ios', 'HAVE_IOS', 'cxx')
532 ]
533
534 for header in headers:
535   if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
536     (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
537     utils.addToConfig('#define %s 1' % header[1])
538   else:
539     utils.addToConfig('/* #undef %s */' % header[1])
540
541 # HAVE_OPEN
542 # HAVE_CLOSE
543 # HAVE_POPEN
544 # HAVE_PCLOSE
545 # HAVE__OPEN
546 # HAVE__CLOSE
547 # HAVE__POPEN
548 # HAVE__PCLOSE
549 # HAVE_GETPID
550 # HAVE__GETPID
551 # HAVE_MKDIR
552 # HAVE__MKDIR
553 # HAVE_MKTEMP
554 # HAVE_MKSTEMP
555 # HAVE_STRERROR
556
557 # Check functions
558 functions = [
559   ('open', 'HAVE_OPEN'),
560   ('close', 'HAVE_CLOSE'),
561   ('popen', 'HAVE_POPEN'),
562   ('pclose', 'HAVE_PCLOSE'),
563   ('_open', 'HAVE__OPEN'),
564   ('_close', 'HAVE__CLOSE'),
565   ('_popen', 'HAVE__POPEN'),
566   ('_pclose', 'HAVE__PCLOSE'),
567   ('getpid', 'HAVE_GETPID'),
568   ('_getpid', 'HAVE__GETPID'),
569   ('mkdir', 'HAVE_MKDIR'),
570   ('_mkdir', 'HAVE__MKDIR'),
571   ('mktemp', 'HAVE_MKTEMP'),
572   ('mkstemp', 'HAVE_MKSTEMP'),
573   ('strerror', 'HAVE_STRERROR')
574 ]
575
576 for func in functions:
577   if conf.CheckFunc(func[0]):
578     utils.addToConfig('#define %s 1' % func[1])
579   else:
580     utils.addToConfig('/* #undef %s */' % func[1])
581
582 # PACKAGE
583 # PACKAGE_VERSION
584 # DEVEL_VERSION
585 utils.addToConfig('#define PACKAGE "%s"' % PACKAGE)
586 utils.addToConfig('#define PACKAGE_VERSION "%s"' % PACKAGE_VERSION)
587 if DEVEL_VERSION:
588   utils.addToConfig('#define DEVEL_VERSION 1')
589
590 # ENABLE_ASSERTIONS
591 # ENABLE_NLS
592 # WITH_WARNINGS
593 # _GLIBCXX_CONCEPT_CHECKS
594
595 # items are (ENV, ARGUMENTS)
596 values = [
597   ('ENABLE_ASSERTIONS', 'assertions'),
598   ('ENABLE_NLS', 'nls'),
599   ('WITH_WARNINGS', 'warnings'),
600   ('_GLIBCXX_CONCEPT_CHECKS', 'concept_checks'),
601 ]
602
603 for val in values:
604   if (env.has_key(val[0]) and env[val[0]]) or \
605       ARGUMENTS.get(val[1]):
606     utils.addToConfig('#define %s 1' % val[0])
607   else:
608     utils.addToConfig('/* #undef %s */' % val[0])
609
610
611 env['EXTRA_LIBS'] = []
612 # HAVE_LIBAIKSAURUS
613 # AIKSAURUS_H_LOCATION
614 if conf.CheckLib('Aiksaurus'):
615   utils.addToConfig("#define HAVE_LIBAIKSAURUS 1")
616   if (conf.CheckCXXHeader("Aiksaurus.h")):
617     utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus.h>")
618   elif (conf.CheckCXXHeader("Aiksaurus/Aiksaurus.h")):
619     utils.addToConfig("#define AIKSAURUS_H_LOCATION <Aiksaurus/Aiksaurus.h>")
620   else:
621     utils.addToConfig("#define AIKSAURUS_H_LOCATION")
622   env['EXTRA_LIBS'].append('Aiksaurus')
623
624 # USE_ASPELL
625 # USE_PSPELL
626 # USE_ISPELL
627
628 # determine headers to use
629 spell_engine = ARGUMENTS.get('spell', 'auto')
630 spell_detected = False
631 if spell_engine in ['auto', 'aspell'] and \
632   conf.CheckLib('aspell'):
633   utils.addToConfig('#define USE_ASPELL 1')
634   env['USE_ASPELL'] = True
635   env['EXTRA_LIBS'].append('aspell')
636   spell_detected = True
637 elif spell_engine in ['auto', 'pspell'] and \
638   conf.CheckLib('pspell'):
639   utils.addToConfig('#define USE_PSPELL 1')
640   env['USE_PSPELL'] = True
641   env['EXTRA_LIBS'].append('pspell')
642   spell_detected = True
643 elif spell_engine in ['auto', 'ispell'] and \
644   conf.CheckLib('ispell'):
645   utils.addToConfig('#define USE_ISPELL 1')
646   env['USE_ISPELL'] = True
647   env['EXTRA_LIBS'].append('ispell')
648   spell_detected = True
649
650 if not spell_detected:
651   # FIXME: can lyx work without an spell engine
652   if spell_engine == 'auto':
653     print "Warning: Can not locate any spell checker"
654   else:
655     print "Warning: Can not locate specified spell checker:", spell_engine
656
657 # USE_POSIX_PACKAGING
658 # USE_MACOSX_PACKAGING
659 # USE_WINDOWS_PACKAGING
660 if packaging_method == 'windows':
661   utils.addToConfig('#define USE_WINDOWS_PACKAGING 1')
662 elif packaging_method == 'posix':
663   utils.addToConfig('#define USE_POSIX_PACKAGING 1')
664 elif packaging_method == 'mac':
665   utils.addToConfig('#define USE_MACOSX_PACKAGING 1')
666
667 # BOOST_POSIX
668 if boost_posix:
669   utils.addToConfig('#define BOOST_POSIX 1')
670 else:
671   utils.addToConfig('/* #undef BOOST_POSIX */')
672
673 # HAVE_PUTENV
674 if conf.CheckPutenv():
675   utils.addToConfig('#define HAVE_PUTENV 1')
676 else:
677   utils.addToConfig('/* #undef HAVE_PUTENV */')
678   
679 # HAVE_DECL_ISTREAMBUF_ITERATOR
680 if conf.CheckIstreambufIterator():
681   utils.addToConfig('#define HAVE_DECL_ISTREAMBUF_ITERATOR 1')
682 else:
683   utils.addToConfig('/* #undef HAVE_DECL_ISTREAMBUF_ITERATOR */')
684
685 # MKDIR_TAKES_ONE_ARG
686 if conf.CheckMkdirOneArg():
687   utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1')
688 else:
689   utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */')
690
691 # HAVE_STD_COUNT
692 if conf.CheckStdCount():
693   utils.addToConfig('#define HAVE_STD_COUNT 1')
694 else:
695   utils.addToConfig('/* #undef HAVE_STD_COUNT */')
696
697 # SELECT_TYPE_ARG1
698 # SELECT_TYPE_ARG234
699 # SELECT_TYPE_ARG5
700 (arg1, arg234, arg5) = conf.CheckSelectArgType()
701 utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1)
702 utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234)
703 utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5)
704
705 # mkstemp
706 # USE_BOOST_FORMAT
707 # WANT_GETFILEATTRIBUTESEX_WRAPPER
708 utils.endConfigH()
709
710 #
711 # Finish auto-configuration
712 env = conf.Finish()
713
714 #----------------------------------------------------------
715 # Now set up our build process accordingly 
716 #----------------------------------------------------------
717
718 #
719 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
720 #
721 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
722 # in their respective directory and specialized env.
723 try:
724   if frontend == 'qt3':
725     # note: env.Tool('qt') my set QT_LIB to qt
726     env['QT_LIB'] = 'qt-mt'
727     env['EXTRA_LIBS'] += ['qt-mt']
728     if platform_name == 'cygwin' and use_X11:
729       env['EXTRA_LIBS'] += ['GL',  'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
730         'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
731         'pthread']
732       env.AppendUnique(LIBPATH = ['/usr/X11R6/lib'])
733   elif frontend == 'qt4':
734     # local qt4 toolset from 
735     # http://www.iua.upf.es/~dgarcia/Codders/sconstools.html
736     if platform_name == "win32":
737       env['QT_LIB'] = ['QtCore4', 'QtGui4', 'Qt3Support4']
738     else:
739       env['QT_LIB'] = ['QtCore', 'QtGui', 'Qt3Support']
740     env['EXTRA_LIBS'] += [x for x in env['QT_LIB']]
741 except:
742   print "Can not locate qt tools"
743   print "What I get is "
744   print "  QTDIR: ", env['QTDIR']
745
746 if platform_name == 'win32':
747   env['SYSTEM_LIBS'] = ['shlwapi', 'zlib1']
748 elif platform_name == 'cygwin':
749   env['SYSTEM_LIBS'] = ['shlwapi', 'z']
750 else:
751   env['SYSTEM_LIBS'] = ['z']
752
753 #
754 # Build parameters CPPPATH etc
755 #
756 # boost is always in
757 env.AppendUnique(CPPPATH = ['#boost', '#src'])
758
759 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
760 # for debug/release mode 
761 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
762   env.AppendUnique(CCFLAGS = [])
763 else:
764   env.AppendUnique(CCFLAGS = [])
765
766 #
767 # Customized builders
768 #
769 # install customized builders
770 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
771 # FIXME: there must be a better way.
772 env['BUILDERS']['fileCopy'] = Builder(action = utils.env_filecopy)
773
774 #
775 # A Link script for cygwin see
776 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
777 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
778 # for details
779
780 if platform_name == 'cygwin' and env['frontend'] == 'qt3':
781   ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
782   ld_script = utils.installCygwinLDScript(ld_script_path)
783   env.AppendUnique(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc', 
784     '-Wl,--script,%s' % ld_script, '-Wl,-s'])
785
786 #
787 # Report results
788 #
789 # src/support/package.C.in needs the following to replace
790 env['LYX_DIR'] = LYX_DIR
791 env['LOCALEDIR'] = LOCALEDIR
792 env['TOP_SRCDIR'] = str(Dir('#'))
793 env['PROGRAM_SUFFIX'] = PROGRAM_SUFFIX
794 # needed by src/version.C.in => src/version.C
795 env['PACKAGE_VERSION'] = PACKAGE_VERSION
796 # fill in the version info
797 env['VERSION_INFO'] = '''Configuration
798   Host type:                      %s
799   Special build flags:            %s
800   C   Compiler:                   %s
801   C   Compiler flags:             %s %s
802   C++ Compiler:                   %s
803   C++ Compiler LyX flags:         %s
804   C++ Compiler flags:             %s %s
805   Linker flags:                   %s
806   Linker user flags:              %s
807 Build info: 
808   Builing directory:              %s
809   Local library directory:        %s
810   Libraries pathes:               %s
811   Boost libraries:                %s
812   Extra libraries:                %s
813   System libraries:               %s
814 Frontend: 
815   Frontend:                       %s
816   Packaging:                      %s
817   LyX binary dir:                 FIXME
818   LyX files dir:                  FIXME
819 ''' % (platform_name, 
820   env.subst('$CCFLAGS'), env.subst('$CC'),
821   env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
822   env.subst('$CXX'), env.subst('$CXXFLAGS'),
823   env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
824   env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
825   env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
826   str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
827   str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']),
828   env['frontend'], packaging_method)
829
830 if env['frontend'] in ['qt3', 'qt4']:
831   env['VERSION_INFO'] += '''  include dir:                    %s
832   library dir:                    %s
833   X11:                            %s
834 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
835
836 print env['VERSION_INFO']
837
838 #
839 # Mingw command line may be too short for our link usage, 
840 # Here we use a trick from scons wiki
841 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
842 #
843 # I also would like to add logging (commands only) capacity to the
844 # spawn system. 
845 logfile = ARGUMENTS.get('logfile', default_log_file)
846 if logfile != '' or platform_name == 'win32':
847   import time
848   utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
849     info = '''# This is a log of commands used by scons to build lyx
850 # Time: %s 
851 # Command: %s
852 # Info: %s
853 ''' % (time.asctime(), ' '.join(sys.argv), 
854   env['VERSION_INFO'].replace('\n','\n# ')) )
855
856
857 #
858 # Cleanup stuff
859 #
860 # save options
861 opts.Save('options.cache', env)
862 # -h will print out help info
863 Help(opts.GenerateHelpText(env))
864
865
866
867 #----------------------------------------------------------
868 # Start building
869 #----------------------------------------------------------
870 Export('env')
871 env.BuildDir('$BUILDDIR', 'src')
872 print "Building all targets recursively"
873
874 client = env.SConscript('#$BUILDDIR/client/SConscript', duplicate = 0)
875 lyx = env.SConscript('#$BUILDDIR/SConscript', duplicate=0)
876 tex2lyx = env.SConscript('#$BUILDDIR/tex2lyx/SConscript', duplicate = 0)
877
878 # avoid using full path to build them
879 Alias('client', client)
880 Alias('tex2lyx', tex2lyx)
881 Alias('lyx', lyx)
882
883 Default('lyx', 'tex2lyx')
884
885 print "Buinging lyx done with targets", map(str, BUILD_TARGETS)
886