Merge pull request #5185 from mensinda/cmakeLLVM

CMake llvm dependency backend
pull/5358/head
Dylan Baker 6 years ago committed by GitHub
commit 6c61edeb30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 75
      mesonbuild/dependencies/base.py
  2. 95
      mesonbuild/dependencies/data/CMakeListsLLVM.txt
  3. 68
      mesonbuild/dependencies/dev.py
  4. 2
      setup.py
  5. 2
      test cases/common/161 config tool variable/meson.build
  6. 2
      test cases/frameworks/15 llvm/meson.build
  7. 2
      test cases/unit/47 native file binary/meson.build

@ -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

@ -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()

@ -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):
'''

@ -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

@ -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

@ -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,
)

@ -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()

Loading…
Cancel
Save