~ubuntu-branches/ubuntu/saucy/xmms2/saucy-proposed

« back to all changes in this revision

Viewing changes to wafadmin/Tools/boost.py

  • Committer: Bazaar Package Importer
  • Author(s): Florian Ragwitz
  • Date: 2009-05-02 08:31:32 UTC
  • mto: (1.1.6 upstream) (6.1.3 sid)
  • mto: This revision was merged to the branch mainline in revision 23.
  • Revision ID: james.westby@ubuntu.com-20090502083132-y0ulwiqbk4lxfd4z
ImportĀ upstreamĀ versionĀ 0.6DrMattDestruction

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# encoding: utf-8
 
3
#
 
4
# partially based on boost.py written by Gernot Vormayr
 
5
# written by Ruediger Sonderfeld <ruediger@c-plusplus.de>, 2008
 
6
# modified by Bjoern Michaelsen, 2008
 
7
# modified by Luca Fossati, 2008
 
8
# rewritten for waf 1.5.1, Thomas Nagy, 2008
 
9
#
 
10
#def set_options(opt):
 
11
#       opt.tool_options('boost')
 
12
#       # ...
 
13
#
 
14
#def configure(conf):
 
15
#       # ... (e.g. conf.check_tool('g++'))
 
16
#       conf.check_tool('boost')
 
17
#   conf.check_boost(lib='signals filesystem', kind='STATIC_BOTH', score_version=(-1000, 1000), tag_minscore=1000)
 
18
#
 
19
#
 
20
#ISSUES:
 
21
# * find_includes should be called only once!
 
22
# * support mandatory
 
23
 
 
24
######## boost update ###########
 
25
## ITA: * the method get_boost_version_number does work
 
26
##      * the rest of the code has not really been tried
 
27
#       * make certain a demo is provided (in demos/adv for example)
 
28
 
 
29
import os.path, glob, types, re, sys
 
30
import Configure, config_c, Options, Utils, Logs
 
31
from Logs import warn
 
32
from Configure import conf
 
33
 
 
34
boost_code = '''
 
35
#include <iostream>
 
36
#include <boost/version.hpp>
 
37
int main() { std::cout << BOOST_VERSION << std::endl; }
 
38
'''
 
39
 
 
40
boost_libpath = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib']
 
41
boost_cpppath = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']
 
42
 
 
43
STATIC_NOSTATIC = 'nostatic'
 
44
STATIC_BOTH = 'both'
 
45
STATIC_ONLYSTATIC = 'onlystatic'
 
46
 
 
47
is_versiontag = re.compile('^\d+_\d+_?\d*$')
 
48
is_threadingtag = re.compile('^mt$')
 
49
is_abitag = re.compile('^[sgydpn]+$')
 
50
is_toolsettag = re.compile('^(acc|borland|como|cw|dmc|darwin|gcc|hp_cxx|intel|kylix|msvc|qcc|sun|vacpp)\d*$')
 
51
 
 
52
def set_options(opt):
 
53
        opt.add_option('--boost-includes', type='string', default='', dest='boostincludes', help='path to the boost directory where the includes are e.g. /usr/local/include/boost-1_35')
 
54
        opt.add_option('--boost-libs', type='string', default='', dest='boostlibs', help='path to the directory where the boost libs are e.g. /usr/local/lib')
 
55
 
 
56
def string_to_version(s):
 
57
        version = s.split('.')
 
58
        if len(version) < 3: return 0
 
59
        return int(version[0])*100000 + int(version[1])*100 + int(version[2])
 
60
 
 
61
def version_string(version):
 
62
        major = version / 100000
 
63
        minor = version / 100 % 1000
 
64
        minor_minor = version % 100
 
65
        if minor_minor == 0:
 
66
                return "%d_%d" % (major, minor)
 
67
        else:
 
68
                return "%d_%d_%d" % (major, minor, minor_minor)
 
69
 
 
70
def libfiles(lib, pattern, lib_paths):
 
71
        result = []
 
72
        for lib_path in lib_paths:
 
73
                libname = pattern % ('boost_' + lib + '*')
 
74
                result += glob.glob(lib_path + '/' + libname)
 
75
        return result
 
76
 
 
77
@conf
 
78
def get_boost_version_number(self, dir):
 
79
        """silently retrieve the boost version number"""
 
80
        try:
 
81
                return self.run_c_code(compiler='cxx', code=boost_code, includes=dir, execute=1, env=self.env.copy(), type='cprogram', compile_mode='cxx', compile_filename='test.cpp')
 
82
        except Configure.ConfigurationError, e:
 
83
                return -1
 
84
 
 
85
def set_default(kw, var, val):
 
86
        if not var in kw:
 
87
                kw[var] = val
 
88
 
 
89
def tags_score(tags, kw):
 
90
        """
 
91
        checks library tags
 
92
 
 
93
        see http://www.boost.org/doc/libs/1_35_0/more/getting_started/unix-variants.html 6.1
 
94
        """
 
95
        score = 0
 
96
        needed_tags = {
 
97
                'threading': kw['tag_threading'],
 
98
                'abi': kw['tag_abi'],
 
99
                'toolset': kw['tag_toolset'],
 
100
                'version': kw['tag_version']
 
101
        }
 
