Add partial_dependency method to dependencies

This adds a new method, partial_dependency to all dependencies. These
sub dependencies are copies of the original dependency, but with one or
more of the attributes replaced with an empty list. This allows creating
a sub dependency that has only cflags or drops link_arguments, for
example.
pull/3372/head
Dylan Baker 7 years ago committed by Jussi Pakkanen
parent 1952ef5ae1
commit 92487ea33d
  1. 26
      docs/markdown/Reference-manual.md
  2. 25
      docs/markdown/snippets/partial-dependencies.md
  3. 56
      mesonbuild/dependencies/base.py
  4. 21
      mesonbuild/interpreter.py
  5. 16
      test cases/common/191 partial dependency/declare_dependency/headers/foo.c
  6. 16
      test cases/common/191 partial dependency/declare_dependency/headers/foo.h
  7. 25
      test cases/common/191 partial dependency/declare_dependency/main.c
  8. 28
      test cases/common/191 partial dependency/declare_dependency/meson.build
  9. 20
      test cases/common/191 partial dependency/declare_dependency/other.c
  10. 17
      test cases/common/191 partial dependency/meson.build
  11. 2
      test cases/frameworks/1 boost/meson.build
  12. 20
      test cases/frameworks/1 boost/partial_dep/foo.cpp
  13. 27
      test cases/frameworks/1 boost/partial_dep/foo.hpp
  14. 28
      test cases/frameworks/1 boost/partial_dep/main.cpp
  15. 31
      test cases/frameworks/1 boost/partial_dep/meson.build

@ -1827,6 +1827,32 @@ an external dependency with the following methods:
- `version()` is the version number as a string, for example `1.2.8` - `version()` is the version number as a string, for example `1.2.8`
- `partial_dependency(compile_args : false, link_args : false, links : false,
includes : false, source : false)` (*added 0.46.0) returns a new dependency
object with the same name, version, found status, type name, and methods as
the object that called it. This new object will only inherit other
attributes from its parent as controlled by keyword arguments.
If the parent has any dependencies, those will be applied to the new
partial dependency with the same rules. So , given:
```meson
dep1 = declare_dependency(compiler_args : '-Werror=foo', link_with : 'libfoo')
dep2 = declare_dependency(compiler_args : '-Werror=bar', dependencies : dep1)
dep3 = dep2.partial_dependency(compile_args : true)
```
dep3 will add `['-Werror=foo', '-Werror=bar']` to the compiler args of
any target it is added to, but libfoo will not be added to the link_args.
The following arguments will add the following attributes:
- compile_args: any arguments passed to the compiler
- link_args: any arguments passed to the linker
- links: anything passed via link_with or link_whole
- includes: any include_directories
- sources: any compiled or static sources the dependency has
### `disabler` object ### `disabler` object
A disabler object is an object that behaves in much the same way as A disabler object is an object that behaves in much the same way as

@ -0,0 +1,25 @@
## Added new partial_dependency method to dependencies and libraries
It is now possible to use only part of a dependency in a target. This allows,
for example, to only use headers with convenience libraries to avoid linking
to the same library multiple times.
```meson
dep = dependency('xcb')
helper = static_library(
'helper',
['helper1.c', 'helper2.c'],
dependencies : dep.partial_dependency(includes : true),
]
final = shared_library(
'final',
['final.c'],
dependencyes : dep,
)
```
A partial dependency will have the same name version as the full dependency it
is derived from, as well as any values requested.

