blob: 72a870665d8d957c6f450f2ff529f35ba7996598 [file] [log] [blame]
akmhoquefa8ee9b2014-03-14 09:06:24 -05001#! /usr/bin/env python
2# encoding: utf-8
3# WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file
4
5'''
6
7This is an extra tool, not bundled with the default waf binary.
8To add the boost tool to the waf file:
9$ ./waf-light --tools=compat15,boost
10 or, if you have waf >= 1.6.2
11$ ./waf update --files=boost
12
13When using this tool, the wscript will look like:
14
15 def options(opt):
16 opt.load('compiler_cxx boost')
17
18 def configure(conf):
19 conf.load('compiler_cxx boost')
20 conf.check_boost(lib='system filesystem')
21
22 def build(bld):
23 bld(source='main.cpp', target='app', use='BOOST')
24
25Options are generated, in order to specify the location of boost includes/libraries.
26The `check_boost` configuration function allows to specify the used boost libraries.
27It can also provide default arguments to the --boost-static and --boost-mt command-line arguments.
28Everything will be packaged together in a BOOST component that you can use.
29
30When using MSVC, a lot of compilation flags need to match your BOOST build configuration:
31 - you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined.
32 Errors: C4530
33 - boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC
34 So before calling `conf.check_boost` you might want to disabling by adding:
35 conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
36 Errors:
37 - boost might also be compiled with /MT, which links the runtime statically.
38 If you have problems with redefined symbols,
39 self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
40 self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc']
41Passing `--boost-linkage_autodetect` might help ensuring having a correct linkage in some basic cases.
42
43'''
44import sys
45import re
46from waflib import Utils,Logs,Errors
47from waflib.Configure import conf
48BOOST_LIBS=['/usr/lib','/usr/local/lib','/opt/local/lib','/sw/lib','/lib']
49BOOST_INCLUDES=['/usr/include','/usr/local/include','/opt/local/include','/sw/include']
50BOOST_VERSION_FILE='boost/version.hpp'
51BOOST_VERSION_CODE='''
52#include <iostream>
53#include <boost/version.hpp>
54int main() { std::cout << BOOST_LIB_VERSION << std::endl; }
55'''
56PLATFORM=Utils.unversioned_sys_platform()
57detect_intel=lambda env:(PLATFORM=='win32')and'iw'or'il'
58detect_clang=lambda env:(PLATFORM=='darwin')and'clang-darwin'or'clang'
59detect_mingw=lambda env:(re.search('MinGW',env.CXX[0]))and'mgw'or'gcc'
60BOOST_TOOLSETS={'borland':'bcb','clang':detect_clang,'como':'como','cw':'cw','darwin':'xgcc','edg':'edg','g++':detect_mingw,'gcc':detect_mingw,'icpc':detect_intel,'intel':detect_intel,'kcc':'kcc','kylix':'bck','mipspro':'mp','mingw':'mgw','msvc':'vc','qcc':'qcc','sun':'sw','sunc++':'sw','tru64cxx':'tru','vacpp':'xlc'}
61def options(opt):
62 opt.add_option('--boost-includes',type='string',default='',dest='boost_includes',help='''path to the boost includes root (~boost root)
63 e.g. /path/to/boost_1_47_0''')
64 opt.add_option('--boost-libs',type='string',default='',dest='boost_libs',help='''path to the directory where the boost libs are
65 e.g. /path/to/boost_1_47_0/stage/lib''')
66 opt.add_option('--boost-static',action='store_true',default=False,dest='boost_static',help='link with static boost libraries (.lib/.a)')
67 opt.add_option('--boost-mt',action='store_true',default=False,dest='boost_mt',help='select multi-threaded libraries')
68 opt.add_option('--boost-abi',type='string',default='',dest='boost_abi',help='''select libraries with tags (dgsyp, d for debug),
69 see doc Boost, Getting Started, chapter 6.1''')
70 opt.add_option('--boost-linkage_autodetect',action="store_true",dest='boost_linkage_autodetect',help="auto-detect boost linkage options (don't get used to it / might break other stuff)")
71 opt.add_option('--boost-toolset',type='string',default='',dest='boost_toolset',help='force a toolset e.g. msvc, vc90, \
72 gcc, mingw, mgw45 (default: auto)')
73 py_version='%d%d'%(sys.version_info[0],sys.version_info[1])
74 opt.add_option('--boost-python',type='string',default=py_version,dest='boost_python',help='select the lib python with this version \
75 (default: %s)'%py_version)
76@conf
77def __boost_get_version_file(self,dir):
78 try:
79 return self.root.find_dir(dir).find_node(BOOST_VERSION_FILE)
80 except:
81 return None
82@conf
83def boost_get_version(self,dir):
84 re_but=re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.*)"$',re.M)
85 try:
86 val=re_but.search(self.__boost_get_version_file(dir).read()).group(1)
87 except:
88 val=self.check_cxx(fragment=BOOST_VERSION_CODE,includes=[dir],execute=False,define_ret=True)
89 return val
90@conf
91def boost_get_includes(self,*k,**kw):
92 includes=k and k[0]or kw.get('includes',None)
93 if includes and self.__boost_get_version_file(includes):
94 return includes
95 for d in Utils.to_list(self.environ.get('INCLUDE',''))+BOOST_INCLUDES:
96 if self.__boost_get_version_file(d):
97 return d
98 if includes:
99 self.end_msg('headers not found in %s'%includes)
100 self.fatal('The configuration failed')
101 else:
102 self.end_msg('headers not found, please provide a --boost-includes argument (see help)')
103 self.fatal('The configuration failed')
104@conf
105def boost_get_toolset(self,cc):
106 toolset=cc
107 if not cc:
108 build_platform=Utils.unversioned_sys_platform()
109 if build_platform in BOOST_TOOLSETS:
110 cc=build_platform
111 else:
112 cc=self.env.CXX_NAME
113 if cc in BOOST_TOOLSETS:
114 toolset=BOOST_TOOLSETS[cc]
115 return isinstance(toolset,str)and toolset or toolset(self.env)
116@conf
117def __boost_get_libs_path(self,*k,**kw):
118 ''' return the lib path and all the files in it '''
119 if'files'in kw:
120 return self.root.find_dir('.'),Utils.to_list(kw['files'])
121 libs=k and k[0]or kw.get('libs',None)
122 if libs:
123 path=self.root.find_dir(libs)
124 files=path.ant_glob('*boost_*')
125 if not libs or not files:
126 for d in Utils.to_list(self.environ.get('LIB',[]))+BOOST_LIBS:
127 try:
128 path=self.root.find_dir(d)
129 files=path.ant_glob('*boost_*')
130 if files:
131 break
132 path=self.root.find_dir(d+'64')
133 files=path.ant_glob('*boost_*')
134 if files:
135 break
136 except:
137 path=None
138 if not path:
139 if libs:
140 self.end_msg('libs not found in %s'%libs)
141 self.fatal('The configuration failed')
142 else:
143 self.end_msg('libs not found, please provide a --boost-libs argument (see help)')
144 self.fatal('The configuration failed')
145 self.to_log('Found the boost path in %r with the libraries:'%path)
146 for x in files:
147 self.to_log(' %r'%x)
148 return path,files
149@conf
150def boost_get_libs(self,*k,**kw):
151 '''
152 return the lib path and the required libs
153 according to the parameters
154 '''
155 path,files=self.__boost_get_libs_path(**kw)
156 t=[]
157 if kw.get('mt',False):
158 t.append('mt')
159 if kw.get('abi',None):
160 t.append(kw['abi'])
161 tags=t and'(-%s)+'%'-'.join(t)or''
162 toolset=self.boost_get_toolset(kw.get('toolset',''))
163 toolset_pat='(-%s[0-9]{0,3})+'%toolset
164 version='(-%s)+'%self.env.BOOST_VERSION
165 def find_lib(re_lib,files):
166 for file in files:
167 if re_lib.search(file.name):
168 self.to_log('Found boost lib %s'%file)
169 return file
170 return None
171 def format_lib_name(name):
172 if name.startswith('lib')and self.env.CC_NAME!='msvc':
173 name=name[3:]
174 return name[:name.rfind('.')]
175 libs=[]
176 for lib in Utils.to_list(k and k[0]or kw.get('lib',None)):
177 py=(lib=='python')and'(-py%s)+'%kw['python']or''
178 for pattern in['boost_%s%s%s%s%s'%(lib,toolset_pat,tags,py,version),'boost_%s%s%s%s'%(lib,tags,py,version),'boost_%s%s%s'%(lib,tags,version),'boost_%s%s%s%s'%(lib,toolset_pat,tags,py),'boost_%s%s%s'%(lib,tags,py),'boost_%s%s'%(lib,tags)]:
179 self.to_log('Trying pattern %s'%pattern)
180 file=find_lib(re.compile(pattern),files)
181 if file:
182 libs.append(format_lib_name(file.name))
183 break
184 else:
185 self.end_msg('lib %s not found in %s'%(lib,path.abspath()))
186 self.fatal('The configuration failed')
187 return path.abspath(),libs
188@conf
189def check_boost(self,*k,**kw):
190 if not self.env['CXX']:
191 self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
192 params={'lib':k and k[0]or kw.get('lib',None)}
193 for key,value in self.options.__dict__.items():
194 if not key.startswith('boost_'):
195 continue
196 key=key[len('boost_'):]
197 params[key]=value and value or kw.get(key,'')
198 var=kw.get('uselib_store','BOOST')
199 self.start_msg('Checking boost includes')
200 self.env['INCLUDES_%s'%var]=inc=self.boost_get_includes(**params)
201 self.env.BOOST_VERSION=self.boost_get_version(inc)
202 self.end_msg(self.env.BOOST_VERSION)
203 if Logs.verbose:
204 Logs.pprint('CYAN',' path : %s'%self.env['INCLUDES_%s'%var])
205 if not params['lib']:
206 return
207 self.start_msg('Checking boost libs')
208 suffix=params.get('static',None)and'ST'or''
209 path,libs=self.boost_get_libs(**params)
210 self.env['%sLIBPATH_%s'%(suffix,var)]=[path]
211 self.env['%sLIB_%s'%(suffix,var)]=libs
212 self.end_msg('ok')
213 if Logs.verbose:
214 Logs.pprint('CYAN',' path : %s'%path)
215 Logs.pprint('CYAN',' libs : %s'%libs)
216 def try_link():
217 if'system'in params['lib']:
218 self.check_cxx(fragment="\n".join(['#include <boost/system/error_code.hpp>','int main() { boost::system::error_code c; }',]),use=var,execute=False,)
219 if'thread'in params['lib']:
220 self.check_cxx(fragment="\n".join(['#include <boost/thread.hpp>','int main() { boost::thread t; }',]),use=var,execute=False,)
221 if params.get('linkage_autodetect',False):
222 self.start_msg("Attempting to detect boost linkage flags")
223 toolset=self.boost_get_toolset(kw.get('toolset',''))
224 if toolset in['vc']:
225 self.env['DEFINES_%s'%var]+=['BOOST_ALL_NO_LIB']
226 has_dlls=False
227 for x in Utils.listdir(path):
228 if x.endswith(self.env.cxxshlib_PATTERN%''):
229 has_dlls=True
230 break
231 if not has_dlls:
232 self.env['STLIBPATH_%s'%var]=[path]
233 self.env['STLIB_%s'%var]=libs
234 del self.env['LIB_%s'%var]
235 del self.env['LIBPATH_%s'%var]
236 for cxxflags in(['/MD','/EHsc'],[]):
237 self.env.stash()
238 self.env["CXXFLAGS_%s"%var]+=cxxflags
239 try:
240 try_link()
241 self.end_msg("ok: winning cxxflags combination: %s"%(self.env["CXXFLAGS_%s"%var]))
242 e=None
243 break
244 except Errors.ConfigurationError as exc:
245 self.env.revert()
246 e=exc
247 if e is not None:
248 self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author",ex=e)
249 self.fatal('The configuration failed')
250 else:
251 self.end_msg("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain")
252 self.fatal('The configuration failed')
253 else:
254 self.start_msg('Checking for boost linkage')
255 try:
256 try_link()
257 except Errors.ConfigurationError ,e:
258 self.end_msg("Could not link against boost libraries using supplied options")
259 self.fatal('The configuration failed')
260 self.end_msg('ok')