commit 1de134d3f16ac4c945d2e53cc901c96ee8b83089 Author: ktlo Date: Thu Sep 5 08:22:25 2019 +0000 C++ Meson Library Project diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc new file mode 100644 index 0000000..d72d5d5 --- /dev/null +++ b/.devcontainer/.bashrc @@ -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' diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..817c2d9 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -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 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..3cd0b33 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -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" + ] +} \ No newline at end of file diff --git a/.devcontainer/meson/cross/arm-linux-gnueabihf b/.devcontainer/meson/cross/arm-linux-gnueabihf new file mode 100644 index 0000000..b6047e8 --- /dev/null +++ b/.devcontainer/meson/cross/arm-linux-gnueabihf @@ -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' diff --git a/.devcontainer/meson/cross/x86_64 b/.devcontainer/meson/cross/x86_64 new file mode 100644 index 0000000..d674292 --- /dev/null +++ b/.devcontainer/meson/cross/x86_64 @@ -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' diff --git a/.devcontainer/meson/cross/x86_64-alpine-linux-musl b/.devcontainer/meson/cross/x86_64-alpine-linux-musl new file mode 100644 index 0000000..927af4f --- /dev/null +++ b/.devcontainer/meson/cross/x86_64-alpine-linux-musl @@ -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' diff --git a/.devcontainer/meson/cross/x86_64-linux-gnu b/.devcontainer/meson/cross/x86_64-linux-gnu new file mode 100644 index 0000000..d674292 --- /dev/null +++ b/.devcontainer/meson/cross/x86_64-linux-gnu @@ -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' diff --git a/.devcontainer/meson/cross/x86_64-w64-mingw32 b/.devcontainer/meson/cross/x86_64-w64-mingw32 new file mode 100644 index 0000000..d7f8c2f --- /dev/null +++ b/.devcontainer/meson/cross/x86_64-w64-mingw32 @@ -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' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..01094c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/build +/cross diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..eefa079 --- /dev/null +++ b/.gitlab-ci.yml @@ -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 diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..e4e37b3 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -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 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7312a38 --- /dev/null +++ b/.vscode/settings.json @@ -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" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..1ff73d1 --- /dev/null +++ b/.vscode/tasks.json @@ -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 + } + } + ] +} \ No newline at end of file diff --git a/gcovr.cfg b/gcovr.cfg new file mode 100644 index 0000000..c11403e --- /dev/null +++ b/gcovr.cfg @@ -0,0 +1 @@ +exclude = '*/test/*' diff --git a/include/meson.build b/include/meson.build new file mode 100644 index 0000000..b29eb0e --- /dev/null +++ b/include/meson.build @@ -0,0 +1,5 @@ +includes = include_directories('.') + +install_headers([ + +]) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..16d813f --- /dev/null +++ b/meson.build @@ -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 ' + +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) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..36a01fb --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('link_type', type : 'combo', choices : ['static', 'shared'], value : 'static') diff --git a/src/config.cpp.in b/src/config.cpp.in new file mode 100644 index 0000000..7443dae --- /dev/null +++ b/src/config.cpp.in @@ -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@"; +} diff --git a/src/config.hpp b/src/config.hpp new file mode 100644 index 0000000..98c972d --- /dev/null +++ b/src/config.hpp @@ -0,0 +1,10 @@ +#include + +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; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..09f5cf1 --- /dev/null +++ b/src/meson.build @@ -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) diff --git a/src/sample_source.cpp b/src/sample_source.cpp new file mode 100644 index 0000000..5977a32 --- /dev/null +++ b/src/sample_source.cpp @@ -0,0 +1,5 @@ +#include "config.hpp" + +void sample_function() { + +} diff --git a/subprojects/.ignore b/subprojects/.ignore new file mode 100644 index 0000000..e69de29 diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000..f5cb4de --- /dev/null +++ b/test/meson.build @@ -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 diff --git a/test/sample_test.cpp b/test/sample_test.cpp new file mode 100644 index 0000000..906a0d4 --- /dev/null +++ b/test/sample_test.cpp @@ -0,0 +1,5 @@ +#include "test.hpp" + +test { + assert_equals(2, 1 + 1); +} diff --git a/test/test.hpp b/test/test.hpp new file mode 100644 index 0000000..1ec251d --- /dev/null +++ b/test/test.hpp @@ -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 +#include +#include +#include +#include + +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 + 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 + 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 + 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 + 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([&]() 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