@ -1,4 +1,4 @@
# Copyright 2013-2017 The Meson development team # Copyright 2013-2018 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -15,6 +15,7 @@
# This file contains the detection logic for external dependencies. # This file contains the detection logic for external dependencies.
# Custom logic for several other packages are in separate files. # Custom logic for several other packages are in separate files.
import copy
import os import os
import re import re
import stat import stat
@ -146,6 +147,23 @@ class Dependency:
def get_configtool_variable(self, variable_name): def get_configtool_variable(self, variable_name):
raise DependencyException('{!r} is not a config-tool dependency'.format(self.name)) raise DependencyException('{!r} is not a config-tool dependency'.format(self.name))
def get_partial_dependency(self, *, compile_args=False, link_args=False,
links=False, includes=False, sources=False):
"""Create a new dependency that contains part of the parent dependency.
The following options can be inherited:
links -- all link_with arguemnts
includes -- all include_directory and -I/-isystem calls
sources -- any source, header, or generated sources
compile_args -- any compile args
link_args -- any link args
Additionally the new dependency will have the version parameter of it's
parent (if any) and the requested values of any dependencies will be
added as well.
"""
RuntimeError('Unreachable code in partial_dependency called')
class InternalDependency(Dependency): class InternalDependency(Dependency):
def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps): def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps):
@ -168,6 +186,21 @@ class InternalDependency(Dependency):
raise DependencyException('Method "get_configtool_variable()" is ' raise DependencyException('Method "get_configtool_variable()" is '
'invalid for an internal dependency') 'invalid for an internal dependency')
def get_partial_dependency(self, *, compile_args=False, link_args=False,
links=False, includes=False, sources=False):
compile_args = self.compile_args.copy() if compile_args else []
link_args = self.link_args.copy() if link_args else []
libraries = self.libraries.copy() if links else []
whole_libraries = self.whole_libraries.copy() if links else []
sources = self.sources.copy() if sources else []
includes = self.include_directories.copy() if includes else []
deps = [d.get_partial_dependency(
compile_args=compile_args, link_args=link_args, links=links,
includes=includes, sources=sources) for d in self.ext_deps]
return InternalDependency(
self.version, includes, compile_args, link_args, libraries,
whole_libraries, sources, deps)
class ExternalDependency(Dependency): class ExternalDependency(Dependency):
def __init__(self, type_name, environment, language, kwargs): def __init__(self, type_name, environment, language, kwargs):
@ -211,6 +244,18 @@ class ExternalDependency(Dependency):
def get_compiler(self): def get_compiler(self):
return self.compiler return self.compiler
def get_partial_dependency(self, *, compile_args=False, link_args=False,
links=False, includes=False, sources=False):
new = copy.copy(self)
if not compile_args:
new.compile_args = []
if not link_args:
new.link_args = []
if not sources:
new.sources = []
return new
class ConfigToolDependency(ExternalDependency): class ConfigToolDependency(ExternalDependency):
@ -887,6 +932,15 @@ class ExternalLibrary(ExternalDependency):
return [] return []
return self.link_args return self.link_args
def get_partial_dependency(self, *, compile_args=False, link_args=False,
links=False, includes=False, sources=False):
# External library only has link_args, so ignore the rest of the
# interface.
new = copy.copy(self)
if not link_args:
new.link_args = []
return new
class ExtraFrameworkDependency(ExternalDependency): class ExtraFrameworkDependency(ExternalDependency):
def __init__(self, name, required, path, env, lang, kwargs): def __init__(self, name, required, path, env, lang, kwargs):

