diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index 1410da0d..159f44cd 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -57,3 +57,29 @@ jobs: - name: Test if: runner.os == 'Linux' run: ctest --verbose --test-dir build + + # Verify the C++20 module target (`import raylib;`) builds. Module + # dependency scanning requires the Ninja generator and a scan-capable + # compiler (LLVM Clang here), so this uses its own job. + modules: + name: C++20 Modules (Ninja Clang) + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install Dependencies + run: sudo apt-get update && sudo apt-get install -y ninja-build clang-18 clang-tools-18 libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev + + - name: Configure + run: > + cmake -B build -S . -G Ninja + -DCMAKE_C_COMPILER=clang-18 + -DCMAKE_CXX_COMPILER=clang++-18 + -DBUILD_RAYLIB_CPP_MODULES=ON + -DCMAKE_CXX_STANDARD=20 + -DGLFW_BUILD_WAYLAND=OFF + -DCMAKE_BUILD_TYPE=Release + + - name: Build modules + run: cmake --build build --target raylib_cpp_modules module diff --git a/README.md b/README.md index c812969f..d0f42958 100644 --- a/README.md +++ b/README.md @@ -255,12 +255,12 @@ raylib::Vector2 newDirection = direction.Rotate(30); ### Modules -If using C++20 or later, by passing `BUILD_RAYLIB_CPP_MODULES` to the build system the library may be imported as a module by using `import raylib;`. +If using C++20 or later, enabling `BUILD_RAYLIB_CPP_MODULES` lets the library be imported as a C++ module with `import raylib;`. Link against the `raylib_cpp_modules` target instead of `raylib_cpp`. ```cpp import raylib; -using raylib::Texture; +using raylib::Color; using raylib::Window; int main() { @@ -268,9 +268,15 @@ int main() { int screenHeight = 450; Window window(screenWidth, screenHeight, "raylib-cpp - basic window"); - Texture logo("raylib_logo.png"); - // ... + while (!window.ShouldClose()) { + window.BeginDrawing(); + window.ClearBackground(raylib::Colors::RAYWHITE); + raylib::DrawText("Imported raylib as a module!", 120, 200, 20, Color::LightGray()); + window.EndDrawing(); + } + + return 0; } ``` diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d65ac409..40f1a5df 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -58,5 +58,23 @@ endforeach() add_executable("multiple" multiple/main.cpp multiple/Player.cpp) target_link_libraries("multiple" PUBLIC raylib_cpp raylib) +# C++20 modules example: only built when modules are enabled and the +# raylib_cpp_modules target was created (CMake 3.28+). +if(BUILD_RAYLIB_CPP_MODULES AND TARGET raylib_cpp_modules) + add_executable("module" module/main.cpp) + target_link_libraries("module" PRIVATE raylib_cpp_modules) + set_target_properties("module" PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + # Match raylib_cpp_modules' language flags: the compiled module (BMI) + # can only be imported by a consumer built with the same C++ standard + # and extension settings, so keep the default extensions here. + CXX_EXTENSIONS ON + # The examples directory defaults to C++11, so module scanning is not + # enabled for this target automatically; turn it on explicitly. + CXX_SCAN_FOR_MODULES ON + ) +endif() + # Copy all the resources file(COPY ${example_resources} DESTINATION "resources/") diff --git a/examples/module/main.cpp b/examples/module/main.cpp new file mode 100644 index 00000000..dfeaa59f --- /dev/null +++ b/examples/module/main.cpp @@ -0,0 +1,29 @@ +/** + * raylib-cpp example using C++20 modules. + * + * Build with modules enabled (requires the Ninja or Visual Studio generator + * and a compiler that can scan for module dependencies): + * + * cmake -B build -G Ninja -DBUILD_RAYLIB_CPP_MODULES=ON -DCMAKE_CXX_STANDARD=20 + * cmake --build build --target module + */ +import raylib; + +using raylib::Color; +using raylib::Window; + +int main() { + int screenWidth = 800; + int screenHeight = 450; + + Window window(screenWidth, screenHeight, "raylib-cpp - modules example"); + + while (!window.ShouldClose()) { + window.BeginDrawing(); + window.ClearBackground(raylib::Colors::RAYWHITE); + raylib::DrawText("Congrats! You imported raylib as a module!", 120, 200, 20, Color::LightGray()); + window.EndDrawing(); + } + + return 0; +} diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 6b2eff04..ad81a0e6 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -1,17 +1,35 @@ -file(GLOB_RECURSE RAYLIB_CPP_MODULES raylib.cppm) +# raylib-cpp C++ module target (`import raylib;`). +# +# Requirements +# - CMake 3.28+ +# - Module dependency scanning generator, like Ninja, VS17.4+ +# - Compiler with scanning support, like CLang (16+, MSVC 19.34+ or GCC 14+ -add_library(raylib_cpp_modules) +if(CMAKE_VERSION VERSION_LESS 3.28) + message(WARNING + "raylib-cpp: C++ modules require CMake 3.28 or newer (found " + "${CMAKE_VERSION}). Skipping the raylib_cpp_modules target.") + return() +endif() + +# Module dependency scanning is only implemented for the Ninja and +# Visual Studio generators. +if(NOT CMAKE_GENERATOR MATCHES "Ninja|Visual Studio") + message(WARNING + "raylib-cpp: building C++ modules requires the Ninja or Visual Studio " + "generator; the '${CMAKE_GENERATOR}' generator cannot discover module " + "import dependencies. Reconfigure with '-G Ninja' to use 'import raylib;'.") +endif() -cmake_minimum_required(VERSION 3.28) +add_library(raylib_cpp_modules STATIC) +# Allow a parent project to customise how the module sources are attached. if(NOT COMMAND configure_cpp_module_target) function(configure_cpp_module_target target) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28) - target_sources(${target} PUBLIC FILE_SET CXX_MODULES FILES ${RAYLIB_CPP_MODULES}) - else() - message(WARNING "C++ modules require CMake 3.28+. Using standard compilation.") - target_sources(${target} PRIVATE ${RAYLIB_CPP_MODULES}) - endif() + target_sources(${target} + PUBLIC + FILE_SET CXX_MODULES FILES ${CMAKE_CURRENT_SOURCE_DIR}/raylib.cppm + ) endfunction() endif() @@ -28,4 +46,6 @@ target_include_directories(raylib_cpp_modules ${PROJECT_SOURCE_DIR}/include ) -target_compile_features(raylib_cpp_modules PUBLIC cxx_std_20) \ No newline at end of file +# C++ modules require at least C++20; propagate the requirement to consumers +# so that module scanning is enabled for targets that `import raylib;`. +target_compile_features(raylib_cpp_modules PUBLIC cxx_std_20) diff --git a/modules/raylib.cppm b/modules/raylib.cppm index e0903f86..0d8e662a 100644 --- a/modules/raylib.cppm +++ b/modules/raylib.cppm @@ -229,7 +229,7 @@ export namespace raylib { using raylib::Mouse::GetTouchX; using raylib::Mouse::GetTouchY; using raylib::Mouse::GetTouchPosition; - using raylib::Mouse::GetRay; + using raylib::Mouse::GetScreenToWorldRay; } /**