Skip to content

C++20 module support v2#1575

Open
DefaultRyan wants to merge 35 commits intomasterfrom
feature/modules_v2
Open

C++20 module support v2#1575
DefaultRyan wants to merge 35 commits intomasterfrom
feature/modules_v2

Conversation

@DefaultRyan
Copy link
Copy Markdown
Member

@DefaultRyan DefaultRyan commented Apr 25, 2026

C++20 Module Support v2: Per-Namespace Modules (import winrt.Windows.Foundation;)

Overview

This PR adds per-namespace C++20 module support to C++/WinRT, building on the approach pioneered by @YexuanXiao's cppwinrtplus fork. Instead of a single monolithic import winrt; module (v1), each WinRT namespace gets its own named module:

import winrt.Windows.Foundation;
import winrt.Windows.Storage;

This provides finer-grained imports, better build parallelism, and first-class support for component authoring with modules.


Key Design Decisions

1. Unconditional guards, flag-controlled generation

Module awareness (guards, WINRT_EXPORT) is always present in projection headers. The -modules flag controls .ixx generation and whether generated component files (module.g.cpp, stub .cpp) use import vs #include. Projection headers themselves are identical regardless of -modules.

2. All three projections generate modules uniformly

When CppWinRTBuildModule=true, -modules is passed to the platform, reference, and component projections. There is no special module-specific handling that distinguishes these projections — the existing differences (e.g., -opt for components, -comp for component stubs) are pre-existing behavior.

3. Per-ProjectReference IFC consumption

CppWinRTConsumeModule is metadata on a ProjectReference, not a project-level property. When set, it suppresses -modules on the platform projection (since IFCs are already available from the referenced project) but does not affect the reference or component projections. This gives precise control over which pre-built IFCs to reuse.

4. SCC consolidation for cyclic namespaces

Tarjan's algorithm groups cyclic namespaces. The alphabetically-first namespace owns the module; others re-export it. Users can import winrt.AnyNamespace; regardless of SCC membership.


What's in This PR

Code generator (cppwinrt/)

File Changes
main.cpp Added -modules, -module_include, -module_exclude CLI options. Two-pass namespace loop: first populates module namespace set, then generates headers with dependency collection. Tarjan's SCC algorithm. .ixx generation loop.
file_writers.h write_macros_h(), write_module_preamble(), write_base_ixx(), write_numerics_ixx(), write_namespace_ixx(), write_namespace_scc_owner_ixx(), write_namespace_reexport_ixx(). Unconditional WINRT_IMPORT_MODULE / WINRT_IMPL_BUILD_MODULE guards on all generated headers. Component .g.h dual-path (import vs include). base.h now #includes winrt/base_macros.h instead of inlining macros.
code_writers.h wrap_module_aware_includes_guard() updated comment. wrap_impl_namespace() uses WINRT_EXPORT namespace winrt::impl.
settings.h Added bool modules, std::set module_include/exclude, winmd::reader::filter module_filter.

String literals (strings/)

Change Files
namespace winrt::implWINRT_EXPORT namespace winrt::impl All files with impl namespace
namespace stdWINRT_IMPL_STD_EXPORT namespace std 4 files (hash/coroutine_traits specializations)
base_macros.h refactored as canonical shared macros Generated as winrt/base_macros.h, used by both base.h and .ixx global fragments
New base_source_location.h Source location macros + slim_source_location (split from base_macros.h)
New base_module_ixx_preamble.h Global module fragment for .ixx files
New base_module_base_ixx.h winrt_base.ixx template
New base_module_numerics_ixx.h winrt_numerics.ixx template
base_extern.h Added WINRT_EXPORT to handler function pointers for module/non-module linkage
base_fast_forward.h Added WINRT_EXPORT fallback definition

MSBuild integration (nuget/)

User-facing properties:

Property / Metadata Scope Default Description
CppWinRTBuildModule Project property false Enables -modules for all three projections, generating .ixx files alongside headers
CppWinRTModuleInclude Project property (all) Semicolon-delimited namespace prefixes to include in module generation
CppWinRTModuleExclude Project property (none) Semicolon-delimited namespace prefixes to exclude from module generation
CppWinRTConsumeModule ProjectReference metadata false Suppresses platform .ixx generation and uses pre-built IFCs from the referenced project

Internal targets (not directly configured by users):

Target Purpose
CppWinRTAddModuleInterfaces Discovers generated .ixx files and adds them as ClCompile items with module compilation metadata
CppWinRTGetModuleOutputs Exports GeneratedFilesDir / IntDir / OutDir for cross-project IFC resolution
CppWinRTResolveModuleReferences Calls CppWinRTGetModuleOutputs on ProjectReferences tagged with CppWinRTConsumeModule

Test projects

Project Description
test/test_cpp20_module/ Standalone test in main solution (9 test cases: URI, events, collections, coroutines, source_location)
test/nuget/TestModuleBuilder/ Static library — pre-builds platform modules
test/nuget/TestModuleComponent1/ Component DLL — Greeter class with Uri return
test/nuget/TestModuleComponent2/ Component DLL — GreeterGroup, depends on Component1
test/nuget/TestModuleConsumerApp/ Console app — consumes builder + both components end-to-end
test/nuget/TestModuleApp/ Single-project — builds and consumes its own modules

Documentation

File Description
nuget/modules.md User-facing adoption guide (Quick Start, properties, troubleshooting)
docs/modules-design.md Maintainer design document (architecture, SCC, MSBuild flow)
.github/instructions/cppwinrt.instructions.md AI agent instructions for the codebase
.github/instructions/modules.instructions.md AI agent instructions for module-specific work

Before / After: User Code

Header mode (unchanged)

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Storage.h>

int main() {
    winrt::init_apartment();
    winrt::Windows::Foundation::Uri uri(L"https://example.com");
    auto folder = winrt::Windows::Storage::KnownFolders::DocumentsLibrary();
}

Module mode (new)

import winrt.Windows.Foundation;
import winrt.Windows.Storage;

int main() {
    winrt::init_apartment();
    winrt::Windows::Foundation::Uri uri(L"https://example.com");
    auto folder = winrt::Windows::Storage::KnownFolders::DocumentsLibrary();
}

Component authoring with modules

// MyComponent.cpp (inside a component DLL)
#include "pch.h"

import winrt.Windows.Foundation;
import winrt.MyComponent;

#include "Greeter.h"
#include "Greeter.g.cpp"

namespace winrt::MyComponent::implementation {
    hstring Greeter::Greet() { return L"Hello from a module!"; }
}

Before / After: Generated Code

Namespace header (winrt/Windows.Foundation.h) — guard changes

Before (no module awareness):

#pragma once
#ifndef WINRT_Windows_Foundation_H
#define WINRT_Windows_Foundation_H
#include "winrt/impl/Windows.Foundation.Collections.2.h"
#include "winrt/impl/Windows.Foundation.2.h"
namespace winrt::impl { /* consume definitions */ }
namespace winrt::Windows::Foundation { /* class wrappers */ }
#endif

After (unconditional module guards):

#pragma once
#ifndef WINRT_Windows_Foundation_H
#define WINRT_Windows_Foundation_H
#ifndef WINRT_IMPORT_MODULE     // ← skips body when consumer imports the module
#ifndef WINRT_IMPL_BUILD_MODULE // ← skips includes when building inside a .ixx
#include "winrt/impl/Windows.Foundation.Collections.2.h"
#include "winrt/impl/Windows.Foundation.2.h"
#endif
WINRT_EXPORT namespace winrt::impl { /* consume definitions */ }
WINRT_EXPORT namespace winrt::Windows::Foundation { /* class wrappers */ }
#endif // WINRT_IMPORT_MODULE
#endif