@ -275,6 +275,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
'version': self.version_method, 'version': self.version_method,
'get_pkgconfig_variable': self.pkgconfig_method, 'get_pkgconfig_variable': self.pkgconfig_method,
'get_configtool_variable': self.configtool_method, 'get_configtool_variable': self.configtool_method,
'partial_dependency': self.partial_dependency_method,
}) })
def type_name_method(self, args, kwargs): def type_name_method(self, args, kwargs):
@ -306,12 +307,18 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
raise InterpreterException('Variable name must be a string.') raise InterpreterException('Variable name must be a string.')
return self.held_object.get_configtool_variable(varname) return self.held_object.get_configtool_variable(varname)
def partial_dependency_method(self, args, kwargs):
if args:
raise InterpreterException('partial_dependency takes no positional arguments')
return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
class InternalDependencyHolder(InterpreterObject, ObjectHolder): class InternalDependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep): def __init__(self, dep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
ObjectHolder.__init__(self, dep) ObjectHolder.__init__(self, dep)
self.methods.update({'found': self.found_method, self.methods.update({'found': self.found_method,
'version': self.version_method, 'version': self.version_method,
'partial_dependency': self.partial_dependency_method,
}) })
def found_method(self, args, kwargs): def found_method(self, args, kwargs):
@ -320,6 +327,11 @@ class InternalDependencyHolder(InterpreterObject, ObjectHolder):
def version_method(self, args, kwargs): def version_method(self, args, kwargs):
return self.held_object.get_version() return self.held_object.get_version()
def partial_dependency_method(self, args, kwargs):
if args:
raise InterpreterException('get_partial_dependency takes no positional arguments')
return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
class ExternalProgramHolder(InterpreterObject, ObjectHolder): class ExternalProgramHolder(InterpreterObject, ObjectHolder):
def __init__(self, ep): def __init__(self, ep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
@ -346,7 +358,9 @@ class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
def __init__(self, el): def __init__(self, el):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
ObjectHolder.__init__(self, el) ObjectHolder.__init__(self, el)
self.methods.update({'found': self.found_method}) self.methods.update({'found': self.found_method,
'partial_dependency': self.partial_dependency_method,
})
def found(self): def found(self):
return self.held_object.found() return self.held_object.found()
@ -366,6 +380,11 @@ class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
def get_exe_args(self): def get_exe_args(self):
return self.held_object.get_exe_args() return self.held_object.get_exe_args()
def partial_dependency_method(self, args, kwargs):
if args:
raise InterpreterException('partial_dependency takes no positional arguments')
return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
class GeneratorHolder(InterpreterObject, ObjectHolder): class GeneratorHolder(InterpreterObject, ObjectHolder):
def __init__(self, interpreter, args, kwargs): def __init__(self, interpreter, args, kwargs):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)

@ -0,0 +1,16 @@
/* Copyright © 2018 Intel Corporation
*
* 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.
*/
#error "Included C sources that shouldn't be."

@ -0,0 +1,16 @@
/* Copyright © 2018 Intel Corporation
*
* 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.
*/
int foo(void);

@ -0,0 +1,25 @@
/* Copyright © 2018 Intel Corporation
*
* 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.
*/
#include "foo.h"
int main() {
int a = foo();
if (a == 1) {
return 0;
} else {
return 1;
}
}

@ -0,0 +1,28 @@
# Copyright © 2018 Intel Corporation
#
# 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.
dec_dep = declare_dependency(
sources : files('headers/foo.c'),
include_directories : include_directories('headers'),
)
sub_dep = dec_dep.partial_dependency(includes : true)
dec_exe = executable(
'declare_dep',
files('main.c', 'other.c'),
dependencies : sub_dep,
)
test('Declare Dependency', dec_exe)

@ -0,0 +1,20 @@
/* Copyright © 2018 Intel Corporation
*
* 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.
*/
#include "foo.h"
int foo(void) {
return 1;
}

@ -0,0 +1,17 @@
# Copyright © 2018 Intel Corporation
#
# 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.
project('partial dependency', ['c', 'cpp'])
subdir('declare_dependency')

@ -31,3 +31,5 @@ test('Boost statictest', staticexe)
test('Boost UTF test', unitexe) test('Boost UTF test', unitexe)
test('Boost nomod', nomodexe) test('Boost nomod', nomodexe)
test('Boost extralib test', extralibexe) test('Boost extralib test', extralibexe)
subdir('partial_dep')

@ -0,0 +1,20 @@
/* Copyright © 2018 Intel Corporation
*
* 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.
*/
#include "foo.hpp"
vec Foo::vector() {
return myvec;
}

@ -0,0 +1,27 @@
/* Copyright © 2018 Intel Corporation
*
* 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.
*/
#include <boost/fusion/container/vector.hpp>
typedef boost::fusion::vector<int> vec;
class Foo {
public:
Foo() {};
vec vector();
private:
const vec myvec = vec(4);
};

@ -0,0 +1,28 @@
/* Copyright © 2018 Intel Corporation
*
* 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.
*/
#include <iostream>
#include <boost/fusion/include/at_c.hpp>
#include "foo.hpp"
int main() {
auto foo = Foo();
vec v = foo.vector();
std::cout << boost::fusion::at_c<0>(v) << std::endl;
return 0;
}

@ -0,0 +1,31 @@
# Copyright © 2018 Intel Corporation
#
# 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.
dep_boost = dependency('boost')
dep_boost_headers = dep_boost.partial_dependency(compile_args : true)
libfoo = static_library(
'foo',
'foo.cpp',
dependencies : dep_boost_headers,
)
exe_external_dep = executable(
'external_dep',
'main.cpp',
dependencies : dep_boost,
link_with : libfoo
)
test('External Dependency', exe_external_dep)
Loading…
Cancel
Save