diff options
-rw-r--r-- | docs/markdown/Builtin-options.md | 8 | ||||
-rw-r--r-- | docs/markdown/Users.md | 3 | ||||
-rw-r--r-- | mesonbuild/compilers/cpp.py | 46 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 92 | ||||
-rw-r--r-- | mesonbuild/dependencies/boost.py | 2 | ||||
-rw-r--r-- | mesonbuild/dependencies/data/CMakeListsLLVM.txt | 95 | ||||
-rw-r--r-- | mesonbuild/dependencies/dev.py | 74 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 4 | ||||
-rw-r--r-- | mesonbuild/msetup.py | 2 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | test cases/common/161 config tool variable/meson.build | 2 | ||||
-rw-r--r-- | test cases/common/91 default options/meson.build | 11 | ||||
-rw-r--r-- | test cases/failing/97 custom target install data/Info.plist.cpp | 1 | ||||
-rw-r--r-- | test cases/failing/97 custom target install data/meson.build | 11 | ||||
-rw-r--r-- | test cases/failing/97 custom target install data/preproc.py | 13 | ||||
-rw-r--r-- | test cases/frameworks/15 llvm/meson.build | 4 | ||||
-rw-r--r-- | test cases/frameworks/2 gtest/meson.build | 2 | ||||
-rw-r--r-- | test cases/frameworks/3 gmock/meson.build | 2 | ||||
-rw-r--r-- | test cases/unit/47 native file binary/meson.build | 2 |
19 files changed, 325 insertions, 51 deletions
diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index d25d7ab..db3af64 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -134,7 +134,7 @@ compiler being used: | cpp_link_args| | free-form comma-separated list | C++ link arguments to use | | cpp_std | none | none, c++98, c++03, c++11, c++14, c++17, <br/>c++1z, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z, <br/> vc++14, vc++17, vc++latest | C++ language standard to use | | cpp_debugstl | false | true, false | C++ STL debug mode | -| cpp_eh | sc | none, a, s, sc | C++ exception handling type | +| cpp_eh | default | none, default, a, s, sc | C++ exception handling type | | cpp_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against | The default values of `c_winlibs` and `cpp_winlibs` are in compiler-specific @@ -144,3 +144,9 @@ shell32, ole32, oleaut32, uuid, comdlg32, advapi32. c_args, cpp_args, c_link_args, and cpp_link_args only affect native builds, when cross compiling they will not be applied to binaries or libraries targeting the host system, only those being run on the build system. + +When using MSVC, `cpp_eh=none` will result in no exception flags being passed, +while the `cpp_eh=[value]` will result in `/EH[value]`. +Since *0.51.0* `cpp_eh=default` will result in `/EHsc` on MSVC. When using +gcc-style compilers, nothing is passed (allowing exceptions to work), while +`cpp_eh=none` passes `-fno-exceptions`. diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md index c0f82f5..acb5161 100644 --- a/docs/markdown/Users.md +++ b/docs/markdown/Users.md @@ -37,6 +37,7 @@ listed in the [`meson` GitHub topic](https://github.com/topics/meson). - [GNOME Software](https://gitlab.gnome.org/GNOME/gnome-software), an app store for GNOME - [GNOME Twitch](https://github.com/vinszent/gnome-twitch), an app for viewing Twitch streams on GNOME desktop - [GNOME Usage](https://gitlab.gnome.org/GNOME/gnome-usage), a GNOME application for visualizing system resources + - [GNU FriBidi](https://github.com/fribidi/fribidi), the open source implementation of the Unicode Bidirectional Algorithm - [Graphene](https://ebassi.github.io/graphene/), a thin type library for graphics - [Grilo](https://git.gnome.org/browse/grilo) and [Grilo plugins](https://git.gnome.org/browse/grilo-plugins), the Grilo multimedia framework - [GStreamer](https://cgit.freedesktop.org/gstreamer/gstreamer/), multimedia framework (not the default yet) @@ -47,6 +48,7 @@ listed in the [`meson` GitHub topic](https://github.com/topics/meson). - [HexChat](https://github.com/hexchat/hexchat), a cross-platform IRC client in C - [IGT](https://cgit.freedesktop.org/xorg/app/intel-gpu-tools/), Linux kernel graphics driver test suite - [iSH](https://github.com/tbodt/ish), Linux shell for iOS + - [Janet](https://github.com/janet-lang/janet), a functional and imperative programming language and bytecode interpreter - [json](https://github.com/nlohmann/json), JSON for Modern C++ - [JsonCpp](https://github.com/open-source-parsers/jsoncpp), a C++ library for interacting with JSON - [Json-glib](https://gitlab.gnome.org/GNOME/json-glib), GLib-based JSON manipulation library @@ -65,6 +67,7 @@ listed in the [`meson` GitHub topic](https://github.com/topics/meson). lookup based on OpenStreetMap data - [libspng](https://gitlab.com/randy408/libspng), a C library for reading and writing Portable Network Graphics (PNG) format files + - [libui](https://github.com/andlabs/libui), a simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports - [Libva](https://github.com/intel/libva), an implementation for the VA (VIdeo Acceleration) API - [Libzim](https://github.com/openzim/libzim), the reference implementation for the ZIM file format - [Marker](https://github.com/fabiocolacio/Marker), a GTK-3 markdown editor diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 910a3e9..12644a2 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -149,7 +149,11 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): def get_options(self): opts = CPPCompiler.get_options(self) - opts.update({'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', + opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', + 'C++ exception handling type.', + ['none', 'default'], + 'default'), + 'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], 'none')}) @@ -160,6 +164,8 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): std = options['cpp_std'] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) + if options['cpp_eh'].value == 'none': + args.append('-fno-exceptions') return args def get_option_link_args(self, options): @@ -181,7 +187,11 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): def get_options(self): opts = CPPCompiler.get_options(self) - opts.update({'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', + opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', + 'C++ exception handling type.', + ['none', 'default'], + 'default'), + 'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'gnu++98', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17'], 'none')}) @@ -192,6 +202,8 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): std = options['cpp_std'] if std.value != 'none': args.append('-std=' + std.value) + if options['cpp_eh'].value == 'none': + args.append('-fno-exceptions') return args def get_option_link_args(self, options): @@ -210,7 +222,11 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): def get_options(self): opts = CPPCompiler.get_options(self) - opts.update({'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', + opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', + 'C++ exception handling type.', + ['none', 'default'], + 'default'), + 'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], 'none'), @@ -228,6 +244,8 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): std = options['cpp_std'] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) + if options['cpp_eh'].value == 'none': + args.append('-fno-exceptions') if options['cpp_debugstl'].value: args.append('-D_GLIBCXX_DEBUG=1') return args @@ -258,7 +276,11 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98. def get_options(self): opts = CPPCompiler.get_options(self) - opts.update({'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', + opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', + 'C++ exception handling type.', + ['none', 'default'], + 'default'), + 'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y', 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'], 'none'), @@ -304,7 +326,11 @@ class IntelCPPCompiler(IntelCompiler, CPPCompiler): c_stds += ['c++17'] if version_compare(self.version, '>=17.0.0'): g_stds += ['gnu++14'] - opts.update({'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', + opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', + 'C++ exception handling type.', + ['none', 'default'], + 'default'), + 'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none'] + c_stds + g_stds, 'none'), 'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', @@ -321,6 +347,8 @@ class IntelCPPCompiler(IntelCompiler, CPPCompiler): 'gnu++03': 'gnu++98' } args.append('-std=' + remap_cpp03.get(std.value, std.value)) + if options['cpp_eh'].value == 'none': + args.append('-fno-exceptions') if options['cpp_debugstl'].value: args.append('-D_GLIBCXX_DEBUG=1') return args @@ -339,8 +367,8 @@ class VisualStudioLikeCPPCompilerMixin: def _get_options_impl(self, opts, cpp_stds: typing.List[str]): opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', 'C++ exception handling type.', - ['none', 'a', 's', 'sc'], - 'sc'), + ['none', 'a', 's', 'sc', 'default'], + 'default'), 'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', cpp_stds, @@ -354,7 +382,9 @@ class VisualStudioLikeCPPCompilerMixin: args = [] eh = options['cpp_eh'] - if eh.value != 'none': + if eh.value == 'default': + args.append('/EHsc') + elif eh.value != 'none': args.append('/EH' + eh.value) vc_version_map = { diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 9664215..8f38d6c 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -25,6 +25,7 @@ import textwrap import platform import itertools import ctypes +import typing from typing import Any, Dict, List, Tuple from enum import Enum from pathlib import Path, PurePath @@ -34,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. @@ -73,6 +74,8 @@ class Dependency: @classmethod def _process_method_kw(cls, kwargs): method = kwargs.get('method', 'auto') + if isinstance(method, DependencyMethods): + return method if method not in [e.value for e in DependencyMethods]: raise DependencyException('method {!r} is invalid'.format(method)) method = DependencyMethods(method) @@ -176,6 +179,20 @@ class Dependency: """ raise RuntimeError('Unreachable code in partial_dependency called') + def _add_sub_dependency(self, dep_type: typing.Type['Dependency'], env: Environment, + kwargs: typing.Dict[str, typing.Any], *, + method: DependencyMethods = DependencyMethods.AUTO) -> None: + """Add an internal dependency of of the given type. + + This method is intended to simplify cases of adding a dependency on + another dependency type (such as threads). This will by default set + the method back to auto, but the 'method' keyword argument can be + used to overwrite this behavior. + """ + kwargs = kwargs.copy() + kwargs['method'] = method + self.ext_deps.append(dep_type(env, kwargs)) + class InternalDependency(Dependency): def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps): @@ -954,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 @@ -973,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 @@ -1044,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))] @@ -1225,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) # @@ -1248,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: @@ -1310,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: @@ -1317,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 @@ -1344,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) @@ -1415,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: @@ -1423,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] @@ -1730,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/boost.py b/mesonbuild/dependencies/boost.py index f5b95f5..0de1372 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -105,7 +105,7 @@ class BoostDependency(ExternalDependency): self.requested_modules = self.get_requested(kwargs) if 'thread' in self.requested_modules: - self.ext_deps.append(ThreadDependency(environment, kwargs)) + self._add_sub_dependency(ThreadDependency, environment, kwargs) self.boost_root = None self.boost_roots = [] 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 c911cfa..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 @@ -46,7 +48,7 @@ class GTestDependency(ExternalDependency): self.main = kwargs.get('main', False) self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src'] self.detect() - self.ext_deps.append(ThreadDependency(environment, kwargs)) + self._add_sub_dependency(ThreadDependency, environment, kwargs) def detect(self): gtest_detect = self.clib_compiler.find_library("gtest", self.env, []) @@ -117,7 +119,7 @@ class GMockDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('gmock', environment, 'cpp', kwargs) self.main = kwargs.get('main', False) - self.ext_deps.append(ThreadDependency(environment, kwargs)) + self._add_sub_dependency(ThreadDependency, environment, kwargs) # If we are getting main() from GMock, we definitely # want to avoid linking in main() from GTest @@ -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. @@ -256,7 +258,7 @@ class LLVMDependency(ConfigToolDependency): self._set_old_link_args() self.link_args = strip_system_libdirs(environment, self.link_args) self.link_args = self.__fix_bogus_link_args(self.link_args) - self.ext_deps.append(ThreadDependency(environment, kwargs)) + self._add_sub_dependency(ThreadDependency, environment, kwargs) @staticmethod def __fix_bogus_link_args(args): @@ -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/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index ba97083..3f9d464 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3421,8 +3421,10 @@ This will become a hard error in the future.''' % kwargs['input'], location=self for s in raw_sources: if isinstance(s, mesonlib.File): sources.append(s) - else: + elif isinstance(s, str): source_strings.append(s) + else: + raise InvalidArguments('Argument {!r} must be string or file.'.format(s)) sources += self.source_strings_to_files(source_strings) install_dir = kwargs.get('install_dir', None) if not isinstance(install_dir, (str, type(None))): diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index 563b811..84bcefb 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -191,7 +191,7 @@ class MesonApp: # Print all default option values that don't match the current value for def_opt_name, def_opt_value, cur_opt_value in intr.get_non_matching_default_options(): mlog.log('Option', mlog.bold(def_opt_name), 'is:', - mlog.bold(make_lower_case(cur_opt_value.printable_value())), + mlog.bold('{}'.format(make_lower_case(cur_opt_value.printable_value()))), '[default: {}]'.format(make_lower_case(def_opt_value))) try: dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat') @@ -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/common/91 default options/meson.build b/test cases/common/91 default options/meson.build index c4c72ef..4a9fc2f 100644 --- a/test cases/common/91 default options/meson.build +++ b/test cases/common/91 default options/meson.build @@ -8,13 +8,10 @@ project('default options', 'cpp', 'c', default_options : [ assert(get_option('buildtype') == 'debugoptimized', 'Build type default value wrong.') -if meson.get_compiler('cpp').get_argument_syntax() == 'msvc' - cpp_eh = get_option('cpp_eh') - assert(cpp_eh == 'none', 'MSVC eh value is "' + cpp_eh + '" instead of "none"') -else - cpp_std = get_option('cpp_std') - assert(cpp_std == 'c++11', 'C++ std value is "' + cpp_std + '" instead of c++11.') -endif +cpp_eh = get_option('cpp_eh') +assert(cpp_eh == 'none', 'EH value is "' + cpp_eh + '" instead of "none"') +cpp_std = get_option('cpp_std') +assert(cpp_std == 'c++11', 'C++ std value is "' + cpp_std + '" instead of c++11.') w_level = get_option('warning_level') assert(w_level == '3', 'warning level "' + w_level + '" instead of "3"') diff --git a/test cases/failing/97 custom target install data/Info.plist.cpp b/test cases/failing/97 custom target install data/Info.plist.cpp new file mode 100644 index 0000000..9ca2fcb --- /dev/null +++ b/test cases/failing/97 custom target install data/Info.plist.cpp @@ -0,0 +1 @@ +Some data which gets processed before installation diff --git a/test cases/failing/97 custom target install data/meson.build b/test cases/failing/97 custom target install data/meson.build new file mode 100644 index 0000000..00d348c --- /dev/null +++ b/test cases/failing/97 custom target install data/meson.build @@ -0,0 +1,11 @@ +project('custom target install data') + +preproc = find_program('preproc.py') + +t = custom_target('Info.plist', + command: [preproc, '@INPUT@', '@OUTPUT@'], + input: 'Info.plist.cpp', + output: 'Info.plist', +) + +install_data(t) diff --git a/test cases/failing/97 custom target install data/preproc.py b/test cases/failing/97 custom target install data/preproc.py new file mode 100644 index 0000000..e6eba4c --- /dev/null +++ b/test cases/failing/97 custom target install data/preproc.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +import sys + +if len(sys.argv) != 3: + print(sys.argv[0], '<input>', '<output>') + +inf = sys.argv[1] +outf = sys.argv[2] + +with open(outf, 'wb') as o: + with open(inf, 'rb') as i: + o.write(i.read()) diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build index b43bb87..af94dae 100644 --- a/test cases/frameworks/15 llvm/meson.build +++ b/test cases/frameworks/15 llvm/meson.build @@ -1,6 +1,6 @@ project('llvmtest', ['c', 'cpp'], default_options : ['c_std=c99']) -d = dependency('llvm', required : false) +d = dependency('llvm', required : false, method : 'config-tool') if not d.found() d = dependency('llvm', required : false, static : true) if not d.found() @@ -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/frameworks/2 gtest/meson.build b/test cases/frameworks/2 gtest/meson.build index e5418e9..3f30215 100644 --- a/test cases/frameworks/2 gtest/meson.build +++ b/test cases/frameworks/2 gtest/meson.build @@ -4,7 +4,7 @@ gtest = dependency('gtest', main : true, required : false) if not gtest.found() error('MESON_SKIP_TEST: gtest not installed.') endif -gtest_nomain = dependency('gtest', main : false) +gtest_nomain = dependency('gtest', main : false, method : 'system') e = executable('testprog', 'test.cc', dependencies : gtest) test('gtest test', e) diff --git a/test cases/frameworks/3 gmock/meson.build b/test cases/frameworks/3 gmock/meson.build index 516547f..58591ae 100644 --- a/test cases/frameworks/3 gmock/meson.build +++ b/test cases/frameworks/3 gmock/meson.build @@ -3,7 +3,7 @@ project('gmock test', 'cpp') # Using gmock without gtest is a pain so just # don't support that then. -gtest = dependency('gtest', main : true, required : false) +gtest = dependency('gtest', main : true, required : false, method : 'system') if not gtest.found() error('MESON_SKIP_TEST: gtest not installed.') endif 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() |