aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Saunier <tsaunier@igalia.com>2018-07-13 13:29:41 -0400
committerJussi Pakkanen <jpakkane@gmail.com>2018-08-27 21:37:18 +0300
commit731906504efb57aa9ae86685501f1d3a0aa22121 (patch)
treef85fe896a96cee352dae1d887f690eaabf8c761b
parent899b0aae9f9afacccfd5963e84df6634e9835b5c (diff)
downloadmeson-731906504efb57aa9ae86685501f1d3a0aa22121.zip
meson-731906504efb57aa9ae86685501f1d3a0aa22121.tar.gz
meson-731906504efb57aa9ae86685501f1d3a0aa22121.tar.bz2
Add a `required` argument to `subproject`
Allowing to use the new "feature" option type and allowing not to fail on subproject if it is not necessary to fail. By default subprojects are "required" so previous behaviour is not changed. Fixes #3880
-rw-r--r--mesonbuild/interpreter.py85
-rwxr-xr-xrun_unittests.py10
-rw-r--r--test cases/common/206 subproject with features/meson.build17
-rw-r--r--test cases/common/206 subproject with features/meson_options.txt3
-rw-r--r--test cases/common/206 subproject with features/nothing.c4
-rw-r--r--test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build3
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build3
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c5
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h6
-rw-r--r--test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build3
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/lib/meson.build2
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/lib/sub.c5
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/lib/sub.h6
-rw-r--r--test cases/common/206 subproject with features/subprojects/sub/meson.build3
14 files changed, 140 insertions, 15 deletions
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 4fbb837..358dd8f 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -383,6 +383,9 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
'partial_dependency': self.partial_dependency_method,
})
+ def found(self):
+ return self.found_method([], {})
+
@noPosargs
@permittedKwargs({})
def type_name_method(self, args, kwargs):
@@ -916,16 +919,30 @@ class Test(InterpreterObject):
class SubprojectHolder(InterpreterObject, ObjectHolder):
- def __init__(self, subinterpreter):
+ def __init__(self, subinterpreter, subproject_dir, name):
InterpreterObject.__init__(self)
ObjectHolder.__init__(self, subinterpreter)
+ self.name = name
+ self.subproject_dir = subproject_dir
self.methods.update({'get_variable': self.get_variable_method,
+ 'found': self.found_method,
})
+ @noPosargs
+ @permittedKwargs({})
+ def found_method(self, args, kwargs):
+ return self.found()
+
+ def found(self):
+ return self.held_object is not None
+
@permittedKwargs({})
def get_variable_method(self, args, kwargs):
if len(args) != 1:
raise InterpreterException('Get_variable takes one argument.')
+ if not self.found():
+ raise InterpreterException('Subproject "%s/%s" disabled can\'t get_variable on it.' % (
+ self.subproject_dir, self.name))
varname = args[0]
if not isinstance(varname, str):
raise InterpreterException('Get_variable takes a string argument.')
@@ -1838,7 +1855,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'},
'both_libraries': known_library_kwargs,
'library': known_library_kwargs,
'subdir': {'if_found'},
- 'subproject': {'version', 'default_options'},
+ 'subproject': {'version', 'default_options', 'required'},
'test': {'args', 'depends', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite'},
'vcs_tag': {'input', 'output', 'fallback', 'command', 'replace_string'},
}
@@ -2219,7 +2236,16 @@ external dependencies (including libraries) must go to "dependencies".''')
dirname = args[0]
return self.do_subproject(dirname, kwargs)
+ def disabled_subproject(self, dirname):
+ self.subprojects[dirname] = SubprojectHolder(None, self.subproject_dir, dirname)
+ return self.subprojects[dirname]
+
def do_subproject(self, dirname, kwargs):
+ disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
+ if disabled:
+ mlog.log('\nSubproject', mlog.bold(dirname), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
+ return self.disabled_subproject(dirname)
+
default_options = mesonlib.stringlistify(kwargs.get('default_options', []))
default_options = coredata.create_options_dict(default_options)
if dirname == '':
@@ -2237,7 +2263,13 @@ external dependencies (including libraries) must go to "dependencies".''')
incpath = ' => '.join(fullstack)
raise InvalidCode('Recursive include of subprojects: %s.' % incpath)
if dirname in self.subprojects:
- return self.subprojects[dirname]
+ subproject = self.subprojects[dirname]
+
+ if required and not subproject.found():
+ raise InterpreterException('Subproject "%s/%s" required but not found.' % (
+ self.subproject_dir, dirname))
+
+ return subproject
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
r = wrap.Resolver(subproject_dir_abs, self.coredata.wrap_mode)
try:
@@ -2249,22 +2281,35 @@ external dependencies (including libraries) must go to "dependencies".''')
# promotion...
self.print_nested_info(dirname)
- msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}'
- raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e))
+ if required:
+ msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}'
+ raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e))
+
+ mlog.log('\nSubproject ', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)\n')
+ return self.disabled_subproject(dirname)
+
subdir = os.path.join(self.subproject_dir, resolved)
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
self.global_args_frozen = True
mlog.log()
with mlog.nested():
- mlog.log('\nExecuting subproject', mlog.bold(dirname), '\n')
- subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
- self.modules, default_options)
- subi.subprojects = self.subprojects
-
- subi.subproject_stack = self.subproject_stack + [dirname]
- current_active = self.active_projectname
- subi.run()
- mlog.log('\nSubproject', mlog.bold(dirname), 'finished.')
+ try:
+ mlog.log('\nExecuting subproject', mlog.bold(dirname), '\n')
+ subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
+ self.modules, default_options)
+ subi.subprojects = self.subprojects
+
+ subi.subproject_stack = self.subproject_stack + [dirname]
+ current_active = self.active_projectname
+ subi.run()
+ mlog.log('\nSubproject', mlog.bold(dirname), 'finished.')
+ except Exception as e:
+ if not required:
+ mlog.log(e)
+ mlog.log('\nSubproject', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)')
+ return self.disabled_subproject(dirname)
+ else:
+ raise e
if 'version' in kwargs:
pv = subi.project_version
@@ -2274,7 +2319,7 @@ external dependencies (including libraries) must go to "dependencies".''')
self.active_projectname = current_active
self.build.subprojects[dirname] = subi.project_version
self.subprojects.update(subi.subprojects)
- self.subprojects[dirname] = SubprojectHolder(subi)
+ self.subprojects[dirname] = SubprojectHolder(subi, self.subproject_dir, dirname)
self.build_def_files += subi.build_def_files
return self.subprojects[dirname]
@@ -2799,6 +2844,13 @@ external dependencies (including libraries) must go to "dependencies".''')
def get_subproject_dep(self, name, dirname, varname, required):
try:
+ subproject = self.subprojects[dirname]
+ if not subproject.found():
+ if not required:
+ return DependencyHolder(NotFoundDependency(self.environment), self.subproject)
+
+ raise DependencyException('Subproject %s was not found.' % (name))
+
dep = self.subprojects[dirname].get_variable_method([varname], {})
except InvalidArguments as e:
if required:
@@ -2820,6 +2872,9 @@ external dependencies (including libraries) must go to "dependencies".''')
dep = self.get_subproject_dep(name, dirname, varname, required)
if not dep:
return False
+ if not dep.found():
+ return dep
+
found = dep.version_method([], {})
# Don't do a version check if the dependency is not found and not required
if not dep.found_method([], {}) and not required:
diff --git a/run_unittests.py b/run_unittests.py
index 5da2798..ebead66 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -2848,6 +2848,16 @@ class FailureTests(BasePlatformTests):
msg = '.*WARNING:.*feature.*build_always_stale.*custom_target.*'
self.assertMesonDoesNotOutput(vcs_tag, msg, meson_version='>=0.43')
+ def test_missing_subproject_not_required_and_required(self):
+ self.assertMesonRaises("sub1 = subproject('not-found-subproject', required: false)\n" +
+ "sub2 = subproject('not-found-subproject', required: true)",
+ """.*Subproject "subprojects/not-found-subproject" required but not found.*""")
+
+ def test_get_variable_on_not_found_project(self):
+ self.assertMesonRaises("sub1 = subproject('not-found-subproject', required: false)\n" +
+ "sub1.get_variable('naaa')",
+ """Subproject "subprojects/not-found-subproject" disabled can't get_variable on it.""")
+
class WindowsTests(BasePlatformTests):
'''
diff --git a/test cases/common/206 subproject with features/meson.build b/test cases/common/206 subproject with features/meson.build
new file mode 100644
index 0000000..5bdfefb
--- /dev/null
+++ b/test cases/common/206 subproject with features/meson.build
@@ -0,0 +1,17 @@
+project('proj', 'c')
+
+auto_subproj = subproject('sub', required: get_option('use-subproject'))
+assert(auto_subproj.found(), 'Subproject should always be buildable and thus found')
+
+auto_dep = dependency('', fallback: ['sub', 'libSub'], required: true)
+assert(auto_dep.found() == true, 'Subproject is required and foundable, dependency should be found.')
+
+disabled_subproj = subproject('disabled_sub', required: get_option('disabled-subproject'))
+assert(disabled_subproj.found() == false, 'Disabled subproject should be NOT found')
+
+disabled_dep = dependency('', fallback: ['disabled_sub', 'libSub'], required: false)
+assert(disabled_dep.found() == false, 'Subprojetc was disabled, it should never be built.')
+nothing = executable('nothing', 'nothing.c', dependencies: [disabled_dep])
+
+subproj_with_missing_dep = subproject('auto_sub_with_missing_dep', required: get_option('auto-sub-with-missing-dep'))
+assert(subproj_with_missing_dep.found() == false, 'Subproject with required=auto and missing dependency should be NOT found')
diff --git a/test cases/common/206 subproject with features/meson_options.txt b/test cases/common/206 subproject with features/meson_options.txt
new file mode 100644
index 0000000..a46e5fb
--- /dev/null
+++ b/test cases/common/206 subproject with features/meson_options.txt
@@ -0,0 +1,3 @@
+option('use-subproject', type : 'feature', value : 'auto')
+option('disabled-subproject', type : 'feature', value : 'disabled')
+option('auto-sub-with-missing-dep', type : 'feature', value : 'auto')
diff --git a/test cases/common/206 subproject with features/nothing.c b/test cases/common/206 subproject with features/nothing.c
new file mode 100644
index 0000000..77750c2
--- /dev/null
+++ b/test cases/common/206 subproject with features/nothing.c
@@ -0,0 +1,4 @@
+int main(int argc, char const *argv[])
+{
+ return 0;
+} \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build b/test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build
new file mode 100644
index 0000000..fa6b011
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/auto_sub_with_missing_dep/meson.build
@@ -0,0 +1,3 @@
+project('sub', 'c')
+
+dependency('no_way_this_exists', required: true) \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build
new file mode 100644
index 0000000..933001a
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/meson.build
@@ -0,0 +1,3 @@
+lib = static_library('sub', 'sub.c')
+
+libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c
new file mode 100644
index 0000000..068a5b8
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.c
@@ -0,0 +1,5 @@
+#include "sub.h"
+
+int sub() {
+ return 0;
+}
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h
new file mode 100644
index 0000000..f1ab0e1
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/lib/sub.h
@@ -0,0 +1,6 @@
+#ifndef SUB_H
+#define SUB_H
+
+int sub();
+
+#endif
diff --git a/test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build b/test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build
new file mode 100644
index 0000000..65fef03
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/disabled_sub/meson.build
@@ -0,0 +1,3 @@
+project('disabled_sub', 'c')
+
+subdir('lib') \ No newline at end of file
diff --git a/test cases/common/206 subproject with features/subprojects/sub/lib/meson.build b/test cases/common/206 subproject with features/subprojects/sub/lib/meson.build
new file mode 100644
index 0000000..731d22b
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/lib/meson.build
@@ -0,0 +1,2 @@
+lib = static_library('sub', 'sub.c')
+libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
diff --git a/test cases/common/206 subproject with features/subprojects/sub/lib/sub.c b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.c
new file mode 100644
index 0000000..ed78306
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.c
@@ -0,0 +1,5 @@
+#include "sub.h"
+
+int sub() {
+ return 0;
+}
diff --git a/test cases/common/206 subproject with features/subprojects/sub/lib/sub.h b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.h
new file mode 100644
index 0000000..f1ab0e1
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/lib/sub.h
@@ -0,0 +1,6 @@
+#ifndef SUB_H
+#define SUB_H
+
+int sub();
+
+#endif
diff --git a/test cases/common/206 subproject with features/subprojects/sub/meson.build b/test cases/common/206 subproject with features/subprojects/sub/meson.build
new file mode 100644
index 0000000..31882ac
--- /dev/null
+++ b/test cases/common/206 subproject with features/subprojects/sub/meson.build
@@ -0,0 +1,3 @@
+project('sub', 'c')
+
+subdir('lib') \ No newline at end of file