From 8c02aaabbe9de3e0ca4d8fe47ca9f56b9c01dcba Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Wed, 13 Dec 2023 13:14:51 -0600 Subject: [PATCH 1/2] Experimental Meson build for MMDevice, MMCore MMDevice builds on its own. MMCore requires a copy (or symlink) of MMDevice to be in its subprojects/ directory. (This is unavoidable as we develop the Meson build in place. When MMDevice and MMCore are in their own repositories (and/or have source tarballs) MMCore will be able to depend on MMDevice as either a git submodule or a Meson wrap.) --- MMCore/meson.build | 98 +++++++++++++++++++++++++++++++++ MMCore/subprojects/.gitignore | 12 ++++ MMCore/subprojects/gtest.wrap | 16 ++++++ MMCore/unittest/meson.build | 57 +++++++++++++++++++ MMDevice/meson.build | 60 ++++++++++++++++++++ MMDevice/subprojects/.gitignore | 10 ++++ MMDevice/subprojects/gtest.wrap | 16 ++++++ MMDevice/unittest/meson.build | 32 +++++++++++ 8 files changed, 301 insertions(+) create mode 100644 MMCore/meson.build create mode 100644 MMCore/subprojects/.gitignore create mode 100644 MMCore/subprojects/gtest.wrap create mode 100644 MMCore/unittest/meson.build create mode 100644 MMDevice/meson.build create mode 100644 MMDevice/subprojects/.gitignore create mode 100644 MMDevice/subprojects/gtest.wrap create mode 100644 MMDevice/unittest/meson.build diff --git a/MMCore/meson.build b/MMCore/meson.build new file mode 100644 index 000000000..b60ab51fc --- /dev/null +++ b/MMCore/meson.build @@ -0,0 +1,98 @@ +# This Meson script is experimental and potentially incomplete. It is not part +# of the supported build system for Micro-Manager or mmCoreAndDevices. + +project( + 'MMCore', + 'cpp', + meson_version: '>=1.1.0', # May relax + default_options: [ + 'cpp_std=c++14', + 'warning_level=3', + ], +) + +cxx = meson.get_compiler('cpp') + +if cxx.get_id() in ['msvc', 'clang-cl'] + add_project_arguments('-DNOMINMAX', language: 'cpp') + add_project_arguments('/wd4290', language: 'cpp') +endif + +# MMDevice must be copied into subprojects/ for this experimental build to work +# (unless MMCore is itself being used as a subproject). +mmdevice_proj = subproject('MMDevice') +mmdevice_dep = mmdevice_proj.get_variable('mmdevice') + +mmcore_sources = files( + 'CircularBuffer.cpp', + 'Configuration.cpp', + 'CoreCallback.cpp', + 'CoreFeatures.cpp', + 'CoreProperty.cpp', + 'DeviceManager.cpp', + 'Devices/AutoFocusInstance.cpp', + 'Devices/CameraInstance.cpp', + 'Devices/DeviceInstance.cpp', + 'Devices/GalvoInstance.cpp', + 'Devices/HubInstance.cpp', + 'Devices/ImageProcessorInstance.cpp', + 'Devices/MagnifierInstance.cpp', + 'Devices/SerialInstance.cpp', + 'Devices/ShutterInstance.cpp', + 'Devices/SignalIOInstance.cpp', + 'Devices/SLMInstance.cpp', + 'Devices/StageInstance.cpp', + 'Devices/StateInstance.cpp', + 'Devices/XYStageInstance.cpp', + 'Error.cpp', + 'FrameBuffer.cpp', + 'LibraryInfo/LibraryPathsUnix.cpp', + 'LibraryInfo/LibraryPathsWindows.cpp', + 'LoadableModules/LoadedDeviceAdapter.cpp', + 'LoadableModules/LoadedModule.cpp', + 'LoadableModules/LoadedModuleImpl.cpp', + 'LoadableModules/LoadedModuleImplUnix.cpp', + 'LoadableModules/LoadedModuleImplWindows.cpp', + 'Logging/Metadata.cpp', + 'LogManager.cpp', + 'MMCore.cpp', + 'PluginManager.cpp', + 'Semaphore.cpp', + 'Task.cpp', + 'TaskSet.cpp', + 'TaskSet_CopyMemory.cpp', + 'ThreadPool.cpp', +) + +mmcore_include_dir = include_directories('.') + +mmcore_public_headers = files( + 'Configuration.h', + 'Error.h', + 'ErrorCodes.h', + 'MMCore.h', + 'MMEventCallback.h', + # TODO MMCore.h currently includes Logging/Logger.h and CoreUtils.h, which + # should not be public. That will need to be fixed before we support + # installing the public headers. +) + +# TODO Allow MMCore to be built as a shared library, too. For that, we'd need +# to define the exported symbols on Windows (__declspec(dllexport)). +mmcore_lib = static_library( + 'MMCore', + sources: mmcore_sources, + include_directories: mmcore_include_dir, + dependencies: mmdevice_dep, + cpp_args: [ + '-D_CRT_SECURE_NO_WARNINGS', # TODO Eliminate the need + ], +) + +subdir('unittest') + +mmcore = declare_dependency( + include_directories: mmcore_include_dir, + link_with: mmcore_lib, + dependencies: mmdevice_dep, +) diff --git a/MMCore/subprojects/.gitignore b/MMCore/subprojects/.gitignore new file mode 100644 index 000000000..479f9fa9c --- /dev/null +++ b/MMCore/subprojects/.gitignore @@ -0,0 +1,12 @@ +/packagecache/ + +/MMDevice/ + +# Subprojects installed by meson wrap +/*-*/ + +# Ignore *.wrap by default (may be auto-installed transitive dependencies) +/*.wrap + +# Do not ignore wraps we provide +!/gtest.wrap \ No newline at end of file diff --git a/MMCore/subprojects/gtest.wrap b/MMCore/subprojects/gtest.wrap new file mode 100644 index 000000000..8c067ff20 --- /dev/null +++ b/MMCore/subprojects/gtest.wrap @@ -0,0 +1,16 @@ +[wrap-file] +directory = googletest-1.14.0 +source_url = https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz +source_filename = gtest-1.14.0.tar.gz +source_hash = 8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7 +patch_filename = gtest_1.14.0-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.14.0-1/get_patch +patch_hash = 2e693c7d3f9370a7aa6dac802bada0874d3198ad4cfdf75647b818f691182b50 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.14.0-1/gtest-1.14.0.tar.gz +wrapdb_version = 1.14.0-1 + +[provide] +gtest = gtest_dep +gtest_main = gtest_main_dep +gmock = gmock_dep +gmock_main = gmock_main_dep diff --git a/MMCore/unittest/meson.build b/MMCore/unittest/meson.build new file mode 100644 index 000000000..05395a28c --- /dev/null +++ b/MMCore/unittest/meson.build @@ -0,0 +1,57 @@ +# This Meson script is experimental and potentially incomplete. It is not part +# of the supported build system for Micro-Manager or mmCoreAndDevices. + +gtest_proj = subproject('gtest') +gtest_dep = gtest_proj.get_variable('gtest_dep') + +# TODO: Use a single executable for all tests -- but that requires modifying +# the sources (to remove main()), so needs to wait until we remove these tests +# from the Automake build. + +mmcore_apierror_test_exe = executable( + 'MMCoreAPIErrorTest', + sources: 'APIError-Tests.cpp', + include_directories: mmcore_include_dir, + link_with: mmcore_lib, + dependencies: [ + mmdevice_dep, + gtest_dep, + ], +) + +test('MMCore APIError test', mmcore_apierror_test_exe) + +mmcore_logger_test_exe = executable( + 'MMCoreLoggerTest', + sources: 'Logger-Tests.cpp', + include_directories: mmcore_include_dir, + link_with: mmcore_lib, + dependencies: [ + mmdevice_dep, + gtest_dep, + ], + cpp_args: [ + '-D_CRT_SECURE_NO_WARNINGS', # TODO Eliminate the need + ], +) + +test('MMCore Logger test', mmcore_logger_test_exe) + +mmcore_loggingsplitentryintolines_test_exe = executable( + 'MMCoreLoggingSplitEntryIntoLinesTest', + sources: 'LoggingSplitEntryIntoLines-Tests.cpp', + include_directories: mmcore_include_dir, + link_with: mmcore_lib, + dependencies: [ + mmdevice_dep, + gtest_dep, + ], + cpp_args: [ + '-D_CRT_SECURE_NO_WARNINGS', # TODO Eliminate the need + ], +) + +test( + 'MMCore LoggingSplitEntryIntoLines test', + mmcore_loggingsplitentryintolines_test_exe +) diff --git a/MMDevice/meson.build b/MMDevice/meson.build new file mode 100644 index 000000000..9f6bdf496 --- /dev/null +++ b/MMDevice/meson.build @@ -0,0 +1,60 @@ +# This Meson script is experimental and potentially incomplete. It is not part +# of the supported build system for Micro-Manager or mmCoreAndDevices. + +project( + 'MMDevice', + 'cpp', + meson_version: '>=1.1.0', # May relax + default_options: [ + 'cpp_std=c++14', + 'warning_level=3', + ], +) + +# We intentionally do NOT define NOMINMAX on Windows. MMDevice should compile +# correctly with or without Windows.h's min()/max() macros. + +mmdevice_sources = files( + 'Debayer.cpp', + 'DeviceUtils.cpp', + 'ImgBuffer.cpp', + 'MMDevice.cpp', + 'ModuleInterface.cpp', + 'Property.cpp', +) + +mmdevice_include_dir = include_directories('.') + +mmdevice_public_headers = files( + 'Debayer.h', + 'DeviceBase.h', + 'DeviceThreads.h', + 'DeviceUtils.h', + 'ImageMetadata.h', + 'ImgBuffer.h', + 'MMDevice.h', + 'MMDeviceConstants.h', + 'ModuleInterface.h', + 'Property.h', +) +# TODO Support installing public headers + +mmdevice_lib = static_library( + 'MMDevice', + sources: mmdevice_sources, + include_directories: mmdevice_include_dir, + cpp_args: [ + '-DMODULE_EXPORTS', + '-D_CRT_SECURE_NO_WARNINGS', # TODO Eliminate the need + ], + # MMDevice does not depend on any external library. This is a big advantage + # in simplifing its usage (given hundreds of device adapters depending on + # MMDevice), so think twice before adding dependencies. +) + +subdir('unittest') + +mmdevice = declare_dependency( + include_directories: mmdevice_include_dir, + link_with: mmdevice_lib, +) diff --git a/MMDevice/subprojects/.gitignore b/MMDevice/subprojects/.gitignore new file mode 100644 index 000000000..8b7ac1334 --- /dev/null +++ b/MMDevice/subprojects/.gitignore @@ -0,0 +1,10 @@ +/packagecache/ + +# Subprojects installed by meson wrap +/*-*/ + +# Ignore *.wrap by default (may be auto-installed transitive dependencies) +/*.wrap + +# Do not ignore wraps we provide +!/gtest.wrap \ No newline at end of file diff --git a/MMDevice/subprojects/gtest.wrap b/MMDevice/subprojects/gtest.wrap new file mode 100644 index 000000000..8c067ff20 --- /dev/null +++ b/MMDevice/subprojects/gtest.wrap @@ -0,0 +1,16 @@ +[wrap-file] +directory = googletest-1.14.0 +source_url = https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz +source_filename = gtest-1.14.0.tar.gz +source_hash = 8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7 +patch_filename = gtest_1.14.0-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.14.0-1/get_patch +patch_hash = 2e693c7d3f9370a7aa6dac802bada0874d3198ad4cfdf75647b818f691182b50 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.14.0-1/gtest-1.14.0.tar.gz +wrapdb_version = 1.14.0-1 + +[provide] +gtest = gtest_dep +gtest_main = gtest_main_dep +gmock = gmock_dep +gmock_main = gmock_main_dep diff --git a/MMDevice/unittest/meson.build b/MMDevice/unittest/meson.build new file mode 100644 index 000000000..0b9296ac2 --- /dev/null +++ b/MMDevice/unittest/meson.build @@ -0,0 +1,32 @@ +# This Meson script is experimental and potentially incomplete. It is not part +# of the supported build system for Micro-Manager or mmCoreAndDevices. + +gtest_proj = subproject('gtest') +gtest_dep = gtest_proj.get_variable('gtest_dep') + +# TODO: Use a single executable for all tests -- but that requires modifying +# the sources (to remove main()), so needs to wait until we remove these tests +# from the Automake build. + +mmdevice_floatpropertytruncation_test_exe = executable( + 'MMDeviceFloatPropertyTruncationTest', + sources: 'FloatPropertyTruncation-Tests.cpp', + include_directories: mmdevice_include_dir, + link_with: mmdevice_lib, + dependencies: gtest_dep, +) + +test( + 'MMDevice FloatPropertyTruncation test', + mmdevice_floatpropertytruncation_test_exe, +) + +mmdevice_mmtime_test_exe = executable( + 'MMDeviceMMTimeTest', + sources: 'MMTime-Tests.cpp', + include_directories: mmdevice_include_dir, + link_with: mmdevice_lib, + dependencies: gtest_dep, +) + +test('MMDevice MMTime test', mmdevice_mmtime_test_exe) From 78f9ea974184dddc61272b1a2ae101b6ee9d4d73 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Thu, 14 Dec 2023 12:26:00 -0600 Subject: [PATCH 2/2] CI for MMDevice/MMCore experimental Meson build --- .github/workflows/ci-mmdevice-mmcore.yml | 67 ++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/ci-mmdevice-mmcore.yml diff --git a/.github/workflows/ci-mmdevice-mmcore.yml b/.github/workflows/ci-mmdevice-mmcore.yml new file mode 100644 index 000000000..bcc16bb02 --- /dev/null +++ b/.github/workflows/ci-mmdevice-mmcore.yml @@ -0,0 +1,67 @@ +name: MMDevice/MMCore experimental Meson build & tests + +on: + pull_request: + paths: + - MMDevice/** + - MMCore/** + push: + branches: + - main + paths: + - MMDevice/** + - MMCore/** + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: + - windows + - macos + - ubuntu + include: + - os: windows + runner: windows-2019 + cxx: cl + - os: macos + runner: macos-11 + cxx: clang++ + - os: ubuntu + runner: ubuntu-22.04 + cxx: g++ + name: ${{ matrix.runner }}-${{ matrix.cxx }} + runs-on: ${{ matrix.runner }} + env: + CXX: ${{ matrix.cxx }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install tools + run: | + python -m pip install --upgrade pip meson ninja + - uses: ilammy/msvc-dev-cmd@v1 + with: + vsversion: '2019' + - name: Build and test MMDevice + run: | + cd MMDevice + meson setup builddir --buildtype debug + meson test -C builddir --print-errorlogs + - name: Prepare MMCore source + shell: bash + run: | + git clean -dxf + cp -R MMDevice MMCore/subprojects + - name: Build and test MMCore + run: | + cd MMCore + meson setup builddir --buildtype debug + meson test -C builddir --print-errorlogs