C++ Meson Library Project

This commit is contained in:
ktlo
2019-09-05 08:22:25 +00:00
commit 1de134d3f1
25 changed files with 608 additions and 0 deletions

7
.devcontainer/.bashrc Normal file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;91m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
umask 022
export LS_OPTIONS='--color=auto'
eval "`dircolors`"
alias ls='ls $LS_OPTIONS'

9
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,9 @@
FROM debian:buster
RUN apt update && apt install -y build-essential crossbuild-essential-amd64 crossbuild-essential-armhf mingw-w64 \
python3 python3-pip python3-setuptools python3-wheel ninja-build \
wget cmake xxd valgrind gcovr lcov git cppcheck gdb \
&& pip3 install meson
COPY meson /usr/local/share/meson
COPY .bashrc /root/.bashrc

View File

@@ -0,0 +1,18 @@
{
"name": "C++",
"dockerFile": "Dockerfile",
"runArgs": [
"--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"
],
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"extensions": [
"ms-vscode.cpptools",
"yzhang.markdown-all-in-one",
"asabil.meson"
]
}

View File

@@ -0,0 +1,11 @@
[binaries]
c = 'arm-linux-gnueabihf-gcc'
cpp = 'arm-linux-gnueabihf-g++'
ar = 'arm-linux-gnueabihf-ar'
strip = 'arm-linux-gnueabihf-strip'
[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'

View File

@@ -0,0 +1,12 @@
[binaries]
c = 'x86_64-linux-gnu-gcc'
cpp = 'x86_64-linux-gnu-g++'
ar = 'x86_64-linux-gnu-ar'
strip = 'x86_64-linux-gnu-strip'
pkgconfig = 'x86_64-linux-gnu-pkg-config'
[host_machine]
system = 'linux'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View File

@@ -0,0 +1,11 @@
[binaries]
c = '/usr/bin/x86_64-alpine-linux-musl-gcc'
cpp = '/usr/bin/x86_64-alpine-linux-musl-g++'
ar = '/usr/bin/x86_64-alpine-linux-musl-gcc-ar'
strip = '/usr/bin/x86_64-alpine-linux-musl-strip'
[host_machine]
system = 'linux'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View File

@@ -0,0 +1,12 @@
[binaries]
c = 'x86_64-linux-gnu-gcc'
cpp = 'x86_64-linux-gnu-g++'
ar = 'x86_64-linux-gnu-ar'
strip = 'x86_64-linux-gnu-strip'
pkgconfig = 'x86_64-linux-gnu-pkg-config'
[host_machine]
system = 'linux'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View File

@@ -0,0 +1,13 @@
[binaries]
c = 'x86_64-w64-mingw32-gcc'
cpp = 'x86_64-w64-mingw32-g++'
ar = 'x86_64-w64-mingw32-ar'
strip = 'x86_64-w64-mingw32-strip'
pkgconfig = 'x86_64-w64-mingw32-pkg-config'
windres = 'x86_64-w64-mingw32-windres'
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/build
/cross

180
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,180 @@
image: reg.handtruth.com/roots/cpp-meson/build:debian
stages:
- setup
- build
- test
- analysis
- package
variables:
GIT_SUBMODULE_STRATEGY: normal
Restore:x86_64-linux-gnu: &restore
stage: setup
variables:
TARGET: x86_64-linux-gnu
script:
- meson -Db_coverage=true build/$TARGET --cross-file=$TARGET
tags: ["default"]
artifacts:
paths:
- build
expire_in: 2 hrs
Restore:arm-linux-gnueabihf:
<<: *restore
variables:
TARGET: arm-linux-gnueabihf
Restore:x86_64-w64-mingw32:
<<: *restore
variables:
TARGET: x86_64-w64-mingw32
Restore:x86_64-alpine-linux-musl:
<<: *restore
image: reg.handtruth.com/roots/cpp-meson/build:alpine
variables:
TARGET: x86_64-alpine-linux-musl
Build:x86_64-linux-gnu: &build
stage: build
variables:
TARGET: x86_64-linux-gnu
script:
- cd build/$TARGET
- ninja
tags: ["default"]
artifacts:
paths:
- build
expire_in: 2 hrs
dependencies:
- Restore:x86_64-linux-gnu
Build:arm-linux-gnueabihf:
<<: *build
variables:
TARGET: arm-linux-gnueabihf
dependencies:
- Restore:arm-linux-gnueabihf
Build:x86_64-alpine-linux-musl:
<<: *build
image: reg.handtruth.com/roots/cpp-meson/build:alpine
variables:
TARGET: x86_64-alpine-linux-musl
dependencies:
- Restore:x86_64-alpine-linux-musl
Build:x86_64-w64-mingw32:
<<: *build
variables:
TARGET: x86_64-w64-mingw32
dependencies:
- Restore:x86_64-w64-mingw32
Test:x86_64-linux-gnu: &test
stage: test
variables:
TARGET: x86_64-linux-gnu
MESON_TESTTHREADS: 1
script:
- cd build/$TARGET
- meson test --wrap='valgrind --error-exitcode=1 --leak-check=full --tool=memcheck --track-origins=yes'
- cat meson-logs/testlog-valgrind.txt
tags: ["default"]
artifacts:
paths:
- build
expire_in: 2 hrs
dependencies:
- Restore:x86_64-linux-gnu
- Build:x86_64-linux-gnu
Test:arm-linux-gnueabihf:
<<: *test
image: reg.handtruth.com/roots/cpp-meson/build:debian-armhf
variables:
TARGET: arm-linux-gnueabihf
tags: ["armhf"]
dependencies:
- Restore:arm-linux-gnueabihf
- Build:arm-linux-gnueabihf
Test:x86_64-alpine-linux-musl:
<<: *test
image: reg.handtruth.com/roots/cpp-meson/build:alpine
variables:
TARGET: x86_64-alpine-linux-musl
dependencies:
- Restore:x86_64-alpine-linux-musl
- Build:x86_64-alpine-linux-musl
Coverage: &coverage
stage: analysis
variables:
TARGET: x86_64-linux-gnu
script:
- cd build/$TARGET
- ninja coverage-text
- cat meson-logs/coverage.txt
coverage: '/^TOTAL\s+\S+\s+\S+\s+(\d+\.?\d+)%/'
tags: ["default"]
artifacts:
paths:
- build
expire_in: 2 hrs
dependencies:
- Restore:x86_64-linux-gnu
- Build:x86_64-linux-gnu
- Test:x86_64-linux-gnu
Check:
stage: analysis
variables:
TARGET: x86_64-linux-gnu
script:
- cd build/$TARGET
- ninja cppcheck
coverage: '/^TOTAL\s+\S+\s+\S+\s+(\d+\.?\d+)%/'
tags: ["default"]
artifacts:
paths:
- build/x86_64-linux-gnu/cppcheck.log
expire_in: 1 week
dependencies:
- Restore:x86_64-linux-gnu
Package:x86_64-linux-gnu: &package
stage: package
variables:
TARGET: x86_64-linux-gnu
script:
- meson -Dprefix=`pwd`/dist/$TARGET -Dbuildtype=release -Doptimization=3 --cross-file=$TARGET package/$TARGET
- cd package/$TARGET
- ninja
- ninja install
tags: ["default"]
artifacts:
paths:
- dist
expire_in: 1 mos
dependencies: []
Package:arm-linux-gnueabihf:
<<: *package
variables:
TARGET: arm-linux-gnueabihf
Package:x86_64-w64-mingw32:
<<: *package
variables:
TARGET: x86_64-w64-mingw32
Package:x86_64-alpine-linux-musl:
<<: *package
image: reg.handtruth.com/roots/cpp-meson/build:alpine
variables:
TARGET: x86_64-alpine-linux-musl

17
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,17 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "gcc-x64",
"compileCommands": "${workspaceFolder}/build/compile_commands.json"
}
],
"version": 4
}

