misc.py 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. # Copyright 2013-2017 The Meson development team
  2. # Licensed under the Apache License, Version 2.0 (the "License");
  3. # you may not use this file except in compliance with the License.
  4. # You may obtain a copy of the License at
  5. # http://www.apache.org/licenses/LICENSE-2.0
  6. # Unless required by applicable law or agreed to in writing, software
  7. # distributed under the License is distributed on an "AS IS" BASIS,
  8. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. # See the License for the specific language governing permissions and
  10. # limitations under the License.
  11. # This file contains the detection logic for miscellaneous external dependencies.
  12. import glob
  13. import os
  14. import re
  15. import shlex
  16. import shutil
  17. import sysconfig
  18. from pathlib import Path
  19. from .. import mlog
  20. from .. import mesonlib
  21. from ..mesonlib import Popen_safe, extract_as_list
  22. from ..environment import detect_cpu_family
  23. from .base import (
  24. DependencyException, DependencyMethods, ExternalDependency,
  25. ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency,
  26. ConfigToolDependency,
  27. )
  28. # On windows 3 directory layouts are supported:
  29. # * The default layout (versioned) installed:
  30. # - $BOOST_ROOT/include/boost-x_x/boost/*.hpp
  31. # - $BOOST_ROOT/lib/*.lib
  32. # * The non-default layout (system) installed:
  33. # - $BOOST_ROOT/include/boost/*.hpp
  34. # - $BOOST_ROOT/lib/*.lib
  35. # * The pre-built binaries from sf.net:
  36. # - $BOOST_ROOT/boost/*.hpp
  37. # - $BOOST_ROOT/lib<arch>-<compiler>/*.lib where arch=32/64 and compiler=msvc-14.1
  38. #
  39. # Library names supported:
  40. # - libboost_<module>-<compiler>-mt-gd-x_x.lib (static)
  41. # - boost_<module>-<compiler>-mt-gd-x_x.lib|.dll (shared)
  42. # - libboost_<module>.lib (static)
  43. # - boost_<module>.lib|.dll (shared)
  44. # where compiler is vc141 for example.
  45. #
  46. # NOTE: -gb means runtime and build time debugging is on
  47. # -mt means threading=multi
  48. #
  49. # The `modules` argument accept library names. This is because every module that
  50. # has libraries to link against also has multiple options regarding how to
  51. # link. See for example:
  52. # * http://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/boost_test/usage_variants.html
  53. # * http://www.boost.org/doc/libs/1_65_1/doc/html/stacktrace/configuration_and_build.html
  54. # * http://www.boost.org/doc/libs/1_65_1/libs/math/doc/html/math_toolkit/main_tr1.html
  55. class BoostDependency(ExternalDependency):
  56. def __init__(self, environment, kwargs):
  57. super().__init__('boost', environment, 'cpp', kwargs)
  58. self.need_static_link = ['boost_exception', 'boost_test_exec_monitor']
  59. self.is_debug = environment.cmd_line_options.buildtype.startswith('debug')
  60. threading = kwargs.get("threading", "multi")
  61. self.is_multithreading = threading == "multi"
  62. self.requested_modules = self.get_requested(kwargs)
  63. invalid_modules = [c for c in self.requested_modules if 'boost_' + c not in BOOST_LIBS]
  64. if invalid_modules:
  65. mlog.warning('Invalid Boost modules: ' + ', '.join(invalid_modules))
  66. self.log_fail()
  67. return
  68. self.boost_root = None
  69. self.boost_roots = []
  70. self.incdir = None
  71. self.libdir = None
  72. if 'BOOST_ROOT' in os.environ:
  73. self.boost_root = os.environ['BOOST_ROOT']
  74. self.boost_roots = [self.boost_root]
  75. if not os.path.isabs(self.boost_root):
  76. raise DependencyException('BOOST_ROOT must be an absolute path.')
  77. if 'BOOST_INCLUDEDIR' in os.environ:
  78. self.incdir = os.environ['BOOST_INCLUDEDIR']
  79. if 'BOOST_LIBRARYDIR' in os.environ:
  80. self.libdir = os.environ['BOOST_LIBRARYDIR']
  81. if self.boost_root is None:
  82. if mesonlib.is_windows():
  83. self.boost_roots = self.detect_win_roots()
  84. else:
  85. self.boost_roots = self.detect_nix_roots()
  86. if self.boost_root is None and not self.boost_roots:
  87. self.log_fail()
  88. return
  89. if self.incdir is None:
  90. if mesonlib.is_windows():
  91. self.incdir = self.detect_win_incdir()
  92. else:
  93. self.incdir = self.detect_nix_incdir()
  94. if self.incdir is None:
  95. self.log_fail()
  96. return
  97. mlog.debug('Boost library root dir is', mlog.bold(self.boost_root))
  98. mlog.debug('Boost include directory is', mlog.bold(self.incdir))
  99. self.lib_modules = {}
  100. self.detect_version()
  101. if self.is_found:
  102. self.detect_lib_modules()
  103. mlog.debug('Boost library directory is', mlog.bold(self.libdir))
  104. self.validate_requested()
  105. self.log_success()
  106. else:
  107. self.log_fail()
  108. def log_fail(self):
  109. module_str = ', '.join(self.requested_modules)
  110. mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO'))
  111. def log_success(self):
  112. module_str = ', '.join(self.requested_modules)
  113. if self.boost_root:
  114. info = self.version + ', ' + self.boost_root
  115. else:
  116. info = self.version
  117. mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info)
  118. def detect_nix_roots(self):
  119. return [os.path.abspath(os.path.join(x, '..'))
  120. for x in self.compiler.get_default_include_dirs()]
  121. def detect_win_roots(self):
  122. res = []
  123. # Where boost documentation says it should be
  124. globtext = 'C:\\Program Files\\boost\\boost_*'
  125. files = glob.glob(globtext)
  126. res.extend(files)
  127. # Where boost built from source actually installs it
  128. if os.path.isdir('C:\\Boost'):
  129. res.append('C:\\Boost')
  130. # Where boost prebuilt binaries are
  131. globtext = 'C:\\local\\boost_*'
  132. files = glob.glob(globtext)
  133. res.extend(files)
  134. return res
  135. def detect_nix_incdir(self):
  136. for root in self.boost_roots:
  137. incdir = os.path.join(root, 'include', 'boost')
  138. if os.path.isdir(incdir):
  139. return os.path.join(root, 'include')
  140. return None
  141. # FIXME: Should pick a version that matches the requested version
  142. # Returns the folder that contains the boost folder.
  143. def detect_win_incdir(self):
  144. for root in self.boost_roots:
  145. globtext = os.path.join(root, 'include', 'boost-*')
  146. incdirs = glob.glob(globtext)
  147. if len(incdirs) > 0:
  148. return incdirs[0]
  149. incboostdir = os.path.join(root, 'include', 'boost')
  150. if os.path.isdir(incboostdir):
  151. return os.path.join(root, 'include')
  152. incboostdir = os.path.join(root, 'boost')
  153. if os.path.isdir(incboostdir):
  154. return root
  155. return None
  156. def get_compile_args(self):
  157. args = []
  158. include_dir = self.incdir
  159. # Use "-isystem" when including boost headers instead of "-I"
  160. # to avoid compiler warnings/failures when "-Werror" is used
  161. # Careful not to use "-isystem" on default include dirs as it
  162. # breaks some of the headers for certain gcc versions
  163. # For example, doing g++ -isystem /usr/include on a simple
  164. # "int main()" source results in the error:
  165. # "/usr/include/c++/6.3.1/cstdlib:75:25: fatal error: stdlib.h: No such file or directory"
  166. # See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129
  167. # and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors
  168. # for more details
  169. if include_dir and include_dir not in self.compiler.get_default_include_dirs():
  170. args.append("".join(self.compiler.get_include_args(include_dir, True)))
  171. return args
  172. def get_requested(self, kwargs):
  173. candidates = extract_as_list(kwargs, 'modules')
  174. for c in candidates:
  175. if not isinstance(c, str):
  176. raise DependencyException('Boost module argument is not a string.')
  177. return candidates
  178. def validate_requested(self):
  179. for m in self.requested_modules:
  180. if 'boost_' + m not in self.lib_modules:
  181. msg = 'Requested Boost library {!r} not found'
  182. raise DependencyException(msg.format(m))
  183. def detect_version(self):
  184. try:
  185. ifile = open(os.path.join(self.incdir, 'boost', 'version.hpp'))
  186. except FileNotFoundError:
  187. return
  188. except TypeError:
  189. return
  190. with ifile:
  191. for line in ifile:
  192. if line.startswith("#define") and 'BOOST_LIB_VERSION' in line:
  193. ver = line.split()[-1]
  194. ver = ver[1:-1]
  195. self.version = ver.replace('_', '.')
  196. self.is_found = True
  197. return
  198. def detect_lib_modules(self):
  199. if mesonlib.is_windows():
  200. return self.detect_lib_modules_win()
  201. return self.detect_lib_modules_nix()
  202. def detect_lib_modules_win(self):
  203. arch = detect_cpu_family(self.env.coredata.compilers)
  204. comp_ts_version = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version()
  205. compiler_ts = comp_ts_version.split('.')
  206. compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1])
  207. if not self.libdir:
  208. # The libdirs in the distributed binaries (from sf)
  209. if arch == 'x86':
  210. lib_sf = 'lib32-msvc-{}'.format(comp_ts_version)
  211. elif arch == 'x86_64':
  212. lib_sf = 'lib64-msvc-{}'.format(comp_ts_version)
  213. else:
  214. # Does anyone do Boost cross-compiling to other archs on Windows?
  215. lib_sf = None
  216. if self.boost_root:
  217. roots = [self.boost_root]
  218. else:
  219. roots = self.boost_roots
  220. for root in roots:
  221. # The default libdir when building
  222. libdir = os.path.join(root, 'lib')
  223. if os.path.isdir(libdir):
  224. self.libdir = libdir
  225. break
  226. if lib_sf:
  227. full_path = os.path.join(root, lib_sf)
  228. if os.path.isdir(full_path):
  229. self.libdir = full_path
  230. break
  231. if not self.libdir:
  232. return
  233. for name in self.need_static_link:
  234. libname = "lib{}".format(name) + '-' + compiler
  235. if self.is_multithreading:
  236. libname = libname + '-mt'
  237. if self.is_debug:
  238. libname = libname + '-gd'
  239. libname = libname + "-{}.lib".format(self.version.replace('.', '_'))
  240. if os.path.isfile(os.path.join(self.libdir, libname)):
  241. modname = libname.split('-', 1)[0][3:]
  242. self.lib_modules[modname] = libname
  243. else:
  244. libname = "lib{}.lib".format(name)
  245. if os.path.isfile(os.path.join(self.libdir, libname)):
  246. self.lib_modules[name[3:]] = libname
  247. # globber1 applies to a layout=system installation
  248. # globber2 applies to a layout=versioned installation
  249. globber1 = 'libboost_*' if self.static else 'boost_*'
  250. globber2 = globber1 + '-' + compiler
  251. if self.is_multithreading:
  252. globber2 = globber2 + '-mt'
  253. if self.is_debug:
  254. globber2 = globber2 + '-gd'
  255. globber2 = globber2 + '-{}'.format(self.version.replace('.', '_'))
  256. globber2_matches = glob.glob(os.path.join(self.libdir, globber2 + '.lib'))
  257. for entry in globber2_matches:
  258. (_, fname) = os.path.split(entry)
  259. modname = fname.split('-', 1)
  260. if len(modname) > 1:
  261. modname = modname[0]
  262. else:
  263. modname = modname.split('.', 1)[0]
  264. if self.static:
  265. modname = modname[3:]
  266. self.lib_modules[modname] = fname
  267. if len(globber2_matches) == 0:
  268. for entry in glob.glob(os.path.join(self.libdir, globber1 + '.lib')):
  269. (_, fname) = os.path.split(entry)
  270. modname = fname.split('.', 1)[0]
  271. if self.static:
  272. modname = modname[3:]
  273. self.lib_modules[modname] = fname
  274. def detect_lib_modules_nix(self):
  275. if self.static:
  276. libsuffix = 'a'
  277. elif mesonlib.is_osx() and not self.want_cross:
  278. libsuffix = 'dylib'
  279. else:
  280. libsuffix = 'so'
  281. globber = 'libboost_*.{}'.format(libsuffix)
  282. if self.libdir:
  283. libdirs = [self.libdir]
  284. elif self.boost_root is None:
  285. libdirs = mesonlib.get_library_dirs()
  286. else:
  287. libdirs = [os.path.join(self.boost_root, 'lib')]
  288. for libdir in libdirs:
  289. for name in self.need_static_link:
  290. libname = 'lib{}.a'.format(name)
  291. if os.path.isfile(os.path.join(libdir, libname)):
  292. self.lib_modules[name] = libname
  293. for entry in glob.glob(os.path.join(libdir, globber)):
  294. lib = os.path.basename(entry)
  295. name = lib.split('.')[0][3:]
  296. # I'm not 100% sure what to do here. Some distros
  297. # have modules such as thread only as -mt versions.
  298. # On debian all packages are built threading=multi
  299. # but not suffixed with -mt.
  300. # FIXME: implement detect_lib_modules_{debian, redhat, ...}
  301. if self.is_multithreading and mesonlib.is_debianlike():
  302. self.lib_modules[name] = lib
  303. elif self.is_multithreading and entry.endswith('-mt.{}'.format(libsuffix)):
  304. self.lib_modules[name] = lib
  305. elif not entry.endswith('-mt.{}'.format(libsuffix)):
  306. self.lib_modules[name] = lib
  307. def get_win_link_args(self):
  308. args = []
  309. # TODO: should this check self.libdir?
  310. if self.libdir:
  311. args.append('-L' + self.libdir)
  312. for lib in self.requested_modules:
  313. args.append(self.lib_modules['boost_' + lib])
  314. return args
  315. def get_link_args(self):
  316. if mesonlib.is_windows():
  317. return self.get_win_link_args()
  318. args = []
  319. if self.boost_root:
  320. args.append('-L' + os.path.join(self.boost_root, 'lib'))
  321. elif self.libdir:
  322. args.append('-L' + self.libdir)
  323. for lib in self.requested_modules:
  324. # The compiler's library detector is the most reliable so use that first.
  325. boost_lib = 'boost_' + lib
  326. default_detect = self.compiler.find_library(boost_lib, self.env, [])
  327. if default_detect is not None:
  328. args += default_detect
  329. elif boost_lib in self.lib_modules:
  330. linkcmd = '-l' + boost_lib
  331. args.append(linkcmd)
  332. return args
  333. def get_sources(self):
  334. return []
  335. def need_threads(self):
  336. return 'thread' in self.requested_modules
  337. class MPIDependency(ExternalDependency):
  338. def __init__(self, environment, kwargs):
  339. language = kwargs.get('language', 'c')
  340. super().__init__('mpi', environment, language, kwargs)
  341. required = kwargs.pop('required', True)
  342. kwargs['required'] = False
  343. kwargs['silent'] = True
  344. self.is_found = False
  345. # NOTE: Only OpenMPI supplies a pkg-config file at the moment.
  346. if language == 'c':
  347. env_vars = ['MPICC']
  348. pkgconfig_files = ['ompi-c']
  349. default_wrappers = ['mpicc']
  350. elif language == 'cpp':
  351. env_vars = ['MPICXX']
  352. pkgconfig_files = ['ompi-cxx']
  353. default_wrappers = ['mpic++', 'mpicxx', 'mpiCC']
  354. elif language == 'fortran':
  355. env_vars = ['MPIFC', 'MPIF90', 'MPIF77']
  356. pkgconfig_files = ['ompi-fort']
  357. default_wrappers = ['mpifort', 'mpif90', 'mpif77']
  358. else:
  359. raise DependencyException('Language {} is not supported with MPI.'.format(language))
  360. for pkg in pkgconfig_files:
  361. try:
  362. pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
  363. if pkgdep.found():
  364. self.compile_args = pkgdep.get_compile_args()
  365. self.link_args = pkgdep.get_link_args()
  366. self.version = pkgdep.get_version()
  367. self.is_found = True
  368. break
  369. except Exception:
  370. pass
  371. if not self.is_found:
  372. # Prefer environment.
  373. for var in env_vars:
  374. if var in os.environ:
  375. wrappers = [os.environ[var]]
  376. break
  377. else:
  378. # Or search for default wrappers.
  379. wrappers = default_wrappers
  380. for prog in wrappers:
  381. result = self._try_openmpi_wrapper(prog)
  382. if result is not None:
  383. self.is_found = True
  384. self.version = result[0]
  385. self.compile_args = self._filter_compile_args(result[1])
  386. self.link_args = self._filter_link_args(result[2])
  387. break
  388. result = self._try_other_wrapper(prog)
  389. if result is not None:
  390. self.is_found = True
  391. self.version = result[0]
  392. self.compile_args = self._filter_compile_args(result[1])
  393. self.link_args = self._filter_link_args(result[2])
  394. break
  395. if not self.is_found and mesonlib.is_windows():
  396. result = self._try_msmpi()
  397. if result is not None:
  398. self.is_found = True
  399. self.version, self.compile_args, self.link_args = result
  400. if self.is_found:
  401. mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.green('YES'), self.version)
  402. else:
  403. mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.red('NO'))
  404. if required:
  405. raise DependencyException('MPI dependency {!r} not found'.format(self.name))
  406. def _filter_compile_args(self, args):
  407. """
  408. MPI wrappers return a bunch of garbage args.
  409. Drop -O2 and everything that is not needed.
  410. """
  411. result = []
  412. multi_args = ('-I', )
  413. if self.language == 'fortran':
  414. fc = self.env.coredata.compilers['fortran']
  415. multi_args += fc.get_module_incdir_args()
  416. include_next = False
  417. for f in args:
  418. if f.startswith(('-D', '-f') + multi_args) or f == '-pthread' \
  419. or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')):
  420. result.append(f)
  421. if f in multi_args:
  422. # Path is a separate argument.
  423. include_next = True
  424. elif include_next:
  425. include_next = False
  426. result.append(f)
  427. return result
  428. def _filter_link_args(self, args):
  429. """
  430. MPI wrappers return a bunch of garbage args.
  431. Drop -O2 and everything that is not needed.
  432. """
  433. result = []
  434. include_next = False
  435. for f in args:
  436. if f.startswith(('-L', '-l', '-Xlinker')) or f == '-pthread' \
  437. or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')):
  438. result.append(f)
  439. if f in ('-L', '-Xlinker'):
  440. include_next = True
  441. elif include_next:
  442. include_next = False
  443. result.append(f)
  444. return result
  445. def _try_openmpi_wrapper(self, prog):
  446. prog = ExternalProgram(prog, silent=True)
  447. if prog.found():
  448. cmd = prog.get_command() + ['--showme:compile']
  449. p, o, e = mesonlib.Popen_safe(cmd)
  450. p.wait()
  451. if p.returncode != 0:
  452. mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
  453. mlog.debug(mlog.bold('Standard output\n'), o)
  454. mlog.debug(mlog.bold('Standard error\n'), e)
  455. return
  456. cargs = shlex.split(o)
  457. cmd = prog.get_command() + ['--showme:link']
  458. p, o, e = mesonlib.Popen_safe(cmd)
  459. p.wait()
  460. if p.returncode != 0:
  461. mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
  462. mlog.debug(mlog.bold('Standard output\n'), o)
  463. mlog.debug(mlog.bold('Standard error\n'), e)
  464. return
  465. libs = shlex.split(o)
  466. cmd = prog.get_command() + ['--showme:version']
  467. p, o, e = mesonlib.Popen_safe(cmd)
  468. p.wait()
  469. if p.returncode != 0:
  470. mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
  471. mlog.debug(mlog.bold('Standard output\n'), o)
  472. mlog.debug(mlog.bold('Standard error\n'), e)
  473. return
  474. version = re.search('\d+.\d+.\d+', o)
  475. if version:
  476. version = version.group(0)
  477. else:
  478. version = 'none'
  479. return version, cargs, libs
  480. def _try_other_wrapper(self, prog):
  481. prog = ExternalProgram(prog, silent=True)
  482. if prog.found():
  483. cmd = prog.get_command() + ['-show']
  484. p, o, e = mesonlib.Popen_safe(cmd)
  485. p.wait()
  486. if p.returncode != 0:
  487. mlog.debug('Command', mlog.bold(cmd), 'failed to run:')
  488. mlog.debug(mlog.bold('Standard output\n'), o)
  489. mlog.debug(mlog.bold('Standard error\n'), e)
  490. return
  491. args = shlex.split(o)
  492. version = 'none'
  493. return version, args, args
  494. def _try_msmpi(self):
  495. if self.language == 'cpp':
  496. # MS-MPI does not support the C++ version of MPI, only the standard C API.
  497. return
  498. if 'MSMPI_INC' not in os.environ:
  499. return
  500. incdir = os.environ['MSMPI_INC']
  501. arch = detect_cpu_family(self.env.coredata.compilers)
  502. if arch == 'x86':
  503. if 'MSMPI_LIB32' not in os.environ:
  504. return
  505. libdir = os.environ['MSMPI_LIB32']
  506. post = 'x86'
  507. elif arch == 'x86_64':
  508. if 'MSMPI_LIB64' not in os.environ:
  509. return
  510. libdir = os.environ['MSMPI_LIB64']
  511. post = 'x64'
  512. else:
  513. return
  514. if self.language == 'fortran':
  515. return ('none',
  516. ['-I' + incdir, '-I' + os.path.join(incdir, post)],
  517. [os.path.join(libdir, 'msmpi.lib'), os.path.join(libdir, 'msmpifec.lib')])
  518. else:
  519. return ('none',
  520. ['-I' + incdir, '-I' + os.path.join(incdir, post)],
  521. [os.path.join(libdir, 'msmpi.lib')])
  522. class ThreadDependency(ExternalDependency):
  523. def __init__(self, environment, kwargs):
  524. super().__init__('threads', environment, None, {})
  525. self.name = 'threads'
  526. self.is_found = True
  527. mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
  528. def need_threads(self):
  529. return True
  530. def get_version(self):
  531. return 'unknown'
  532. class Python3Dependency(ExternalDependency):
  533. def __init__(self, environment, kwargs):
  534. super().__init__('python3', environment, None, kwargs)
  535. self.name = 'python3'
  536. self.static = kwargs.get('static', False)
  537. # We can only be sure that it is Python 3 at this point
  538. self.version = '3'
  539. self.pkgdep = None
  540. if DependencyMethods.PKGCONFIG in self.methods:
  541. try:
  542. self.pkgdep = PkgConfigDependency('python3', environment, kwargs)
  543. if self.pkgdep.found():
  544. self.compile_args = self.pkgdep.get_compile_args()
  545. self.link_args = self.pkgdep.get_link_args()
  546. self.version = self.pkgdep.get_version()
  547. self.is_found = True
  548. return
  549. else:
  550. self.pkgdep = None
  551. except Exception:
  552. pass
  553. if not self.is_found:
  554. if mesonlib.is_windows() and DependencyMethods.SYSCONFIG in self.methods:
  555. self._find_libpy3_windows(environment)
  556. elif mesonlib.is_osx() and DependencyMethods.EXTRAFRAMEWORK in self.methods:
  557. # In OSX the Python 3 framework does not have a version
  558. # number in its name.
  559. # There is a python in /System/Library/Frameworks, but that's
  560. # python 2, Python 3 will always bin in /Library
  561. fw = ExtraFrameworkDependency(
  562. 'python', False, '/Library/Frameworks', self.env, self.language, kwargs)
  563. if fw.found():
  564. self.compile_args = fw.get_compile_args()
  565. self.link_args = fw.get_link_args()
  566. self.is_found = True
  567. if self.is_found:
  568. mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
  569. else:
  570. mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
  571. @staticmethod
  572. def get_windows_python_arch():
  573. pyplat = sysconfig.get_platform()
  574. if pyplat == 'mingw':
  575. pycc = sysconfig.get_config_var('CC')
  576. if pycc.startswith('x86_64'):
  577. return '64'
  578. elif pycc.startswith(('i686', 'i386')):
  579. return '32'
  580. else:
  581. mlog.log('MinGW Python built with unknown CC {!r}, please file'
  582. 'a bug'.format(pycc))
  583. return None
  584. elif pyplat == 'win32':
  585. return '32'
  586. elif pyplat in ('win64', 'win-amd64'):
  587. return '64'
  588. mlog.log('Unknown Windows Python platform {!r}'.format(pyplat))
  589. return None
  590. def get_windows_link_args(self):
  591. pyplat = sysconfig.get_platform()
  592. if pyplat.startswith('win'):
  593. vernum = sysconfig.get_config_var('py_version_nodot')
  594. if self.static:
  595. libname = 'libpython{}.a'.format(vernum)
  596. else:
  597. libname = 'python{}.lib'.format(vernum)
  598. lib = Path(sysconfig.get_config_var('base')) / 'libs' / libname
  599. elif pyplat == 'mingw':
  600. if self.static:
  601. libname = sysconfig.get_config_var('LIBRARY')
  602. else:
  603. libname = sysconfig.get_config_var('LDLIBRARY')
  604. lib = Path(sysconfig.get_config_var('LIBDIR')) / libname
  605. if not lib.exists():
  606. mlog.log('Could not find Python3 library {!r}'.format(str(lib)))
  607. return None
  608. return [str(lib)]
  609. def _find_libpy3_windows(self, env):
  610. '''
  611. Find python3 libraries on Windows and also verify that the arch matches
  612. what we are building for.
  613. '''
  614. pyarch = self.get_windows_python_arch()
  615. if pyarch is None:
  616. self.is_found = False
  617. return
  618. arch = detect_cpu_family(env.coredata.compilers)
  619. if arch == 'x86':
  620. arch = '32'
  621. elif arch == 'x86_64':
  622. arch = '64'
  623. else:
  624. # We can't cross-compile Python 3 dependencies on Windows yet
  625. mlog.log('Unknown architecture {!r} for'.format(arch),
  626. mlog.bold(self.name))
  627. self.is_found = False
  628. return
  629. # Pyarch ends in '32' or '64'
  630. if arch != pyarch:
  631. mlog.log('Need', mlog.bold(self.name), 'for {}-bit, but '
  632. 'found {}-bit'.format(arch, pyarch))
  633. self.is_found = False
  634. return
  635. # This can fail if the library is not found
  636. largs = self.get_windows_link_args()
  637. if largs is None:
  638. self.is_found = False
  639. return
  640. self.link_args = largs
  641. # Compile args
  642. inc = sysconfig.get_path('include')
  643. platinc = sysconfig.get_path('platinclude')
  644. self.compile_args = ['-I' + inc]
  645. if inc != platinc:
  646. self.compile_args.append('-I' + platinc)
  647. self.version = sysconfig.get_config_var('py_version')
  648. self.is_found = True
  649. def get_methods(self):
  650. if mesonlib.is_windows():
  651. return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG]
  652. elif mesonlib.is_osx():
  653. return [DependencyMethods.PKGCONFIG, DependencyMethods.EXTRAFRAMEWORK]
  654. else:
  655. return [DependencyMethods.PKGCONFIG]
  656. def get_pkgconfig_variable(self, variable_name, kwargs):
  657. if self.pkgdep:
  658. return self.pkgdep.get_pkgconfig_variable(variable_name, kwargs)
  659. else:
  660. return super().get_pkgconfig_variable(variable_name, kwargs)
  661. class PcapDependency(ExternalDependency):
  662. def __init__(self, environment, kwargs):
  663. super().__init__('pcap', environment, None, kwargs)
  664. kwargs['required'] = False
  665. if DependencyMethods.PKGCONFIG in self.methods:
  666. try:
  667. pcdep = PkgConfigDependency('pcap', environment, kwargs)
  668. if pcdep.found():
  669. self.type_name = 'pkgconfig'
  670. self.is_found = True
  671. self.compile_args = pcdep.get_compile_args()
  672. self.link_args = pcdep.get_link_args()
  673. self.version = pcdep.get_version()
  674. return
  675. except Exception as e:
  676. mlog.debug('Pcap not found via pkgconfig. Trying next, error was:', str(e))
  677. if DependencyMethods.CONFIG_TOOL in self.methods:
  678. try:
  679. ctdep = ConfigToolDependency.factory(
  680. 'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config')
  681. if ctdep.found():
  682. self.config = ctdep.config
  683. self.type_name = 'config-tool'
  684. self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
  685. self.link_args = ctdep.get_config_value(['--libs'], 'link_args')
  686. self.version = self.get_pcap_lib_version()
  687. self.is_found = True
  688. return
  689. except Exception as e:
  690. mlog.debug('Pcap not found via pcap-config. Trying next, error was:', str(e))
  691. def get_methods(self):
  692. if mesonlib.is_osx():
  693. return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
  694. else:
  695. return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
  696. def get_pcap_lib_version(self):
  697. return self.compiler.get_return_value('pcap_lib_version', 'string',
  698. '#include <pcap.h>', self.env, [], [self])
  699. class CupsDependency(ExternalDependency):
  700. def __init__(self, environment, kwargs):
  701. super().__init__('cups', environment, None, kwargs)
  702. kwargs['required'] = False
  703. if DependencyMethods.PKGCONFIG in self.methods:
  704. try:
  705. pcdep = PkgConfigDependency('cups', environment, kwargs)
  706. if pcdep.found():
  707. self.type_name = 'pkgconfig'
  708. self.is_found = True
  709. self.compile_args = pcdep.get_compile_args()
  710. self.link_args = pcdep.get_link_args()
  711. self.version = pcdep.get_version()
  712. return
  713. except Exception as e:
  714. mlog.debug('cups not found via pkgconfig. Trying next, error was:', str(e))
  715. if DependencyMethods.CONFIG_TOOL in self.methods:
  716. try:
  717. ctdep = ConfigToolDependency.factory(
  718. 'cups', environment, None, kwargs, ['cups-config'], 'cups-config')
  719. if ctdep.found():
  720. self.config = ctdep.config
  721. self.type_name = 'config-tool'
  722. self.version = ctdep.version
  723. self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
  724. self.link_args = ctdep.get_config_value(['--libs'], 'link_args')
  725. self.is_found = True
  726. return
  727. except Exception as e:
  728. mlog.debug('cups not found via cups-config. Trying next, error was:', str(e))
  729. if DependencyMethods.EXTRAFRAMEWORK in self.methods:
  730. if mesonlib.is_osx():
  731. fwdep = ExtraFrameworkDependency('cups', False, None, self.env,
  732. self.language, kwargs)
  733. if fwdep.found():
  734. self.is_found = True
  735. self.compile_args = fwdep.get_compile_args()
  736. self.link_args = fwdep.get_link_args()
  737. self.version = fwdep.get_version()
  738. return
  739. mlog.log('Dependency', mlog.bold('cups'), 'found:', mlog.red('NO'))
  740. def get_methods(self):
  741. if mesonlib.is_osx():
  742. return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
  743. else:
  744. return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
  745. class LibWmfDependency(ExternalDependency):
  746. def __init__(self, environment, kwargs):
  747. super().__init__('libwmf', environment, None, kwargs)
  748. if DependencyMethods.PKGCONFIG in self.methods:
  749. try:
  750. kwargs['required'] = False
  751. pcdep = PkgConfigDependency('libwmf', environment, kwargs)
  752. if pcdep.found():
  753. self.type_name = 'pkgconfig'
  754. self.is_found = True
  755. self.compile_args = pcdep.get_compile_args()
  756. self.link_args = pcdep.get_link_args()
  757. self.version = pcdep.get_version()
  758. return
  759. except Exception as e:
  760. mlog.debug('LibWmf not found via pkgconfig. Trying next, error was:', str(e))
  761. if DependencyMethods.CONFIG_TOOL in self.methods:
  762. try:
  763. ctdep = ConfigToolDependency.factory(
  764. 'libwmf', environment, None, kwargs, ['libwmf-config'], 'libwmf-config')
  765. if ctdep.found():
  766. self.config = ctdep.config
  767. self.type_name = 'config-too'
  768. self.version = ctdep.version
  769. self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
  770. self.link_args = ctdep.get_config_value(['--libs'], 'link_args')
  771. self.is_found = True
  772. return
  773. except Exception as e:
  774. mlog.debug('cups not found via libwmf-config. Trying next, error was:', str(e))
  775. def get_methods(self):
  776. if mesonlib.is_osx():
  777. return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
  778. else:
  779. return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
  780. # Generated with boost_names.py
  781. BOOST_LIBS = [
  782. 'boost_atomic',
  783. 'boost_chrono',
  784. 'boost_chrono',
  785. 'boost_container',
  786. 'boost_context',
  787. 'boost_coroutine',
  788. 'boost_date_time',
  789. 'boost_exception',
  790. 'boost_fiber',
  791. 'boost_filesystem',
  792. 'boost_graph',
  793. 'boost_iostreams',
  794. 'boost_locale',
  795. 'boost_log',
  796. 'boost_log_setup',
  797. 'boost_math_tr1',
  798. 'boost_math_tr1f',
  799. 'boost_math_tr1l',
  800. 'boost_math_c99',
  801. 'boost_math_c99f',
  802. 'boost_math_c99l',
  803. 'boost_math_tr1',
  804. 'boost_math_tr1f',
  805. 'boost_math_tr1l',
  806. 'boost_math_c99',
  807. 'boost_math_c99f',
  808. 'boost_math_c99l',
  809. 'boost_math_tr1',
  810. 'boost_math_tr1f',
  811. 'boost_math_tr1l',
  812. 'boost_math_c99',
  813. 'boost_math_c99f',
  814. 'boost_math_c99l',
  815. 'boost_math_tr1',
  816. 'boost_math_tr1f',
  817. 'boost_math_tr1l',
  818. 'boost_math_c99',
  819. 'boost_math_c99f',
  820. 'boost_math_c99l',
  821. 'boost_math_tr1',
  822. 'boost_math_tr1f',
  823. 'boost_math_tr1l',
  824. 'boost_math_c99',
  825. 'boost_math_c99f',
  826. 'boost_math_c99l',
  827. 'boost_math_tr1',
  828. 'boost_math_tr1f',
  829. 'boost_math_tr1l',
  830. 'boost_math_c99',
  831. 'boost_math_c99f',
  832. 'boost_math_c99l',
  833. 'boost_mpi',
  834. 'boost_program_options',
  835. 'boost_python',
  836. 'boost_python3',
  837. 'boost_numpy',
  838. 'boost_numpy3',
  839. 'boost_random',
  840. 'boost_regex',
  841. 'boost_serialization',
  842. 'boost_wserialization',
  843. 'boost_signals',
  844. 'boost_stacktrace_noop',
  845. 'boost_stacktrace_backtrace',
  846. 'boost_stacktrace_addr2line',
  847. 'boost_stacktrace_basic',
  848. 'boost_stacktrace_windbg',
  849. 'boost_stacktrace_windbg_cached',
  850. 'boost_system',
  851. 'boost_prg_exec_monitor',
  852. 'boost_test_exec_monitor',
  853. 'boost_unit_test_framework',
  854. 'boost_thread',
  855. 'boost_timer',
  856. 'boost_type_erasure',
  857. 'boost_wave'
  858. ]