New: Generated module interface (winrt.Windows.Foundation.ixx)

// WARNING: Please don't edit this file. It was generated by C++/WinRT
module;
#define WINRT_IMPL_BUILD_MODULE
#include <intrin.h>
#include <cstddef>
#include <version>
#include "winrt/base_macros.h"

export module winrt.Windows.Foundation;

// Module dependencies:
//   - std
//   - winrt_base (re-exported)
//   - winrt.Windows.Foundation.Collections

import std;
export import winrt_base;
import winrt.Windows.Foundation.Collections;

#include "winrt/impl/Windows.Foundation.0.h"
#include "winrt/impl/Windows.Foundation.1.h"
#include "winrt/impl/Windows.Foundation.2.h"
#include "winrt/Windows.Foundation.h"

New: SCC owner module (cycle breaker)

When namespaces form dependency cycles (e.g., Windows.FoundationWindows.Foundation.Collections), the alphabetically-first namespace becomes the SCC owner:

// winrt.Windows.Foundation.ixx (SCC owner)
export module winrt.Windows.Foundation;

// This module is an SCC owner (cycle breaker). The following namespaces
// form a dependency cycle and are consolidated into this single module:
//   - Windows.Foundation
//   - Windows.Foundation.Collections
// Other SCC namespaces are emitted as re-export stubs.

import std;
export import winrt_base;
// Forward declarations for all SCC types...
// All impl headers in phase order...
// winrt.Windows.Foundation.Collections.ixx (re-export stub)
// NOTE: This module does not define declarations of its own.
// It re-exports all declarations from the 'winrt.Windows.Foundation' module.
export module winrt.Windows.Foundation.Collections;
export import winrt.Windows.Foundation;

New: Component .g.h (dual-path)

#pragma once
// ...
#ifdef WINRT_IMPORT_MODULE
#include "winrt/base_macros.h"
import winrt.Windows.Foundation;
import winrt.MyComponent;
#else
#include "winrt/Windows.Foundation.h"
#include "winrt/MyComponent.h"
#endif
// ... component implementation scaffolding

Differences from the cppwinrtplus Fork

This implementation shares the same core architecture as @YexuanXiao's cppwinrtplus fork — per-namespace modules, Tarjan SCC cycle breaking, WINRT_EXPORT macro — but diverges in several areas:

Module naming

cppwinrtplus This PR
Base module winrt.base winrt_base
Numerics module winrt.numerics winrt_numerics
Namespace modules <Namespace>.ixx (e.g. Windows.Foundation.ixx) winrt.<Namespace>.ixx (e.g. winrt.Windows.Foundation.ixx)

The winrt. prefix on namespace modules avoids potential collisions if other code generators produce modules with the same namespace names. The winrt_base / winrt_numerics underscore form avoids a dotted name that could imply a namespace hierarchy.

Module namespace filtering

cppwinrtplus uses a CppWinRT.config XML file in the solution directory with <exclude><prefix> elements to exclude namespaces from module generation. This PR uses -module_include / -module_exclude CLI flags with prefix matching, exposed as CppWinRTModuleInclude / CppWinRTModuleExclude MSBuild properties. The CLI approach integrates directly into MSBuild response files without needing a separate config file, and supports both include and exclude semantics.

Guard macros

cppwinrtplus This PR
Build-side guard WINRT_MODULE WINRT_IMPL_BUILD_MODULE
Consume-side guard WINRT_CONSUME_MODULE WINRT_IMPORT_MODULE
Guard conditionality Conditional on -modules flag Unconditional — always emitted

Making guards unconditional means the -modules flag controls .ixx generation and module-aware component code generation (.g.cpp, module.g.cpp, stub .cpp), but does NOT change the content of projection headers — they work in both module and header mode without regeneration.

Builder/consumer architecture

cppwinrtplus does not have a concept of sharing pre-built IFCs across projects — each project builds all its own modules. This PR introduces:

  • CppWinRTBuildModule — project-level property to enable module generation for all three projections
  • CppWinRTConsumeModule — per-ProjectReference metadata that suppresses platform .ixx generation and lets the project use pre-built IFCs from the referenced project instead
  • CppWinRTGetModuleOutputs / CppWinRTResolveModuleReferences — Internal MSBuild targets for cross-project IFC path resolution

Acknowledgements

Credit to @YexuanXiao and the cppwinrtplus fork for the per-namespace module architecture, SCC algorithm, and initial demonstration of viability. Also @sylveon, @Scottj1s, and @zadjii-msft for early module exploration and feedback on v1.

DefaultRyan and others added 15 commits April 24, 2026 17:04
…t_base/winrt_numerics

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
…names and built ifc files.

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: YexuanXiao <bizwen@nykz.org>
Co-authored-by: Copilot <copilot@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces v2 C++20 module support for C++/WinRT by generating per-namespace named modules (e.g., import winrt.Windows.Foundation;) with SCC (cycle) consolidation, updates the projection/base strings to be module-export-friendly, and adds MSBuild + test coverage for module generation/consumption.

Changes:

  • Extend cppwinrt.exe to generate per-namespace .ixx files (with Tarjan SCC cycle breaking) and emit module-aware guards/exports in generated headers.
  • Add MSBuild plumbing (CppWinRTBuildModule, include/exclude filters, CppWinRTConsumeModule, .ixx discovery) plus docs describing usage and internals.
  • Add new standalone + NuGet integration test projects that build and consume the generated modules end-to-end.

Reviewed changes