48
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,48 @@
{
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"typeinfo": "cpp",
"config.cpp.in": "cpp"
}
}

29
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
// Документацию по формату tasks.json см.
// по адресу https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"type": "meson",
"mode": "build",
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "meson",
"mode": "test",
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "test",
"isDefault": true
}
}
]
}

1
gcovr.cfg Normal file
View File

@@ -0,0 +1 @@
exclude = '*/test/*'

5
include/meson.build Normal file
View File

@@ -0,0 +1,5 @@
includes = include_directories('.')
install_headers([
])

45
meson.build Normal file
View File

@@ -0,0 +1,45 @@
project('cpp-meson', 'cpp',
version : run_command('git', 'describe', '--abbrev=0', '--tags').stdout().strip(),
default_options : ['warning_level=3',
'cpp_std=c++17'])
group = 'com.handtruth'
maintainer = 'someone <someone@handtruth.com>'
modules = [
]
######################################
module_deps = []
foreach module : modules
module_deps += dependency(module, fallback : [module, 'dep'])
endforeach
subdir('include')
subdir('src')
subdir('test')
if get_option('link_type') == 'static'
chosen_lib = static_lib
else
chosen_lib = shared_lib
endif
dep = declare_dependency(link_with : chosen_lib, include_directories : includes)
cppcheck = custom_target('cppcheck_internal',
output : 'cppcheck.log',
input : sources + test_files,
command : [
'cppcheck',
'--enable=all',
'-I', meson.current_source_dir() / 'include',
'-I', meson.current_source_dir() / 'src',
'@INPUT@',
# '--project=compile_commands.json',
'--output-file=cppcheck.log'
])
run_target('cppcheck', command : ['cat', meson.current_build_dir() / 'cppcheck.log'], depends : cppcheck)

