Add bytefield.sty latex package to doclib
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, glob, os.path, datetime, pwd, time, fnmatch, string
4 sys.path.append(Dir('#/senfscons').abspath)
5 sys.path.append(Dir('#/doclib').abspath)
6 import SENFSCons
7
8 ###########################################################################
9
10 # This hack is needed for SCons V 0.96.1 compatibility. In current SCons versions
11 # we can just use 'env.AlwaysBuild(env.Alias(target), [], action)'
12 def PhonyTarget(env, target, action, sources=[]):
13     env.AlwaysBuild(env.Command(target + '.phony', [ 'SConstruct' ] + sources, env.Action(action)))
14     env.Alias(target, target + '.phony')
15
16 def updateRevision(target, source, env):
17     rev = env['ENV']['REVISION'][1:]
18     if ':' in rev:
19         print
20         print "Working copy not clean. Run 'svn update'"
21         print
22         return 1
23     if 'm' in rev and not ARGUMENTS.get('force_deb'):
24         print
25         print "Working copy contains local changes. Commit first"
26         print
27         return 1
28     if 's' in rev:
29         rev = rev[:-1]
30     if 'm' in rev:
31         rev = rev[:-1]
32     url = None
33     for line in os.popen("svn info"):
34         elts=line.split(':',1)
35         if elts[0] == 'URL':
36             url = elts[1].strip()
37     version = None
38     if '/tags/' in url:
39         version = url.rsplit('/',1)[-1].split('_',1)[0]
40         if version[0] not in string.digits:
41             version = None
42     if version is None:
43         version = '1:0r%s' % rev
44     changelog = file('debian/changelog.template').read() % {
45         'version': version,
46         'rev': rev,
47         'user': pwd.getpwuid(os.getuid()).pw_gecos.split(',')[0].strip(),
48         'date': time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) }
49     file('debian/changelog','w').write(changelog)
50
51 def nonemptyFile(f):
52     try: return os.stat(f).st_size > 0
53     except OSError: return False
54
55 def checkLocalConf(target, source, env):
56     if [ True for f in env['LOCAL_CONFIG_FILES'] if nonemptyFile(f) ]:
57         print
58         print "You have made local modifications to one of the following local configuration"
59         print "files:"
60         for f in env['LOCAL_CONFIG_FILES']:
61             print "    ",f
62         print
63         print "Building a debian package would remove those files."
64         print
65         print "To continue, remove the offending file(s) and try again. Alternatively,"
66         print "build a source package using 'scons debsrc' and may then build debian"
67         print "binary packages from this source-package without disrupting your local"
68         print "configuration."
69         print
70         return 1
71
72 ###########################################################################
73 # Load utilities and setup libraries and configure build
74
75 SENFSCons.UseBoost()
76 SENFSCons.UseSTLPort()
77 env = SENFSCons.MakeEnvironment()
78
79 env.Help("""
80 Additional top-level build targets:
81
82 prepare      Create all source files not part of the repository
83 all_tests    Build and run unit tests for all modules
84 all_docs     Build documentation for all modules
85 all          Build everything
86 install_all  Install SENF into $PREFIX
87 deb          Build debian source and binary package
88 debsrc       Build debian source package
89 debbin       Build debian binary package
90 linklint     Check links of doxygen documentation with 'linklint'
91 fixlinks     Fix broken links in doxygen documentation
92 valgrind     Run all tests under valgrind/memcheck
93 """)
94
95 if os.environ.get('debian_build'):
96     rev = os.popen("dpkg-parsechangelog | awk '/^Version:/{print $2}'").read().strip()
97 else:
98     rev = 'r' + os.popen("svnversion").read().strip().lower()
99
100 logname = os.environ.get('LOGNAME')
101 if not logname:
102     logname = pwd.getpwuid(os.getuid()).pw_name
103
104 def dpkgIgnoredFilesOpts(target, source, env, for_signature):
105     return [ '-I%s' % (('/' in f) and (os.path.split(os.getcwd())[1])+f or f)
106              for f in env.subst('$DPKG_IGNORED_FILES').split() ]
107
108 # Options used to debug inlining:
109 #
110 # INLINE_OPTS = [ '-finline-limit=20000', '--param','large-function-growth=10000',
111 #                 '--param', 'large-function-insns=10000', '--param','inline-unit-growth=10000',
112 #                 '-fvisibility-inlines-hidden', '-fno-inline-functions', '-Winline' ]
113 #
114 # BEWARE: You need lots of ram to compile with these settings (approx 1G)
115 #
116
117 INLINE_OPTS = [ '-finline-limit=5000' ]
118
119 env.Append(
120    CPPPATH = [ '#/include' ],
121    CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long' ] + INLINE_OPTS,
122    LIBS = [ 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
123             '$BOOSTFSLIB' ],
124    TEST_EXTRA_LIBS = [ ],
125    DOXY_XREF_TYPES = [ 'bug', 'fixme', 'todo', 'idea' ],
126    DOXY_HTML_XSL = '#/doclib/html-munge.xsl',
127    ENV = { 'TODAY' : str(datetime.date.today()),
128            'REVISION' : rev,
129            'LOGNAME' : logname, # needed by the debian build scripts
130            'CONCURRENCY_LEVEL' : env.GetOption('num_jobs') or "1",
131            'SCONS' : 1,
132            'PATH' : os.environ.get('PATH'),
133            'TEXINPUTS' : os.environ.get('TEXINPUTS',env.Dir('#/doclib').abspath + ':'),
134          },
135    LOCAL_CONFIG_FILES = [ '/Doxyfile.local', '/SConfig', '/local_config.hh' ],
136    DPKG_IGNORED_FILES = [ '$LOCAL_CONFIG_FILES', '.svn', '/_templates' ],
137    DPKG_IGNORED_FILES_OPTS = dpkgIgnoredFilesOpts,
138    CLEAN_PATTERNS = [ '*~', '#*#', '*.pyc', 'semantic.cache', '.sconsign', '.sconsign.dblite' ],
139    BUILDPACKAGE_COMMAND = "dpkg-buildpackage -us -uc -rfakeroot $DPKG_IGNORED_FILES_OPTS",
140    TOP_INCLUDES = [ 'Packets', 'PPI', 'Scheduler', 'Socket', 'Utils', 'Console',
141                     'config.hh', 'local_config.hh' ],
142 )
143
144 def parseLogOption(value):
145     stream, area, level = ( x.strip() for x in value.strip().split('|') )
146     if stream  : stream = ''.join('(%s)' % x for x in stream.split('::') )
147     else       : stream = '(_)'
148     if area : area = ''.join( '(%s)' % x for x in area.split('::') )
149     else    : area = '(_)'
150     return '(( %s,%s,%s ))' % (stream,area,level)
151
152 def expandLogOption(target, source, env, for_signature):
153     return ' '.join( parseLogOption(x) for x in env.subst('$LOGLEVELS').split() )
154
155 if env.subst('$LOGLEVELS'):
156     env.Append( expandLogOption=expandLogOption )
157     env.Append( CPPDEFINES = { 'SENF_LOG_CONF': '$expandLogOption' } )
158
159 env.SetDefault(
160        LIBSENF = "senf"
161 )
162
163 Export('env')
164
165 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
166 # Create it even when cleaning, to silence the doxygen builder warnings
167 if not os.path.exists("Doxyfile.local"):
168     Execute(Touch("Doxyfile.local"))
169
170 # Create local_config.h
171 if not env.GetOption('clean') and not os.path.exists("local_config.hh"):
172     Execute(Touch("local_config.hh"))
173
174 ###########################################################################
175 # Define build targets
176
177 # Before defining any targets, check wether this is the first build in
178 # pristine directory tree. If so, call 'scons prepare' so the dependencies
179 # created later are correct
180
181 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
182    and not os.environ.get("SCONS") and COMMAND_LINE_TARGETS != [ 'prepare' ]:
183     env.Execute([ "scons prepare" ])
184
185 env.Clean('all', '.prepare-stamp')
186
187 SConscript(glob.glob("*/SConscript"))
188
189 SENFSCons.StandardTargets(env)
190 SENFSCons.GlobalTargets(env)
191 SENFSCons.Doxygen(env)
192 SENFSCons.DoxyXRef(env,
193                    HTML_HEADER = '#/doclib/doxy-header.html',
194                    HTML_FOOTER = '#/doclib/doxy-footer.html')
195
196 SENFSCons.InstallIncludeFiles(env, [ 'config.hh' ])
197
198 # Build combined library 'libsenf'
199 libsenf = env.Library(env.subst("$LIBSENF$LIBADDSUFFIX"), env['ALLOBJECTS'])
200 env.Default(libsenf)
201 env.Clean('all', libsenf)
202 env.Alias('default', libsenf)
203
204 env.Alias('install_all', env.Install('$LIBINSTALLDIR', libsenf))
205
206 if env.GetOption('clean'):
207     env.Clean('all', [ os.path.join(path,f)
208                        for path, subdirs, files in os.walk('.')
209                        for pattern in env['CLEAN_PATTERNS']
210                        for f in fnmatch.filter(files,pattern) ])
211
212 PhonyTarget(env, 'deb', [
213     checkLocalConf,
214     updateRevision,
215     "$BUILDPACKAGE_COMMAND",
216     "fakeroot ./debian/rules debclean"
217 ])
218
219 PhonyTarget(env, 'debsrc', [
220     updateRevision,
221     "$BUILDPACKAGE_COMMAND -S",
222 ])
223
224 PhonyTarget(env, 'debbin', [
225     checkLocalConf,
226     updateRevision,
227     "$BUILDPACKAGE_COMMAND -b",
228     "fakeroot ./debian/rules debclean"
229 ])
230
231 PhonyTarget(env, 'linklint', [
232     'rm -rf linklint',
233     'linklint -doc linklint -limit 99999999 `find -type d -name html -printf "/%P/@ "`',
234     '[ ! -r linklint/errorX.html ] || python doclib/linklint_addnames.py <linklint/errorX.html >linklint/errorX.html.new',
235     '[ ! -r linklint/errorX.html.new ] || mv linklint/errorX.html.new linklint/errorX.html',
236     '[ ! -r linklint/errorAX.html ] || python doclib/linklint_addnames.py <linklint/errorAX.html >linklint/errorAX.html.new',
237     '[ ! -r linklint/errorAX.html.new ] || mv linklint/errorAX.html.new linklint/errorAX.html',
238     'echo -e "\\nLokal link check results: linklint/index.html\\nRemote link check results: linklint/urlindex.html\\n"',
239 ])
240
241 PhonyTarget(env, 'fixlinks', [
242     'python doclib/fix-links.py -v -s .svn -s linklint -s debian linklint/errorX.txt linklint/errorAX.txt',
243 ])
244
245 PhonyTarget(env, 'prepare', [])
246
247 PhonyTarget(env, 'valgrind', [
248     'find -name .test.bin | while read test; do echo; echo "Running $$test"; echo; valgrind --tool=memcheck --error-exitcode=99 --suppressions=valgrind.sup $$test $BOOSTTESTARGS; [ $$? -ne 99 ] || exit 1; done'
249     ], [ 'all_tests' ])
250
251 env.Clean('all', env.Dir('linklint'))
252
253 env.Clean('all','.prepare-stamp')
254 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
255     Execute(Touch(".prepare-stamp"))