From 4c1bea02ce6905331cb95668c97d934e5d9a59a6 Mon Sep 17 00:00:00 2001 From: Toyosatomimi no Miko <110693261+mikomikotaishi@users.noreply.github.com> Date: Sun, 17 Aug 2025 19:43:45 -0400 Subject: [PATCH] Add support for C++20 modules --- CMakeLists.txt | 13 +++++++++++++ README.md | 2 ++ RtMidi.cpp | 5 +++++ RtMidi.h | 3 +++ modules/CMakeLists.txt | 27 +++++++++++++++++++++++++++ modules/RtMidi.cppm | 16 ++++++++++++++++ 6 files changed, 66 insertions(+) create mode 100644 modules/CMakeLists.txt create mode 100644 modules/RtMidi.cppm diff --git a/CMakeLists.txt b/CMakeLists.txt index db7cd701..de93a228 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,10 @@ option(RTMIDI_API_CORE "Compile with CoreMIDI support." ${APPLE}) option(RTMIDI_API_ALSA "Compile with ALSA support." ${ALSA}) option(RTMIDI_API_AMIDI "Compile with Android support." ${ANDROID}) +# Module options +option(RTMIDI_BUILD_MODULES "Build C++ modules for RtMidi" OFF) +option(RTMIDI_USE_NAMESPACE "Use namespace rtmidi for module" ON) + # Add -Wall if possible if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") @@ -215,6 +219,15 @@ target_compile_definitions(rtmidi PRIVATE RTMIDI_EXPORT) target_link_libraries(rtmidi PUBLIC ${PUBLICLINKLIBS} PRIVATE ${LINKLIBS}) +if(RTMIDI_BUILD_MODULES) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28) + message(STATUS "Building rtmidi C++ module") + add_subdirectory(modules) + else() + message(WARNING "Skipping rtmidi C++ module (requires CMake 3.28+, found ${CMAKE_VERSION})") + endif() +endif() + # Add tests if requested. option(RTMIDI_BUILD_TESTING "Build test programs" ON) if (NOT DEFINED RTMIDI_BUILD_TESTING OR RTMIDI_BUILD_TESTING STREQUAL "") diff --git a/README.md b/README.md index 3c40814b..ab02e7fc 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ RtMidi is a set of C++ classes (`RtMidiIn`, `RtMidiOut`, and API specific classe MIDI input and output functionality are separated into two classes, `RtMidiIn` and `RtMidiOut`. Each class instance supports only a single MIDI connection. RtMidi does not provide timing functionality (i.e., output messages are sent immediately). Input messages are timestamped with delta times in seconds (via a `double` floating point type). MIDI data is passed to the user as raw bytes using an `std::vector`. +RtMidi is also offered as a module, which is enabled with `RTMIDI_BUILD_MODULES`, and is accessed with `import rtmidi;`. Namespaces are inlined, so classes can be accessed through namespace `rtmidi` or through the global namespace (for example, `rtmidi::MidiApi` and `::MidiApi` are both valid). + ## Windows In some cases, for example to use RtMidi with GS Synth, it may be necessary for your program to call `CoInitializeEx` and `CoUninitialize` on entry to and exit from the thread that uses RtMidi. diff --git a/RtMidi.cpp b/RtMidi.cpp index 95b6680b..3e34267f 100644 --- a/RtMidi.cpp +++ b/RtMidi.cpp @@ -39,6 +39,9 @@ #include "RtMidi.h" #include + +inline namespace rtmidi { + #if defined(__APPLE__) #include #endif @@ -5269,3 +5272,5 @@ void MidiOutAndroid :: sendMessage( const unsigned char *message, size_t size ) } #endif // __AMIDI__ + +} diff --git a/RtMidi.h b/RtMidi.h index 16bc60e1..28c69100 100644 --- a/RtMidi.h +++ b/RtMidi.h @@ -82,6 +82,7 @@ #include #include +inline namespace rtmidi { /************************************************************************/ /*! \class RtMidiError @@ -674,4 +675,6 @@ inline void RtMidiOut :: sendMessage( const std::vector *message inline void RtMidiOut :: sendMessage( const unsigned char *message, size_t size ) { static_cast(rtapi_)->sendMessage( message, size ); } inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); } +} + #endif diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt new file mode 100644 index 00000000..91578c8c --- /dev/null +++ b/modules/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.28) + +add_library(rtmidi_modules) + +set(RTMIDI_MODULES + RtMidi.cppm +) + +if(NOT COMMAND configure_cpp_module_target) + function(configure_cpp_module_target target) + target_sources(${target} PUBLIC FILE_SET CXX_MODULES FILES ${RTMIDI_MODULES}) + endfunction() +endif() + +configure_cpp_module_target(rtmidi_modules) + +target_link_libraries(rtmidi_modules + PUBLIC + rtmidi +) + +target_include_directories(rtmidi_modules + PRIVATE + ${PROJECT_SOURCE_DIR} +) + +target_compile_features(rtmidi_modules PUBLIC cxx_std_20) \ No newline at end of file diff --git a/modules/RtMidi.cppm b/modules/RtMidi.cppm new file mode 100644 index 00000000..e9c994fa --- /dev/null +++ b/modules/RtMidi.cppm @@ -0,0 +1,16 @@ +module; + +#include "RtMidi.h" + +export module rtmidi; + +export inline namespace rtmidi { + using rtmidi::RtMidiError; + using rtmidi::RtMidiErrorCallback; + using rtmidi::RtMidi; + using rtmidi::RtMidiIn; + using rtmidi::RtMidiOut; + using rtmidi::MidiApi; + using rtmidi::MidiInApi; + using rtmidi::MidiOutApi; +}