1
meson_options.txt Normal file
View File

@@ -0,0 +1 @@
option('link_type', type : 'combo', choices : ['static', 'shared'], value : 'static')

10
src/config.cpp.in Normal file
View File

@@ -0,0 +1,10 @@
#include "config.hpp"
namespace config {
const std::string group = "@group@";
const std::string version = "@version@";
const std::string project = "@project@";
const std::string build = "@build@";
const std::string maintainer = "@maintainer@";
}

10
src/config.hpp Normal file
View File

@@ -0,0 +1,10 @@
#include <string>
namespace config {
extern const std::string group;
extern const std::string version;
extern const std::string project;
extern const std::string build;
extern const std::string maintainer;
}

17
src/meson.build Normal file
View File

@@ -0,0 +1,17 @@
sources = files([
'sample_source.cpp'
])
src = include_directories('.')
sources += configure_file(output : 'config.cpp', input : 'config.cpp.in',
configuration : {
'group' : group,
'project' : meson.project_name(),
'version' : meson.project_version(),
'build' : run_command('git', 'describe').stdout().strip(),
'maintainer' : maintainer,
})
static_lib = static_library(meson.project_name(), sources, include_directories : includes, install: true, dependencies: module_deps)
shared_lib = shared_library(meson.project_name(), sources, include_directories : includes, install: true, dependencies: module_deps)

5
src/sample_source.cpp Normal file
View File

@@ -0,0 +1,5 @@
#include "config.hpp"
void sample_function() {
}

0
subprojects/.ignore Normal file
View File

11
test/meson.build Normal file
View File

@@ -0,0 +1,11 @@
test_names = [
'sample_test'
]
test_files = []
foreach test_name : test_names
test_files += files(test_name + '.cpp')
test_exe = executable(test_name + '.test', test_files[-1], link_with : static_lib, include_directories : [includes, src], dependencies : module_deps)
test(test_name, test_exe)
endforeach

5
test/sample_test.cpp Normal file
View File

