aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/cmake/interpreter.py18
-rw-r--r--mesonbuild/interpreter.py30
-rw-r--r--mesonbuild/modules/cmake.py70
-rwxr-xr-xmesonbuild/msubprojects.py2
-rw-r--r--mesonbuild/wrap/wrap.py15
5 files changed, 106 insertions, 29 deletions
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
index 7782555..406723f 100644
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -25,7 +25,7 @@ from ..backend.backends import Backend
from ..compilers.compilers import obj_suffixes
from ..dependencies.base import CMakeDependency, ExternalProgram
from subprocess import Popen, PIPE, STDOUT
-from typing import List
+from typing import List, Dict, Optional
import os, re
backend_generator_map = {
@@ -284,6 +284,9 @@ class CMakeInterpreter:
self.languages = []
self.targets = []
+ # Generated meson data
+ self.generated_targets = {}
+
def configure(self, extra_cmake_options: List[str]) -> None:
# Find CMake
cmake_exe, cmake_vers, _ = CMakeDependency.find_cmake_binary(self.env)
@@ -297,7 +300,7 @@ class CMakeInterpreter:
cmake_args = cmake_exe.get_command()
# Map meson compiler to CMake variables
- for lang, comp in self.build.compilers.items():
+ for lang, comp in self.env.coredata.compilers.items():
if lang not in language_map:
continue
cmake_lang = language_map[lang]
@@ -530,11 +533,20 @@ class CMakeInterpreter:
# Add the nodes to the ast
root_cb.lines += [inc_node, src_node, tgt_node, dep_node]
- processed[tgt.name] = {'inc': inc_var, 'src': src_var, 'dep': dep_var, 'tgt': tgt_var}
+ processed[tgt.name] = {'inc': inc_var, 'src': src_var, 'dep': dep_var, 'tgt': tgt_var, 'func': tgt_func}
# Now generate the target function calls
for i in self.targets:
if i.name not in processed:
process_target(i)
+ self.generated_targets = processed
return root_cb
+
+ def target_info(self, target: str) -> Optional[Dict[str, str]]:
+ if target in self.generated_targets:
+ return self.generated_targets[target]
+ return None
+
+ def target_list(self) -> List[str]:
+ return list(self.generated_targets.keys())
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 0e50202..1ac4cd9 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -2247,7 +2247,7 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Stdlib definition for %s should have exactly two elements.'
% l)
projname, depname = di
- subproj = self.do_subproject(projname, {})
+ subproj = self.do_subproject(projname, 'meson', {})
self.build.cross_stdlibs[l] = subproj.get_variable_method([depname], {})
except KeyError:
pass
@@ -2416,20 +2416,19 @@ external dependencies (including libraries) must go to "dependencies".''')
raise InterpreterException('Tried to call option() in build description file. All options must be in the option file.')
@FeatureNewKwargs('subproject', '0.38.0', ['default_options'])
- @FeatureNewKwargs('subproject', '0.51.0', ['method', 'cmake_options'])
@permittedKwargs(permitted_kwargs['subproject'])
@stringArgs
def func_subproject(self, nodes, args, kwargs):
if len(args) != 1:
raise InterpreterException('Subproject takes exactly one argument')
dirname = args[0]
- return self.do_subproject(dirname, kwargs)
+ return self.do_subproject(dirname, 'meson', 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):
+ def do_subproject(self, dirname: str, method: str, kwargs):
disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
if disabled:
mlog.log('Subproject', mlog.bold(dirname), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
@@ -2437,7 +2436,6 @@ external dependencies (including libraries) must go to "dependencies".''')
default_options = mesonlib.stringlistify(kwargs.get('default_options', []))
default_options = coredata.create_options_dict(default_options)
- method = kwargs.get('method', 'auto')
if dirname == '':
raise InterpreterException('Subproject dir name must not be empty.')
if dirname[0] == '.':
@@ -2463,7 +2461,7 @@ external dependencies (including libraries) must go to "dependencies".''')
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
r = wrap.Resolver(subproject_dir_abs, self.coredata.get_builtin_option('wrap_mode'))
try:
- resolved = r.resolve(dirname)
+ resolved = r.resolve(dirname, method)
except wrap.WrapException as e:
subprojdir = os.path.join(self.subproject_dir, r.directory)
if isinstance(e, wrap.WrapNotFoundException):
@@ -2483,21 +2481,14 @@ external dependencies (including libraries) must go to "dependencies".''')
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
self.global_args_frozen = True
- # Determine the method to use when 'auto' is given
- if method == 'auto':
- if os.path.exists(os.path.join(subdir_abs, environment.build_filename)):
- method = 'meson'
- elif os.path.exists(os.path.join(subdir_abs, 'CMakeLists.txt')):
- method = 'cmake'
-
mlog.log()
with mlog.nested():
mlog.log('Executing subproject', mlog.bold(dirname), 'method', mlog.bold(method), '\n')
try:
if method == 'meson':
- return self.do_subproject_meson(dirname, subdir, default_options, required, kwargs)
+ return self._do_subproject_meson(dirname, subdir, default_options, required, kwargs)
elif method == 'cmake':
- return self.do_subproject_cmake(dirname, subdir, subdir_abs, default_options, required, kwargs)
+ return self._do_subproject_cmake(dirname, subdir, subdir_abs, default_options, required, kwargs)
else:
raise InterpreterException('The method {} is invalid for the subproject {}'.format(method, dirname))
# Invalid code is always an error
@@ -2513,7 +2504,7 @@ external dependencies (including libraries) must go to "dependencies".''')
return self.disabled_subproject(dirname)
raise e
- def do_subproject_meson(self, dirname, subdir, default_options, required, kwargs, ast=None, build_def_files=None):
+ def _do_subproject_meson(self, dirname, subdir, default_options, required, kwargs, ast=None, build_def_files=None):
with mlog.nested():
new_build = self.build.copy()
subi = Interpreter(new_build, self.backend, dirname, subdir, self.subproject_dir,
@@ -2544,7 +2535,7 @@ external dependencies (including libraries) must go to "dependencies".''')
self.build.subprojects[dirname] = subi.project_version
return self.subprojects[dirname]
- def do_subproject_cmake(self, dirname, subdir, subdir_abs, default_options, required, kwargs):
+ def _do_subproject_cmake(self, dirname, subdir, subdir_abs, default_options, required, kwargs):
with mlog.nested():
new_build = self.build.copy()
prefix = self.coredata.builtins['prefix'].value
@@ -2572,7 +2563,8 @@ external dependencies (including libraries) must go to "dependencies".''')
mlog.debug('=== END meson.build ===')
mlog.debug()
- result = self.do_subproject_meson(dirname, subdir, default_options, required, kwargs, ast, cm_int.bs_files)
+ result = self._do_subproject_meson(dirname, subdir, default_options, required, kwargs, ast, cm_int.bs_files)
+ result.cm_interpreter = cm_int
mlog.log()
return result
@@ -3164,7 +3156,7 @@ external dependencies (including libraries) must go to "dependencies".''')
'default_options': kwargs.get('default_options', []),
'required': kwargs.get('required', True),
}
- self.do_subproject(dirname, sp_kwargs)
+ self.do_subproject(dirname, 'meson', sp_kwargs)
return self.get_subproject_dep(display_name, dirname, varname, kwargs)
@FeatureNewKwargs('executable', '0.42.0', ['implib'])
diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py
index d72ceca..8ce5aef 100644
--- a/mesonbuild/modules/cmake.py
+++ b/mesonbuild/modules/cmake.py
@@ -18,8 +18,8 @@ import shutil
from . import ExtensionModule, ModuleReturnValue
from .. import build, dependencies, mesonlib, mlog
-from ..interpreterbase import permittedKwargs
-from ..interpreter import ConfigurationDataHolder
+from ..interpreterbase import permittedKwargs, FeatureNew, stringArgs, InterpreterObject, ObjectHolder
+from ..interpreter import ConfigurationDataHolder, InterpreterException, SubprojectHolder
COMPATIBILITIES = ['AnyNewerVersion', 'SameMajorVersion', 'SameMinorVersion', 'ExactVersion']
@@ -43,6 +43,62 @@ unset(_realOrig)
unset(_realCurr)
'''
+class CMakeSubprojectHolder(InterpreterObject, ObjectHolder):
+ def __init__(self, subp, pv):
+ assert(isinstance(subp, SubprojectHolder))
+ assert(hasattr(subp, 'cm_interpreter'))
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, subp, pv)
+ self.methods.update({'get_variable': self.get_variable,
+ 'dependency': self.dependency,
+ 'include_directories': self.include_directories,
+ 'target': self.target,
+ 'target_type': self.target_type,
+ 'target_list': self.target_list,
+ })
+
+ def _args_to_info(self, args):
+ if len(args) != 1:
+ raise InterpreterException('Exactly one argument is required.')
+
+ tgt = args[0]
+ res = self.held_object.cm_interpreter.target_info(tgt)
+ if res is None:
+ raise InterpreterException('The CMake target {} does not exist'.format(tgt))
+
+ # Make sure that all keys are present (if not this is a bug)
+ assert(all([x in res for x in ['inc', 'src', 'dep', 'tgt', 'func']]))
+ return res
+
+ @permittedKwargs({})
+ def get_variable(self, args, kwargs):
+ return self.held_object.get_variable_method(args, kwargs)
+
+ @permittedKwargs({})
+ def dependency(self, args, kwargs):
+ info = self._args_to_info(args)
+ return self.get_variable([info['dep']], kwargs)
+
+ @permittedKwargs({})
+ def include_directories(self, args, kwargs):
+ info = self._args_to_info(args)
+ return self.get_variable([info['inc']], kwargs)
+
+ @permittedKwargs({})
+ def target(self, args, kwargs):
+ info = self._args_to_info(args)
+ return self.get_variable([info['tgt']], kwargs)
+
+ @permittedKwargs({})
+ def target_type(self, args, kwargs):
+ info = self._args_to_info(args)
+ return info['func']
+
+ @permittedKwargs({})
+ def target_list(self, args, kwargs):
+ if len(args) > 0:
+ raise InterpreterException('target_list does not take any parameters.')
+ return self.held_object.cm_interpreter.target_list()
class CmakeModule(ExtensionModule):
cmake_detected = False
@@ -51,6 +107,7 @@ class CmakeModule(ExtensionModule):
def __init__(self, interpreter):
super().__init__(interpreter)
self.snippets.add('configure_package_config_file')
+ self.snippets.add('subproject')
def detect_voidp_size(self, env):
compilers = env.coredata.compilers
@@ -210,5 +267,14 @@ class CmakeModule(ExtensionModule):
return res
+ @FeatureNew('subproject', '0.51.0')
+ @permittedKwargs({'cmake_options'})
+ @stringArgs
+ def subproject(self, interpreter, state, args, kwargs):
+ if len(args) != 1:
+ raise InterpreterException('Subproject takes exactly one argument')
+ dirname = args[0]
+ return CMakeSubprojectHolder(interpreter.do_subproject(dirname, 'cmake', kwargs), dirname)
+
def initialize(*args, **kwargs):
return CmakeModule(*args, **kwargs)
diff --git a/mesonbuild/msubprojects.py b/mesonbuild/msubprojects.py
index 4162af6..bc6a6ce 100755
--- a/mesonbuild/msubprojects.py
+++ b/mesonbuild/msubprojects.py
@@ -163,7 +163,7 @@ def download(wrap, repo_dir, options):
return
try:
r = Resolver(os.path.dirname(repo_dir))
- r.resolve(wrap.name)
+ r.resolve(wrap.name, 'meson')
mlog.log(' -> done')
except WrapException as e:
mlog.log(' ->', mlog.red(str(e)))
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index 47db985..55f86bc 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -111,7 +111,7 @@ class Resolver:
self.subdir_root = subdir_root
self.cachedir = os.path.join(self.subdir_root, 'packagecache')
- def resolve(self, packagename):
+ def resolve(self, packagename: str, method: str):
self.packagename = packagename
self.directory = packagename
# We always have to load the wrap file, if it exists, because it could
@@ -125,8 +125,13 @@ class Resolver:
meson_file = os.path.join(self.dirname, 'meson.build')
cmake_file = os.path.join(self.dirname, 'CMakeLists.txt')
+ if method not in ['meson', 'cmake']:
+ raise WrapException('Only the methods "meson" and "cmake" are supported')
+
# The directory is there and has meson.build? Great, use it.
- if os.path.exists(meson_file) or os.path.exists(cmake_file):
+ if method == 'meson' and os.path.exists(meson_file):
+ return self.directory
+ if method == 'cmake' and os.path.exists(cmake_file):
return self.directory
# Check if the subproject is a git submodule
@@ -154,9 +159,11 @@ class Resolver:
else:
raise WrapException('Unknown wrap type {!r}'.format(self.wrap.type))
- # A meson.build file is required in the directory
- if not os.path.exists(meson_file):
+ # A meson.build or CMakeLists.txt file is required in the directory
+ if method == 'meson' and not os.path.exists(meson_file):
raise WrapException('Subproject exists but has no meson.build file')
+ if method == 'cmake' and not os.path.exists(cmake_file):
+ raise WrapException('Subproject exists but has no CMakeLists.txt file')
return self.directory