Again some doc-build fixes
[senf.git] / senfscons / SENFSCons.py
1 import os.path, glob
2 import  SCons.Options, SCons.Environment, SCons.Script.SConscript, SCons.Node.FS, SCons.Defaults
3
4 SCONS_TOOLS = [
5     "Doxygen",
6     "Dia2Png",
7 ]
8
9 opts = None
10 finalizers = []
11
12 basedir = os.path.abspath(os.path.split(__file__)[0])
13
14 def InitOpts():
15     global opts
16     if opts is not None: return
17     opts = SCons.Options.Options('SConfig')
18     opts.Add('CXX', 'C++ compiler to use', 'g++')
19     opts.Add('EXTRA_DEFINES', 'Additional preprocessor defines', '')
20     opts.Add('EXTRA_LIBS', 'Additional libraries to link against', '')
21     opts.Add(SCons.Options.BoolOption('final','Enable optimization',0))
22
23 def Finalizer(f):
24     global finalizers
25     finalizers.append(f)
26
27 def UseBoost():
28     global opts
29     InitOpts()
30     opts.Add('BOOST_INCLUDES', 'Boost include directory', '')
31     opts.Add('BOOST_VARIANT', 'The boost variant to use', '')
32     opts.Add('BOOST_TOOLSET', 'The boost toolset to use', '')
33     opts.Add('BOOST_RUNTIME', 'The boost runtime to use', '')
34     opts.Add('BOOST_DEBUG_RUNTIME', 'The boost debug runtime to use', '')
35     opts.Add('BOOST_LIBDIR', 'The directory of the boost libraries', '')
36     Finalizer(FinalizeBoost)
37
38 def FinalizeBoost(env):
39     env.Tool('BoostUnitTests', [basedir])
40
41     if env['BOOST_TOOLSET']:
42         runtime = ""
43         if env['final'] : runtime += env.get('BOOST_RUNTIME','')
44         else            : runtime += env.get('BOOST_DEBUG_RUNTIME','gd')
45         if env['STLPORT_LIB'] : runtime += "p"
46         if runtime: runtime = "-" + runtime
47         env['BOOST_VARIANT'] = "-" + env['BOOST_TOOLSET'] + runtime
48
49     env['BOOSTTESTLIB'] = 'libboost_unit_test_framework' + env['BOOST_VARIANT']
50
51     env.Append(LIBPATH = [ '$BOOST_LIBDIR' ],
52                CPPPATH = [ '$BOOST_INCLUDES' ])
53
54 def UseSTLPort():
55     global opts
56     InitOpts()
57     opts.Add('STLPORT_INCLUDES', 'STLport include directory', '')
58     opts.Add('STLPORT_LIB', 'Name of the stlport library or empty to not use stlport', '')
59     opts.Add('STLPORT_DEBUGLIB', 'Name of the stlport debug library','')
60     opts.Add('STLPORT_LIBDIR', 'The directory of the stlport libraries','')
61     Finalizer(FinalizeSTLPort)
62
63 def FinalizeSTLPort(env):
64     if env['STLPORT_LIB']:
65         if not env['STLPORT_DEBUGLIB']:
66             env['STLPORT_DEBUGLIB'] = env['STLPORT_LIB'] + '_stldebug'
67         env.Append(LIBPATH = [ '$STLPORT_LIBDIR' ],
68                    CPPPATH = [ '$STLPORT_INCLUDES' ])
69         if env['final']:
70             env.Append(LIBS = [ '$STLPORT_LIB' ])
71         else:
72             env.Append(LIBS = [ '$STLPORT_DEBUGLIB' ],
73                        CPPDEFINES = [ '_STLP_DEBUG' ])
74
75 def MakeEnvironment():
76     global opts, finalizers
77     InitOpts()
78     env = SCons.Environment.Environment(options=opts)
79     if SCons.Script.SConscript.Arguments.get('final'):
80         env['final'] = 1
81     env.Help(opts.GenerateHelpText(env))
82     #conf = env.Configure()
83     #env = conf.env
84     if os.environ.has_key('SSH_AUTH_SOCK'):
85         env.Append( ENV = { 'SSH_AUTH_SOCK': os.environ['SSH_AUTH_SOCK'] } )
86
87     for finalizer in finalizers:
88         finalizer(env)
89
90     for tool in SCONS_TOOLS:
91         env.Tool(tool, [basedir])
92
93     env.Append(CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long' ],
94                LOCALLIBDIR = [ '#' ],
95                LIBPATH = [ '$LOCALLIBDIR' ])
96
97     if env['final']:
98         env.Append(CXXFLAGS = [ '-O3' ],
99                    CPPDEFINES = [ 'NDEBUG' ])
100     else:
101         env.Append(CXXFLAGS = [ '-O0', '-g', '-fno-inline' ],
102                    LINKFLAGS = [ '-g' ])
103
104     env.Append(CPPDEFINES = [ '$EXTRA_DEFINES' ],
105                LIBS = [ '$EXTRA_LIBS' ])
106
107     #return conf.Finish()
108     return env
109
110 def GlobSources(exclude=[]):
111     testSources = glob.glob("*.test.cc")
112     sources = [ x for x in glob.glob("*.cc") if x not in testSources and x not in exclude ]
113     return (sources, testSources)
114     
115 def StandardTargets(env):
116     all = env.Alias('all')
117     env.Clean(all, [ '.sconsign', '.sconf_temp', 'config.log' ])
118     env.Depends(all, '.')
119
120 def GlobalTargets(env):
121     pass
122
123 def LibPath(lib): return '$LOCALLIBDIR/lib%s.a' % lib
124     
125 def Objects(env, sources, testSources = None, LIBS = []):
126     if type(sources) == type(()):
127         testSources = sources[1]
128         sources = sources[0]
129
130     objects = None
131     if sources:
132         objects = env.Object(sources)
133
134     if testSources:
135         test = env.BoostUnitTests(
136             target = 'test',
137             source = sources,
138             test_source = testSources,
139             LIBS = LIBS,
140             DEPENDS = [ env.File(LibPath(x)) for x in LIBS ])
141         env.Alias('all_tests', test)
142         # Hmm ... here I'd like to use an Alias instead of a file
143         # however the alias does not seem to live in the subdirectory
144         # which breaks 'scons -u test'
145         env.Alias(env.File('test'), test)
146
147     return objects
148
149 def Doxygen(env, doxyfile = "Doxyfile", extra_sources = []):
150     # ARGHHH !!! without the [:] we are changing the target list
151     #        ||| WITHIN THE DOXYGEN BUILDER
152     docs = env.Doxygen(doxyfile)[:]
153     xmlnode = None
154     tagnode = None
155     for doc in docs:
156         if isinstance(doc,SCons.Node.FS.Dir): continue
157         if doc.name == 'xml.stamp' : xmlnode = doc
158         if os.path.splitext(doc.name)[1] == '.stamp' : continue # file stamp
159         # otherwise it must be the tag file
160         tagnode = doc
161
162     if tagnode:
163         # Postprocess the tag file to remove the (broken) namespace
164         # references
165         env.AddPostAction(
166             docs,
167             env.Action("xsltproc -o %(target)s.temp %(template)s %(target)s && mv %(target)s.temp %(target)s"
168                        % { 'target': tagnode.abspath,
169                            'template': os.path.join(basedir,"tagmunge.xsl") }))
170
171     if xmlnode:
172         xrefs = []
173         for type in env.get("DOXY_XREF_TYPES",[ "bug", "todo" ]):
174             xref = os.path.join(xmlnode.dir.abspath,type+".xml")
175             xref_pp = env.Command(xref+'i', [ xref, os.path.join(basedir,'xrefxtract.xslt'), xmlnode ],
176                                   [ "test -s $SOURCE && xsltproc -o $TARGET" +
177                                     " --stringparam module $MODULE" + 
178                                     " --stringparam type $TYPE" +
179                                     " ${SOURCES[1]} $SOURCE || touch $TARGET" ],
180                                   MODULE = xmlnode.dir.dir.dir.name,
181                                   TYPE = type)
182             env.SideEffect(xref, xmlnode)
183             env.AddPreAction(docs, "rm -f %s" % (xref,))
184             env.AddPostAction(docs, "test -r %s || touch %s" % (xref,xref))
185             xrefs.extend(xref_pp)
186         docs.extend(xrefs)
187
188     env.Depends(docs,extra_sources)
189     for doc in docs :
190         env.Alias('all_docs', doc)
191         env.Clean('all_docs', doc)
192         env.Clean('all', doc)
193     return docs
194
195 def DoxyXRef(env, docs=None,
196              HTML_HEADER = None, HTML_FOOTER = None,
197              TITLE = "Cross-reference of action points"):
198     if docs is None:
199         docs = env.Alias('all_docs')[0].sources
200     xrefs = [ doc for doc in docs if os.path.splitext(doc.name)[1] == ".xmli" ]
201     xref = env.Command("doc/html/xref.xml", xrefs,
202                        [ "echo -e '<?xml version=\"1.0\"?>\\n<xref>' >$TARGET",
203                          "cat $SOURCES >> $TARGET",
204                          "echo '</xref>' >>$TARGET" ])
205
206     # Lastly we create the html file
207     sources = [ xref, "%s/xrefhtml.xslt" % basedir ]
208     if HTML_HEADER : sources.append(HTML_HEADER)
209     if HTML_FOOTER : sources.append(HTML_FOOTER)
210
211     commands = []
212     if HTML_HEADER:
213         commands.append(
214             "sed -e 's/\\$$title/$TITLE/g' -e 's/\\$$projectname/Overview/g' ${SOURCES[2]} > $TARGET")
215     commands.append("xsltproc --stringparam title '$TITLE' ${SOURCES[1]} $SOURCE >> $TARGET")
216     if HTML_FOOTER:
217         commands.append(
218             "sed -e 's/\\$$title/$TITLE/g' -e 's/\\$$projectname/Overview/g' ${SOURCES[%d]} >> $TARGET"
219             % (HTML_HEADER and 3 or 2))
220     
221     xref = env.Command("doc/html/xref.html", sources, commands,
222                        TITLE = TITLE)
223
224     env.Alias('all_docs',xref)
225     return xref
226
227 def Lib(env, library, sources, testSources = None, LIBS = []):
228     objects = Objects(env,sources,testSources,LIBS=LIBS)
229     lib = None
230     if objects:
231         lib = env.Library(env.File(LibPath(library)),objects)
232         env.Default(lib)
233         env.Append(ALLLIBS = library)
234     return lib
235
236 def Binary(env, binary, sources, testSources = None, LIBS = []):
237     objects = Objects(env,sources,testSources,LIBS=LIBS)
238     program = None
239     if objects:
240         progEnv = env.Copy()
241         progEnv.Prepend(LIBS = LIBS)
242         program = progEnv.Program(target=binary,source=objects)
243         env.Default(program)
244         env.Depends(program, [ env.File(LibPath(x)) for x in LIBS ])
245     return program