Copilot reviewed 93 out of 93 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
test/test_cpp20_module/test_cpp20_module.vcxproj New standalone VS project that runs cppwinrt with -modules and compiles generated .ixx files.
test/test_cpp20_module/pch.h Catch2 PCH header for module test.
test/test_cpp20_module/pch.cpp Builds the PCH for module test.
test/test_cpp20_module/main.cpp Catch2 runner for module test using import winrt_base;.
test/test_cpp20_module/foundation.cpp Module-mode tests for Windows.Foundation APIs.
test/test_cpp20_module/coroutines.cpp Module-mode coroutine tests using IAsync* types.
test/test_cpp20_module/collections.cpp Module-mode collections tests (vector/map/iterable).
test/nuget/TestModuleConsumerApp/pch.h PCH header for NuGet consumer app test.
test/nuget/TestModuleConsumerApp/pch.cpp Builds the PCH for NuGet consumer app test.
test/nuget/TestModuleConsumerApp/main.cpp Consumer app importing platform + component modules.
test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj Consumer app MSBuild config exercising CppWinRTConsumeModule.
test/nuget/TestModuleConsumerApp/PropertySheet.props Minimal property sheet for NuGet consumer app project.
test/nuget/TestModuleComponent2/pch.h PCH header for component 2 test.
test/nuget/TestModuleComponent2/pch.cpp Builds the PCH for component 2 test.
test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj Component 2 MSBuild config with module generation + consumption.
test/nuget/TestModuleComponent2/TestModuleComponent2.idl IDL for GreeterGroup runtimeclass.
test/nuget/TestModuleComponent2/TestModuleComponent2.def DEF exports for component DLL activation.
test/nuget/TestModuleComponent2/PropertySheet.props Minimal property sheet for component 2.
test/nuget/TestModuleComponent2/GreeterGroup.h Component implementation header for GreeterGroup.
test/nuget/TestModuleComponent2/GreeterGroup.cpp Component implementation TU using module imports.
test/nuget/TestModuleComponent1/pch.h PCH header for component 1 test.
test/nuget/TestModuleComponent1/pch.cpp Builds the PCH for component 1 test.
test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj Component 1 MSBuild config with module generation + consumption.
test/nuget/TestModuleComponent1/TestModuleComponent1.idl IDL for Greeter runtimeclass.
test/nuget/TestModuleComponent1/TestModuleComponent1.def DEF exports for component DLL activation.
test/nuget/TestModuleComponent1/PropertySheet.props Minimal property sheet for component 1.
test/nuget/TestModuleComponent1/Greeter.h Component implementation header for Greeter.
test/nuget/TestModuleComponent1/Greeter.cpp Component implementation TU using module imports.
test/nuget/TestModuleBuilder/pch.h PCH header for “builder” static lib project.
test/nuget/TestModuleBuilder/pch.cpp Builds the PCH for module builder.
test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj Static lib project that pre-builds platform modules.
test/nuget/TestModuleBuilder/PropertySheet.props Minimal property sheet for module builder.
test/nuget/TestModuleApp/pch.h PCH header for single-project module app test.
test/nuget/TestModuleApp/pch.cpp Builds the PCH for single-project module app test.
test/nuget/TestModuleApp/main.cpp Single-project app importing platform modules + exercising component types.
test/nuget/TestModuleApp/TestModuleApp.vcxproj Single-project module build + consumption configuration.
test/nuget/TestModuleApp/TestModuleApp.idl IDL for test component types including XAML inheritance scenario.
test/nuget/TestModuleApp/TestModuleApp.def DEF exports for TestModuleApp DLL activation.
test/nuget/TestModuleApp/PropertySheet.props Minimal property sheet for single-project module app.
test/nuget/TestModuleApp/ModuleTestHelper.h Component implementation header for helper runtimeclass.
test/nuget/TestModuleApp/ModuleTestHelper.cpp Component implementation TU using module imports.
test/nuget/TestModuleApp/CustomDependencyObject.h Component implementation header for XAML-derived runtimeclass.
test/nuget/TestModuleApp/CustomDependencyObject.cpp Component implementation TU importing XAML and foundation modules.
test/nuget/NuGetTest.sln Adds the new module test projects to NuGetTest solution.
strings/base_xaml_typename.h Switches winrt::impl namespace blocks to WINRT_EXPORT for module export.
strings/base_windows.h Same: exports winrt::impl content under modules.
strings/base_types.h Same: exports winrt::impl blocks under modules.
strings/base_string_operators.h Same: exports winrt::impl blocks under modules.
strings/base_string_input.h Same: exports winrt::impl blocks under modules.
strings/base_string.h Same: exports winrt::impl blocks under modules.
strings/base_std_hash.h Exports winrt::impl and std specializations via WINRT_EXPORT.
strings/base_reference_produce.h Exports winrt::impl blocks under modules.
strings/base_natvis.h Exports natvis helpers under WINRT_EXPORT winrt::impl.
strings/base_meta.h Exports winrt::impl meta helpers under modules.
strings/base_marshaler.h Exports winrt::impl marshaler helpers under modules.
strings/base_macros.h Adds numerics include guard for module/import builds + exports winrt::impl.
strings/base_iterator.h Exports winrt::impl iterator helpers under modules.
strings/base_implements.h Exports winrt::impl implements helpers under modules.
strings/base_identity.h Exports winrt::impl identity helpers under modules.
strings/base_foundation.h Exports winrt::impl foundation helpers under modules.
strings/base_fast_forward.h Exports winrt::impl fast-forward helpers under modules.
strings/base_events.h Exports winrt::impl event helpers under modules.
strings/base_error.h Exports winrt::impl error helpers under modules.
strings/base_delegate.h Exports winrt::impl delegate helpers under modules.
strings/base_coroutine_threadpool.h Exports winrt::impl and std coroutine specializations under modules.
strings/base_coroutine_foundation.h Exports winrt::impl and std coroutine specializations under modules.
strings/base_composable.h Exports winrt::impl composable helpers under modules.
strings/base_com_ptr.h Exports winrt::impl com_ptr helpers under modules.
strings/base_collections_vector.h Exports winrt::impl collections helpers under modules.
strings/base_collections_map.h Exports winrt::impl and std tuple specializations under modules.
strings/base_collections_input_vector_view.h Exports winrt::impl collections helpers under modules.
strings/base_collections_input_vector.h Exports winrt::impl collections helpers under modules.
strings/base_collections_input_map_view.h Exports winrt::impl collections helpers under modules.
strings/base_collections_input_map.h Exports winrt::impl collections helpers under modules.
strings/base_collections_input_iterable.h Exports winrt::impl collections helpers under modules.
strings/base_collections_base.h Exports winrt::impl collections base helpers under modules.
strings/base_collections.h Exports winrt::impl collections helpers under modules.
strings/base_array.h Exports winrt::impl array helpers under modules.
strings/base_agile_ref.h Exports winrt::impl agile_ref helpers under modules.
strings/base_activation.h Exports winrt::impl activation helpers under modules.
strings/base_abi.h Exports winrt::impl ABI helpers under modules.
nuget/readme.md Documents new module-related MSBuild properties/metadata.
nuget/modules.md Adds user guide for enabling/building/consuming modules.
nuget/Microsoft.Windows.CppWinRT.targets Adds module properties, .ixx discovery target, and ProjectReference metadata flow.
docs/modules-design.md Adds maintainer-focused design doc for per-namespace modules + SCC + MSBuild flow.
cppwinrt/settings.h Adds generator settings for modules + include/exclude filter sets.
cppwinrt/main.cpp Adds CLI flags, module filter construction, dependency collection, SCC detection, and .ixx generation.
cppwinrt/file_writers.h Adds module writers (module.h, base/numerics/namespace .ixx), module-aware include guards, and component import/include dual-path.
cppwinrt/component_writers.h Adjusts component module.g.cpp generation to avoid base include when modules enabled.
cppwinrt/code_writers.h Adds module-aware include guard helper and exports winrt::impl namespace blocks via WINRT_EXPORT.
cppwinrt.sln Adds new standalone module test project to main solution.
.github/instructions/modules.instructions.md Adds module-specific agent instructions.
.github/instructions/cppwinrt.instructions.md Adds repo-wide agent instructions including module notes and build/test steps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread nuget/Microsoft.Windows.CppWinRT.targets Outdated
Comment thread nuget/Microsoft.Windows.CppWinRT.targets
Comment thread nuget/modules.md Outdated
Comment thread test/nuget/TestModuleComponent2/GreeterGroup.cpp
Comment thread cppwinrt/main.cpp
Comment thread test/nuget/TestModuleConsumerApp/main.cpp
Comment thread test/nuget/TestModuleApp/main.cpp
Comment thread test/test_cpp20_module/coroutines.cpp
Comment thread nuget/Microsoft.Windows.CppWinRT.targets Outdated
DefaultRyan and others added 2 commits April 24, 2026 20:50
Co-authored-by: Copilot <copilot@github.com>
DefaultRyan and others added 2 commits April 24, 2026 21:30
@YexuanXiao
Copy link
Copy Markdown
Contributor

YexuanXiao commented Apr 25, 2026

