From 70f6b769a69aa741bd7757d82829e50a93303c50 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 24 Mar 2013 15:04:51 +0200 Subject: [PATCH] Added custom detector framework and a Boost detector to it. --- dependencies.py | 100 +++++++++++++++++++++ environment.py | 20 +++++ interpreter.py | 2 +- run_tests.py | 6 ++ test cases/frameworks/1 boost/meson.build | 13 ++- test cases/frameworks/1 boost/nolinkexe.cc | 20 ----- 6 files changed, 132 insertions(+), 29 deletions(-) create mode 100644 dependencies.py delete mode 100644 test cases/frameworks/1 boost/nolinkexe.cc diff --git a/dependencies.py b/dependencies.py new file mode 100644 index 000000000..10d59104d --- /dev/null +++ b/dependencies.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 -tt + +# Copyright 2013 Jussi Pakkanen + +# 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 all those +# packages and frameworks that either don't provide +# a pkg-confg file or require extra functionality +# that can't be expressed with it. + +# Currently one file, should probably be split into a +# package before this gets too big. + +import os, stat, glob +from interpreter import InvalidArguments + +class BoostDependency(): + def __init__(self, kwargs): + self.incdir = '/usr/include/boost' + self.libdir = '/usr/lib' + self.src_modules = {} + self.lib_modules = {} + self.detect_version() + self.requested_modules = self.get_requested(kwargs) + + if self.version is not None: + self.detect_src_modules() + self.detect_lib_modules() + self.validate_requested() + + def get_compile_flags(self): + return [] + + def get_requested(self, kwargs): + modules = 'modules' + if not modules in kwargs: + raise InvalidArguments('Boost dependency must specify "%s" keyword.' % modules) + candidates = kwargs[modules] + if isinstance(candidates, str): + return [candidates] + for c in candidates: + if not isinstance(c, str): + raise InvalidArguments('Boost module argument is not a string.') + return candidates + + def validate_requested(self): + for m in self.requested_modules: + if m not in self.src_modules: + raise InvalidArguments('Requested Boost module "%s" not found.' % m) + + def found(self): + return self.version is not None + + def get_version(self): + return self.version + + def detect_version(self): + ifile = open(os.path.join(self.incdir, 'version.hpp')) + for line in ifile: + if line.startswith("#define") and 'BOOST_LIB_VERSION' in line: + ver = line.split()[-1] + ver = ver[1:-1] + self.version = ver.replace('_', '.') + return + self.version = None + + def detect_src_modules(self): + for entry in os.listdir(self.incdir): + entry = os.path.join(self.incdir, entry) + if stat.S_ISDIR(os.stat(entry).st_mode): + self.src_modules[os.path.split(entry)[-1]] = True + + def detect_lib_modules(self): + globber = 'libboost_*.so' # FIXME, make platform independent. + for entry in glob.glob(os.path.join(self.libdir, globber)): + if entry.endswith('-mt.so'): # Fixme, seems to be Windows specific. + continue + lib = os.path.basename(entry) + self.lib_modules[(lib.split('.')[0].split('_', 1)[-1])] = True + + def get_link_flags(self): + flags = [] # Fixme, add -L if necessary. + for module in self.requested_modules: + if module in self.lib_modules: + linkcmd = '-lboost_' + module + flags.append(linkcmd) + return flags + +packages = {'boost': BoostDependency} diff --git a/environment.py b/environment.py index db44e5364..a6af07afe 100755 --- a/environment.py +++ b/environment.py @@ -16,6 +16,7 @@ import subprocess, os.path, platform import coredata +import dependencies from glob import glob build_filename = 'meson.build' @@ -461,6 +462,20 @@ class Dependency(): def found(self): return False +class PackageDependency(Dependency): # Custom detector, not pkg-config. + def __init__(self, dep): + Dependency.__init__(self) + self.dep = dep + + def get_link_flags(self): + return self.dep.get_link_flags() + + def get_compile_flags(self): + return self.dep.get_compile_flags() + + def found(self): + return self.dep.found() + # This should be an InterpreterObject. Fix it. class PkgConfigDependency(Dependency): @@ -552,6 +567,11 @@ class ExternalLibrary(Dependency): def find_external_dependency(name, kwargs): required = kwargs.get('required', False) + if name in dependencies.packages: + dep = dependencies.packages[name](kwargs) + if required and not dep.found(): + raise EnvironmentException('Dependency "%s" not found' % name) + return PackageDependency(dep) return PkgConfigDependency(name, required) def test_pkg_config(): diff --git a/interpreter.py b/interpreter.py index 2c39344c8..87b4e0bf5 100755 --- a/interpreter.py +++ b/interpreter.py @@ -824,7 +824,7 @@ class Interpreter(): def is_assignable(self, value): if isinstance(value, InterpreterObject) or \ - isinstance(value, environment.PkgConfigDependency) or\ + isinstance(value, environment.Dependency) or\ isinstance(value, nodes.StringStatement) or\ isinstance(value, nodes.BoolStatement) or\ isinstance(value, nodes.IntStatement) or\ diff --git a/run_tests.py b/run_tests.py index 04a6c20d1..ec598c149 100755 --- a/run_tests.py +++ b/run_tests.py @@ -72,6 +72,10 @@ def run_tests(): platformtests = gather_tests('test cases/windows') else: platformtests = gather_tests('test cases/linuxlike') + if not environment.is_osx() and not environment.is_windows(): + frameworktests = gather_tests('test cases/frameworks') + else: + frameworktests = [] try: os.mkdir(test_build_dir) except OSError: @@ -84,6 +88,8 @@ def run_tests(): [run_test(t) for t in commontests] print('\nRunning platform dependent tests.\n') [run_test(t) for t in platformtests] + print('\nRunning framework tests.\n') + [run_test(t) for t in frameworktests] if __name__ == '__main__': script_dir = os.path.split(__file__)[0] diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build index 15455c507..968cf232b 100644 --- a/test cases/frameworks/1 boost/meson.build +++ b/test cases/frameworks/1 boost/meson.build @@ -1,14 +1,11 @@ project('boosttest', 'cxx') -# One test case for a Boost module that is -# header only and one test case for a module that -# requires linking with a shared library. +# Use a Boost module that requires a shared library. +# Eventually we would like to be able to detect Boost +# multiple times with different library combinations. -nolinkdep = find_dep('boost', modules : 'utility', required : true) linkdep = find_dep('boost', modules : 'thread', required : true) -nolinkexe = executable('nolinkexe', 'nolinkexe.cc', dep : nolinkdep) -linkexe = executable('linkedexe', 'linkexe.cc', dep : linkdep) +linkexe = executable('linkedexe', 'linkexe.cc', deps : linkdep) -add_test('nolinktest', nolinkexe) -add_test('linktext', linkexe) +add_test('Boost linktext', linkexe) diff --git a/test cases/frameworks/1 boost/nolinkexe.cc b/test cases/frameworks/1 boost/nolinkexe.cc deleted file mode 100644 index e81f3fb31..000000000 --- a/test cases/frameworks/1 boost/nolinkexe.cc +++ /dev/null @@ -1,20 +0,0 @@ -#include - -class MyClass : boost::noncopyable { -private: - int x; - -public: - MyClass() { - x = 44; - } - - int getValue() const { return x; } -}; - -int main(int argc, char **argv) { - MyClass foo; - if(foo.getValue() == 44) - return 0; - return 1; -}