diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index 4ff5a2a18..259f09e25 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -148,6 +148,14 @@ it automatically. cmake_dep = dependency('ZLIB', method : 'cmake', modules : ['ZLIB::ZLIB']) ``` +It is also possible to reuse existing `Find.cmake` files with the +`cmake_module_path` property. Using this property is equivalent to setting the +`CMAKE_MODULE_PATH` variable in CMake. The path(s) given to `cmake_module_path` +should all be relative to the project source directory. Absolute paths +should only be used if the CMake files are not stored in the project itself. + +Additional CMake parameters can be specified with the `cmake_args` property. + ### Some notes on Dub Please understand that meson is only able to find dependencies that diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md index 3d8515ff8..8ae4fdeff 100644 --- a/docs/markdown/howtox.md +++ b/docs/markdown/howtox.md @@ -203,3 +203,20 @@ executable(..., dependencies : m_dep) ```meson executable(..., install : true, install_dir : get_option('libexecdir')) ``` + +## Use existing `Find.cmake` files + +Meson can use the CMake `find_package()` ecosystem if CMake is installed. +To find a dependency with custom `Find.cmake`, set the `cmake_module_path` +property to the path in your project where the CMake scripts are stored. + +Example for a `FindCmakeOnlyDep.cmake` in a `cmake` subdirectory: + +```meson +cm_dep = dependency('CmakeOnlyDep', cmake_module_path : 'cmake') +``` + +The `cmake_module_path` property is only needed for custom CMake scripts. System +wide CMake scripts are found automatically. + +More information can be found [here](Dependencies.md#cmake) diff --git a/docs/markdown/snippets/cmake_module_path.md b/docs/markdown/snippets/cmake_module_path.md new file mode 100644 index 000000000..7beb453a8 --- /dev/null +++ b/docs/markdown/snippets/cmake_module_path.md @@ -0,0 +1,9 @@ +## Added `cmake_module_path` and `cmake_args` to dependency + +The CMake dependency backend can now make use of existing `Find.cmake` +files by setting the `CMAKE_MODULE_PATH` with the new `dependency()` property +`cmake_module_path`. The paths given to `cmake_module_path` should be relative +to the project source directory. + +Furthermore the property `cmake_args` was added to give CMake additional +parameters. diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 1f74de494..586c7167e 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -27,13 +27,14 @@ import textwrap import platform import itertools import ctypes +from typing import List from enum import Enum from pathlib import Path, PurePath from .. import mlog from .. import mesonlib from ..compilers import clib_langs -from ..environment import BinaryTable +from ..environment import BinaryTable, Environment from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify from ..mesonlib import Version @@ -926,7 +927,7 @@ class CMakeDependency(ExternalDependency): def _gen_exception(self, msg): return DependencyException('Dependency {} not found: {}'.format(self.name, msg)) - def __init__(self, name, environment, kwargs, language=None): + def __init__(self, name: str, environment: Environment, kwargs, language=None): super().__init__('cmake', environment, language, kwargs) self.name = name self.is_libtool = False @@ -1010,16 +1011,25 @@ class CMakeDependency(ExternalDependency): return modules = kwargs.get('modules', []) + cm_path = kwargs.get('cmake_module_path', []) + cm_args = kwargs.get('cmake_args', []) if not isinstance(modules, list): modules = [modules] - self._detect_dep(name, modules) + if not isinstance(cm_path, list): + cm_path = [cm_path] + if not isinstance(cm_args, list): + cm_args = [cm_args] + cm_path = [x if os.path.isabs(x) else os.path.join(environment.get_source_dir(), x) for x in cm_path] + if cm_path: + cm_args += ['-DCMAKE_MODULE_PATH={}'.format(';'.join(cm_path))] + self._detect_dep(name, modules, cm_args) def __repr__(self): s = '<{0} {1}: {2} {3}>' return s.format(self.__class__.__name__, self.name, self.is_found, self.version_reqs) - def _detect_dep(self, name, modules): + def _detect_dep(self, name: str, modules: List[str], args: List[str]): # Detect a dependency with CMake using the '--find-package' mode # and the trace output (stderr) # @@ -1035,7 +1045,7 @@ class CMakeDependency(ExternalDependency): mlog.debug('Try CMake generator: {}'.format(i if len(i) > 0 else 'auto')) # Prepare options - cmake_opts = ['--trace-expand', '-DNAME={}'.format(name), '.'] + cmake_opts = ['--trace-expand', '-DNAME={}'.format(name)] + args + ['.'] if len(i) > 0: cmake_opts = ['-G', i] + cmake_opts diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 0b9ce7153..fb4c4682c 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1929,6 +1929,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, 'main', 'method', 'modules', + 'cmake_module_path', 'optional_modules', 'native', 'not_found_message', @@ -1936,6 +1937,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, 'static', 'version', 'private_headers', + 'cmake_args', }, 'declare_dependency': {'include_directories', 'link_with', @@ -2903,10 +2905,10 @@ external dependencies (including libraries) must go to "dependencies".''') elif name == 'openmp': FeatureNew('OpenMP Dependency', '0.46.0').use(self.subproject) + @FeatureNewKwargs('dependency', '0.50.0', ['not_found_message', 'cmake_module_path', 'cmake_args']) @FeatureNewKwargs('dependency', '0.49.0', ['disabler']) @FeatureNewKwargs('dependency', '0.40.0', ['method']) @FeatureNewKwargs('dependency', '0.38.0', ['default_options']) - @FeatureNewKwargs('dependency', '0.50.0', ['not_found_message']) @disablerIfNotFound @permittedKwargs(permitted_kwargs['dependency']) def func_dependency(self, node, args, kwargs): diff --git a/test cases/linuxlike/13 cmake dependency/cmake/FindSomethingLikeZLIB.cmake b/test cases/linuxlike/13 cmake dependency/cmake/FindSomethingLikeZLIB.cmake new file mode 100644 index 000000000..a2f84565f --- /dev/null +++ b/test cases/linuxlike/13 cmake dependency/cmake/FindSomethingLikeZLIB.cmake @@ -0,0 +1,9 @@ +find_package(ZLIB) + +if(ZLIB_FOUND OR ZLIB_Found) + set(SomethingLikeZLIB_FOUND ON) + set(SomethingLikeZLIB_LIBRARIES ${ZLIB_LIBRARY}) + set(SomethingLikeZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR}) +else() + set(SomethingLikeZLIB_FOUND OFF) +endif() diff --git a/test cases/linuxlike/13 cmake dependency/meson.build b/test cases/linuxlike/13 cmake dependency/meson.build index 72773b29b..a18cd848a 100644 --- a/test cases/linuxlike/13 cmake dependency/meson.build +++ b/test cases/linuxlike/13 cmake dependency/meson.build @@ -36,6 +36,12 @@ depf2 = dependency('ZLIB', required : false, method : 'cmake', modules : 'dfggh: assert(depf2.found() == false, 'Invalid CMake targets should fail') +# Try to find a dependency with a custom CMake module + +depm1 = dependency('SomethingLikeZLIB', required : true, method : 'cmake', cmake_module_path : 'cmake') +depm2 = dependency('SomethingLikeZLIB', required : true, method : 'cmake', cmake_module_path : ['cmake']) +depm3 = dependency('SomethingLikeZLIB', required : true, cmake_module_path : 'cmake') + # Try to compile a test that takes a dep and an include_directories cc = meson.get_compiler('c')