I think we can append a module export list at the end of each base_*.h file and guard it with WINRT_MODULE:

#ifdef WINRT_MODULE
export namespace winrt
{
	using winrt::xxx;
}
#endif

I think this approach is the most maintainable.

I've tried this approach on my fork, and I think it's pretty good. It removes WINRT_EXPORT before declarations from all headers under strings, and different function overloads only need to mark export once.

@YexuanXiao

This comment was marked as resolved.

@YexuanXiao
Copy link
Copy Markdown
Contributor

YexuanXiao commented Apr 26, 2026

@DefaultRyan I discovered that the reason MSVC generates warning 5244 for windowsnumerics.impl.h is that it uses angle bracket #include instead of double quotes because compilers (MSVC and Clang) consider that system headers should not be treated as module implementation files. Therefore, it can be changed to double quotes and a comment can be added to prevent regression, instead of suppressing the warning.

@YexuanXiao
Copy link
Copy Markdown
Contributor

YexuanXiao commented Apr 26, 2026

I believe I have discovered a bug in MSVC, but I am unable to reproduce it in a new project. In short, the pattern like this:
extern "C++" { export namespace winrt { struct foo{}; template<> struct consume<foo>{}; } }
causes the specialization of consume to be unfindable, leading to a template instantiation failure. However, if rewritten as:
export extern "C++" namespace winrt { struct foo{}; template<> struct consume<foo>{}; }
everything works fine. So if anyone is trying to investigate compilation errors caused by the first form, don’t waste your time.

@YexuanXiao
Copy link
Copy Markdown
Contributor

YexuanXiao commented Apr 26, 2026

@DefaultRyan Nine days after the last commit about module, I opened a new simple PR for my fork that does a basic cleanup of WINRT_EXPORT and extern "C++". Other cleanups require large scale modifications to base*.h. If you think it's time to do these cleanups, you should take a look, it's designed not to break the existing base*.h patterns.

Comment thread cppwinrt/code_writers.h Outdated
Comment thread .github/workflows/ci.yml
Comment thread cppwinrt/file_writers.h Outdated
Comment thread cppwinrt/file_writers.h Outdated
Comment thread cppwinrt/file_writers.h Outdated
Comment thread cppwinrt/file_writers.h

