tomlplusplus/meson.build
Andrea Pappacoda 36030cace8 build(meson): use system deps when avalable
When building tests, Meson will now look for system dependencies and use
them if found. Otherwise, it will check if the submodules are cloned and
create a dependency object wrapping the include path of each external
dependency (this breaks Meson's sandbox, but the previous approach did
too). This also allows passing actual dependencies to the various build
targets instead of include paths (a bit more idiomatic).

I've also made it possible to skip the tl-optional tests when the lib is
not found, so that it is still possible to run tests even from a
tarball (i.e. no git checkout)
2022-02-17 22:45:07 +02:00

480 lines
13 KiB
Meson

project(
'tomlplusplus',
'cpp',
version: '3.0.1',
meson_version: '>=0.54.0',
license: 'MIT',
subproject_dir: 'external',
default_options: [ # https://mesonbuild.com/Builtin-options.html
# core options
'buildtype=release',
'warning_level=3',
'werror=true',
# base options
'b_lto=true',
'b_ndebug=if-release',
# compiler options
'cpp_std=c++17'
]
)
#######################################################################################################################
# compiler management
#######################################################################################################################
compiler = meson.get_compiler('cpp')
message('target cpu_family: @0@'.format(host_machine.cpu_family()))
message('target cpu: @0@'.format(host_machine.cpu()))
message('target system: @0@'.format(host_machine.system()))
message('target endian: @0@'.format(host_machine.endian()))
is_gcc = compiler.get_id() == 'gcc'
is_clang = compiler.get_id() == 'clang'
is_msvc = compiler.get_id() == 'msvc'
is_icc_cl = compiler.get_id() == 'intel-cl'
is_icc = is_icc_cl or compiler.get_id() == 'intel'
is_lld = compiler.get_linker_id() == 'ld.lld'
is_debug = get_option('debug')
is_release = not is_debug
is_pedantic = get_option('pedantic')
is_windows = host_machine.system() == 'windows'
is_x64 = host_machine.cpu_family() == 'x86_64'
is_subproject = meson.is_subproject()
has_exceptions = get_option('cpp_eh') != 'none'
include_dir = include_directories('include')
overrides = []
universal_args = [] # args used in tests, examples, lib, everything
devel_args = [] # args used in everything *but* the lib
message('is_release: @0@'.format(is_release))
message('is_windows: @0@'.format(is_windows))
message('is_x64: @0@'.format(is_x64))
message('has_exceptions: @0@'.format(has_exceptions))
# compiler argument references:
# msvc: https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically?view=vs-2019
# intel and intel-cl: https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-oneapi-dev-guide-and-reference/top/compiler-reference/compiler-options/alphabetical-list-of-compiler-options.html
# gcc:
# clang:
# GCC or Clang
if is_gcc or is_clang
devel_args += '-march=native'
endif
# GCC
if is_gcc
universal_args += [
'-fmax-errors=5',
'-Wno-init-list-lifetime',
]
if is_pedantic
universal_args += [
'-Wcast-align',
'-Wcast-qual',
'-Wctor-dtor-privacy',
'-Wdisabled-optimization',
'-Wfloat-equal',
'-Wimport',
'-Winit-self',
'-Wlogical-op',
'-Wmissing-declarations',
'-Wmissing-field-initializers',
'-Wmissing-format-attribute',
'-Wmissing-include-dirs',
'-Wmissing-noreturn',
'-Wnoexcept',
'-Wold-style-cast',
'-Woverloaded-virtual',
'-Wpacked',
'-Wpadded',
'-Wpointer-arith',
'-Wredundant-decls',
'-Wshadow',
'-Wsign-conversion',
'-Wsign-promo',
'-Wstack-protector',
'-Wstrict-null-sentinel',
'-Wswitch-default',
'-Wswitch-enum',
'-Wundef',
'-Wunreachable-code',
'-Wunused',
'-Wunused-parameter',
'-Wuseless-cast',
'-Wvariadic-macros',
'-Wwrite-strings',
'-Wmissing-noreturn',
]
endif
if is_release and is_pedantic
universal_args += [
'-Wsuggest-attribute=const',
'-Wsuggest-attribute=pure',
]
endif
endif
# Clang
if is_clang
if is_pedantic
universal_args += '-Weverything'
endif
universal_args += [
'-ferror-limit=5',
'-Wno-unused-command-line-argument',
# flags from here down are disabling stupidly pedantic warnings that only appear with -Weverything
'-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic',
'-Wno-documentation',
'-Wno-documentation-unknown-command',
'-Wno-switch-enum',
'-Wno-covered-switch-default',
]
if get_option('time_trace')
universal_args += ['-ftime-trace']
endif
endif
# MSVC or icc-cl
if is_msvc or is_icc_cl
universal_args += [
'/bigobj',
'/fp:except-', # disable floating-point exceptions
'/Gy', # function-level linking
'/GF', # string pooling
'/openmp-',
'/permissive-',
'/utf-8',
'/Zc:inline'
]
if has_exceptions
universal_args += '/Zc:throwingNew'
endif
if is_release
universal_args += [
'/GL', # whole program optimization
'/Gw', # Optimize Global Data
'/Ob3', # aggressive inlining
'/Oy', # omit frame pointers
'/Oi', # generate intrinsics
]
add_project_link_arguments('/ltcg', language: 'cpp')
endif
if is_pedantic
universal_args += '/W4'
endif
endif
# icc-cl
if is_icc_cl
universal_args += [
'/wd82', # storage class is not first
'/wd177', # unreferenced var
'/wd280', # selector expression is constant (why the fuck is that a warning?)
'/wd411', # class provides no constructor (duh, it's an aggregate)
'/wd869', # parameter "blah" was never referenced
'/wd1011', # missing return statement (false negative)
'/wd1628', # function marked [[noreturn]] returns (false positive)
'/wd2261', # assume with side effects discarded
'/wd2557', # mismatched sign compare
'/wd3280', # declaration hides member (triggered in Catch2)
]
endif
# icc (any)
if is_icc
universal_args += [
'/Qdiag-error-limit:5',
'/Qoption,cpp,--unicode_source_kind,UTF-8',
'/D__builtin_bit_cast(T, v)=([&]()noexcept{ T val; memcpy(&val, &v, sizeof(T)); return val; })()', # __builtin_bit_cast workaround
]
endif
# windows stuff
if is_windows
universal_args += has_exceptions ? '-D_HAS_EXCEPTIONS=1' : '-D_HAS_EXCEPTIONS=0'
elif is_release
overrides += 'strip=true'
endif
# LTO
if is_lld or is_debug or (is_windows and is_clang)
overrides += 'b_lto=false'
endif
#######################################################################################################################
# c++ 20 check
#######################################################################################################################
compiler_supports_cpp20_args = []
if is_gcc or is_clang
compiler_supports_cpp20_args += '-std=c++2a'
elif is_icc
compiler_supports_cpp20_args += '/Qstd=c++2a'
elif is_msvc
compiler_supports_cpp20_args += '/std:c++latest'
endif
compiler_supports_cpp20 = compiler_supports_cpp20_args.length() > 0 and compiler.links('''
#include <version>
#include <string>
#include <iostream>
#include <cstdint>
#include <cstddef>
#include <cstring>
#include <cfloat>
#include <climits>
#include <cmath>
#include <limits>
#include <memory>
#include <iosfwd>
#include <type_traits>
int main()
{
std::string s = "kek";
std::cout << s << std::endl;
return 0;
}
''',
name: 'supports c++20',
args: compiler_supports_cpp20_args
)
#######################################################################################################################
# char8_t check
#######################################################################################################################
compiler_supports_char8_args = []
if is_gcc or is_clang
compiler_supports_char8_args += '-fchar8_t'
endif
compiler_supports_char8_args_private = []
compiler_supports_char8_args_private += compiler_supports_cpp20_args
compiler_supports_char8_args_private += compiler_supports_char8_args
compiler_supports_char8 = compiler_supports_cpp20 and compiler.links('''
#include <version>
#include <string_view>
#include <string>
#include <type_traits>
using namespace std::string_view_literals;
#if !defined(__cpp_char8_t) || __cpp_char8_t < 201811 || !defined(__cpp_lib_char8_t) || __cpp_lib_char8_t < 201907
#error oh noes
#endif
static_assert(!std::is_same_v<char, char8_t>);
static_assert(!std::is_same_v<std::string, std::u8string>);
std::u8string func()
{
return std::u8string{ u8"this is a test."sv };
}
int main()
{
return 0;
}
''',
name: 'supports char8_t',
args: compiler_supports_char8_args_private
)
#######################################################################################################################
# consteval check
# (this doesn't inform the build in any way; it's just so i can see who supports it properly)
#######################################################################################################################
compiler_supports_consteval = compiler_supports_cpp20 and compiler.compiles('''
consteval int test() noexcept
{
return 42;
}
int main()
{
constexpr auto val = test(); // test() should be compiletime-callable
return val;
}
''',
name: 'supports consteval keyword',
args: compiler_supports_cpp20_args
)
compiler_supports_consteval_properly = compiler_supports_consteval and not compiler.compiles('''
consteval int test(int i) noexcept
{
return 42 + i;
}
int get_value() noexcept;
int main()
{
return test(get_value()); // test() should not be runtime-callable
}
''',
name: 'consteval is just renamed constexpr',
args: compiler_supports_cpp20_args
)
#######################################################################################################################
# __fp16 and _Float16 checks
#######################################################################################################################
float_16_preprocessor_single_check_template = '''
#ifndef @0@
#error @0@ wasn't defined!
#else
#pragma message("@0@: " MAKE_STRING(@0@))
#endif
#if @0@ != @1@
#error @0@ was not @1@!
#endif
'''
float_16_preprocessor_checks = '''
#define MAKE_STRING(s) MAKE_STRING_1(s)
#define MAKE_STRING_1(s) #s
''' + float_16_preprocessor_single_check_template.format('__FLT_RADIX__', '2') \
+ float_16_preprocessor_single_check_template.format('__FLT16_MANT_DIG__', '11') \
+ float_16_preprocessor_single_check_template.format('__FLT16_DIG__', '3') \
+ float_16_preprocessor_single_check_template.format('__FLT16_MIN_EXP__', '-13') \
+ float_16_preprocessor_single_check_template.format('__FLT16_MIN_10_EXP__', '-4') \
+ float_16_preprocessor_single_check_template.format('__FLT16_MAX_EXP__', '16') \
+ float_16_preprocessor_single_check_template.format('__FLT16_MAX_10_EXP__', '4')
compiler_supports_float16_args = []
if is_gcc
compiler_supports_float16_args += '-mfp16-format=ieee'
endif
compiler_supports_fp16 = compiler.links('''
int main()
{
static_assert(sizeof(__fp16) == 2);
__fp16 f = static_cast<__fp16>(1);
const auto f2 = static_cast<float>(f);
const auto f3 = static_cast<__fp16>(0.2L);
return 0;
}
''',
name: 'supports __fp16',
args: compiler_supports_float16_args
)
compiler_supports_float16 = compiler.links('''
@0@
int main()
{
static_assert(sizeof(_Float16) == 2);
_Float16 f = static_cast<_Float16>(1);
const auto f2 = static_cast<float>(f);
const auto f3 = static_cast<_Float16>(0.2L);
return 0;
}
'''.format(float_16_preprocessor_checks),
name: 'supports _Float16',
args: compiler_supports_float16_args
)
if compiler_supports_fp16 or compiler_supports_float16
devel_args += compiler_supports_float16_args
endif
#######################################################################################################################
# int128 check
#######################################################################################################################
compiler_supports_int128 = compiler.links('''
#ifndef __SIZEOF_INT128__
#error __SIZEOF_INT128__ wasn't defined!
#endif
#include <cstdint>
int main()
{
static_assert(__SIZEOF_INT128__ == 16);
static_assert(sizeof(__int128_t) == 16);
static_assert(sizeof(__uint128_t) == 16);
__int128_t i = static_cast<__int128_t>(1);
const auto i2 = static_cast<int64_t>(i);
const auto i3 = static_cast<int32_t>(i);
return 0;
}
''',
name: 'supports __int128_t'
)
#######################################################################################################################
# float128 check
#######################################################################################################################
compiler_supports_float128 = compiler.links('''
#ifndef __SIZEOF_FLOAT128__
#error __SIZEOF_FLOAT128__ wasn't defined!
#endif
#ifndef __FLT128_MANT_DIG__
#error __FLT128_MANT_DIG__ wasn't defined!
#endif
#ifndef __LDBL_MANT_DIG__
#error __LDBL_MANT_DIG__ wasn't defined!
#endif
#if __FLT128_MANT_DIG__ <= __LDBL_MANT_DIG__
#error __FLT128_MANT_DIG__ was <= __LDBL_MANT_DIG__
#endif
int main()
{
static_assert(__SIZEOF_FLOAT128__ == 16);
static_assert(sizeof(__float128) == 16);
__float128 f = static_cast<__float128>(1);
const auto f2 = static_cast<long double>(f);
const auto f3 = static_cast<double>(f);
return 0;
}
''',
name: 'supports __float128'
)
if compiler_supports_float128 and is_gcc and not is_subproject
add_global_arguments('-fext-numeric-literals', language: 'cpp')
endif
#######################################################################################################################
# subdirectories
#######################################################################################################################
# Empty dependency that will be filled either in src/ or include/
tomlplusplus_dep = dependency('', required: false)
if get_option('compile_library')
subdir('src')
else
subdir('include')
endif
build_tests = get_option('build_tests') and not is_subproject
if build_tests
subdir('tests')
endif
build_examples = get_option('build_examples') and not is_subproject
if build_examples
subdir('examples')
endif
build_tt = (get_option('build_tt_encoder') or get_option('build_tt_encoder')) and not is_subproject
if build_tt
subdir('toml-test')
endif
if not is_subproject
install_subdir('include'/'toml++', install_dir: get_option('includedir'))
endif
# Allow subproject usage
meson.override_dependency(meson.project_name(), tomlplusplus_dep)