123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- # Copyright 2013-2017 The Meson development team
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- # http://www.apache.org/licenses/LICENSE-2.0
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- # This file contains the detection logic for external dependencies useful for
- # development purposes, such as testing, debugging, etc..
- import os
- import shlex
- import shutil
- from .. import mlog
- from .. import mesonlib
- from ..mesonlib import version_compare, Popen_safe
- from .base import DependencyException, ExternalDependency, PkgConfigDependency
- class GTestDependency(ExternalDependency):
- def __init__(self, environment, kwargs):
- super().__init__('gtest', environment, 'cpp', kwargs)
- self.main = kwargs.get('main', False)
- self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src']
- self.detect()
- def detect(self):
- self.version = '1.something_maybe'
- gtest_detect = self.compiler.find_library("gtest", self.env, [])
- gtest_main_detect = self.compiler.find_library("gtest_main", self.env, [])
- if gtest_detect and (not self.main or gtest_main_detect):
- self.is_found = True
- self.compile_args = []
- self.link_args = gtest_detect
- if self.main:
- self.link_args += gtest_main_detect
- self.sources = []
- mlog.log('Dependency GTest found:', mlog.green('YES'), '(prebuilt)')
- elif self.detect_srcdir():
- self.is_found = True
- self.compile_args = ['-I' + self.src_include_dir]
- self.link_args = []
- if self.main:
- self.sources = [self.all_src, self.main_src]
- else:
- self.sources = [self.all_src]
- mlog.log('Dependency GTest found:', mlog.green('YES'), '(building self)')
- else:
- mlog.log('Dependency GTest found:', mlog.red('NO'))
- self.is_found = False
- def detect_srcdir(self):
- for s in self.src_dirs:
- if os.path.exists(s):
- self.src_dir = s
- self.all_src = mesonlib.File.from_absolute_file(
- os.path.join(self.src_dir, 'gtest-all.cc'))
- self.main_src = mesonlib.File.from_absolute_file(
- os.path.join(self.src_dir, 'gtest_main.cc'))
- self.src_include_dir = os.path.normpath(os.path.join(self.src_dir, '..'))
- return True
- return False
- def need_threads(self):
- return True
- class GMockDependency(ExternalDependency):
- def __init__(self, environment, kwargs):
- super().__init__('gmock', environment, 'cpp', kwargs)
- self.version = '1.something_maybe'
- # GMock may be a library or just source.
- # Work with both.
- gmock_detect = self.compiler.find_library("gmock", self.env, [])
- if gmock_detect:
- self.is_found = True
- self.compile_args = []
- self.link_args = gmock_detect
- self.sources = []
- mlog.log('Dependency GMock found:', mlog.green('YES'), '(prebuilt)')
- return
- for d in ['/usr/src/googletest/googlemock/src', '/usr/src/gmock/src', '/usr/src/gmock']:
- if os.path.exists(d):
- self.is_found = True
- # Yes, we need both because there are multiple
- # versions of gmock that do different things.
- d2 = os.path.normpath(os.path.join(d, '..'))
- self.compile_args = ['-I' + d, '-I' + d2]
- self.link_args = []
- all_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock-all.cc'))
- main_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock_main.cc'))
- if kwargs.get('main', False):
- self.sources = [all_src, main_src]
- else:
- self.sources = [all_src]
- mlog.log('Dependency GMock found:', mlog.green('YES'), '(building self)')
- return
- mlog.log('Dependency GMock found:', mlog.red('NO'))
- self.is_found = False
- class LLVMDependency(ExternalDependency):
- """
- LLVM uses a special tool, llvm-config, which has arguments for getting
- c args, cxx args, and ldargs as well as version.
- """
- # Ordered list of llvm-config binaries to try. Start with base, then try
- # newest back to oldest (3.5 is abitrary), and finally the devel version.
- # Please note that llvm-config-5.0 is a development snapshot and it should
- # not be moved to the beginning of the list. The only difference between
- # llvm-config-5.0 and llvm-config-devel is that the former is used by
- # Debian and the latter is used by FreeBSD.
- llvm_config_bins = [
- 'llvm-config', # base
- 'llvm-config-4.0', 'llvm-config40', # latest stable release
- 'llvm-config-3.9', 'llvm-config39', # old stable releases
- 'llvm-config-3.8', 'llvm-config38',
- 'llvm-config-3.7', 'llvm-config37',
- 'llvm-config-3.6', 'llvm-config36',
- 'llvm-config-3.5', 'llvm-config35',
- 'llvm-config-5.0', 'llvm-config-devel', # development snapshot
- ]
- llvmconfig = None
- _llvmconfig_found = False
- __best_found = None
- __cpp_blacklist = {'-DNDEBUG'}
- def __init__(self, environment, kwargs):
- # It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0
- # the C linker works fine if only using the C API.
- super().__init__('llvm-config', environment, 'cpp', kwargs)
- self.modules = []
- # FIXME: Support multiple version requirements ala PkgConfigDependency
- req_version = kwargs.get('version', None)
- if self.llvmconfig is None:
- self.check_llvmconfig(req_version)
- if not self._llvmconfig_found:
- if self.__best_found is not None:
- mlog.log('found {!r} but need:'.format(self.__best_found),
- req_version)
- else:
- mlog.log("No llvm-config found; can't detect dependency")
- mlog.log('Dependency LLVM found:', mlog.red('NO'))
- if self.required:
- raise DependencyException('Dependency LLVM not found')
- return
- p, out, err = Popen_safe([self.llvmconfig, '--version'])
- if p.returncode != 0:
- mlog.debug('stdout: {}\nstderr: {}'.format(out, err))
- if self.required:
- raise DependencyException('Dependency LLVM not found')
- return
- else:
- self.version = out.strip()
- mlog.log('Dependency LLVM found:', mlog.green('YES'))
- self.is_found = True
- p, out = Popen_safe(
- [self.llvmconfig, '--libs', '--ldflags', '--system-libs'])[:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate libs for LLVM.')
- self.link_args = shlex.split(out)
- p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate includedir for LLVM.')
- cargs = mesonlib.OrderedSet(shlex.split(out))
- self.compile_args = list(cargs.difference(self.__cpp_blacklist))
- p, out = Popen_safe([self.llvmconfig, '--components'])[:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate modules for LLVM.')
- self.modules = shlex.split(out)
- modules = mesonlib.stringlistify(kwargs.get('modules', []))
- for mod in modules:
- if mod not in self.modules:
- mlog.log('LLVM module', mod, 'found:', mlog.red('NO'))
- self.is_found = False
- if self.required:
- raise DependencyException(
- 'Could not find required LLVM Component: {}'.format(mod))
- else:
- mlog.log('LLVM module', mod, 'found:', mlog.green('YES'))
- @classmethod
- def check_llvmconfig(cls, version_req):
- """Try to find the highest version of llvm-config."""
- for llvmconfig in cls.llvm_config_bins:
- try:
- p, out = Popen_safe([llvmconfig, '--version'])[0:2]
- out = out.strip()
- if p.returncode != 0:
- continue
- # FIXME: As soon as some llvm-config is found, version checks
- # in further dependnecy() calls will be ignored
- if version_req:
- if version_compare(out, version_req, strict=True):
- if cls.__best_found and version_compare(out, '<={}'.format(cls.__best_found), strict=True):
- continue
- cls.__best_found = out
- cls.llvmconfig = llvmconfig
- else:
- # If no specific version is requested use the first version
- # found, since that should be the best.
- cls.__best_found = out
- cls.llvmconfig = llvmconfig
- break
- except (FileNotFoundError, PermissionError):
- pass
- if cls.__best_found:
- mlog.log('Found llvm-config:',
- mlog.bold(shutil.which(cls.llvmconfig)),
- '({})'.format(out.strip()))
- cls._llvmconfig_found = True
- else:
- cls.llvmconfig = False
- def need_threads(self):
- return True
- class ValgrindDependency(PkgConfigDependency):
- '''
- Consumers of Valgrind usually only need the compile args and do not want to
- link to its (static) libraries.
- '''
- def __init__(self, env, kwargs):
- super().__init__('valgrind', env, kwargs)
- def get_link_args(self):
- return []
|