]> git.lyx.org Git - features.git/blob - SConstruct
3f3c81fd7a575536799aee891acd6c1eb6d0ddba
[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 config_h = os.path.join('src', 'config.h')
98 default_log_file = 'scons_lyx.log'
99
100 # FIXME: what is this? (They are used in src/support/package.C.in
101 LOCALEDIR = "../locale/"
102 LYX_DIR = "/usr/local/share/lyx"
103
104 # platform dependent default build_dir and other settings
105 #
106 # I know, somebody would say: 
107 #   This is TOTALLY wrong! Everything should be automatically
108 #   determined.
109 #
110 if os.name == 'nt':
111   platform_name = 'win32'
112   default_frontend = 'qt4'
113   # boost and gettext are unlikely to be installed already
114   default_boost_opt = 'included'
115   default_gettext_opt = 'included'
116   default_pch_opt = False
117   default_with_x = False
118   spell_checker = 'auto'
119   # FIXME: I need to know what exactly is boost_posix
120   boost_posix = False
121   packaging_method = 'windows'
122 elif os.name == 'posix' and sys.platform != 'cygwin':
123   platform_name = 'linux'
124   default_frontend = 'qt3'
125   # try to use system boost/gettext libraries
126   default_boost_opt = 'auto'
127   default_gettext_opt = 'auto'
128   default_pch_opt = False
129   default_with_x = True
130   boost_posix = False
131   packaging_method = 'posix'
132 elif os.name == 'posix' and sys.platform == 'cygwin':
133   platform_name = 'cygwin'
134   default_frontend = 'qt3'
135   # force the use of cygwin/boost/gettext
136   default_boost_opt = 'system'
137   default_gettext_opt = 'system'
138   default_pch_opt = False
139   default_with_x = True
140   boost_posix = True
141   packaging_method = 'posix'
142 elif os.name == 'darwin':
143   platform_name = 'mac'
144   default_frontend = 'qt3'
145   # to be safe
146   default_boost_opt = 'included'
147   default_gettext_opt = 'included'
148   default_pch_opt = False
149   default_with_x = False
150   boost_posix = False
151   packaging_method = 'msc'
152 else:  # unsupported system
153   platform_name = 'others'
154   default_frontend = 'qt3'
155   # to be safe
156   default_boost_opt = 'included'
157   default_gettext_opt = 'included'
158   default_pch_opt = False
159   default_with_x = True
160   boost_posix = False
161   packaging_method = 'posix'
162
163 #---------------------------------------------------------
164 # Handling options
165 #----------------------------------------------------------
166 # Note that if you set the options via the command line, 
167 # they will be remembered in the file 'options.cache'
168
169 # NOTE: the scons people are trying to fix scons so that
170 # options like --prefix will be accepted. Right now,
171 # we have to use the KEY=VALUE style of scons
172
173 if os.path.isfile('options.cache'):
174   print "Getting options from auto-saved options.cache..."
175   print open('options.cache').read()
176 if os.path.isfile('config.py'):
177   print "Getting options from config.py..."
178   print open('config.py').read()
179
180 opts = Options(['options.cache', 'config.py'])
181 opts.AddOptions(
182   # frontend, 
183   EnumOption('frontend', 'Main GUI', 
184     default_frontend,
185     allowed_values = ('xform', 'qt3', 'qt4', 'gtk') ),
186   # debug or release build
187   EnumOption('mode', 'Building method', default_build_mode,
188     allowed_values = ('debug', 'release') ),
189   # boost libraries
190   EnumOption('boost', 
191     'Use included, system boost library, or try sytem first.', 
192     default_boost_opt,
193     allowed_values = (
194       'auto',       # detect boost, if not found, use included
195       'included',   # always use included boost
196       'system',     # always use system boost, fail if can not find
197       ) ),
198   EnumOption('gettext', 
199     'Use included, system gettext library, or try sytem first', 
200     default_gettext_opt,
201     allowed_values = (
202       'auto',       # detect gettext, if not found, use included
203       'included',   # always use included gettext
204       'system',     # always use system gettext, fail if can not find
205       ) ),
206   # FIXME: I am not allowed to use '' as default, '.' is not good either.
207   PathOption('qt_dir', 'Path to qt directory', '.'),
208   PathOption('qt_include_path', 'Path to qt include directory', '.'),
209   PathOption('qt_lib_path', 'Path to qt library directory', '.'),
210   # FIXME: I do not know how pch is working. Ignore this option now.
211   BoolOption('pch', '(NA) Whether or not use pch', default_pch_opt),
212   # FIXME: Not implemented yet.
213   BoolOption('version_suffix', '(NA) Whether or not add version suffix', False),
214   # build directory, will replace build_dir if set
215   PathOption('build_dir', 'Build directory', '.'),
216   # extra include and libpath
217   PathOption('extra_inc_path', 'Extra include path', '.'),
218   PathOption('extra_lib_path', 'Extra library path', '.'),
219   PathOption('extra_inc_path1', 'Extra include path', '.'),
220   PathOption('extra_lib_path1', 'Extra library path', '.'),
221   # enable assertion, (config.h has  ENABLE_ASSERTIOS
222   BoolOption('assertions', 'Use assertions', True),
223   # enable warning, (config.h has  WITH_WARNINGS)
224   BoolOption('warnings', 'Use warnings', True),
225   # enable glib, (config.h has  _GLIBCXX_CONCEPT_CHECKS)
226   BoolOption('concept_checks', 'Enable concept checks', True),
227   # FIXME: I do not know what is nls
228   BoolOption('nls', '(NA) Whether or not use native language support', False),
229   # FIXME: not implemented
230   BoolOption('profile', '(NA) Whether or not enable profiling', False),
231   # FIXME: not implemented
232   PathOption('prefix', '(NA) install architecture-independent files in PREFIX', '.'),
233   # FIXME: not implemented
234   PathOption('exec_prefix', '(NA) install architecture-independent executable files in PREFIX', '.'),
235   # FIXME: not implemented
236   BoolOption('std_debug', '(NA) Whether or not turn on stdlib debug', False),
237   # using x11?
238   BoolOption('X11', 'Use x11 windows system', default_with_x),
239   # FIXME: not implemented
240   BoolOption('libintl', '(NA) Use libintl library', False),
241   # FIXME: not implemented
242   PathOption('intl_prefix', '(NA) Path to intl library', '.'),
243   # log file
244   ('logfile', 'save commands (not outputs) to logfile', default_log_file),
245   # Path to aikasurus
246   PathOption('aikasurus_path', 'Path to aikasurus library', '.'),
247   #
248   EnumOption('spell', 'Choose spell checker to use.', 'auto',
249     allowed_values = ('aspell', 'pspell', 'ispell', 'auto') ),
250   # environment variable can be set as options
251   ('CC', '$CC', 'gcc'),
252   ('CPP', '$CPP', 'gcc'),
253   ('CXX', '$CXX', 'g++'),
254   ('CXXCPP', '$CXXCPP', 'g++'),
255   ('CCFLAGS', '$CCFLAGS', ''),
256   ('CPPFLAGS', '$CPPFLAGS', ''),
257   ('CPPPATH', '$CPPPATH', ''),
258   ('LDFLAGS', '$LDFLAGS', ''),
259 )  
260
261 # Determine the frontend to use
262 frontend = ARGUMENTS.get('frontend', default_frontend)
263 use_X11 = ARGUMENTS.get('X11', default_with_x)
264
265 #---------------------------------------------------------
266 # Setting up environment
267 #---------------------------------------------------------
268
269 env = Environment(
270   options = opts 
271 )
272
273 # set environment since I do not really like ENV = os.environ
274 env['ENV']['PATH'] = os.environ.get('PATH')
275 env['ENV']['HOME'] = os.environ.get('HOME')
276 # speed up source file processing
277 #env['CPPSUFFIXES'] = ['.C', '.cc', '.cpp']
278 #env['CXXSUFFIX'] = ['.C']
279
280 def getEnvVariable(env, name):
281   # first try command line argument (override environment settings)
282   if ARGUMENTS.has_key(name) and ARGUMENTS[name].strip() != '':
283     env[name] = ARGUMENTS[name]
284   # then try environment variable  
285   elif os.environ.has_key(name) and os.environ[name].strip() != '':
286     env[name] = os.environ[name]
287     print "Acquiring varaible %s from system environment: %s" % (name, env[name])
288
289 getEnvVariable(env, 'CC')
290 getEnvVariable(env, 'CPP')
291 getEnvVariable(env, 'CXX')
292 getEnvVariable(env, 'CXXCPP')
293 getEnvVariable(env, 'CCFLAGS')
294 getEnvVariable(env, 'CXXFLAGS')
295 getEnvVariable(env, 'CPPFLAGS')
296 getEnvVariable(env, 'CPPPATH')
297 getEnvVariable(env, 'LDFLAGS')
298
299 env['ENV']['PKG_CONFIG_PATH'] = os.environ.get('PKG_CONFIG_PATH')
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.Append(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.Append(LIBPATH = [os.path.join(ARGUMENTS['qt_dir'], 'lib')])
341   env.Append(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['ENV']['PATH'] = os.path.join(ARGUMENTS['qt_dir'], 'bin') + os.pathsep + env['ENV']['PATH']
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.Append(LIBPATH = ['$QT_LIB_PATH'])
352 # qt4 seems to be using pkg_config
353 env['ENV']['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.Append(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.Append(CPPPATH = [ARGUMENTS['extra_inc_path']])
368 if ARGUMENTS.has_key('extra_lib_path'):
369   env.Append(LIBPATH = [ARGUMENTS['extra_lib_path']])
370 if ARGUMENTS.has_key('extra_inc_path1'):
371   env.Append(CPPPATH = [ARGUMENTS['extra_inc_path1']])
372 if ARGUMENTS.has_key('extra_lib_path1'):
373   env.Append(LIBPATH = [ARGUMENTS['extra_lib_path1']])
374 if ARGUMENTS.has_key('aikasurus_path'):
375   env.Append(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.Append(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.Append(socket_libs = ['socket'])
451
452 # FIXME: What is nsl, is it related to socket?
453 if conf.CheckLib('nsl'):
454   env.Append(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.Append(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 ", 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(config_h)
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 # AIKSAURUS_H_LOCATION
613 if conf.CheckLib('Aiksaurus'):
614   utils.addToConfig("#define AIKSAURUS_H_LOCATION")
615   env['EXTRA_LIBS'].append('Aiksaurus')
616
617 # USE_ASPELL
618 # USE_PSPELL
619 # USE_ISPELL
620
621 # determine headers to use
622 spell_engine = ARGUMENTS.get('spell', 'auto')
623 spell_detected = False
624 if spell_engine in ['auto', 'aspell'] and \
625   conf.CheckLib('aspell'):
626   utils.addToConfig('#define USE_ASPELL 1')
627   env['EXTRA_LIBS'].appnend('aspell')
628   spell_detected = True
629 elif spell_engine in ['auto', 'pspell'] and \
630   conf.CheckLib('pspell'):
631   utils.addToConfig('#define USE_PSPELL 1')
632   env['EXTRA_LIBS'].appnend('pspell')
633   spell_detected = True
634 elif spell_engine in ['auto', 'ispell'] and \
635   conf.CheckLib('ispell'):
636   utils.addToConfig('#define USE_ISPELL 1')
637   env['EXTRA_LIBS'].appnend('ispell')
638   spell_detected = False
639
640 if not spell_detected:
641   # FIXME: can lyx work without an spell engine
642   if spell_engine == 'auto':
643     print "Warning: Can not locate any spell checker"
644   else:
645     print "Warning: Can not locate specified spell checker:", spell_engine
646
647 # USE_POSIX_PACKAGING
648 # USE_MACOSX_PACKAGING
649 # USE_WINDOWS_PACKAGING
650 if packaging_method == 'windows':
651   utils.addToConfig('#define USE_WINDOWS_PACKAGING 1')
652 elif packaging_method == 'posix':
653   utils.addToConfig('#define USE_POSIX_PACKAGING 1')
654 elif packaging_method == 'mac':
655   utils.addToConfig('#define USE_MACOSX_PACKAGING 1')
656
657 # BOOST_POSIX
658 if boost_posix:
659   utils.addToConfig('#define BOOST_POSIX 1')
660 else:
661   utils.addToConfig('/* #undef BOOST_POSIX */')
662
663 # HAVE_PUTENV
664 if conf.CheckPutenv():
665   utils.addToConfig('#define HAVE_PUTENV 1')
666 else:
667   utils.addToConfig('/* #undef HAVE_PUTENV */')
668   
669 # HAVE_DECL_ISTREAMBUF_ITERATOR
670 if conf.CheckIstreambufIterator():
671   utils.addToConfig('#define HAVE_DECL_ISTREAMBUF_ITERATOR 1')
672 else:
673   utils.addToConfig('/* #undef HAVE_DECL_ISTREAMBUF_ITERATOR */')
674
675 # MKDIR_TAKES_ONE_ARG
676 if conf.CheckMkdirOneArg():
677   utils.addToConfig('#define MKDIR_TAKES_ONE_ARG 1')
678 else:
679   utils.addToConfig('/* #undef MKDIR_TAKES_ONE_ARG */')
680
681 # HAVE_STD_COUNT
682 if conf.CheckStdCount():
683   utils.addToConfig('#define HAVE_STD_COUNT 1')
684 else:
685   utils.addToConfig('/* #undef HAVE_STD_COUNT */')
686
687 # SELECT_TYPE_ARG1
688 # SELECT_TYPE_ARG234
689 # SELECT_TYPE_ARG5
690 (arg1, arg234, arg5) = conf.CheckSelectArgType()
691 utils.addToConfig('#define SELECT_TYPE_ARG1 %s' % arg1)
692 utils.addToConfig('#define SELECT_TYPE_ARG234 %s' % arg234)
693 utils.addToConfig('#define SELECT_TYPE_ARG5 %s' % arg5)
694
695 # mkstemp
696 # USE_BOOST_FORMAT
697 # WANT_GETFILEATTRIBUTESEX_WRAPPER
698 utils.endConfigH(config_h)
699
700 #
701 # Finish auto-configuration
702 env = conf.Finish()
703
704 #----------------------------------------------------------
705 # Now set up our build process accordingly 
706 #----------------------------------------------------------
707
708 #
709 # QT_LIB etc (EXTRA_LIBS holds lib for each frontend)
710 #
711 # NOTE: Tool('qt') or Tool('qt4') will be loaded later
712 # in their respective directory and specialized env.
713 try:
714   if frontend == 'qt3':
715     # note: env.Tool('qt') my set QT_LIB to qt
716     env['QT_LIB'] = 'qt-mt'
717     env['EXTRA_LIBS'] += ['qt-mt']
718     if platform_name == 'cygwin' and use_X11:
719       env['EXTRA_LIBS'] += ['GL',  'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor',
720         'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', 'resolv',
721         'pthread']
722       env.Append(LIBPATH = ['/usr/X11R6/lib'])
723   elif frontend == 'qt4':
724     # local qt4 toolset from 
725     # http://www.iua.upf.es/~dgarcia/Codders/sconstools.html
726     if platform_name == "win32":
727       env['QT_LIB'] = ['QtCore4', 'QtGui4', 'Qt3Support4']
728     else:
729       env['QT_LIB'] = ['QtCore', 'QtGui', 'Qt3Support']
730     env['EXTRA_LIBS'] += [x for x in env['QT_LIB']]
731 except:
732   print "Can not locate qt tools"
733   print "What I get is "
734   print "  QTDIR: ", env['QTDIR']
735
736 if platform_name == 'win32':
737   env['SYSTEM_LIBS'] = ['shlwapi', 'zlib1']
738 elif platform_name == 'cygwin':
739   env['SYSTEM_LIBS'] = ['shlwapi', 'z']
740 else:
741   env['SYSTEM_LIBS'] = ['z']
742
743 #
744 # Build parameters CPPPATH etc
745 #
746 # boost is always in
747 env.Append(CPPPATH = ['#boost', '#src'])
748
749 # TODO: add (more) appropriate compiling options (-DNDEBUG etc)
750 # for debug/release mode 
751 if ARGUMENTS.get('mode', default_build_mode) == 'debug':
752   env.Append(CCFLAGS = [])
753 else:
754   env.Append(CCFLAGS = [])
755
756 #
757 # Customized builders
758 #
759 # install customized builders
760 env['BUILDERS']['substFile'] = Builder(action = utils.env_subst)
761 # FIXME: there must be a better way.
762 env['BUILDERS']['fileCopy'] = Builder(action = utils.env_filecopy)
763
764 #
765 # A Link script for cygwin see
766 # http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
767 # http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
768 # for details
769
770 if platform_name == 'cygwin' and env['frontend'] == 'qt3':
771   ld_script_path = '/usr/lib/qt3/mkspecs/cygwin-g++'
772   ld_script = utils.installCygwinLDScript(ld_script_path)
773   env.Append(LINKFLAGS = ['-Wl,--enable-runtime-pseudo-reloc', 
774     '-Wl,--script,%s' % ld_script, '-Wl,-s'])
775
776 #
777 # Report results
778 #
779 # src/support/package.C.in needs the following to replace
780 env['LYX_DIR'] = LYX_DIR
781 env['LOCALEDIR'] = LOCALEDIR
782 env['TOP_SRCDIR'] = str(Dir('#'))
783 env['PROGRAM_SUFFIX'] = PROGRAM_SUFFIX
784 # needed by src/version.C.in => src/version.C
785 env['PACKAGE_VERSION'] = PACKAGE_VERSION
786 # fill in the version info
787 env['VERSION_INFO'] = '''Configuration
788   Host type:                      %s
789   Special build flags:            %s
790   C   Compiler:                   %s
791   C   Compiler flags:             %s %s
792   C++ Compiler:                   %s
793   C++ Compiler LyX flags:         %s
794   C++ Compiler flags:             %s %s
795   Linker flags:                   %s
796   Linker user flags:              %s
797 Build info: 
798   Builing directory:              %s
799   Local library directory:        %s
800   Libraries pathes:               %s
801   Boost libraries:                %s
802   Extra libraries:                %s
803   System libraries:               %s
804 Frontend: 
805   Frontend:                       %s
806   Packaging:                      %s
807   LyX binary dir:                 FIXME
808   LyX files dir:                  FIXME
809 ''' % (platform_name, 
810   env.subst('$CCFLAGS'), env.subst('$CC'),
811   env.subst('$CPPFLAGS'), env.subst('$CFLAGS'),
812   env.subst('$CXX'), env.subst('$CXXFLAGS'),
813   env.subst('$CPPFLAGS'), env.subst('$CXXFLAGS'),
814   env.subst('$LINKFLAGS'), env.subst('$LINKFLAGS'),
815   env.subst('$BUILDDIR'), env.subst('$LOCALLIBPATH'),
816   str(env['LIBPATH']), str(env['BOOST_LIBRARIES']),
817   str(env['EXTRA_LIBS']), str(env['SYSTEM_LIBS']),
818   env['frontend'], packaging_method)
819
820 if env['frontend'] in ['qt3', 'qt4']:
821   env['VERSION_INFO'] += '''  include dir:                    %s
822   library dir:                    %s
823   X11:                            %s
824 ''' % (env.subst('$QT_INC_PATH'), env.subst('$QT_LIB_PATH'), use_X11)
825
826 print env['VERSION_INFO']
827
828 #
829 # Mingw command line may be too short for our link usage, 
830 # Here we use a trick from scons wiki
831 # http://www.scons.org/cgi-sys/cgiwrap/scons/moin.cgi/LongCmdLinesOnWin32
832 #
833 # I also would like to add logging (commands only) capacity to the
834 # spawn system. 
835 logfile = ARGUMENTS.get('logfile', default_log_file)
836 if logfile != '' or platform_name == 'win32':
837   import time
838   utils.setLoggedSpawn(env, logfile, longarg = (platform_name == 'win32'),
839     info = '''# This is a log of commands used by scons to build lyx
840 # Time: %s 
841 # Command: %s
842 # Info: %s
843 ''' % (time.asctime(), ' '.join(sys.argv), 
844   env['VERSION_INFO'].replace('\n','\n# ')) )
845
846
847 #
848 # Cleanup stuff
849 #
850 # save options
851 opts.Save('options.cache', env)
852 # -h will print out help info
853 Help(opts.GenerateHelpText(env))
854
855
856
857 #----------------------------------------------------------
858 # Start building
859 #----------------------------------------------------------
860 Export('env')
861 env.BuildDir('$BUILDDIR', 'src')
862 print "Building all targets recursively"
863
864 client = env.SConscript('#$BUILDDIR/client/SConscript', duplicate = 0)
865 lyx = env.SConscript('#$BUILDDIR/SConscript', duplicate=0)
866 tex2lyx = env.SConscript('#$BUILDDIR/tex2lyx/SConscript', duplicate = 0)
867
868 # avoid using full path to build them
869 Alias('client', client)
870 Alias('tex2lyx', tex2lyx)
871 Alias('lyx', lyx)
872
873 Default('lyx', 'tex2lyx')
874
875 print "Buinging lyx done with targets", map(str, BUILD_TARGETS)
876