From 38d4f0285e6157ee840ea82a9b90aba71c8a705d Mon Sep 17 00:00:00 2001 From: Zephyr Lykos Date: Thu, 19 Sep 2024 13:02:08 +0000 Subject: [PATCH] Add meson build system support (#75) --- .github/workflows/main.yml | 131 ++++++++++++++++++---- Doxyfile.in | 31 ++++++ examples/meson.build | 11 ++ meson.build | 220 +++++++++++++++++++++++++++++++++++++ meson_options.txt | 25 +++++ resources/VersionInfo.rc | 2 +- subprojects/gtest.wrap | 16 +++ tests/meson.build | 38 +++++++ 8 files changed, 454 insertions(+), 20 deletions(-) create mode 100644 Doxyfile.in create mode 100644 examples/meson.build create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 subprojects/gtest.wrap create mode 100644 tests/meson.build diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 953e4d6..9517960 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,29 +8,29 @@ on: types: [opened, synchronize, reopened] jobs: - build-linux: - name: Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) + build-linux-cmake: + name: CMake Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: - platform: + platform: - { name: x86, flags: "-m32" } - { name: x64, flags: "-m64" } compiler: - - { name: GNU, CC: gcc } - - { name: LLVM, CC: clang } - flavor: + - { name: GNU, CC: gcc, CXX: g++ } + - { name: LLVM, CC: clang, CXX: clang++ } + flavor: - Debug - Release - mode: - - { name: default, args: "" } + mode: + - { name: default, args: "" } - { name: NO_LIBC, args: -DZYAN_NO_LIBC=ON } steps: - name: Checkout - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v4 - if: matrix.platform.name == 'x86' name: Bootstrap @@ -47,40 +47,133 @@ jobs: mkdir build cd build cmake -DCMAKE_C_FLAGS=${{ matrix.platform.flags }} -DCMAKE_CXX_FLAGS=${{ matrix.platform.flags }} -DZYAN_DEV_MODE=ON ${{ matrix.mode.args }} .. - + - name: Build run: | cmake --build build --config ${{ matrix.flavor }} - build-windows: - name: Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) + build-linux-meson: + name: Meson Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + platform: + - { name: x86, flags: "-m32" } + - { name: x64, flags: "-m64" } + compiler: + - { name: GNU, CC: gcc, CXX: g++ } + - { name: LLVM, CC: clang, CXX: clang++ } + flavor: + - debug + - release + mode: + - { name: default, args: -Dtests=enabled } + - { name: NO_LIBC, args: -Dnolibc=true } + + steps: + - name: Setup meson + run: | + pipx install meson + sudo apt-get install -y ninja-build + + - name: Checkout + uses: actions/checkout@v4 + + - if: matrix.platform.name == 'x86' + name: Bootstrap + run: | + sudo dpkg --add-architecture i386 + sudo rm /etc/apt/sources.list.d/* && sudo apt-get update + sudo apt-get install -y g++-multilib g++ + + - name: Configure + env: + CC: ${{ matrix.compiler.CC }} + CXX: ${{ matrix.compiler.CXX }} + run: | + meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} -Dc_extra_args="${{ matrix.platform.flags }}" -Dcpp_extra_args="${{ matrix.platform.flags }}" + + - name: Build + run: | + meson compile -C build-${{ matrix.flavor }} + + - name: Run tests + run: | + meson test -C build-${{ matrix.flavor }} + + build-windows-cmake: + name: CMake Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) runs-on: windows-latest strategy: fail-fast: false matrix: - platform: + platform: - { name: x86, flags: "Win32" } - - { name: x64, flags: "x64" } + - { name: x64, flags: "x64" } compiler: - { name: MSVC } - flavor: + flavor: - Debug - Release - mode: - - { name: default, args: "" } + mode: + - { name: default, args: "" } - { name: NO_LIBC, args: -DZYAN_NO_LIBC=ON } steps: - name: Checkout - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v4 - name: Configure run: | mkdir build cd build cmake -DCMAKE_GENERATOR_PLATFORM=${{ matrix.platform.flags }} -DZYAN_DEV_MODE=ON ${{ matrix.mode.args }} .. - + - name: Build run: | cmake --build build --config ${{ matrix.flavor }} + + build-windows-meson: + name: Meson Build ${{ matrix.platform.name }} ${{ matrix.compiler.name }} ${{ matrix.flavor }} (${{ matrix.mode.name }}) + runs-on: windows-latest + + strategy: + fail-fast: false + matrix: + platform: + - { name: x86, flags: "amd64_x86" } + - { name: x64, flags: "amd64" } + compiler: + - { name: MSVC } + flavor: + - debug + - release + mode: + - { name: default, args: -Dtests=enabled } + - { name: NO_LIBC, args: -Dnolibc=true } + + steps: + - name: Setup meson + run: | + pipx install meson + choco install ninja + + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure + run: | + $VCPATH = vswhere -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath -latest + & $VCPATH\VC\Auxiliary\Build\vcvarsall.bat ${{ matrix.platform.flags }} + meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} + + - name: Build + run: | + meson compile -C build-${{ matrix.flavor }} + + - name: Run tests + run: | + meson test -C build-${{ matrix.flavor }} diff --git a/Doxyfile.in b/Doxyfile.in new file mode 100644 index 0000000..8e8d2c9 --- /dev/null +++ b/Doxyfile.in @@ -0,0 +1,31 @@ +PROJECT_NAME = Zycore +PROJECT_NUMBER = @VERSION@ +PROJECT_BRIEF = "Zyan Core Library for C" +OUTPUT_DIRECTORY = "@TOP_BUILDDIR@/doc" +STRIP_FROM_PATH = "@TOP_SRCDIR@" +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = YES +OPTIMIZE_OUTPUT_FOR_C = YES +TOC_INCLUDE_HEADINGS = 0 +EXTRACT_ALL = YES +EXTRACT_LOCAL_CLASSES = NO +HIDE_SCOPE_NAMES = YES +INPUT = "@TOP_SRCDIR@/include" \ + "@TOP_SRCDIR@/README.md" +RECURSIVE = YES +EXAMPLE_PATH = "@TOP_SRCDIR@/examples" +USE_MDFILE_AS_MAINPAGE = "@TOP_SRCDIR@/README.md" +GENERATE_TREEVIEW = YES +USE_MATHJAX = YES +MATHJAX_VERSION = MathJax_3 +GENERATE_LATEX = NO +MACRO_EXPANSION = YES +PREDEFINED = @PREDEFINED@ +DOT_COMMON_ATTR = "fontname=\"sans-serif\",fontsize=10" +DOT_EDGE_ATTR = "labelfontname=\"sans-serif\",labelfontsize=10" +DOT_IMAGE_FORMAT = svg +INTERACTIVE_SVG = YES +HAVE_DOT = @HAVE_DOT@ +DOT_MULTI_TARGETS = @HAVE_DOT_1_8_10@ +DOT_PATH = "@DOT_PATH@" +HTML_FORMULA_FORMAT = @HTML_FORMULA_FORMAT@ diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..90c6d32 --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,11 @@ +examples_req = examples.enabled() + +if examples_req + executable('String', 'String.c', dependencies: [zycore_dep]) + executable('Vector', 'Vector.c', dependencies: [zycore_dep]) +endif + +summary( + {'examples': examples_req}, + section: 'Features', +) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..72dd103 --- /dev/null +++ b/meson.build @@ -0,0 +1,220 @@ +project( + 'Zycore', + 'c', + version: '1.5.0', + license: 'MIT', + license_files: 'LICENSE', + meson_version: '>=1.3', + default_options: [ + 'c_std=c11', + 'cpp_std=c++17,vc++17', + 'warning_level=3', + ], +) + +cc = meson.get_compiler('c') + +if cc.get_argument_syntax() == 'msvc' + if get_option('b_lto') + add_project_arguments( + '/GL', # -flto + language: 'c', + ) + add_project_link_arguments( + '/LTCG', + language: 'c', + ) + endif +endif + +inc = include_directories('include') + +dep = [] + +hdrs_api = files( + # API + 'include/Zycore/API/Memory.h', + 'include/Zycore/API/Process.h', + 'include/Zycore/API/Synchronization.h', + 'include/Zycore/API/Terminal.h', + 'include/Zycore/API/Thread.h', +) + +hdrs_common = files( + # Common + 'include/Zycore/Allocator.h', + 'include/Zycore/ArgParse.h', + 'include/Zycore/Atomic.h', + 'include/Zycore/Bitset.h', + 'include/Zycore/Comparison.h', + 'include/Zycore/Defines.h', + 'include/Zycore/Format.h', + 'include/Zycore/LibC.h', + 'include/Zycore/List.h', + 'include/Zycore/Object.h', + 'include/Zycore/Status.h', + 'include/Zycore/String.h', + 'include/Zycore/Types.h', + 'include/Zycore/Vector.h', + 'include/Zycore/Zycore.h', +) + +hdrs_internal = files( + 'include/Zycore/Internal/AtomicGNU.h', + 'include/Zycore/Internal/AtomicMSVC.h', +) + +hdrs = hdrs_api + hdrs_common + hdrs_internal + +src = files( + # API + 'src/API/Memory.c', + 'src/API/Process.c', + 'src/API/Synchronization.c', + 'src/API/Terminal.c', + 'src/API/Thread.c', + # Common + 'src/Allocator.c', + 'src/ArgParse.c', + 'src/Bitset.c', + 'src/Format.c', + 'src/List.c', + 'src/String.c', + 'src/Vector.c', + 'src/Zycore.c', +) + +if host_machine.system() == 'windows' + windows = import('windows') + src += windows.compile_resources('resources/VersionInfo.rc') +endif + +root = not meson.is_subproject() + +nolibc = get_option('nolibc') + +examples = get_option('examples') +doc = get_option('doc') +tests = get_option('tests') + +# Extra targets +examples = examples.disable_if(nolibc) +tests = tests.disable_if(nolibc) + +doc = doc.disable_auto_if(not root) +examples = examples.disable_auto_if(not root).enable_auto_if(root) +tests = tests.disable_auto_if(not root) + +if nolibc + add_project_arguments( + '-DZYAN_NO_LIBC', + '-fno-stack-protector', + language: 'c', + ) + dep += declare_dependency(link_args: ['-nostdlib', '-nodefaultlibs']) +elif host_machine.system() == 'linux' + add_project_arguments( + '-D_GNU_SOURCE', + language: 'c', + ) + dep += dependency('threads') +endif + +zycore_lib = library( + 'Zycore', + src + hdrs, + c_static_args: ['-DZYCORE_STATIC_BUILD'], + c_shared_args: ['-DZYCORE_SHOULD_EXPORT'], + include_directories: inc, + implicit_include_directories: false, + dependencies: dep, + version: meson.project_version(), + install: true, +) + +install_headers(hdrs_common, subdir: 'Zycore') +install_headers(hdrs_api, subdir: 'Zycore/API') +install_headers(hdrs_internal, subdir: 'Zycore/Internal') + +extra_cflags = nolibc ? ['-DZYAN_NO_LIBC'] : [] + +# Note: on MSVC, define ZYCORE_STATIC_BUILD accordingly in the user project. +zycore_dep = declare_dependency( + include_directories: inc, + link_with: zycore_lib, + compile_args: extra_cflags, +) + +subdir('examples') +subdir('tests') + +pkg = import('pkgconfig') +pkg.generate( + zycore_lib, + name: 'zycore', + description: 'Zyan Core Library for C', + url: 'https://github.com/zyantific/zycore-c', + extra_cflags: extra_cflags, +) + +meson.override_dependency('zycore', zycore_dep) + +doxygen_exe = find_program('doxygen', required: doc) +doc_req = doxygen_exe.found() +if doc_req + cdata = configuration_data() + cdata.set('VERSION', meson.project_version()) + cdata.set('TOP_SRCDIR', meson.project_source_root()) + cdata.set('TOP_BUILDDIR', meson.project_build_root()) + + dot_exe = find_program('dot', required: false) + if dot_exe.found() + cdata.set('HAVE_DOT', 'YES') + cdata.set('DOT_PATH', dot_exe.full_path()) + cdata.set( + 'HAVE_DOT_1_8_10', + dot_exe.version().version_compare('>=1.8.10') ? 'YES' : 'NO', + ) + else + cdata.set('HAVE_DOT', 'NO') + endif + + if find_program('pdf2svg', required: false).found() or find_program('inkscape', required: false).found() + cdata.set('HTML_FORMULA_FORMAT', 'svg') + else + cdata.set('HTML_FORMULA_FORMAT', 'png') + endif + + cdata.set('PREDEFINED', nolibc ? 'ZYAN_NO_LIBC' : '') + + doxyfile = configure_file( + input: 'Doxyfile.in', + output: 'Doxyfile', + configuration: cdata, + install: false, + ) + + datadir = join_paths(get_option('datadir'), 'doc', 'Zycore') + custom_target( + 'ZycoreDoc', + input: doxyfile, + output: 'doc', + command: [doxygen_exe, doxyfile], + depend_files: [hdrs], + install: true, + install_dir: datadir, + ) + + summary( + { + 'dot': cdata.get('HAVE_DOT') == 'YES', + 'formula format': cdata.get('HTML_FORMULA_FORMAT'), + }, + section: 'Doxygen', + ) +endif + +summary( + {'doc': doc_req, 'nolibc': nolibc}, + section: 'Features', +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..0d38cfc --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,25 @@ +option( + 'nolibc', + type: 'boolean', + value: false, + description: 'Do not use any C standard library functions (for exotic build-envs like kernel drivers)', + yield: true, +) +option( + 'doc', + type: 'feature', + value: 'auto', + description: 'Build doxygen documentation (requires Doxygen)', +) +option( + 'examples', + type: 'feature', + value: 'auto', + description: 'Build examples', +) +option( + 'tests', + type: 'feature', + value: 'auto', + description: 'Build tests', +) diff --git a/resources/VersionInfo.rc b/resources/VersionInfo.rc index f3587e8..5388515 100644 --- a/resources/VersionInfo.rc +++ b/resources/VersionInfo.rc @@ -47,7 +47,7 @@ BEGIN VALUE "FileDescription", "Zyan Core Library for C" VALUE "FileVersion", "1.5.0.0" VALUE "InternalName", "Zycore" - VALUE "LegalCopyright", "Copyright (C) 2018-2024 by zyantific.com" + VALUE "LegalCopyright", "Copyright \xA9 2018-2024 by zyantific.com" VALUE "OriginalFilename", "Zycore.dll" VALUE "ProductName", "Zyan Core Library for C" VALUE "ProductVersion", "1.5.0.0" diff --git a/subprojects/gtest.wrap b/subprojects/gtest.wrap new file mode 100644 index 0000000..91afad5 --- /dev/null +++ b/subprojects/gtest.wrap @@ -0,0 +1,16 @@ +[wrap-file] +directory = googletest-1.15.0 +source_url = https://github.com/google/googletest/archive/refs/tags/v1.15.0.tar.gz +source_filename = gtest-1.15.0.tar.gz +source_hash = 7315acb6bf10e99f332c8a43f00d5fbb1ee6ca48c52f6b936991b216c586aaad +patch_filename = gtest_1.15.0-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.15.0-1/get_patch +patch_hash = 5f8e484c48fdc1029c7fd08807bd2615f8c9d16f90df6d81984f4f292752c925 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.15.0-1/gtest-1.15.0.tar.gz +wrapdb_version = 1.15.0-1 + +[provide] +gtest = gtest_dep +gtest_main = gtest_main_dep +gmock = gmock_dep +gmock_main = gmock_main_dep diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..54f1968 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,38 @@ +gtest_dep = dependency('gtest', required: tests) + +tests_req = gtest_dep.found() and add_languages('cpp', native: false, required: tests) + +if tests_req + test( + 'string', + executable( + 'test_string', + 'String.cpp', + dependencies: [gtest_dep, zycore_dep], + ), + protocol: 'gtest', + ) + test( + 'vector', + executable( + 'test_vector', + 'Vector.cpp', + dependencies: [gtest_dep, zycore_dep], + ), + protocol: 'gtest', + ) + test( + 'argparse', + executable( + 'test_argparse', + 'ArgParse.cpp', + dependencies: [gtest_dep, zycore_dep], + ), + protocol: 'gtest', + ) + + summary( + {'tests': tests_req}, + section: 'Features', + ) +endif