From acdef2e588430709e44a3f5214b10b25a37b38a7 Mon Sep 17 00:00:00 2001 From: Afief Halumi Date: Fri, 15 May 2015 20:01:21 +0300 Subject: [PATCH] Allow user to specify subproject directory in project definition project() now takes an optional keyword argument `subproject_dir` which specifies the directory in which Meson will look for subproject. This argument is ignored in subprojects as all subprojects are owned by the top level project. subproject() now looks for the subproject in ${MESON_SOURCE_ROOT}/${SUBPROJECT_DIR}/foo where SUBPROJECT_DIR can be assigned using project() in the top level project. --- interpreter.py | 31 ++++++++++++------- .../common/82 custom subproject dir/a.c | 13 ++++++++ .../custom_subproject_dir/B/b.c | 9 ++++++ .../custom_subproject_dir/B/meson.build | 4 +++ .../custom_subproject_dir/C/c.c | 3 ++ .../custom_subproject_dir/C/meson.build | 2 ++ .../82 custom subproject dir/meson.build | 10 ++++++ 7 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 test cases/common/82 custom subproject dir/a.c create mode 100644 test cases/common/82 custom subproject dir/custom_subproject_dir/B/b.c create mode 100644 test cases/common/82 custom subproject dir/custom_subproject_dir/B/meson.build create mode 100644 test cases/common/82 custom subproject dir/custom_subproject_dir/C/c.c create mode 100644 test cases/common/82 custom subproject dir/custom_subproject_dir/C/meson.build create mode 100644 test cases/common/82 custom subproject dir/meson.build diff --git a/interpreter.py b/interpreter.py index 0ab729148..2aae94459 100644 --- a/interpreter.py +++ b/interpreter.py @@ -723,15 +723,16 @@ class MesonMain(InterpreterObject): return self.build.environment.coredata.unity def is_subproject_method(self, args, kwargs): - return self.interpreter.subproject != '' + return self.interpreter.is_subproject() class Interpreter(): - def __init__(self, build, subproject='', subdir=''): + def __init__(self, build, subproject='', subdir='', subproject_dir='subprojects'): self.build = build self.subproject = subproject self.subdir = subdir self.source_root = build.environment.get_source_dir() + self.subproject_dir = subproject_dir option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt') if os.path.exists(option_file): oi = optinterpreter.OptionInterpreter(self.subproject,\ @@ -1040,7 +1041,7 @@ class Interpreter(): dirname = args[0] if self.subdir != '': segs = os.path.split(self.subdir) - if len(segs) != 2 or segs[0] != 'subprojects': + if len(segs) != 2 or segs[0] != self.subproject_dir: raise InterpreterException('Subprojects must be defined at the root directory.') if dirname in self.subproject_stack: fullstack = self.subproject_stack + [dirname] @@ -1048,16 +1049,16 @@ class Interpreter(): raise InterpreterException('Recursive include of subprojects: %s.' % incpath) if dirname in self.subprojects: return self.subprojects[dirname] - subdir = os.path.join('subprojects', dirname) - r = wrap.Resolver(os.path.join(self.build.environment.get_source_dir(), 'subprojects')) + subdir = os.path.join(self.subproject_dir, dirname) + r = wrap.Resolver(os.path.join(self.build.environment.get_source_dir(), self.subproject_dir)) resolved = r.resolve(dirname) if resolved is None: raise InterpreterException('Subproject directory does not exist and can not be downloaded.') - subdir = os.path.join('subprojects', resolved) + 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('\nExecuting subproject ', mlog.bold(dirname), '.\n', sep='') - subi = Interpreter(self.build, dirname, subdir) + subi = Interpreter(self.build, dirname, subdir, self.subproject_dir) subi.subprojects = self.subprojects subi.subproject_stack = self.subproject_stack + [dirname] @@ -1075,7 +1076,7 @@ class Interpreter(): if len(args) != 1: raise InterpreterException('Argument required for get_option.') optname = args[0] - if self.subproject != '': + if self.is_subproject(): optname = self.subproject + ':' + optname try: return self.environment.get_coredata().get_builtin_option(optname) @@ -1092,14 +1093,19 @@ class Interpreter(): return ConfigurationDataHolder() @stringArgs - @noKwargs def func_project(self, node, args, kwargs): if len(args)< 2: raise InvalidArguments('Not enough arguments to project(). Needs at least the project name and one language') - if self.subproject == '': + if list(kwargs.keys()) != ['subproject_dir'] and len(kwargs) != 0: + raise InvalidArguments('project() only accepts the keyword argument "subproject_dir"') + + if not self.is_subproject(): self.build.project_name = args[0] if self.subproject in self.build.projects: raise InvalidCode('Second call to project().') + if not self.is_subproject() and 'subproject_dir' in kwargs: + self.subproject_dir = kwargs['subproject_dir'] + self.build.projects[self.subproject] = args[0] mlog.log('Project name: ', mlog.bold(args[0]), sep='') self.add_languages(node, args[1:]) @@ -1377,7 +1383,7 @@ class Interpreter(): self.validate_arguments(args, 1, [str]) if '..' in args[0]: raise InvalidArguments('Subdir contains ..') - if self.subdir == '' and args[0] == 'subprojects': + if self.subdir == '' and args[0] == self.subproject_dir: raise InvalidArguments('Must not go into subprojects dir with subdir(), use subproject() instead.') prev_subdir = self.subdir subdir = os.path.join(prev_subdir, args[0]) @@ -1830,3 +1836,6 @@ class Interpreter(): if len(kwargs) > 0: raise InvalidCode('Keyword arguments are invalid in array construction.') return arguments + + def is_subproject(self): + return self.subproject != '' diff --git a/test cases/common/82 custom subproject dir/a.c b/test cases/common/82 custom subproject dir/a.c new file mode 100644 index 000000000..6ed96fa05 --- /dev/null +++ b/test cases/common/82 custom subproject dir/a.c @@ -0,0 +1,13 @@ +#include +char func_b(); +char func_c(); + +int main(int argc, char **argv) { + if(func_b() != 'b') { + return 1; + } + if(func_c() != 'c') { + return 2; + } + return 0; +} diff --git a/test cases/common/82 custom subproject dir/custom_subproject_dir/B/b.c b/test cases/common/82 custom subproject dir/custom_subproject_dir/B/b.c new file mode 100644 index 000000000..03b0cc72e --- /dev/null +++ b/test cases/common/82 custom subproject dir/custom_subproject_dir/B/b.c @@ -0,0 +1,9 @@ +#include +char func_c(); + +char func_b() { + if(func_c() != 'c') { + exit(3); + } + return 'b'; +} diff --git a/test cases/common/82 custom subproject dir/custom_subproject_dir/B/meson.build b/test cases/common/82 custom subproject dir/custom_subproject_dir/B/meson.build new file mode 100644 index 000000000..280c60ce2 --- /dev/null +++ b/test cases/common/82 custom subproject dir/custom_subproject_dir/B/meson.build @@ -0,0 +1,4 @@ +project('B', 'c') +C = subproject('C') +c = C.get_variable('c') +b = shared_library('b', 'b.c', link_with : c) diff --git a/test cases/common/82 custom subproject dir/custom_subproject_dir/C/c.c b/test cases/common/82 custom subproject dir/custom_subproject_dir/C/c.c new file mode 100644 index 000000000..3bbac08c9 --- /dev/null +++ b/test cases/common/82 custom subproject dir/custom_subproject_dir/C/c.c @@ -0,0 +1,3 @@ +char func_c() { + return 'c'; +} diff --git a/test cases/common/82 custom subproject dir/custom_subproject_dir/C/meson.build b/test cases/common/82 custom subproject dir/custom_subproject_dir/C/meson.build new file mode 100644 index 000000000..abf0b1e26 --- /dev/null +++ b/test cases/common/82 custom subproject dir/custom_subproject_dir/C/meson.build @@ -0,0 +1,2 @@ +project('C', 'c') +c = shared_library('c', 'c.c') diff --git a/test cases/common/82 custom subproject dir/meson.build b/test cases/common/82 custom subproject dir/meson.build new file mode 100644 index 000000000..d9ba649b1 --- /dev/null +++ b/test cases/common/82 custom subproject dir/meson.build @@ -0,0 +1,10 @@ +project('A', 'c', subproject_dir:'custom_subproject_dir') + +B = subproject('B') +b = B.get_variable('b') + +C = subproject('C') +c = C.get_variable('c') + +a = executable('a', 'a.c', link_with : [b, c]) +test('a test', a)