5fd8c881141d051a2c0baf1bf68eabb7dcf4ee47
[senf.git] / SConstruct
1 # -*- python -*-
2
3 import sys, glob, os.path, datetime, pwd, time, fnmatch
4 sys.path.append('senfscons')
5 import SENFSCons
6
7 ###########################################################################
8
9 # This hack is needed for SCons V 0.96.1 compatibility. In current SCons versions
10 # we can just use 'env.AlwaysBuild(env.Alias(target), [], action)'
11 def PhonyTarget(env, target, action):
12     env.AlwaysBuild(env.Command(target + '.phony', 'SConstruct', env.Action(action)))
13     env.Alias(target, target + '.phony')
14
15 def updateRevision(target, source, env):
16     rev = env['ENV']['REVISION'][1:]
17     if ':' in rev:
18         print
19         print "Working copy not clean. Run 'svn update'"
20         print
21         return 1
22     if 'm' in rev and not ARGUMENTS.get('force_deb'):
23         print
24         print "Working copy contains local changes. Commit first"
25         print
26         return 1
27     if 's' in rev:
28         rev = rev[:-1]
29     if 'm' in rev:
30         rev = rev[:-1]
31     changelog = file('debian/changelog.template').read() % {
32         'rev': rev,
33         'user': pwd.getpwuid(os.getuid()).pw_gecos.split(',')[0].strip(),
34         'date': time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) }
35     file('debian/changelog','w').write(changelog)
36
37 def nonemptyFile(f):
38     try: return os.stat(f).st_size > 0
39     except OSError: return False
40
41 def checkLocalConf(target, source, env):
42     if [ True for f in env['CONFIG_FILES'] if nonemptyFile(f) ]:
43         print
44         print "You have made local modifications to 'SConfig' and/or 'Doxyfile.local'."
45         print "Building a debian package would remove those files."
46         print
47         print "To continue, remove the offending file(s) and try again. Alternatively,"
48         print "build a source package using 'scons debsrc' and may then build debian"
49         print "binary packages from this source-package without disrupting your print local"
50         print "configuration."
51         print
52         return 1
53
54 ###########################################################################
55 # Load utilities and setup libraries and configure build
56
57 SENFSCons.UseBoost()
58 SENFSCons.UseSTLPort()
59 env = SENFSCons.MakeEnvironment()
60
61 env.Help("""
62 Additional top-level build targets:
63
64 prepare      Create all source files not part of the repository
65 all_tests    Build and run unit tests for all modules
66 all_docs     Build documentation for all modules
67 all          Build everything
68 install_all  Install SENF into $PREFIX
69 deb          Build debian source and binary package
70 debsrc       Build debian source package
71 debbin       Build debian binary package
72 linklint     Check links of doxygen documentation with 'linklint'
73 fixlinks     Fix broken links in doxygen documentation
74 """)
75
76 if os.environ.get('debian_build'):
77     rev = os.popen("dpkg-parsechangelog | awk '/^Version:/{print $2}'").read().strip()
78 else:
79     rev = 'r' + os.popen("svnversion").read().strip().lower()
80
81 logname = os.environ.get('LOGNAME')
82 if not logname:
83     logname = pwd.getpwuid(os.getuid()).pw_name
84
85 def configFilesOpts(target, source, env, for_signature):
86     return [ '-I%s' % os.path.split(f)[1] for f in env['CONFIG_FILES'] ]
87
88 env.Append(
89    CPPPATH = [ '#/include' ],
90    LIBS = [ 'iberty', '$BOOSTREGEXLIB', '$BOOSTFSLIB' ],
91    DOXY_XREF_TYPES = [ 'bug', 'fixme', 'todo', 'idea' ],
92    DOXY_HTML_XSL = '#/doclib/html-munge.xsl',
93    ENV = { 'TODAY' : str(datetime.date.today()),
94            'REVISION' : rev,
95            'LOGNAME' : logname, # needed by the debian build scripts
96            'CONCURRENCY_LEVEL' : env.GetOption('num_jobs') or "1",
97            'SCONS' : 1
98            },
99    CONFIG_FILES = [ 'Doxyfile.local', 'SConfig', 'local_config.hh' ],
100    CONFIG_FILES_OPTS = configFilesOpts,
101    CLEAN_PATTERNS = [ '*.pyc', 'semantic.cache', '.sconsign', '.sconsign.dblite' ],
102    BUILDPACKAGE_COMMAND = "dpkg-buildpackage -us -uc -rfakeroot -I.svn $CONFIG_FILES_OPTS",
103    TOP_INCLUDES = [ 'Packets', 'PPI', 'Scheduler', 'Socket', 'Utils',
104                     'config.hh', 'local_config.hh' ]
105 )
106
107 Export('env')
108
109 # Create Doxyfile.local otherwise doxygen will barf on this non-existent file
110 if not env.GetOption('clean') and not os.path.exists("Doxyfile.local"):
111     Execute(Touch("Doxyfile.local"))
112
113 # Create local_config.h
114 if not env.GetOption('clean') and not os.path.exists("local_config.hh"):
115     Execute(Touch("local_config.hh"))
116
117 ###########################################################################
118 # Define build targets
119
120 # Before defining any targets, check wether this is the first build in
121 # pristine directory tree. If so, call 'scons prepare' so the dependencies
122 # created later are correct
123
124 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
125    and not os.environ.get("SCONS"):
126     env.Execute([ "scons prepare" ])
127
128 env.Clean('all', '.prepare-stamp')
129
130 SConscript(glob.glob("*/SConscript"))
131
132 SENFSCons.StandardTargets(env)
133 SENFSCons.GlobalTargets(env)
134 SENFSCons.Doxygen(env)
135 SENFSCons.DoxyXRef(env,
136                    HTML_HEADER = '#/doclib/doxy-header-overview.html',
137                    HTML_FOOTER = '#/doclib/doxy-footer.html')
138
139 SENFSCons.InstallIncludeFiles(env, [ 'config.hh' ])
140
141 # Build combined library 'libsenf'
142 libsenf = env.Library(
143     SENFSCons.LibPath('senf'),
144     Flatten([ env.File(SENFSCons.LibPath(lib)).sources for lib in env['ALLLIBS'] ]))
145 env.Default(libsenf)
146 env.Clean('all', 'libsenf.a')
147 env.Alias('default', 'libsenf.a')
148
149 env.Alias('install_all', env.Install('$LIBINSTALLDIR', libsenf))
150
151 env.Clean('all', [ os.path.join(path,f)
152                    for path, subdirs, files in os.walk('.')
153                    for pattern in env['CLEAN_PATTERNS']
154                    for f in fnmatch.filter(files,pattern) ])
155
156 PhonyTarget(env, 'deb', [
157     checkLocalConf,
158     updateRevision,
159     "$BUILDPACKAGE_COMMAND",
160 ])
161
162 PhonyTarget(env, 'debsrc', [
163     updateRevision,
164     "$BUILDPACKAGE_COMMAND -S",
165 ])
166
167 PhonyTarget(env, 'debbin', [
168     checkLocalConf,
169     updateRevision,
170     "$BUILDPACKAGE_COMMAND -nc",
171 ])
172
173 PhonyTarget(env, 'linklint', [
174     'rm -rf linklint',
175     'linklint -doc linklint -net -limit 99999999 `find -type d -name html -printf "/%P/@ "`',
176     '[ ! -r linklint/errorX.html ] || python linklint_addnames.py <linklint/errorX.html >linklint/errorX.html.new',
177     '[ ! -r linklint/errorX.html.new ] || mv linklint/errorX.html.new linklint/errorX.html',
178     '[ ! -r linklint/errorAX.html ] || python linklint_addnames.py <linklint/errorAX.html >linklint/errorAX.html.new',
179     '[ ! -r linklint/errorAX.html.new ] || mv linklint/errorAX.html.new linklint/errorAX.html',
180     'echo -e "\\nLokal link check results: linklint/index.html\\nRemote link check results: linklint/urlindex.html\\n"',
181 ])
182
183 PhonyTarget(env, 'fixlinks', [
184     'python doclib/fix-links.py -v -s .svn -s linklint -s debian linklint/errorX.txt linklint/errorAX.txt',
185 ])
186
187 PhonyTarget(env, 'prepare', [])
188
189 env.Clean('all', env.Dir('linklint'))
190
191 env.Clean('all','.prepare-stamp')
192 if not env.GetOption('clean') and not os.path.exists(".prepare-stamp"):
193     Execute(Touch(".prepare-stamp"))