diff options
-rw-r--r-- | docs/markdown/CMake-module.md | 77 | ||||
-rw-r--r-- | docs/markdown/snippets/cmake.md | 17 | ||||
-rw-r--r-- | mesonbuild/cmake/__init__.py | 5 | ||||
-rw-r--r-- | mesonbuild/cmake/common.py | 95 | ||||
-rw-r--r-- | mesonbuild/cmake/interpreter.py | 21 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 12 | ||||
-rw-r--r-- | mesonbuild/modules/cmake.py | 110 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/main.cpp | 18 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/meson.build | 29 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/subprojects/cmOpts/CMakeLists.txt | 18 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.cpp | 31 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.hpp | 14 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.cpp | 25 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.hpp | 3 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/subprojects/cmOpts/main.cpp | 10 | ||||
-rw-r--r-- | test cases/cmake/19 advanced options/test.json | 8 |
16 files changed, 470 insertions, 23 deletions
diff --git a/docs/markdown/CMake-module.md b/docs/markdown/CMake-module.md index 7103608..fc6157e 100644 --- a/docs/markdown/CMake-module.md +++ b/docs/markdown/CMake-module.md @@ -48,8 +48,6 @@ The `subproject` method is almost identical to the normal meson `subproject` function. The only difference is that a CMake project instead of a meson project is configured. -Also, project specific CMake options can be added with the `cmake_options` key. - The returned `sub_proj` supports the same options as a "normal" subproject. Meson automatically detects CMake build targets, which can be accessed with the methods listed [below](#subproject-object). @@ -87,6 +85,49 @@ It should be noted that not all projects are guaranteed to work. The safest approach would still be to create a `meson.build` for the subprojects in question. +### Configuration options + +*New in meson 0.55.0* + +Meson also supports passing configuration options to CMake and overriding +certain build details extracted from the CMake subproject. + +```meson +cmake = import('cmake') +opt_var = cmake.subproject_options() + +# Call CMake with `-DSOME_OTHER_VAR=ON` +opt_var.add_cmake_defines({'SOME_OTHER_VAR': true}) + +# Globally override the C++ standard to c++11 +opt_var.set_override_option('cpp_std', 'c++11') + +# Override the previous global C++ standard +# with c++14 only for the CMake target someLib +opt_var.set_override_option('cpp_std', 'c++14', target: 'someLib') + +sub_pro = cmake.subproject('someLibProject', options: opt_var) + +# Further changes to opt_var have no effect +``` + +See [the CMake options object](#cmake-options-object) for a complete reference +of all supported functions. + +The CMake configuration options object is very similar to the +[configuration data object](Reference-manual.md#configuration-data-object) object +returned by [`configuration_data`](Reference-manual.md#configuration_data). It +is generated by the `subproject_options` function + +All configuration options have to be set *before* the subproject is configured +and must be passed to the `subproject` method via the `options` key. Altering +the configuration object won't have any effect on previous `cmake.subproject` +calls. + +In earlier meson versions CMake command-line parameters could be set with the +`cmake_options` kwarg. However, this feature is deprecated since 0.55.0 and only +kept for compatibility. It will not work together with the `options` kwarg. + ### `subproject` object This object is returned by the `subproject` function described above @@ -103,7 +144,37 @@ and supports the following methods: the subproject. Usually `dependency()` or `target()` should be preferred to extract build targets. - `found` returns true if the subproject is available, otherwise false - *new in in 0.53.2* + *new in meson 0.53.2* + +### `cmake options` object + +This object is returned by the `subproject_options()` function and consumed by +the `options` kwarg of the `subproject` function. The following methods are +supported: + + - `add_cmake_defines({'opt1': val1, ...})` add additional CMake commandline defines + - `set_override_option(opt, val)` set specific [build options](Build-options.md) + for targets. This will effectively add `opt=val` to the `override_options` + array of the [build target](Reference-manual.md#executable) + - `set_install(bool)` override wether targets should be installed or not + - `append_compile_args(lang, arg1, ...)` append compile flags for a specific + language to the targets + - `append_link_args(arg1, ...)` append linger args to the targets + - `clear()` reset all data in the `cmake options` object + +The methods `set_override_option`, `set_install`, `append_compile_args` and +`append_link_args` support the optional `target` kwarg. If specified, the set +options affect the specific target. The effect of the option is global for the +subproject otherwise. + +If, for instance, `opt_var.set_install(false)` is called, no target will be +installed regardless of what is set by CMake. However, it is still possible to +install specific targets (here `foo`) by setting the `target` kwarg: +`opt_var.set_install(true, target: 'foo')` + +Options that are not set won't affect the generated subproject. So, if for +instance, `set_install` was not called then the values extracted from CMake will +be used. ## CMake configuration files diff --git a/docs/markdown/snippets/cmake.md b/docs/markdown/snippets/cmake.md new file mode 100644 index 0000000..16da78e --- /dev/null +++ b/docs/markdown/snippets/cmake.md @@ -0,0 +1,17 @@ +## Configure CMake subprojects with meson.subproject_options + +Meson now supports passing configuration options to CMake and overriding +certain build details extracted from the CMake subproject. + +The new CMake configuration options object is very similar to the +[configuration data object](Reference-manual.md#configuration-data-object) object +returned by [`configuration_data`](Reference-manual.md#configuration_data). It +is generated by the `subproject_options` function + +All configuration options have to be set *before* the subproject is configured +and must be passed to the `subproject` method via the `options` key. Altering +the configuration object won't have any effect on previous `cmake.subproject` +calls. + +**Note:** The `cmake_options` kwarg for the `subproject` function is now +deprecated since it is replaced by the new `options` system. diff --git a/mesonbuild/cmake/__init__.py b/mesonbuild/cmake/__init__.py index 01cc3f9..db7aefd 100644 --- a/mesonbuild/cmake/__init__.py +++ b/mesonbuild/cmake/__init__.py @@ -24,11 +24,14 @@ __all__ = [ 'CMakeTarget', 'CMakeTraceLine', 'CMakeTraceParser', + 'SingleTargetOptions', + 'TargetOptions', 'parse_generator_expressions', 'language_map', + 'cmake_defines_to_args', ] -from .common import CMakeException +from .common import CMakeException, SingleTargetOptions, TargetOptions, cmake_defines_to_args from .client import CMakeClient from .executor import CMakeExecutor from .fileapi import CMakeFileAPI diff --git a/mesonbuild/cmake/common.py b/mesonbuild/cmake/common.py index e7da0d7..4510b5d 100644 --- a/mesonbuild/cmake/common.py +++ b/mesonbuild/cmake/common.py @@ -60,6 +60,26 @@ def _flags_to_list(raw: str) -> T.List[str]: res = list(filter(lambda x: len(x) > 0, res)) return res +def cmake_defines_to_args(raw: T.Any, permissive: bool = False) -> T.List[str]: + res = [] # type: T.List[str] + if not isinstance(raw, list): + raw = [raw] + + for i in raw: + if not isinstance(i, dict): + raise MesonException('Invalid CMake defines. Expected a dict, but got a {}'.format(type(i).__name__)) + for key, val in i.items(): + assert isinstance(key, str) + if isinstance(val, (str, int, float)): + res += ['-D{}={}'.format(key, val)] + elif isinstance(val, bool): + val_str = 'ON' if val else 'OFF' + res += ['-D{}={}'.format(key, val_str)] + else: + raise MesonException('Type "{}" of "{}" is not supported as for a CMake define value'.format(type(val).__name__, key)) + + return res + class CMakeFileGroup: def __init__(self, data: dict): self.defines = data.get('defines', '') @@ -163,3 +183,78 @@ class CMakeConfiguration: mlog.log('Project {}:'.format(idx)) with mlog.nested(): i.log() + +class SingleTargetOptions: + def __init__(self) -> None: + self.opts = {} # type: T.Dict[str, str] + self.lang_args = {} # type: T.Dict[str, T.List[str]] + self.link_args = [] # type: T.List[str] + self.install = 'preserve' + + def set_opt(self, opt: str, val: str) -> None: + self.opts[opt] = val + + def append_args(self, lang: str, args: T.List[str]) -> None: + if lang not in self.lang_args: + self.lang_args[lang] = [] + self.lang_args[lang] += args + + def append_link_args(self, args: T.List[str]) -> None: + self.link_args += args + + def set_install(self, install: bool) -> None: + self.install = 'true' if install else 'false' + + def get_override_options(self, initial: T.List[str]) -> T.List[str]: + res = [] # type: T.List[str] + for i in initial: + opt = i[:i.find('=')] + if opt not in self.opts: + res += [i] + res += ['{}={}'.format(k, v) for k, v in self.opts.items()] + return res + + def get_compile_args(self, lang: str, initial: T.List[str]) -> T.List[str]: + if lang in self.lang_args: + return initial + self.lang_args[lang] + return initial + + def get_link_args(self, initial: T.List[str]) -> T.List[str]: + return initial + self.link_args + + def get_install(self, initial: bool) -> bool: + return {'preserve': initial, 'true': True, 'false': False}[self.install] + +class TargetOptions: + def __init__(self) -> None: + self.global_options = SingleTargetOptions() + self.target_options = {} # type: T.Dict[str, SingleTargetOptions] + + def __getitem__(self, tgt: str) -> SingleTargetOptions: + if tgt not in self.target_options: + self.target_options[tgt] = SingleTargetOptions() + return self.target_options[tgt] + + def get_override_options(self, tgt: str, initial: T.List[str]) -> T.List[str]: + initial = self.global_options.get_override_options(initial) + if tgt in self.target_options: + initial = self.target_options[tgt].get_override_options(initial) + return initial + + def get_compile_args(self, tgt: str, lang: str, initial: T.List[str]) -> T.List[str]: + initial = self.global_options.get_compile_args(lang, initial) + if tgt in self.target_options: + initial = self.target_options[tgt].get_compile_args(lang, initial) + return initial + + def get_link_args(self, tgt: str, initial: T.List[str]) -> T.List[str]: + initial = self.global_options.get_link_args(initial) + if tgt in self.target_options: + initial = self.target_options[tgt].get_link_args(initial) + return initial + + def get_install(self, tgt: str, initial: bool) -> bool: + initial = self.global_options.get_install(initial) + if tgt in self.target_options: + initial = self.target_options[tgt].get_install(initial) + return initial diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 2857527..0516947 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -17,7 +17,7 @@ import pkg_resources -from .common import CMakeException, CMakeTarget +from .common import CMakeException, CMakeTarget, TargetOptions from .client import CMakeClient, RequestCMakeInputs, RequestConfigure, RequestCompute, RequestCodeModel from .fileapi import CMakeFileAPI from .executor import CMakeExecutor @@ -993,7 +993,7 @@ class CMakeInterpreter: mlog.log('CMake project', mlog.bold(self.project_name), 'has', mlog.bold(str(len(self.targets) + len(self.custom_targets))), 'build targets.') - def pretend_to_be_meson(self) -> CodeBlockNode: + def pretend_to_be_meson(self, options: TargetOptions) -> CodeBlockNode: if not self.project_name: raise CMakeException('CMakeInterpreter was not analysed') @@ -1154,21 +1154,26 @@ class CMakeInterpreter: dep_var = '{}_dep'.format(tgt.name) tgt_var = tgt.name + install_tgt = options.get_install(tgt.cmake_name, tgt.install) + # Generate target kwargs tgt_kwargs = { - 'build_by_default': tgt.install, - 'link_args': tgt.link_flags + tgt.link_libraries, + 'build_by_default': install_tgt, + 'link_args': options.get_link_args(tgt.cmake_name, tgt.link_flags + tgt.link_libraries), 'link_with': link_with, 'include_directories': id_node(inc_var), - 'install': tgt.install, - 'install_dir': tgt.install_dir, - 'override_options': tgt.override_options, + 'install': install_tgt, + 'override_options': options.get_override_options(tgt.cmake_name, tgt.override_options), 'objects': [method(x, 'extract_all_objects') for x in objec_libs], } + # Only set if installed and only override if it is set + if install_tgt and tgt.install_dir: + tgt_kwargs['install_dir'] = tgt.install_dir + # Handle compiler args for key, val in tgt.compile_opts.items(): - tgt_kwargs['{}_args'.format(key)] = val + tgt_kwargs['{}_args'.format(key)] = options.get_compile_args(tgt.cmake_name, key, val) # Handle -fPCI, etc if tgt_func == 'executable': diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 76c8254..487bdd6 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2444,7 +2444,7 @@ class Interpreter(InterpreterBase): if isinstance(item, build.CustomTarget): return CustomTargetHolder(item, self) - elif isinstance(item, (int, str, bool, Disabler)) or item is None: + elif isinstance(item, (int, str, bool, Disabler, InterpreterObject)) or item is None: return item elif isinstance(item, build.Executable): return ExecutableHolder(item, self) @@ -2867,13 +2867,21 @@ external dependencies (including libraries) must go to "dependencies".''') with mlog.nested(): new_build = self.build.copy() prefix = self.coredata.builtins['prefix'].value + + from .modules.cmake import CMakeSubprojectOptions + options = kwargs.get('options', CMakeSubprojectOptions()) + if not isinstance(options, CMakeSubprojectOptions): + raise InterpreterException('"options" kwarg must be CMakeSubprojectOptions' + ' object (created by cmake.subproject_options())') + cmake_options = mesonlib.stringlistify(kwargs.get('cmake_options', [])) + cmake_options += options.cmake_options cm_int = CMakeInterpreter(new_build, subdir, subdir_abs, prefix, new_build.environment, self.backend) cm_int.initialise(cmake_options) cm_int.analyse() # Generate a meson ast and execute it with the normal do_subproject_meson - ast = cm_int.pretend_to_be_meson() + ast = cm_int.pretend_to_be_meson(options.target_options) mlog.log() with mlog.nested(): diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 6d91b99..ca98b1c 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -14,12 +14,28 @@ import re import os, os.path, pathlib import shutil +import typing as T from . import ExtensionModule, ModuleReturnValue from .. import build, dependencies, mesonlib, mlog -from ..interpreterbase import permittedKwargs, FeatureNew, stringArgs, InterpreterObject, ObjectHolder, noPosargs +from ..cmake import SingleTargetOptions, TargetOptions, cmake_defines_to_args from ..interpreter import ConfigurationDataHolder, InterpreterException, SubprojectHolder +from ..interpreterbase import ( + InterpreterObject, + ObjectHolder, + + FeatureNew, + FeatureNewKwargs, + FeatureDeprecatedKwargs, + + stringArgs, + permittedKwargs, + noPosargs, + noKwargs, + + InvalidArguments, +) COMPATIBILITIES = ['AnyNewerVersion', 'SameMajorVersion', 'SameMinorVersion', 'ExactVersion'] @@ -82,42 +98,107 @@ class CMakeSubprojectHolder(InterpreterObject, ObjectHolder): assert(all([x in res for x in ['inc', 'src', 'dep', 'tgt', 'func']])) return res - @permittedKwargs({}) + @noKwargs + @stringArgs def get_variable(self, args, kwargs): return self.held_object.get_variable_method(args, kwargs) - @permittedKwargs({}) + @noKwargs + @stringArgs def dependency(self, args, kwargs): info = self._args_to_info(args) return self.get_variable([info['dep']], kwargs) - @permittedKwargs({}) + @noKwargs + @stringArgs def include_directories(self, args, kwargs): info = self._args_to_info(args) return self.get_variable([info['inc']], kwargs) - @permittedKwargs({}) + @noKwargs + @stringArgs def target(self, args, kwargs): info = self._args_to_info(args) return self.get_variable([info['tgt']], kwargs) - @permittedKwargs({}) + @noKwargs + @stringArgs def target_type(self, args, kwargs): info = self._args_to_info(args) return info['func'] @noPosargs - @permittedKwargs({}) + @noKwargs def target_list(self, args, kwargs): return self.held_object.cm_interpreter.target_list() @noPosargs - @permittedKwargs({}) + @noKwargs @FeatureNew('CMakeSubproject.found()', '0.53.2') def found_method(self, args, kwargs): return self.held_object is not None +class CMakeSubprojectOptions(InterpreterObject): + def __init__(self) -> None: + super().__init__() + self.cmake_options = [] # type: T.List[str] + self.target_options = TargetOptions() + + self.methods.update( + { + 'add_cmake_defines': self.add_cmake_defines, + 'set_override_option': self.set_override_option, + 'set_install': self.set_install, + 'append_compile_args': self.append_compile_args, + 'append_link_args': self.append_link_args, + 'clear': self.clear, + } + ) + + def _get_opts(self, kwargs: dict) -> SingleTargetOptions: + if 'target' in kwargs: + return self.target_options[kwargs['target']] + return self.target_options.global_options + + @noKwargs + def add_cmake_defines(self, args, kwargs) -> None: + self.cmake_options += cmake_defines_to_args(args) + + @stringArgs + @permittedKwargs({'target'}) + def set_override_option(self, args, kwargs) -> None: + if len(args) != 2: + raise InvalidArguments('set_override_option takes exactly 2 positional arguments') + self._get_opts(kwargs).set_opt(args[0], args[1]) + + @permittedKwargs({'target'}) + def set_install(self, args, kwargs) -> None: + if len(args) != 1 or not isinstance(args[0], bool): + raise InvalidArguments('set_install takes exactly 1 boolean argument') + self._get_opts(kwargs).set_install(args[0]) + + @stringArgs + @permittedKwargs({'target'}) + def append_compile_args(self, args, kwargs) -> None: + if len(args) < 2: + raise InvalidArguments('append_compile_args takes at least 2 positional arguments') + self._get_opts(kwargs).append_args(args[0], args[1:]) + + @stringArgs + @permittedKwargs({'target'}) + def append_link_args(self, args, kwargs) -> None: + if not args: + raise InvalidArguments('append_link_args takes at least 1 positional argument') + self._get_opts(kwargs).append_link_args(args) + + @noPosargs + @noKwargs + def clear(self, args, kwargs) -> None: + self.cmake_options.clear() + self.target_options = TargetOptions() + + class CmakeModule(ExtensionModule): cmake_detected = False cmake_root = None @@ -286,16 +367,27 @@ class CmakeModule(ExtensionModule): return res @FeatureNew('subproject', '0.51.0') - @permittedKwargs({'cmake_options', 'required'}) + @FeatureNewKwargs('subproject', '0.55.0', ['options']) + @FeatureDeprecatedKwargs('subproject', '0.55.0', ['cmake_options']) + @permittedKwargs({'cmake_options', 'required', 'options'}) @stringArgs def subproject(self, interpreter, state, args, kwargs): if len(args) != 1: raise InterpreterException('Subproject takes exactly one argument') + if 'cmake_options' in kwargs and 'options' in kwargs: + raise InterpreterException('"options" cannot be used together with "cmake_options"') dirname = args[0] subp = interpreter.do_subproject(dirname, 'cmake', kwargs) if not subp.held_object: return subp return CMakeSubprojectHolder(subp, dirname) + @FeatureNew('subproject_options', '0.55.0') + @noKwargs + @noPosargs + def subproject_options(self, state, args, kwargs) -> ModuleReturnValue: + opts = CMakeSubprojectOptions() + return ModuleReturnValue(opts, []) + def initialize(*args, **kwargs): return CmakeModule(*args, **kwargs) diff --git a/test cases/cmake/19 advanced options/main.cpp b/test cases/cmake/19 advanced options/main.cpp new file mode 100644 index 0000000..6a071cc --- /dev/null +++ b/test cases/cmake/19 advanced options/main.cpp @@ -0,0 +1,18 @@ +#include <iostream> +#include <cmMod.hpp> +#include <cmTest.hpp> + +using namespace std; + +int main(void) { + cmModClass obj("Hello"); + cout << obj.getStr() << endl; + + int v1 = obj.getInt(); + int v2 = getTestInt(); + if (v1 != ((1 + v2) * 2)) { + cerr << "Number test failed" << endl; + return 1; + } + return 0; +} diff --git a/test cases/cmake/19 advanced options/meson.build b/test cases/cmake/19 advanced options/meson.build new file mode 100644 index 0000000..6332ca4 --- /dev/null +++ b/test cases/cmake/19 advanced options/meson.build @@ -0,0 +1,29 @@ +project('cmake_set_opt', ['c', 'cpp']) + +comp = meson.get_compiler('cpp') +if comp.get_argument_syntax() == 'msvc' + error('MESON_SKIP_TEST: MSVC is not supported because it does not support C++11') +endif + +cm = import('cmake') +opts = cm.subproject_options() + +opts.add_cmake_defines({'SOME_CMAKE_VAR': 'something', 'SOME_OTHER_VAR': true}) + +opts.set_override_option('cpp_std', 'c++11') # Global is C++11 +opts.set_override_option('cpp_std', 'c++14', target: 'cmModLib++') # Override it with C++14 for cmModLib++ + +opts.append_compile_args('cpp', '-DMESON_GLOBAL_FLAG=1') +opts.append_compile_args('cpp', ['-DMESON_SPECIAL_FLAG1=1', ['-DMESON_SPECIAL_FLAG2=1']], target: 'cmModLib++') +opts.append_compile_args('cpp', '-DMESON_MAGIC_INT=42', target: 'cmModLib++') +opts.append_compile_args('cpp', [[[['-DMESON_MAGIC_INT=20']]]], target: 'cmTestLib') + +opts.set_install(false) +opts.set_install(true, target: 'testEXE') + +sp = cm.subproject('cmOpts', options: opts) +dep1 = sp.dependency('cmModLib++') +dep2 = sp.dependency('cmTestLib') + +exe1 = executable('main', ['main.cpp'], dependencies: [dep1, dep2]) +test('test1', exe1) diff --git a/test cases/cmake/19 advanced options/subprojects/cmOpts/CMakeLists.txt b/test cases/cmake/19 advanced options/subprojects/cmOpts/CMakeLists.txt new file mode 100644 index 0000000..584841e --- /dev/null +++ b/test cases/cmake/19 advanced options/subprojects/cmOpts/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +project(CmOpts) + +set(CMAKE_CXX_STANDARD 98) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(NOT "${SOME_CMAKE_VAR}" STREQUAL "something") + message(FATAL_ERROR "Setting the CMake var failed") +endif() + +add_library(cmModLib++ STATIC cmMod.cpp) +add_library(cmTestLib STATIC cmTest.cpp) +add_executable(testEXE main.cpp) + +target_link_libraries(testEXE cmModLib++) + +install(TARGETS cmTestLib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) diff --git a/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.cpp b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.cpp new file mode 100644 index 0000000..7651b60 --- /dev/null +++ b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.cpp @@ -0,0 +1,31 @@ +#include "cmMod.hpp" + +using namespace std; + +#if __cplusplus < 201402L +#error "At least C++14 is required" +#endif + +#ifndef MESON_GLOBAL_FLAG +#error "MESON_GLOBAL_FLAG was not set" +#endif + +#ifndef MESON_SPECIAL_FLAG1 +#error "MESON_SPECIAL_FLAG1 was not set" +#endif + +#ifndef MESON_SPECIAL_FLAG2 +#error "MESON_SPECIAL_FLAG2 was not set" +#endif + +cmModClass::cmModClass(string foo) { + str = foo + " World"; +} + +string cmModClass::getStr() const { + return str; +} + +int cmModClass::getInt() const { + return MESON_MAGIC_INT; +} diff --git a/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.hpp b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.hpp new file mode 100644 index 0000000..0748936 --- /dev/null +++ b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmMod.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <string> + +class cmModClass { +private: + std::string str; + +public: + cmModClass(std::string foo); + + std::string getStr() const; + int getInt() const; +}; diff --git a/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.cpp b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.cpp new file mode 100644 index 0000000..a00cdcd --- /dev/null +++ b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.cpp @@ -0,0 +1,25 @@ +#include "cmTest.hpp" + +#if __cplusplus < 201103L +#error "At least C++11 is required" +#endif + +#if __cplusplus >= 201402L +#error "At most C++11 is required" +#endif + +#ifndef MESON_GLOBAL_FLAG +#error "MESON_GLOBAL_FLAG was not set" +#endif + +#ifdef MESON_SPECIAL_FLAG1 +#error "MESON_SPECIAL_FLAG1 *was* set" +#endif + +#ifdef MESON_SPECIAL_FLAG2 +#error "MESON_SPECIAL_FLAG2 *was* set" +#endif + +int getTestInt() { + return MESON_MAGIC_INT; +} diff --git a/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.hpp b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.hpp new file mode 100644 index 0000000..5a3bf7b --- /dev/null +++ b/test cases/cmake/19 advanced options/subprojects/cmOpts/cmTest.hpp @@ -0,0 +1,3 @@ +#pragma once + +int getTestInt(); diff --git a/test cases/cmake/19 advanced options/subprojects/cmOpts/main.cpp b/test cases/cmake/19 advanced options/subprojects/cmOpts/main.cpp new file mode 100644 index 0000000..497d1ce --- /dev/null +++ b/test cases/cmake/19 advanced options/subprojects/cmOpts/main.cpp @@ -0,0 +1,10 @@ +#include <iostream> +#include "cmMod.hpp" + +using namespace std; + +int main(void) { + cmModClass obj("Hello (LIB TEST)"); + cout << obj.getStr() << endl; + return 0; +} diff --git a/test cases/cmake/19 advanced options/test.json b/test cases/cmake/19 advanced options/test.json new file mode 100644 index 0000000..e2d9c05 --- /dev/null +++ b/test cases/cmake/19 advanced options/test.json @@ -0,0 +1,8 @@ +{ + "installed": [ + {"type": "exe", "file": "usr/bin/cm_testEXE"} + ], + "tools": { + "cmake": ">=3.11" + } +} |