Replace SENFSCons.InstallIncludeFiles with InstallSubdir builder calls
[senf.git] / senfscons / SENFSCons.py
1 import os.path, glob
2 import SCons.Options, SCons.Environment, SCons.Script.SConscript, SCons.Node.FS
3 import SCons.Defaults, SCons.Action
4 from SCons.Script import *
5
6 def GlobSources(env, exclude=[], subdirs=[]):
7     testSources = glob.glob("*.test.cc")
8     sources = [ x for x in glob.glob("*.cc") if x not in testSources and x not in exclude ]
9     for subdir in subdirs:
10         testSources += glob.glob(os.path.join(subdir,"*.test.cc"))
11         sources += [ x for x in glob.glob(os.path.join(subdir,"*.cc"))
12                      if x not in testSources and x not in exclude ]
13     return (sources, testSources)
14
15 def GlobIncludes(env, exclude=[], subdirs=[]):
16     includes = []
17     for d in [ '.' ] + subdirs:
18         for f in os.listdir(d):
19             ext = '.' + f.split('.',1)[-1]
20             p = os.path.join(d,f)
21             if ext in env['CPP_INCLUDE_EXTENSIONS'] \
22                and ext not in env['CPP_EXCLUDE_EXTENSIONS'] \
23                and p not in exclude:
24                 includes.append(p)
25     return includes
26
27 def Glob(env, exclude=[], subdirs=[]):
28     return ( GlobSources(env, exclude, subdirs),
29              GlobIncludes(env, exclude, subdirs) )
30
31 def LibPath(lib): return '${LOCALLIBDIR}/${LIBPREFIX}%s${LIBADDSUFFIX}${LIBSUFFIX}' % lib
32
33 def Test(env, sources, LIBS = [], OBJECTS = []):
34     test = [ env.BoostUnitTests(
35         target = 'test',
36         objects = [],
37         test_sources = sources,
38         LIBS = [ '$LIBSENF$LIBADDSUFFIX' ],
39         OBJECTS = OBJECTS,
40         DEPENDS = [ env.File(LibPath(env['LIBSENF'])) ]) ]
41     compileTestSources = [ src for src in sources
42                            if 'COMPILE_CHECK' in file(src).read() ]
43     if compileTestSources:
44         test.extend(env.CompileCheck(source = compileTestSources))
45     env.Alias('all_tests', test)
46     env.Command(env.File('test'), test, [ 'true' ])
47     
48
49 def Objects(env, sources, testSources = None, OBJECTS = []):
50     if type(sources) == type(()):
51         testSources = sources[1]
52         sources = sources[0]
53     if type(sources) is not type([]):
54         sources = [ sources ]
55
56     objects = None
57     if sources:
58         obsources = [ source
59                       for source in sources
60                       if type(source) is type('') and not source.endswith('.o') ]
61         objects = [ source
62                     for source in sources
63                     if type(source) is not type('') or source.endswith('.o') ]
64         if obsources:
65             objects += env.Object(obsources)
66
67     if testSources:
68         test = [ env.BoostUnitTests(
69             target = 'test',
70             objects = objects,
71             test_sources = testSources,
72             LIBS = [ '$LIBSENF$LIBADDSUFFIX' ],
73             OBJECTS = OBJECTS,
74             DEPENDS = [ env.File(LibPath(env['LIBSENF'])) ]) ]
75         compileTestSources = [ src for src in testSources
76                                if 'COMPILE_CHECK' in file(src).read() ]
77         if compileTestSources:
78             test.extend(env.CompileCheck(source = compileTestSources))
79         env.Alias('all_tests', test)
80         # Hmm ... here I'd like to use an Alias instead of a file
81         # however the alias does not seem to live in the subdirectory
82         # which breaks 'scons -u test'
83         env.Command(env.File('test'), test, [ 'true' ])
84         #env.Alias(env.File('test'), test)
85
86     return objects
87
88 ## \brief Build documentation with doxygen
89 #
90 # \ingroup target
91 def Doxygen(env, doxyfile = "Doxyfile", extra_sources = []):
92     # There is one small problem we need to solve with this builder: The Doxygen builder reads
93     # the Doxyfile and thus depends on the environment variables set by doclib/doxygen.sh. We
94     # thus have to provide all necessary definitions here manually via DOXYENV !
95
96     if type(doxyfile) is type(""):
97         doxyfile = env.File(doxyfile)
98
99     # Module name is derived from the doxyfile path
100     # Utils/Console/Doxyfile -> Utils_Console
101     module = doxyfile.dir.abspath[len(env.Dir('#').abspath)+1:].replace('/','_')
102     if not module : module = "Main"
103
104     # Rule to generate tagfile
105     # (need to exclude the 'clean' case, otherwise we'll have duplicate nodes)
106     if not env.GetOption('clean'):
107         tagfile = env.Doxygen(doxyfile,
108                               DOXYOPTS = [ '--tagfile-name', '"${MODULE}.tag"',
109                                            '--tagfile' ],
110                               DOXYENV  = { 'TOPDIR'          : env.Dir('#').abspath,
111                                            'output_dir'      : 'doc',
112                                            'html_dir'        : 'html',
113                                            'html'            : 'NO',
114                                            'generate_tagfile': 'doc/${MODULE}.tag' },
115                               MODULE   = module )
116         env.Append(ALL_TAGFILES = tagfile[0].abspath)
117         env.Depends(tagfile, env.File('#/doclib/doxygen.sh'))
118
119     # Rule to generate HTML documentation
120     doc = env.Doxygen(doxyfile,
121                       DOXYOPTS = [ '--tagfiles', '"$ALL_TAGFILES"',
122                                    '--tagfile-name', '"${MODULE}.tag"',
123                                    '--html' ],
124                       MODULE   = module,
125                       DOXYENV  = { 'TOPDIR'          : env.Dir('#').abspath,
126                                    'tagfiles'        : '${ALL_TAGFILES}',
127                                    'output_dir'      : 'doc',
128                                    'html_dir'        : 'html',
129                                    'html'            : 'YES' } )
130     env.Depends(doc, env.File('#/doclib/doxygen.sh'))
131
132     # Copy the extra_sources (the images) into the documentation directory
133     # (need to exclude the 'clean' case otherwise there are multiple ways to clean the copies)
134     if not env.GetOption('clean'):
135         if extra_sources:
136             env.Depends(doc,
137                         [ env.CopyToDir( source=source, target=doc[0].dir )
138                           for source in extra_sources ])
139
140     # Install documentation into DOCINSTALLDIR
141     l = len(env.Dir('#').abspath)
142     env.Alias('install_all',
143               env.Command('$DOCINSTALLDIR' + doc[0].dir.abspath[l:], doc[0].dir,
144                           [ SCons.Defaults.Copy('$TARGET','$SOURCE') ]))
145
146     # Useful aliases
147     env.Alias('all_docs', doc)
148     env.Clean('all_docs', doc)
149     env.Clean('all', doc)
150
151     return doc
152
153 def Lib(env, sources, testSources = None, OBJECTS = []):
154     objects = Objects(env,sources,testSources,OBJECTS=OBJECTS)
155     env.Append(ALLOBJECTS = objects)
156     return objects
157
158 def Object(env, target, sources, testSources = None, OBJECTS = []):
159     objects = Objects(env,sources,testSources,OBJECTS=OBJECTS)
160     ob = env.Command(target+"${OBJADDSUFFIX}${OBJSUFFIX}", objects, "ld -r -o $TARGET $SOURCES")
161     env.Default(ob)
162     env.Alias('default', ob)
163     env.Alias('install_all', env.Install("$OBJINSTALLDIR", ob))
164     return ob
165
166 def Binary(env, binary, sources, testSources = None, OBJECTS = []):
167     objects = Objects(env, sources, testSources, OBJECTS=OBJECTS)
168     program = env.Program(target = binary, 
169                           source = objects+OBJECTS,
170                           LIBS   = [ '$LIBSENF$LIBADDSUFFIX' ] + env['LIBS'])
171     env.Default(program)
172     env.Alias('default', program)
173     env.Alias('install_all', env.Install('$BININSTALLDIR', program))
174     return program
175
176 def AllIncludesHH(env, headers):
177     headers.sort()
178     target = env.File("all_includes.hh")
179     file(target.abspath,"w").write("".join([ '#include "%s"\n' % f
180                                              for f in headers ]))
181     env.Clean('all', target)
182
183 def PhonyTarget(env, target, action, sources=[]):
184     env.AlwaysBuild(env.Alias(target, sources, env.Action(action)))