C++ Modules¶
How to use libwinui through import winui; instead of its headers.
Build the Modules¶
The modules are opt-in. Configure libwinui with LIBWINUI_BUILD_MODULES=ON, with the Ninja or Visual Studio generator. It adds two targets:
winui::moduleforimport winui;, the whole public API of<winui/winui.hpp>winui::testing_moduleforimport winui.testing;, the testing tier, withwinuire-exported
Link the module target next to winui::main:
cmake_minimum_required(VERSION 3.28)
project(my_app LANGUAGES CXX)
set(LIBWINUI_BUILD_MODULES ON CACHE BOOL "" FORCE)
add_subdirectory(libwinui)
add_executable(my_app WIN32 main.cpp)
target_link_libraries(my_app PRIVATE winui::main winui::module)
A cmake_minimum_required of 3.28 or newer turns on the module scanning a file with an import needs. With an older minimum, set the target's CXX_SCAN_FOR_MODULES property to ON.
An installed libwinui built with the option has the same targets: find_package(winui CONFIG REQUIRED) gives winui::module, and COMPONENTS testing adds winui::testing_module. The package ships the module sources, not compiled modules, since a compiled module only works with the compiler and options it was made with. Your build compiles them once per configuration.
Import It¶
The first tutorial's window, with the import:
#include <format>
import winui;
int main()
{
ui::Property<int> clicks{0};
ui::Window window{{.title = "My first window", .size = {480, 320}}};
window.set_content(ui::VerticalStack{
.spacing = 12,
.content =
{
ui::Text{.text = ui::bind(clicks, [](int n) { return std::format("Clicks: {}", n); })},
ui::Button{.text = "Click me", .on_click = [&] { ++clicks; }},
},
});
return ui::run(window);
}
The rules for a file that imports the module:
- Put the
#includelines of the standard library before theimport. - Include the standard headers you use yourself. The module exports the names in
uiand nothing else, sostd::optional,std::moveandstd::vectorneed<optional>,<utility>and<vector>even where a libwinui type uses them. A coroutine that awaits aui::Taskneeds<coroutine>. - Don't include libwinui headers in the same file, also not through a header of your own. Keep a file on either the headers or the module.
- The literals work as before, with
using namespace ui::literals;orusing ui::operator""_fr;.
Files that include the headers and files that import the module can be mixed in one program. The module is made from the headers, so both see the same types and link the same library.
Macros¶
A module exports no macros. What the headers define for the preprocessor has a replacement or takes effect when the module is compiled:
- The version is also
ui::VersionMajor,ui::VersionMinorandui::VersionPatch, which work inif constexprandstatic_assert. A file that needsLIBWINUI_VERSION_MAJORin an#ifincludes<winui/core/Version.hpp>. LIBWINUI_NO_DEPRECATION_WARNINGSsilences the deprecation warnings only when the module is compiled with it. Add it as a compile definition for the whole build, not with a#definein a source file.LIBWINUI_THREAD_CHECKScomes from the CMake option of the same name, so the module and your files agree on it.
Compilers¶
CI builds the modules with MSVC and clang-cl, imports them in every tutorial but the one that hosts native controls, and imports the installed package once more from a project outside the tree. GCC is not tested. The modules sit on the static library; with LIBWINUI_BUILD_SHARED the shared library stays header-only.