102
 
 
103
        if kw['tag_toolset'] is None:
 
104
                v = kw['env']
 
105
                toolset = v['CXX_NAME']
 
106
                if v['CXX_VERSION']:
 
107
                        version_no = v['CXX_VERSION'].split('.')
 
108
                        toolset += version_no[0]
 
109
                        if len(version_no) > 1:
 
110
                                toolset += version_no[1]
 
111
                needed_tags['toolset'] = toolset
 
112
 
 
113
        found_tags = {}
 
114
        for tag in tags:
 
115
                if is_versiontag.match(tag): found_tags['version'] = tag
 
116
                if is_threadingtag.match(tag): found_tags['threading'] = tag
 
117
                if is_abitag.match(tag): found_tags['abi'] = tag
 
118
                if is_toolsettag.match(tag): found_tags['toolset'] = tag
 
119
 
 
120
        for tagname in needed_tags.iterkeys():
 
121
                if needed_tags[tagname] is not None and tagname in found_tags:
 
122
                        if re.compile(needed_tags[tagname]).match(found_tags[tagname]):
 
123
                                score += kw['score_' + tagname][0]
 
124
                        else:
 
125
                                score += kw['score_' + tagname][1]
 
126
        return score
 
127
 
 
128
@conf
 
129
def validate_boost(self, kw):
 
130
        ver = kw.get('version', '')
 
131
 
 
132
        for x in 'min_version max_version version'.split():
 
133
                set_default(kw, x, ver)
 
134
 
 
135
        set_default(kw, 'lib', '')
 
136
        kw['lib'] = Utils.to_list(kw['lib'])
 
137
 
 
138
        set_default(kw, 'env', self.env)
 
139
 
 
140
        set_default(kw, 'libpath', boost_libpath)
 
141
        set_default(kw, 'cpppath', boost_cpppath)
 
142
 
 
143
        for x in 'tag_threading tag_version tag_toolset'.split():
 
144
                set_default(kw, x, None)
 
145
        set_default(kw, 'tag_abi', '^[^d]*$')
 
146
 
 
147
        set_default(kw, 'score_threading', (10, -10))
 
148
        set_default(kw, 'score_abi', (10, -10))
 
149
        set_default(kw, 'score_toolset', (1, -1))
 
150
        set_default(kw, 'score_version', (100, -100))
 
151
 
 
152
        set_default(kw, 'score_min', 0)
 
153
        set_default(kw, 'static', STATIC_NOSTATIC)
 
154
        set_default(kw, 'found_includes', False)
 
155
        set_default(kw, 'min_score', 0)
 
156
 
 
157
        set_default(kw, 'errmsg', 'not found')
 
158
        set_default(kw, 'okmsg', 'ok')
 
159
 
 
160
@conf
 
161
def find_boost_includes(self, kw):
 
162
        """
 
163
        check every path in kw['cpppath'] for subdir
 
164
        that either starts with boost- or is named boost.
 
165
 
 
166
        Then the version is checked and selected accordingly to
 
167
        min_version/max_version. The highest possible version number is
 
168
        selected!
 
169
 
 
170
        If no versiontag is set the versiontag is set accordingly to the
 
171
        selected library and CPPPATH_BOOST is set.
 
172
        """
 
173
        boostPath = getattr(Options.options, 'boostincludes', '')
 
174
        if boostPath:
 
175
                boostPath = [os.path.normpath(os.path.expandvars(os.path.expanduser(boostPath)))]
 
176
        else:
 
177
                boostPath = Utils.to_list(kw['cpppath'])
 
178
 
 
179
        min_version = string_to_version(kw.get('min_version', ''))
 
180
        max_version = string_to_version(kw.get('max_version', '')) or (sys.maxint - 1)
 
181
 
 
182
        version = 0
 
183
        for include_path in boostPath:
 
184
                boost_paths = glob.glob(os.path.join(include_path, 'boost*'))
 
185
                for path in boost_paths:
 
186
                        pathname = os.path.split(path)[-1]
 
187
                        ret = -1
 
188
                        if pathname == 'boost':
 
189
                                path = include_path
 
190
                                ret = self.get_boost_version_number(path)
 
191
                        elif pathname.startswith('boost-'):
 
192
                                ret = self.get_boost_version_number(path)
 
193
                        ret = int(ret)
 
194
 
 
195
                        if ret != -1 and ret >= min_version and ret <= max_version and ret > version:
 
196
                                boost_path = path
 
197
                                version = ret
 
198
                                break
 
199
        if not version:
 
200
                self.fatal('boost headers not found! (required version min: %s max: %s)'
 
201
                          % (kw['min_version'], kw['max_version']))
 
202
                return False
 
203
 
 
204
        found_version = version_string(version)
 
205
        versiontag = '^' + found_version + '$'
 
206
        if kw['tag_version'] is None:
 
207
                kw['tag_version'] = versiontag
 
208
        elif kw['tag_version'] != versiontag:
 
209
                warn('boost header version %r and tag_version %r do not match!' % (versiontag, kw['tag_version']))
 