// Module declaration (owner namespace)
w.write("// This module is an SCC owner (cycle breaker). The following namespaces\n");
w.write("// form a dependency cycle and are consolidated into this single module:\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if there is data on what cycles exist and how big they are. Using the output of your build would probably make that pretty simple to grep for.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's what I've got, assuming I scanned the ixx files correctly. Out of 342 Windows.* namespaces

  • Most namespaces (248) don't participare in cycles.
  • There are a few mini-cycles, like Windows.Foundation <-> Windows.Foundation.Collections, or Windows.AI.Actions <-> Windows.AI.Actions.Hosting
  • A couple of mid-sized cycles. Windows.UI.Xaml.* and Windows.Media.Audio.* tend to interconnect.
  • There is one massive cycle (62 namespaces!) encompassing cross-references all over the place. I'll see if I can easily cook up a diagram or something for it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For lolz, here's a table of the interdependencies. For extra lolz, I generated a mermaid diagram after that.

A quick perusal suggests that most of this is because tons of namespaces depend on Windows.Storage.Streams, Windows.Storage.Streams depends on Windows.System, and Windows.System depends on a surprising bunch of random bits.

Source (Windows.) Dependencies (Windows.)
ApplicationModel ApplicationModel_Activation, ApplicationModel_Appointments, ApplicationModel_Appointments_AppointmentsProvider, ApplicationModel_AppService, ApplicationModel_Background, ApplicationModel_Calls, ApplicationModel_Contacts, ApplicationModel_Contacts_Provider, ApplicationModel_Core, ApplicationModel_DataTransfer, ApplicationModel_DataTransfer_ShareTarget, ApplicationModel_Email, ApplicationModel_Search, ApplicationModel_UserDataAccounts, ApplicationModel_UserDataAccounts_Provider, ApplicationModel_UserDataTasks, ApplicationModel_Wallet, Devices_Bluetooth_Background, Devices_Bluetooth_GenericAttributeProfile, Devices_Sensors, Devices_SmartCards, Devices_Sms, Security_Authentication_Web_Core, Security_Credentials, Storage, Storage_Streams, System, System_RemoteSystems, UI_Notifications
ApplicationModel_Activation ApplicationModel, ApplicationModel_Appointments_AppointmentsProvider, ApplicationModel_Background, ApplicationModel_Calls, ApplicationModel_Contacts, ApplicationModel_Contacts_Provider, ApplicationModel_DataTransfer_ShareTarget, ApplicationModel_Search, ApplicationModel_UserDataAccounts_Provider, ApplicationModel_Wallet, Devices_Enumeration, Media_SpeechRecognition, Security_Authentication_Web_Provider, Storage, Storage_Pickers_Provider, Storage_Provider, Storage_Search, System, UI_Notifications, UI_ViewManagement
ApplicationModel_Appointments ApplicationModel, ApplicationModel_Appointments_AppointmentsProvider, System
ApplicationModel_Appointments_AppointmentsProvider ApplicationModel_Appointments
ApplicationModel_AppService ApplicationModel, System, System_RemoteSystems
ApplicationModel_Background ApplicationModel, ApplicationModel_Activation, Devices_Bluetooth, Devices_Bluetooth_Advertisement, Devices_Bluetooth_Background, Devices_Bluetooth_GenericAttributeProfile, Devices_Sensors, Devices_SmartCards, Devices_Sms, Networking, Networking_Sockets, Storage, Storage_Provider, System, UI_Notifications
ApplicationModel_Calls ApplicationModel, ApplicationModel_Contacts, Devices_Enumeration, System
ApplicationModel_Contacts ApplicationModel, ApplicationModel_Contacts_Provider, Data_Text, Storage_Streams, System, UI_ViewManagement
ApplicationModel_Contacts_Provider ApplicationModel_Contacts
ApplicationModel_Core ApplicationModel, ApplicationModel_Activation, System, UI_Core
ApplicationModel_DataTransfer ApplicationModel, ApplicationModel_DataTransfer_ShareTarget, Security_EnterpriseData, Storage, Storage_Streams
ApplicationModel_DataTransfer_ShareTarget ApplicationModel_Contacts, ApplicationModel_DataTransfer, Storage_Streams
ApplicationModel_Email ApplicationModel, ApplicationModel_Appointments, Security_Cryptography_Certificates, Storage_Streams, System
ApplicationModel_Search ApplicationModel, Storage, Storage_Streams
ApplicationModel_UserDataAccounts ApplicationModel, ApplicationModel_Appointments, ApplicationModel_Contacts, ApplicationModel_Email, ApplicationModel_UserDataAccounts_Provider, ApplicationModel_UserDataTasks, Storage_Streams, System
ApplicationModel_UserDataAccounts_Provider ApplicationModel_UserDataAccounts
ApplicationModel_UserDataTasks ApplicationModel, System
ApplicationModel_Wallet ApplicationModel, Storage_Streams
Data_Text UI_Text_Core
Data_Xml_Dom Storage, Storage_Streams
Devices_Bluetooth Devices_Bluetooth_Advertisement, Devices_Bluetooth_Background, Devices_Bluetooth_GenericAttributeProfile, Devices_Bluetooth_Rfcomm, Devices_Enumeration, Networking, Storage_Streams
Devices_Bluetooth_Advertisement Devices_Bluetooth, Storage_Streams
Devices_Bluetooth_Background Devices_Bluetooth, Devices_Bluetooth_Advertisement, Devices_Bluetooth_GenericAttributeProfile, Devices_Bluetooth_Rfcomm, Networking_Sockets, Storage_Streams
Devices_Bluetooth_GenericAttributeProfile Devices_Bluetooth, Devices_Enumeration, Storage_Streams
Devices_Bluetooth_Rfcomm Devices_Bluetooth, Devices_Enumeration, Networking, Networking_Sockets, Storage_Streams
Devices_Enumeration ApplicationModel_Background, Security_Credentials, Storage_Streams
Devices_Sensors Graphics_Display
Devices_SmartCards Security_Cryptography_Core, Storage_Streams
Devices_Sms Storage_Streams
Globalization System
Graphics_Display Storage_Streams
Media_SpeechRecognition Globalization, Storage
Networking ApplicationModel_Activation, ApplicationModel_Background, Networking_Connectivity, Networking_Sockets, Storage_Streams, System
Networking_Connectivity Networking, Storage_Streams
Networking_Sockets ApplicationModel_Background, Networking, Networking_Connectivity, Security_Credentials, Security_Cryptography_Certificates, Storage_Streams, Web
Security_Authentication_Web_Core Security_Credentials, System
Security_Authentication_Web_Provider Security_Authentication_Web_Core, Security_Credentials, Security_Cryptography_Core, Storage_Streams, System, Web_Http
Security_Credentials Security_Cryptography_Core, Storage_Streams, System
Security_Cryptography_Certificates Networking, Storage_Streams
Security_Cryptography_Core Security_Cryptography_Certificates, Storage_Streams
Security_EnterpriseData Networking, Storage, Storage_Streams
Storage Storage_FileProperties, Storage_Pickers_Provider, Storage_Provider, Storage_Search, Storage_Streams, System
Storage_FileProperties Storage, Storage_Streams
Storage_Pickers_Provider Storage
Storage_Provider Storage, Storage_Search, Storage_Streams
Storage_Search Data_Text, Storage, Storage_FileProperties, Storage_Streams
Storage_Streams Storage, System
System ApplicationModel, ApplicationModel_AppService, Networking, Security_Credentials, Storage, Storage_Search, Storage_Streams, System_Diagnostics, System_RemoteSystems, UI_ViewManagement
System_Diagnostics ApplicationModel_AppService, System
System_RemoteSystems ApplicationModel_AppService, Networking, Security_Credentials, System
UI_Composition System, UI_Core
UI_Core System, UI_Composition, UI_Input, UI_WindowManagement
UI_Input ApplicationModel_Core, Storage_Streams, System, UI_Composition, UI_Core, UI_Text, UI_WindowManagement
UI_Notifications ApplicationModel, Data_Xml_Dom, System
UI_Text Storage_Streams, UI_Text_Core
UI_Text_Core Globalization, UI_Text, UI_ViewManagement
UI_ViewManagement Devices_Enumeration, UI_Core, UI_WindowManagement
UI_WindowManagement System, UI_Composition
Web Globalization, Security_Credentials, Storage_Streams, System, System_Diagnostics, Web_Http, Web_Http_Filters, Web_Http_Headers
Web_Http Globalization, Networking_Sockets, Security_Cryptography_Certificates, Storage_Streams, System, System_Diagnostics, Web, Web_Http_Filters, Web_Http_Headers
Web_Http_Filters Networking_Sockets, Security_Credentials, Security_Cryptography_Certificates, System, Web_Http
Web_Http_Headers Globalization, Networking, Storage_Streams, Web_Http
graph LR
    ApplicationModel_Activation --> ApplicationModel
    ApplicationModel_Activation --> ApplicationModel_Appointments_AppointmentsProvider
    ApplicationModel_Activation --> ApplicationModel_Background
    ApplicationModel_Activation --> ApplicationModel_Calls
    ApplicationModel_Activation --> ApplicationModel_Contacts
    ApplicationModel_Activation --> ApplicationModel_Contacts_Provider
    ApplicationModel_Activation --> ApplicationModel_DataTransfer_ShareTarget
    ApplicationModel_Activation --> ApplicationModel_Search
    ApplicationModel_Activation --> ApplicationModel_UserDataAccounts_Provider
    ApplicationModel_Activation --> ApplicationModel_Wallet
    ApplicationModel_Activation --> Devices_Enumeration
    ApplicationModel_Activation --> Media_SpeechRecognition
    ApplicationModel_Activation --> Security_Authentication_Web_Provider
    ApplicationModel_Activation --> Storage
    ApplicationModel_Activation --> Storage_Pickers_Provider
    ApplicationModel_Activation --> Storage_Provider
    ApplicationModel_Activation --> Storage_Search
    ApplicationModel_Activation --> System
    ApplicationModel_Activation --> UI_Notifications
    ApplicationModel_Activation --> UI_ViewManagement
    ApplicationModel_Appointments_AppointmentsProvider --> ApplicationModel_Appointments
    ApplicationModel_Appointments --> ApplicationModel
    ApplicationModel_Appointments --> ApplicationModel_Appointments_AppointmentsProvider
    ApplicationModel_Appointments --> System
    ApplicationModel_AppService --> ApplicationModel
    ApplicationModel_AppService --> System
    ApplicationModel_AppService --> System_RemoteSystems
    ApplicationModel_Background --> ApplicationModel
    ApplicationModel_Background --> ApplicationModel_Activation
    ApplicationModel_Background --> Devices_Bluetooth
    ApplicationModel_Background --> Devices_Bluetooth_Advertisement
    ApplicationModel_Background --> Devices_Bluetooth_Background
    ApplicationModel_Background --> Devices_Bluetooth_GenericAttributeProfile
    ApplicationModel_Background --> Devices_Sensors
    ApplicationModel_Background --> Devices_SmartCards
    ApplicationModel_Background --> Devices_Sms
    ApplicationModel_Background --> Networking
    ApplicationModel_Background --> Networking_Sockets
    ApplicationModel_Background --> Storage
    ApplicationModel_Background --> Storage_Provider
    ApplicationModel_Background --> System
    ApplicationModel_Background --> UI_Notifications
    ApplicationModel_Calls --> ApplicationModel
    ApplicationModel_Calls --> ApplicationModel_Contacts
    ApplicationModel_Calls --> Devices_Enumeration
    ApplicationModel_Calls --> System
    ApplicationModel_Contacts_Provider --> ApplicationModel_Contacts
    ApplicationModel_Contacts --> ApplicationModel
    ApplicationModel_Contacts --> ApplicationModel_Contacts_Provider
    ApplicationModel_Contacts --> Data_Text
    ApplicationModel_Contacts --> Storage_Streams
    ApplicationModel_Contacts --> System
    ApplicationModel_Contacts --> UI_ViewManagement
    ApplicationModel_Core --> ApplicationModel
    ApplicationModel_Core --> ApplicationModel_Activation
    ApplicationModel_Core --> System
    ApplicationModel_Core --> UI_Core
    ApplicationModel_DataTransfer_ShareTarget --> ApplicationModel_Contacts
    ApplicationModel_DataTransfer_ShareTarget --> ApplicationModel_DataTransfer
    ApplicationModel_DataTransfer_ShareTarget --> Storage_Streams
    ApplicationModel_DataTransfer --> ApplicationModel
    ApplicationModel_DataTransfer --> ApplicationModel_DataTransfer_ShareTarget
    ApplicationModel_DataTransfer --> Security_EnterpriseData
    ApplicationModel_DataTransfer --> Storage
    ApplicationModel_DataTransfer --> Storage_Streams
    ApplicationModel_Email --> ApplicationModel
    ApplicationModel_Email --> ApplicationModel_Appointments
    ApplicationModel_Email --> Security_Cryptography_Certificates
    ApplicationModel_Email --> Storage_Streams
    ApplicationModel_Email --> System
    ApplicationModel_Search --> ApplicationModel
    ApplicationModel_Search --> Storage
    ApplicationModel_Search --> Storage_Streams
    ApplicationModel_UserDataAccounts_Provider --> ApplicationModel_UserDataAccounts
    ApplicationModel_UserDataAccounts --> ApplicationModel
    ApplicationModel_UserDataAccounts --> ApplicationModel_Appointments
    ApplicationModel_UserDataAccounts --> ApplicationModel_Contacts
    ApplicationModel_UserDataAccounts --> ApplicationModel_Email
    ApplicationModel_UserDataAccounts --> ApplicationModel_UserDataAccounts_Provider
    ApplicationModel_UserDataAccounts --> ApplicationModel_UserDataTasks
    ApplicationModel_UserDataAccounts --> Storage_Streams
    ApplicationModel_UserDataAccounts --> System
    ApplicationModel_UserDataTasks --> ApplicationModel
    ApplicationModel_UserDataTasks --> System
    ApplicationModel_Wallet --> ApplicationModel
    ApplicationModel_Wallet --> Storage_Streams
    ApplicationModel --> ApplicationModel_Activation
    ApplicationModel --> ApplicationModel_Appointments
    ApplicationModel --> ApplicationModel_Appointments_AppointmentsProvider
    ApplicationModel --> ApplicationModel_AppService
    ApplicationModel --> ApplicationModel_Background
    ApplicationModel --> ApplicationModel_Calls
    ApplicationModel --> ApplicationModel_Contacts
    ApplicationModel --> ApplicationModel_Contacts_Provider
    ApplicationModel --> ApplicationModel_Core
    ApplicationModel --> ApplicationModel_DataTransfer
    ApplicationModel --> ApplicationModel_DataTransfer_ShareTarget
    ApplicationModel --> ApplicationModel_Email
    ApplicationModel --> ApplicationModel_Search
    ApplicationModel --> ApplicationModel_UserDataAccounts
    ApplicationModel --> ApplicationModel_UserDataAccounts_Provider
    ApplicationModel --> ApplicationModel_UserDataTasks
    ApplicationModel --> ApplicationModel_Wallet
    ApplicationModel --> Devices_Bluetooth_Background
    ApplicationModel --> Devices_Bluetooth_GenericAttributeProfile
    ApplicationModel --> Devices_Sensors
    ApplicationModel --> Devices_SmartCards
    ApplicationModel --> Devices_Sms
    ApplicationModel --> Security_Authentication_Web_Core
    ApplicationModel --> Security_Credentials
    ApplicationModel --> Storage
    ApplicationModel --> Storage_Streams
    ApplicationModel --> System
    ApplicationModel --> System_RemoteSystems
    ApplicationModel --> UI_Notifications
    Data_Text --> UI_Text_Core
    Data_Xml_Dom --> Storage
    Data_Xml_Dom --> Storage_Streams
    Devices_Bluetooth_Advertisement --> Devices_Bluetooth
    Devices_Bluetooth_Advertisement --> Storage_Streams
    Devices_Bluetooth_Background --> Devices_Bluetooth
    Devices_Bluetooth_Background --> Devices_Bluetooth_Advertisement
    Devices_Bluetooth_Background --> Devices_Bluetooth_GenericAttributeProfile
    Devices_Bluetooth_Background --> Devices_Bluetooth_Rfcomm
    Devices_Bluetooth_Background --> Networking_Sockets
    Devices_Bluetooth_Background --> Storage_Streams
    Devices_Bluetooth_GenericAttributeProfile --> Devices_Bluetooth
    Devices_Bluetooth_GenericAttributeProfile --> Devices_Enumeration
    Devices_Bluetooth_GenericAttributeProfile --> Storage_Streams
    Devices_Bluetooth_Rfcomm --> Devices_Bluetooth
    Devices_Bluetooth_Rfcomm --> Devices_Enumeration
    Devices_Bluetooth_Rfcomm --> Networking
    Devices_Bluetooth_Rfcomm --> Networking_Sockets
    Devices_Bluetooth_Rfcomm --> Storage_Streams
    Devices_Bluetooth --> Devices_Bluetooth_Advertisement
    Devices_Bluetooth --> Devices_Bluetooth_Background
    Devices_Bluetooth --> Devices_Bluetooth_GenericAttributeProfile
    Devices_Bluetooth --> Devices_Bluetooth_Rfcomm
    Devices_Bluetooth --> Devices_Enumeration
    Devices_Bluetooth --> Networking
    Devices_Bluetooth --> Storage_Streams
    Devices_Enumeration --> ApplicationModel_Background
    Devices_Enumeration --> Security_Credentials
    Devices_Enumeration --> Storage_Streams
    Devices_Sensors --> Graphics_Display
    Devices_SmartCards --> Security_Cryptography_Core
    Devices_SmartCards --> Storage_Streams
    Devices_Sms --> Storage_Streams
    Globalization --> System
    Graphics_Display --> Storage_Streams
    Media_SpeechRecognition --> Globalization
    Media_SpeechRecognition --> Storage
    Networking_Connectivity --> Networking
    Networking_Connectivity --> Storage_Streams
    Networking_Sockets --> ApplicationModel_Background
    Networking_Sockets --> Networking
    Networking_Sockets --> Networking_Connectivity
    Networking_Sockets --> Security_Credentials
    Networking_Sockets --> Security_Cryptography_Certificates
    Networking_Sockets --> Storage_Streams
    Networking_Sockets --> Web
    Networking --> ApplicationModel_Activation
    Networking --> ApplicationModel_Background
    Networking --> Networking_Connectivity
    Networking --> Networking_Sockets
    Networking --> Storage_Streams
    Networking --> System
    Security_Authentication_Web_Core --> Security_Credentials
    Security_Authentication_Web_Core --> System
    Security_Authentication_Web_Provider --> Security_Authentication_Web_Core
    Security_Authentication_Web_Provider --> Security_Credentials
    Security_Authentication_Web_Provider --> Security_Cryptography_Core
    Security_Authentication_Web_Provider --> Storage_Streams
    Security_Authentication_Web_Provider --> System
    Security_Authentication_Web_Provider --> Web_Http
    Security_Credentials --> Security_Cryptography_Core
    Security_Credentials --> Storage_Streams
    Security_Credentials --> System
    Security_Cryptography_Certificates --> Networking
    Security_Cryptography_Certificates --> Storage_Streams
    Security_Cryptography_Core --> Security_Cryptography_Certificates
    Security_Cryptography_Core --> Storage_Streams
    Security_EnterpriseData --> Networking
    Security_EnterpriseData --> Storage
    Security_EnterpriseData --> Storage_Streams
    Storage_FileProperties --> Storage
    Storage_FileProperties --> Storage_Streams
    Storage_Pickers_Provider --> Storage
    Storage_Provider --> Storage
    Storage_Provider --> Storage_Search
    Storage_Provider --> Storage_Streams
    Storage_Search --> Data_Text
    Storage_Search --> Storage
    Storage_Search --> Storage_FileProperties
    Storage_Search --> Storage_Streams
    Storage_Streams --> Storage
    Storage_Streams --> System
    Storage --> Storage_FileProperties
    Storage --> Storage_Pickers_Provider
    Storage --> Storage_Provider
    Storage --> Storage_Search
    Storage --> Storage_Streams
    Storage --> System
    System_Diagnostics --> ApplicationModel_AppService
    System_Diagnostics --> System
    System_RemoteSystems --> ApplicationModel_AppService
    System_RemoteSystems --> Networking
    System_RemoteSystems --> Security_Credentials
    System_RemoteSystems --> System
    System --> ApplicationModel
    System --> ApplicationModel_AppService
    System --> Networking
    System --> Security_Credentials
    System --> Storage
    System --> Storage_Search
    System --> Storage_Streams
    System --> System_Diagnostics
    System --> System_RemoteSystems
    System --> UI_ViewManagement
    UI_Composition --> System
    UI_Composition --> UI_Core
    UI_Core --> System
    UI_Core --> UI_Composition
    UI_Core --> UI_Input
    UI_Core --> UI_WindowManagement
    UI_Input --> ApplicationModel_Core
    UI_Input --> Storage_Streams
    UI_Input --> System
    UI_Input --> UI_Composition
    UI_Input --> UI_Core
    UI_Input --> UI_Text
    UI_Input --> UI_WindowManagement
    UI_Notifications --> ApplicationModel
    UI_Notifications --> Data_Xml_Dom
    UI_Notifications --> System
    UI_Text_Core --> Globalization
    UI_Text_Core --> UI_Text
    UI_Text_Core --> UI_ViewManagement
    UI_Text --> Storage_Streams
    UI_Text --> UI_Text_Core
    UI_ViewManagement --> Devices_Enumeration
    UI_ViewManagement --> UI_Core
    UI_ViewManagement --> UI_WindowManagement
    UI_WindowManagement --> System
    UI_WindowManagement --> UI_Composition
    Web_Http_Filters --> Networking_Sockets
    Web_Http_Filters --> Security_Credentials
    Web_Http_Filters --> Security_Cryptography_Certificates
    Web_Http_Filters --> System
    Web_Http_Filters --> Web_Http
    Web_Http_Headers --> Globalization
    Web_Http_Headers --> Networking
    Web_Http_Headers --> Storage_Streams
    Web_Http_Headers --> Web_Http
    Web_Http --> Globalization
    Web_Http --> Networking_Sockets
    Web_Http --> Security_Cryptography_Certificates
    Web_Http --> Storage_Streams
    Web_Http --> System
    Web_Http --> System_Diagnostics
    Web_Http --> Web
    Web_Http --> Web_Http_Filters
    Web_Http --> Web_Http_Headers
    Web --> Globalization
    Web --> Security_Credentials
    Web --> Storage_Streams
    Web --> System
    Web --> System_Diagnostics
    Web --> Web_Http
    Web --> Web_Http_Filters
Loading

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this huge reference cycle means that the SCC ends up with a massive amount of code.

Comment thread cppwinrt/file_writers.h
Comment thread nuget/modules.md
Comment thread nuget/modules.md

## Requirements

- MSVC v145 toolset (Visual Studio 2026) or later recommended
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth calling out a patch level on top of just v145? It seems like very recent fixes are needed for this to work at all. Even the RTM build of VS 2026 is too old (I think).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. The runner image has "only" VS2026 18.2, with the 14.50 MSVC build tools. I know 18.0 RTM shipped with some version of 14.50, but not sure how much older it is, and what the differences are.

I think the main point is that this is building and running on the 14.50 MSVC build tools, and so far doesn't do anything that requires the newer 14.51 tools (which are planned for VS 18.6).

Comment thread nuget/modules.md Outdated
Comment thread test/nuget/TestModuleApp/pch.h
Comment thread test/nuget/TestModuleApp/TestModuleApp.vcxproj
Comment thread test/test_cpp20_module/foundation.cpp
Copy link
Copy Markdown
Member

@Scottj1s Scottj1s left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First part of comments - GH is failing to add any more atm

Comment thread .github/workflows/ci.yml
## Common Gotchas

- Module IFCs are NOT compatible across toolset versions — always clean rebuild when switching
- PCH and modules can coexist but PCH must NOT contain imports from WinRT headers when using modules, and winrt imports are preferred over textual inclusion
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the sharp edges of combining modules with pches (which strikes me as basically an anti-pattern anyway), should we MSBuild warn a user about mixing & matching?


## Common Gotchas

- Module IFCs are NOT compatible across toolset versions — always clean rebuild when switching
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this reminds me - do we still have the #pragma detect mismatch protection to prevent mixing cppwinrt versions across a build? that was a snag I ran into in early experiments (due do it being macro-based). do we have a test case to validate?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TLDR; Good point. Fix incoming.

Full version:
I had to think about this one for a sec, and I think there might be a small gap, which I'll try to test for.
But at the same time, modules offer stronger built-in protection for some cases.

To refresh my memory and review what we have, here is what I believe works right now:

  • The #pragma detect_mismatch and check_version are still present in base.h, and therefore the winrt_base module.
  • "header mode" still works the same, defends against "multiple version of base.h" as well as "base.h is a different version than this namespace header".
  • Headers and winrt_base having different versions should still hit the #pragma detect_mismatch
  • Importing multiple versions of winrt_base into a binary should still hit the #pragma detect_mismatch
  • It is probably quite hard to import multiple versions of winrt_base into a translation unit, even if they were the same CPPWINRT_VERSION, but if you manage to pull it off, I'd still expect #pragma detect_mismatch to catch it.

The gap is:

  • Namespace module imports winrt_base of a different version. (We still have a single version of winrt_base in the binary, but a namespace module of a different version is importing it)

We're probably covered on many of the "scary" cases, like silent ODR violations of base types causing undefined behavior, but not all of it. The interesting machinery types are all owned by winrt_base, and the various namespace modules mostly build on it to create the WinRT projections. ABI-breaking changes to types in base would probably cause a build error, e.g. "wrong number of parameters in winrt::some_function" or " type bar doesn't exist in namespace winrt". But an update could violate assumptions on how those building blocks are supposed to be used, and do so in a way that doesn't break the build.

When compiling the namespace modules, we're importing winrt_base instead of #including base.h. Both base.h and all the modules #include base_macros.h, but CPPWINRT_VERSION-related stuff is directly in base.h, so the namespace modules don't see it.

Comment thread .github/workflows/ci.yml
& "_build\$target_platform\$target_configuration\cppwinrt.exe" -in local -out _build\$target_platform\$target_configuration -verbose

- name: Remove module test projects on v143
if: matrix.toolchain.platform_toolset == 'v143'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we detect/enforce v145 requirement? is there a graceful degradation path to v143, et al? is that not worthwhile?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are fundemental limitations in the v143 toolset. One particular pain point is that v143 modules don't like the auto return types. This breaks the "quality of life" improvements we made that turn missing headers into compile erros instead of link errors.

Here's a CI run when it aattempted to use v143: https://github.com/microsoft/cppwinrt/actions/runs/24921696485/job/72984385782

Even after working around that by wrapping the return type like WINRT_IMPL_AUTO(FooReturnType), there was still a bit of pain. I'm not sure how worthwhile it is to try and light it up for v143, especially when I look at the list of bugfixes that have been going into v145. (See https://devblogs.microsoft.com/cppblog/c-language-updates-in-msvc-build-tools-v14-50/#c++-modules and https://devblogs.microsoft.com/cppblog/msvc-build-tools-version-14-51-release-candidate-now-available/#tickets-fixed)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, rather than relying on a cryptic build error to leave a user wondering if they held it wrong, we could issue a #warning or #error if we detect trying to build a module using _MSC_VER less than 1950.

I'm leaning towards a warning like "This probably won't work on this version", rather than forbidding it. I bet winrt_base still (mostly) works on v143, as it doesn't deal with splitting decls and defs across namespace impl headers and all that. Thoughts?

Comment thread cppwinrt/main.cpp
{
continue;
}
if (settings.module_filter.empty() || settings.module_filter.includes(members))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if module_filter is empty, should/does it fall back to CppWinRTInclude/CppWinRTExclude settings?

Comment thread cppwinrt/main.cpp

group.get();

// Generate per-namespace module interface files (.ixx)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this include subnamespaces? i.e., is there compositional support for importing any level of namespace, as there is for #inclusion?
import winrt // give me everything
import winrt.Microsoft // give me all of WinAppSDK
import winrt.Microsoft.UI.Xaml // give me all of WinUI3
...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think we had this compositional support today via inclusion. Windows.UI.Xaml is a distinct namespace that has its own types distinct from the subnamespaces. For example, #include <winrt/Windows.UI.Xaml.h> completely omits WUX.Resources, WUX.Printing, WUX.Markup, etc...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, this is not true even today.

Comment thread nuget/modules.md

**Linker errors for component constructors** — You may be importing a component's internal module instead of building your own reference projection. Remove explicit `/reference` flags for component IFCs and ensure your project has `CppWinRTBuildModule=true` so it builds reference projection modules from the component's `.winmd`.

**Redefinition errors** — Don't mix `#include` and `import` for the same namespace in the same translation unit. Use `import` consistently.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this something we can detect in MSBuild, break the build, and issue a diagnostic?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll clarify the doc. This guidance exists because violating it will break the build. In the C++ kingdom of "foot guns", the addition of modules both introduces new foot guns, and provides opportunities to hold old foot guns in new ways. 😉

For the first case, you can do that with headers today. If component A.dll somehow consuming component B.dll's projection headers that were built with -opt. The direct construction functions that bypass activation factories wouldn't exist in component B, resulting in a linker error.

For the second case, MSVC++ modules currently don't like it if you import and then #include. You get redefinition errors. The guidance is to try and avoid that.

I'm also going to update and flesh out this guidance based on lessons learned from the Terminal prototype.

Comment thread nuget/readme.md
}
```

## C++20 Modules
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meta: how do plan to message out? last update to https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/news was March 2020, so there's lots of content we could announce, not necessarily just 3.0-specific work like modules. will we also coordinate a VSIX update with DevDiv for generic natvis support?

<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have we confirmed compat with arm64ec? cl.exe and link.exe are deeply involved there, so wouldn't surprise me if there's a bad interaction with modules. if so, we should provide MSBuild diagnostic.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to work for me. On my ARM64 Surface Pro, I successfully built and ran both the x64 and arm64 configurations.

Is this what you were thinking, or is there something deeper I need to worry about?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a sample that also consumes the Windows SDK headers? that was a major incompatibility when I was experimenting

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By Windows SDK headers, do you mean the non-cppwinrt headers, like <Windows.h> and <Unknwn.h>?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also - test cases for mixing & matching import/include across WinAppSDK, WindowsSDK, std? there was that include-after-import bug in cl.exe for a while.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include after import is still broken in MSVC AFAIK.

Comment thread cppwinrt/file_writers.h Outdated
auto wrap_includes = wrap_module_aware_includes_guard(w, true);
w.write(strings::base_includes);
}
w.write("#include \"winrt/base_macros.h\"\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use write_include to use "" or <> depending on settings.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread cppwinrt/file_writers.h Outdated
w.write(strings::base_natvis);
w.write(strings::base_version);

w.write("#endif // WINRT_IMPORT_MODULE\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap_ifndef?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment thread cppwinrt/file_writers.h Outdated
write_namespace_special(w, ns);

write_close_file_guard(w);
w.write("#endif\n"); // WINRT_IMPORT_MODULE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endif doesn't seem to have a matching ifdef

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's below the call to w.swap(). It mirrors the write_open_file_guard()/write_close_file_guard() pair.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh slightly confusing. Might be good to add a comment.

Comment thread cppwinrt/file_writers.h
write_preamble(w);
write_include_guard(w);

w.write("#ifdef WINRT_IMPORT_MODULE\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap_ifdef

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also has a #else before the #endif. I'm adding a trailing comment to the #else to make this clearer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be able to use wrap_ifdef nonetheless, no?

Comment thread cppwinrt/file_writers.h

if (settings.modules)
{
// The .g.h handles its own imports, but the implementation .h
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally implementers would also be able to use ixx for their types, not headers.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll think about it. It sounds nice, but I'm not sure how much value it provides in practice. Also, it carries some implications:

  • Currently, you're under no obligation to use the component-generated Class.g.cpp and Class.g.h files. It's highly recommended, and good luck keeping your code up to date when C++/WinRT changes the codegen in that area, but if folks feel like breaking the warranty and going off-road, they can do that. And in either case, they don't have to add anything to the project. Just #include (or not) the .g.* files from their Class.cpp and Class.h files. Making this a module means that our targets should add these Class Implementation ixx files to the build by default, and we need to consider whether that needs to be configurable.
  • The XAML compiler emits module-unaware code. In my Terminal prototype, I've managed to work around the places where it includes projection headers. I have a module preamble that imports the types instead and defines WINRT_IMPORT_MODULE to make those later inclusions inert. But XAML also generates XamlMetaDataProvider.h that includes cppwinrt's XamlMetaDataProvider.g.h, which I hesitate to workaround in the same way, because importing implementation modules into the project's module preamble header seems... gross.

Folks should definitely continue investigating these line of thinking though, but for a future commit.

import std;
export import winrt_numerics;

#if __has_include(<windowsnumerics.impl.h>)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this here if export import winrt_numerics is right above?

@@ -0,0 +1,7 @@
module;
#define WINRT_IMPL_BUILD_MODULE
#include <version>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not move these includes to base_macros.h?


export module winrt_numerics;

#if __has_include(<windowsnumerics.impl.h>)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentionned earlier, make this its own string instead of duplicating it.

#ifdef _DEBUG
#include <crtdbg.h>
#endif // _DEBUG
#include "winrt/base_macros.h"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be write_includes in code to use the "" or <> depending on project settings. This string isn't needed.

(void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
(void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
return Catch::Session().run(argc, argv);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we maybe add some tests that exercise the std specializations, like format or maps, to ensure those are properly working?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I'll add some more. I've already added modules test cases to check range-based for and structured binding across IKeyValuePair<K, V>, and the latter requires exporting specializations of std::tuple_size and std::tuple_element, which I originally missed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know the format specializations used to trigger ICEs, so I'm curious if they are still problematic.

@YexuanXiao
Copy link
Copy Markdown
Contributor

In module builds with legacy COM enabled, TrustLevel, IUnknown, and GUID should be placed in the global module fragment. C++/WinRT should not provide them within the module implementation. I forgot about this issue before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants