aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2019-05-03 10:17:20 -0700
committerGitHub <noreply@github.com>2019-05-03 10:17:20 -0700
commit6c61edeb3036a6b2efd1e8c94496a9954c52b039 (patch)
treedecd649a536ed2c4d050d4715b2d04cfd542f48d
parent529d3788ab70785e12735d4aa9a3cf9e64023bc9 (diff)
parent25de6dd67568d1c02ad0ad5358cd3719c428b88b (diff)
downloadmeson-6c61edeb3036a6b2efd1e8c94496a9954c52b039.zip
meson-6c61edeb3036a6b2efd1e8c94496a9954c52b039.tar.gz
meson-6c61edeb3036a6b2efd1e8c94496a9954c52b039.tar.bz2
Merge pull request #5185 from mensinda/cmakeLLVM
CMake llvm dependency backend
-rw-r--r--mesonbuild/dependencies/base.py75
-rw-r--r--mesonbuild/dependencies/data/CMakeListsLLVM.txt95
-rw-r--r--mesonbuild/dependencies/dev.py68
-rw-r--r--setup.py2
-rw-r--r--test cases/common/161 config tool variable/meson.build2
-rw-r--r--test cases/frameworks/15 llvm/meson.build2
-rw-r--r--test cases/unit/47 native file binary/meson.build2
7 files changed, 220 insertions, 26 deletions
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 7a10d69..8f38d6c 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -35,7 +35,7 @@ from .. import mesonlib
from ..compilers import clib_langs
from ..environment import BinaryTable, Environment, MachineInfo
from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine
-from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify
+from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list
from ..mesonlib import Version, LibType
# These must be defined in this file to avoid cyclical references.
@@ -971,6 +971,24 @@ class CMakeDependency(ExternalDependency):
def _gen_exception(self, msg):
return DependencyException('Dependency {} not found: {}'.format(self.name, msg))
+ def _main_cmake_file(self) -> str:
+ return 'CMakeLists.txt'
+
+ def _extra_cmake_opts(self) -> List[str]:
+ return []
+
+ def _map_module_list(self, modules: List[Tuple[str, bool]]) -> List[Tuple[str, bool]]:
+ # Map the input module list to something else
+ # This function will only be executed AFTER the initial CMake
+ # interpreter pass has completed. Thus variables defined in the
+ # CMakeLists.txt can be accessed here.
+ return modules
+
+ def _original_module_name(self, module: str) -> str:
+ # Reverse the module mapping done by _map_module_list for
+ # one module
+ return module
+
def __init__(self, name: str, environment: Environment, kwargs, language=None):
super().__init__('cmake', environment, language, kwargs)
self.name = name
@@ -990,6 +1008,9 @@ class CMakeDependency(ExternalDependency):
# Where all CMake "build dirs" are located
self.cmake_root_dir = environment.scratch_dir
+ # List of successfully found modules
+ self.found_modules = []
+
# When finding dependencies for cross-compiling, we don't care about
# the 'native' CMake binary
# TODO: Test if this works as expected
@@ -1061,15 +1082,10 @@ class CMakeDependency(ExternalDependency):
if self.cmakeinfo is None:
raise self._gen_exception('Unable to obtain CMake system information')
- modules = kwargs.get('modules', [])
- cm_path = kwargs.get('cmake_module_path', [])
- cm_args = kwargs.get('cmake_args', [])
- if not isinstance(modules, list):
- modules = [modules]
- if not isinstance(cm_path, list):
- cm_path = [cm_path]
- if not isinstance(cm_args, list):
- cm_args = [cm_args]
+ modules = [(x, True) for x in stringlistify(extract_as_list(kwargs, 'modules'))]
+ modules += [(x, False) for x in stringlistify(extract_as_list(kwargs, 'optional_modules'))]
+ cm_path = stringlistify(extract_as_list(kwargs, 'cmake_module_path'))
+ cm_args = stringlistify(extract_as_list(kwargs, 'cmake_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))]
@@ -1242,7 +1258,7 @@ class CMakeDependency(ExternalDependency):
return False
- def _detect_dep(self, name: str, modules: List[str], args: List[str]):
+ def _detect_dep(self, name: str, modules: List[Tuple[str, bool]], args: List[str]):
# Detect a dependency with CMake using the '--find-package' mode
# and the trace output (stderr)
#
@@ -1265,11 +1281,12 @@ class CMakeDependency(ExternalDependency):
# Prepare options
cmake_opts = ['--trace-expand', '-DNAME={}'.format(name), '-DARCHS={}'.format(';'.join(self.cmakeinfo['archs']))] + args + ['.']
+ cmake_opts += self._extra_cmake_opts()
if len(i) > 0:
cmake_opts = ['-G', i] + cmake_opts
# Run CMake
- ret1, out1, err1 = self._call_cmake(cmake_opts, 'CMakeLists.txt')
+ ret1, out1, err1 = self._call_cmake(cmake_opts, self._main_cmake_file())
# Current generator was successful
if ret1 == 0:
@@ -1327,6 +1344,11 @@ class CMakeDependency(ExternalDependency):
self.version = vers_raw[0]
self.version.strip('"\' ')
+ # Post-process module list. Used in derived classes to modify the
+ # module list (append prepend a string, etc.).
+ modules = self._map_module_list(modules)
+ autodetected_module_list = False
+
# Try guessing a CMake target if none is provided
if len(modules) == 0:
for i in self.targets:
@@ -1334,17 +1356,19 @@ class CMakeDependency(ExternalDependency):
lname = name.lower()
if '{}::{}'.format(lname, lname) == tg or lname == tg.replace('::', ''):
mlog.debug('Guessed CMake target \'{}\''.format(i))
- modules = [i]
+ modules = [(i, True)]
+ autodetected_module_list = True
break
# Failed to guess a target --> try the old-style method
if len(modules) == 0:
incDirs = self.get_first_cmake_var_of(['PACKAGE_INCLUDE_DIRS'])
+ defs = self.get_first_cmake_var_of(['PACKAGE_DEFINITIONS'])
libs = self.get_first_cmake_var_of(['PACKAGE_LIBRARIES'])
# Try to use old style variables if no module is specified
if len(libs) > 0:
- self.compile_args = list(map(lambda x: '-I{}'.format(x), incDirs))
+ self.compile_args = list(map(lambda x: '-I{}'.format(x), incDirs)) + defs
self.link_args = libs
mlog.debug('using old-style CMake variables for dependency {}'.format(name))
return
@@ -1361,13 +1385,19 @@ class CMakeDependency(ExternalDependency):
compileDefinitions = []
compileOptions = []
libraries = []
- for i in modules:
+ for i, required in modules:
if i not in self.targets:
- raise self._gen_exception('CMake: invalid CMake target {} for {}.\n'
+ if not required:
+ mlog.warning('CMake: Optional module', mlog.bold(self._original_module_name(i)), 'for', mlog.bold(name), 'was not found')
+ continue
+ raise self._gen_exception('CMake: invalid module {} for {}.\n'
'Try to explicitly specify one or more targets with the "modules" property.\n'
- 'Valid targets are:\n{}'.format(i, name, list(self.targets.keys())))
+ 'Valid targets are:\n{}'.format(self._original_module_name(i), name, list(self.targets.keys())))
targets = [i]
+ if not autodetected_module_list:
+ self.found_modules += [i]
+
while len(targets) > 0:
curr = targets.pop(0)
@@ -1432,7 +1462,7 @@ class CMakeDependency(ExternalDependency):
self.compile_args = compileOptions + compileDefinitions + list(map(lambda x: '-I{}'.format(x), incDirs))
self.link_args = libraries
- def get_first_cmake_var_of(self, var_list):
+ def get_first_cmake_var_of(self, var_list: List[str]) -> List[str]:
# Return the first found CMake variable in list var_list
for i in var_list:
if i in self.vars:
@@ -1440,7 +1470,7 @@ class CMakeDependency(ExternalDependency):
return []
- def get_cmake_var(self, var):
+ def get_cmake_var(self, var: str) -> List[str]:
# Return the value of the CMake variable var or an empty list if var does not exist
if var in self.vars:
return self.vars[var]
@@ -1747,6 +1777,13 @@ set(CMAKE_SIZEOF_VOID_P "{}")
def log_tried(self):
return self.type_name
+ def log_details(self) -> str:
+ modules = [self._original_module_name(x) for x in self.found_modules]
+ modules = sorted(set(modules))
+ if modules:
+ return 'modules: ' + ', '.join(modules)
+ return ''
+
class DubDependency(ExternalDependency):
class_dubbin = None
diff --git a/mesonbuild/dependencies/data/CMakeListsLLVM.txt b/mesonbuild/dependencies/data/CMakeListsLLVM.txt
new file mode 100644
index 0000000..9d3e412
--- /dev/null
+++ b/mesonbuild/dependencies/data/CMakeListsLLVM.txt
@@ -0,0 +1,95 @@
+cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} )
+
+set(PACKAGE_FOUND FALSE)
+
+while(TRUE)
+ find_package(LLVM REQUIRED CONFIG QUIET)
+
+ # ARCHS has to be set via the CMD interface
+ if(LLVM_FOUND OR "${ARCHS}" STREQUAL "")
+ break()
+ endif()
+
+ list(GET ARCHS 0 CMAKE_LIBRARY_ARCHITECTURE)
+ list(REMOVE_AT ARCHS 0)
+endwhile()
+
+if(LLVM_FOUND)
+ set(PACKAGE_FOUND TRUE)
+
+ foreach(mod IN LISTS LLVM_MESON_MODULES)
+ # Reset variables
+ set(out_mods)
+ set(real_mods)
+
+ # Generate a lower and upper case version
+ string(TOLOWER "${mod}" mod_L)
+ string(TOUPPER "${mod}" mod_U)
+
+ # Get the mapped components
+ llvm_map_components_to_libnames(out_mods ${mod} ${mod_L} ${mod_U})
+ list(SORT out_mods)
+ list(REMOVE_DUPLICATES out_mods)
+
+ # Make sure that the modules exist
+ foreach(i IN LISTS out_mods)
+ if(TARGET ${i})
+ list(APPEND real_mods ${i})
+ endif()
+ endforeach()
+
+ # Set the output variables
+ set(MESON_LLVM_TARGETS_${mod} ${real_mods})
+ foreach(i IN LISTS real_mods)
+ set(MESON_TARGET_TO_LLVM_${i} ${mod})
+ endforeach()
+ endforeach()
+
+ # Check the following variables:
+ # LLVM_PACKAGE_VERSION
+ # LLVM_VERSION
+ # LLVM_VERSION_STRING
+ if(NOT DEFINED PACKAGE_VERSION)
+ if(DEFINED LLVM_PACKAGE_VERSION)
+ set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
+ elseif(DEFINED LLVM_VERSION)
+ set(PACKAGE_VERSION "${LLVM_VERSION}")
+ elseif(DEFINED LLVM_VERSION_STRING)
+ set(PACKAGE_VERSION "${LLVM_VERSION_STRING}")
+ endif()
+ endif()
+
+ # Check the following variables:
+ # LLVM_LIBRARIES
+ # LLVM_LIBS
+ set(libs)
+ if(DEFINED LLVM_LIBRARIES)
+ set(libs LLVM_LIBRARIES)
+ elseif(DEFINED LLVM_LIBS)
+ set(libs LLVM_LIBS)
+ endif()
+
+ # Check the following variables:
+ # LLVM_INCLUDE_DIRS
+ # LLVM_INCLUDES
+ # LLVM_INCLUDE_DIR
+ set(includes)
+ if(DEFINED LLVM_INCLUDE_DIRS)
+ set(includes LLVM_INCLUDE_DIRS)
+ elseif(DEFINED LLVM_INCLUDES)
+ set(includes LLVM_INCLUDES)
+ elseif(DEFINED LLVM_INCLUDE_DIR)
+ set(includes LLVM_INCLUDE_DIR)
+ endif()
+
+ # Check the following variables:
+ # LLVM_DEFINITIONS
+ set(definitions)
+ if(DEFINED LLVM_DEFINITIONS)
+ set(definitions LLVM_DEFINITIONS)
+ endif()
+
+ set(PACKAGE_INCLUDE_DIRS "${${includes}}")
+ set(PACKAGE_DEFINITIONS "${${definitions}}")
+ set(PACKAGE_LIBRARIES "${${libs}}")
+endif()
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index 5ee85bf..4d541a3 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -20,14 +20,16 @@ import glob
import os
import re
-from .. import mesonlib
+from .. import mesonlib, mlog
from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineChoice
from .base import (
DependencyException, DependencyMethods, ExternalDependency, PkgConfigDependency,
- strip_system_libdirs, ConfigToolDependency,
+ strip_system_libdirs, ConfigToolDependency, CMakeDependency
)
from .misc import ThreadDependency
+from typing import List, Tuple
+
def get_shared_library_suffix(environment, native):
"""This is only gauranteed to work for languages that compile to machine
@@ -192,7 +194,7 @@ class GMockDependency(ExternalDependency):
return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]
-class LLVMDependency(ConfigToolDependency):
+class LLVMDependencyConfigTool(ConfigToolDependency):
"""
LLVM uses a special tool, llvm-config, which has arguments for getting
c args, cxx args, and ldargs as well as version.
@@ -399,6 +401,66 @@ class LLVMDependency(ConfigToolDependency):
return 'modules: ' + ', '.join(self.module_details)
return ''
+class LLVMDependencyCMake(CMakeDependency):
+ def __init__(self, env, kwargs):
+ self.llvm_modules = stringlistify(extract_as_list(kwargs, 'modules'))
+ self.llvm_opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules'))
+ super().__init__(name='LLVM', environment=env, language='cpp', kwargs=kwargs)
+
+ # Extract extra include directories and definitions
+ inc_dirs = self.get_cmake_var('PACKAGE_INCLUDE_DIRS')
+ defs = self.get_cmake_var('PACKAGE_DEFINITIONS')
+ temp = ['-I' + x for x in inc_dirs] + defs
+ self.compile_args += [x for x in temp if x not in self.compile_args]
+ self._add_sub_dependency(ThreadDependency, env, kwargs)
+
+ def _main_cmake_file(self) -> str:
+ # Use a custom CMakeLists.txt for LLVM
+ return 'CMakeListsLLVM.txt'
+
+ def _extra_cmake_opts(self) -> List[str]:
+ return ['-DLLVM_MESON_MODULES={}'.format(';'.join(self.llvm_modules + self.llvm_opt_modules))]
+
+ def _map_module_list(self, modules: List[Tuple[str, bool]]) -> List[Tuple[str, bool]]:
+ res = []
+ for mod, required in modules:
+ cm_targets = self.get_cmake_var('MESON_LLVM_TARGETS_{}'.format(mod))
+ if not cm_targets:
+ if required:
+ raise self._gen_exception('LLVM module {} was not found'.format(mod))
+ else:
+ mlog.warning('Optional LLVM module', mlog.bold(mod), 'was not found')
+ continue
+ for i in cm_targets:
+ res += [(i, required)]
+ return res
+
+ def _original_module_name(self, module: str) -> str:
+ orig_name = self.get_cmake_var('MESON_TARGET_TO_LLVM_{}'.format(module))
+ if orig_name:
+ return orig_name[0]
+ return module
+
+class LLVMDependency(ExternalDependency):
+ def __init__(self, env, kwargs):
+ super().__init__('LLVM', env, 'cpp', kwargs)
+
+ @classmethod
+ def _factory(cls, env, kwargs):
+ methods = cls._process_method_kw(kwargs)
+ candidates = []
+
+ if DependencyMethods.CMAKE in methods:
+ candidates.append(functools.partial(LLVMDependencyCMake, env, kwargs))
+
+ if DependencyMethods.CONFIG_TOOL in methods:
+ candidates.append(functools.partial(LLVMDependencyConfigTool, env, kwargs))
+
+ return candidates
+
+ @staticmethod
+ def get_methods():
+ return [DependencyMethods.CMAKE, DependencyMethods.CONFIG_TOOL]
class ValgrindDependency(PkgConfigDependency):
'''
diff --git a/setup.py b/setup.py
index 07bd3dd..aab740e 100644
--- a/setup.py
+++ b/setup.py
@@ -35,7 +35,7 @@ packages = ['mesonbuild',
'mesonbuild.modules',
'mesonbuild.scripts',
'mesonbuild.wrap']
-package_data = {'mesonbuild.dependencies': ['data/CMakeLists.txt', 'data/CMakePathInfo.txt']}
+package_data = {'mesonbuild.dependencies': ['data/CMakeLists.txt', 'data/CMakeListsLLVM.txt', 'data/CMakePathInfo.txt']}
data_files = []
if sys.platform != 'win32':
# Only useful on UNIX-like systems
diff --git a/test cases/common/161 config tool variable/meson.build b/test cases/common/161 config tool variable/meson.build
index 0643042..9584117 100644
--- a/test cases/common/161 config tool variable/meson.build
+++ b/test cases/common/161 config tool variable/meson.build
@@ -15,7 +15,7 @@
project('config tool variable', 'cpp')
-dep_llvm = dependency('llvm', required : false)
+dep_llvm = dependency('llvm', method : 'config-tool', required : false)
if not dep_llvm.found()
error('MESON_SKIP_TEST LLVM not installed.')
endif
diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build
index fc75084..af94dae 100644
--- a/test cases/frameworks/15 llvm/meson.build
+++ b/test cases/frameworks/15 llvm/meson.build
@@ -35,7 +35,7 @@ foreach static : [true, false]
llvm_dep = dependency(
'llvm',
modules : ['bitwriter', 'asmprinter', 'executionengine', 'target',
- 'mcjit', 'nativecodegen'],
+ 'mcjit', 'nativecodegen', 'amdgpu'],
required : false,
static : static,
)
diff --git a/test cases/unit/47 native file binary/meson.build b/test cases/unit/47 native file binary/meson.build
index 4489ac1..c9b6e5d 100644
--- a/test cases/unit/47 native file binary/meson.build
+++ b/test cases/unit/47 native file binary/meson.build
@@ -8,7 +8,7 @@ if case == 'find_program'
assert(result.stdout().strip().endswith('12345'), 'Didn\'t load bash from config file')
elif case == 'config_dep'
add_languages('cpp')
- dep = dependency('llvm')
+ dep = dependency('llvm', method : 'config-tool')
assert(dep.get_configtool_variable('version').endswith('12345'), 'Didn\'t load llvm from config file')
elif case == 'python3'
prog = import('python3').find_python()