210
        env = self.env
 
211
        env['CPPPATH_BOOST'] = boost_path
 
212
        env['BOOST_VERSION'] = found_version
 
213
        self.found_includes = 1
 
214
        ret = 'Version %s (%s)' % (found_version, boost_path)
 
215
        return ret
 
216
 
 
217
@conf
 
218
def find_boost_library(self, lib, kw):
 
219
 
 
220
        def find_library_from_list(lib, files):
 
221
                lib_pattern = re.compile('.*boost_(.*?)\..*')
 
222
                result = (None, None)
 
223
                resultscore = kw['min_score'] - 1
 
224
                for file in files:
 
225
                        m = lib_pattern.search(file, 1)
 
226
                        if m:
 
227
                                libname = m.group(1)
 
228
                                libtags = libname.split('-')[1:]
 
229
                                currentscore = tags_score(libtags, kw)
 
230
                                if currentscore > resultscore:
 
231
                                        result = (libname, file)
 
232
                                        resultscore = currentscore
 
233
                return result
 
234
 
 
235
        lib_paths = getattr(Options.options, 'boostlibs', '')
 
236
        if lib_paths:
 
237
                lib_paths = [os.path.normpath(os.path.expandvars(os.path.expanduser(lib_paths)))]
 
238
        else:
 
239
                lib_paths = Utils.to_list(kw['libpath'])
 
240
 
 
241
        v = kw.get('env', self.env)
 
242
 
 
243
        (libname, file) = (None, None)
 
244
        if kw['static'] in [STATIC_NOSTATIC, STATIC_BOTH]:
 
245
                st_env_prefix = 'LIB'
 
246
                files = libfiles(lib, v['shlib_PATTERN'], lib_paths)
 
247
                (libname, file) = find_library_from_list(lib, files)
 
248
        if libname is None and kw['static'] in [STATIC_ONLYSTATIC, STATIC_BOTH]:
 
249
                st_env_prefix = 'STATICLIB'
 
250
                files = libfiles(lib, v['staticlib_PATTERN'], lib_paths)
 
251
                (libname, file) = find_library_from_list(lib, files)
 
252
        if libname is not None:
 
253
                v['LIBPATH_BOOST_' + lib.upper()] = os.path.split(file)[0]
 
254
                v[st_env_prefix + '_BOOST_' + lib.upper()] = 'boost_'+libname
 
255
                return
 
256
        self.fatal('lib boost_' + lib + ' not found!')
 
257
 
 
258
@conf
 
259
def check_boost(self, *k, **kw):
 
260
        """
 
261
        This should be the main entry point
 
262
 
 
263
- min_version
 
264
- max_version
 
265
- version
 
266
- include_path
 
267
- lib_path
 
268
- lib
 
269
- toolsettag   - None or a regexp
 
270
- threadingtag - None or a regexp
 
271
- abitag       - None or a regexp
 
272
- versiontag   - WARNING: you should rather use version or min_version/max_version
 
273
- static       - look for static libs (values:
 
274
          'nostatic'   or STATIC_NOSTATIC   - ignore static libs (default)
 
275
          'both'       or STATIC_BOTH       - find static libs, too
 
276
          'onlystatic' or STATIC_ONLYSTATIC - find only static libs
 
277
- score_version
 
278
- score_abi
 
279
- scores_threading
 
280
- score_toolset
 
281
 * the scores are tuples (match_score, nomatch_score)
 
282
   match_score is the added to the score if the tag is matched
 
283
   nomatch_score is added when a tag is found and does not match
 
284
- min_score
 
285
        """
 
286
 
 
287
        self.validate_boost(kw)
 
288
        ret = None
 
289
        try:
 
290
                if not kw.get('found_includes', None):
 
291
                        self.check_message_1(kw.get('msg_includes', 'boost headers'))
 
292
                        ret = self.find_boost_includes(kw)
 
293
 
 
294
        except Configure.ConfigurationError, e:
 
295
                if 'errmsg' in kw:
 
296
                        self.check_message_2(kw['errmsg'], 'YELLOW')
 
297
                if 'mandatory' in kw:
 
298
                        if Logs.verbose > 1:
 
299
                                raise
 
300
                        else:
 
301
                                self.fatal('the configuration failed (see config.log)')
 
302
        else:
 
303
                if 'okmsg' in kw:
 
304
                        self.check_message_2(kw.get('okmsg_includes', ret))
 
305
 
 
306
        for lib in kw['lib']:
 
307
                self.check_message_1('library boost_'+lib)
 
308
                try:
 
309
                        self.find_boost_library(lib, kw)
 
310
                except Configure.ConfigurationError, e:
 
311
                        if 'errmsg' in kw:
 
312
                                self.check_message_2(kw['errmsg'], 'YELLOW')
 
313
                        if 'mandatory' in kw:
 
314
                                if Logs.verbose > 1:
 
315
                                        raise
 
316
                                else:
 
317
                                        self.fatal('the configuration failed (see config.log)')
 
318
                else:
 
319
                        if 'okmsg' in kw:
 
320
                                self.check_message_2(kw['okmsg'])
 
321
 
 
322
        return ret
 
323