@@ -0,0 +1,5 @@
#include "test.hpp"
test {
assert_equals(2, 1 + 1);
}

129
test/test.hpp Normal file
View File

@@ -0,0 +1,129 @@
#ifdef __TEST_HEAD
# error "test.hpp header can't be included several times"
#else
# define __TEST_HEAD
#endif
// LCOV_EXCL_START
#include <string>
#include <stdexcept>
#include <iostream>
#include <functional>
#include <vector>
namespace std {
inline string to_string(const std::string & str) {
return str;
}
}
namespace tests {
class assertion_error : std::runtime_error {
public:
explicit assertion_error(const std::string & message) : ::std::runtime_error(message) {}
};
struct {
int success = 0;
template <typename first, typename second>
void assert_eq(const first & expect, const second & actual, const char * file, std::size_t line) {
if (actual != expect) {
std::string message = std::string(file) + ":" + std::to_string(line) + ": assertion failed (\"" + std::to_string(expect) +
"\" expected, got \"" + std::to_string(actual) + "\")";
std::cout << "test failed: " << message << std::endl;
throw assertion_error(message);
} else
success++;
}
template <typename first, typename second>
void assert_ne(const first & expect, const second & actual, const char * file, std::size_t line) {
if (actual == expect) {
std::string message = std::string(file) + ":" + std::to_string(line) + ": assertion failed (\"" + std::to_string(expect) +
"\" equals to \"" + std::to_string(actual) + "\")";
std::cout << "test failed: " << message << std::endl;
throw assertion_error(message);
} else
success++;
}
template <typename E, typename F>
void assert_ex_with(F fun, const char * file, std::size_t line) {
try {
fun();
} catch (const E & e) {
success++;
return;
} catch (...) {
std::cout << "test failed: " << std::string(file) << ':' << std::to_string(line)
<< ": cought unexpected exception type." << std::endl;
throw;
}
std::string message = std::string(file) + ":" + std::to_string(line) + ": no exception cought.";
std::cout << "test failed: " << message << std::endl;
throw assertion_error(message);
}
template <typename F>
void assert_ex(F fun, const char * file, std::size_t line) {
try {
fun();
} catch (...) {
success++;
return;
}
std::string message = std::string(file) + ":" + std::to_string(line) + ": no exception cought.";
std::cout << "test failed: " << message << std::endl;
throw assertion_error(message);
}
void assert_tr(bool value, const char * file, std::size_t line, const char * expression) {
if (value) {
success++;
} else {
std::string message = std::string(file) + ":" + std::to_string(line) + ": value (" + expression + ") was false.";
std::cout << "test failed: " << message << std::endl;
throw assertion_error(message);
}
}
void assert_fa(bool value, const char * file, std::size_t line, const char * expression) {
if (!value) {
success++;
} else {
std::string message = std::string(file) + ":" + std::to_string(line) + ": value (" + expression + ") was true.";
std::cout << "test failed: " << message << std::endl;
throw assertion_error(message);
}
}
} assert;
#define test \
void test_function()
#define assert_equals(expect, actual) \
::tests::assert.assert_eq(expect, actual, __FILE__, __LINE__)
#define assert_not_equals(expect, actual) \
::tests::assert.assert_ne(expect, actual, __FILE__, __LINE__)
#define assert_fails_with(E, fun) \
::tests::assert.assert_ex_with<E>([&]() fun, __FILE__, __LINE__)
#define assert_fails(fun) \
::tests::assert.assert_ex([&]() fun, __FILE__, __LINE__)
#define assert_true(value) \
::tests::assert.assert_tr(value, __FILE__, __LINE__, #value)
#define assert_false(value) \
::tests::assert.assert_fa(value, __FILE__, __LINE__, #value)
}
void test_function();
int main() {
std::cout << "entering test..." << std::endl;
test_function();
std::cout << "success: " << tests::assert.success << " assertions passed";
}
// LCOV_EXCL_STOP