Skip to content

Commit 4ff8c7b

Browse files
committed
Explicitly generate list of module namespaces and use that for header exclusion.
1 parent 9ef6792 commit 4ff8c7b

File tree

11 files changed

+107
-16
lines changed

11 files changed

+107
-16
lines changed

cppwinrt/code_writers.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,17 @@ namespace cppwinrt
4141
// consuming the module (WINRT_MODULE, project-wide), base.h types are
4242
// already available. Macros don't cross module boundaries, so include
4343
// base_macros.h for the version check and other macros.
44-
// WINRT_IMPL_SKIP_INCLUDES also triggers this (used locally in .g.h files).
45-
auto format_guard = R"(#if defined(WINRT_BUILD_MODULE) || defined(WINRT_MODULE) || defined(WINRT_IMPL_SKIP_INCLUDES)
44+
// When WINRT_MODULE is defined, also include winrt_module_namespaces.h
45+
// which declares per-namespace macros (WINRT_MODULE_NS_*) so that
46+
// cross-namespace #include guards can precisely skip only the namespaces
47+
// that are in the module.
48+
auto format_guard = R"(#if defined(WINRT_BUILD_MODULE) || defined(WINRT_MODULE)
4649
#include "winrt/base_macros.h"
47-
#else
50+
#endif
51+
#if defined(WINRT_MODULE) && !defined(WINRT_BUILD_MODULE)
52+
#include "winrt/winrt_module_namespaces.h"
53+
#endif
54+
#if !defined(WINRT_BUILD_MODULE) && !defined(WINRT_MODULE)
4855
)";
4956
auto format_end = R"(#endif
5057
)";

cppwinrt/file_writers.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,15 +285,16 @@ import std;
285285

286286
// In module mode (WINRT_MODULE defined), SDK types and exported impl
287287
// templates come from 'import winrt;'. Component-specific types come
288-
// from the component's own projection headers, included with
289-
// WINRT_IMPL_SKIP_INCLUDES to skip SDK dependencies already in the module.
290-
// WINRT_IMPL_SKIP_INCLUDES may already be defined project-wide by the
291-
// NuGet targets, so use #ifndef to avoid redefinition warnings.
288+
// from the component's own projection headers. The version assert in
289+
// each header includes winrt_module_namespaces.h (when WINRT_MODULE is
290+
// defined), which provides per-namespace WINRT_MODULE_NS_* macros.
291+
// Cross-namespace deps use these per-namespace guards: platform deps
292+
// (in the module) are skipped, component deps (not in the module) are
293+
// included normally.
292294
w.write("#ifdef WINRT_MODULE\n");
293295
w.write("#include \"winrt/base_macros.h\"\n");
294296
w.write("#ifdef WINRT_IMPORT_STD\nimport std;\n#endif\n");
295297
w.write("import winrt;\n");
296-
w.write("#ifndef WINRT_IMPL_SKIP_INCLUDES\n#define WINRT_IMPL_SKIP_INCLUDES\n#endif\n");
297298
w.write("#endif\n");
298299
for (auto&& depends : w.depends)
299300
{

cppwinrt/main.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder
344344
group.synchronous(args.exists("synchronous"));
345345
writer ixx;
346346
write_preamble(ixx);
347-
ixx.write("module;\n#define WINRT_BUILD_MODULE\n#undef WINRT_IMPL_SKIP_INCLUDES\n");
347+
ixx.write("module;\n#define WINRT_BUILD_MODULE\n");
348348
ixx.write(strings::base_includes);
349349
ixx.write(strings::base_std_includes);
350350
ixx.write("\nexport module winrt;\n#define WINRT_EXPORT export\n#define WINRT_IMPL_INCLUDES_HANDLED\n\n");
@@ -373,6 +373,31 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder
373373
write_base_h();
374374
write_base_macros_h();
375375
ixx.flush_to_file(settings.output_folder + "winrt/winrt.ixx");
376+
377+
// Generate a companion header that declares which namespaces are
378+
// in the module. Consumer projects include this (via WINRT_MODULE)
379+
// so that cross-namespace #include guards can precisely skip only
380+
// namespaces available from the module, while still including
381+
// component and other non-module namespace deps.
382+
// Only generated alongside the ixx (not for component projections
383+
// which may also set -base but shouldn't produce module metadata).
384+
if (!settings.component)
385+
{
386+
writer module_ns;
387+
write_preamble(module_ns);
388+
module_ns.write("#pragma once\n");
389+
for (auto&&[ns, members] : c.namespaces())
390+
{
391+
if (!has_projected_types(members) || !settings.projection_filter.includes(members))
392+
{
393+
continue;
394+
}
395+
std::string ns_macro{ ns };
396+
std::replace(ns_macro.begin(), ns_macro.end(), '.', '_');
397+
module_ns.write("#define WINRT_MODULE_NS_%\n", ns_macro);
398+
}
399+
module_ns.flush_to_file(settings.output_folder + "winrt/winrt_module_namespaces.h");
400+
}
376401
}
377402

378403
if (settings.component)

cppwinrt/type_writers.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,12 +566,30 @@ namespace cppwinrt
566566

567567
void write_root_include_guarded(std::string_view const& include)
568568
{
569-
auto format = R"(#ifndef WINRT_IMPL_SKIP_INCLUDES
569+
// Extract the namespace from the include path. The include is either
570+
// "NS" (for main headers) or "impl/NS.N" (for impl headers).
571+
// The per-namespace guard macro is WINRT_MODULE_NS_<ns_with_underscores>.
572+
std::string ns_part;
573+
if (include.size() > 5 && include.substr(0, 5) == "impl/")
574+
{
575+
auto remainder = include.substr(5); // skip "impl/"
576+
auto dot = remainder.rfind('.');
577+
ns_part = std::string(remainder.substr(0, dot));
578+
}
579+
else
580+
{
581+
ns_part = std::string(include);
582+
}
583+
std::string ns_macro = ns_part;
584+
std::replace(ns_macro.begin(), ns_macro.end(), '.', '_');
585+
586+
auto format = R"(#ifndef WINRT_MODULE_NS_%
570587
#include %winrt/%.h%
571588
#endif
572589
)";
573590

574591
write(format,
592+
ns_macro,
575593
settings.brackets ? '<' : '\"',
576594
include,
577595
settings.brackets ? '>' : '\"');

nuget/Microsoft.Windows.CppWinRT.targets

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -897,11 +897,12 @@ $(XamlMetaDataProviderPch)
897897
</ClCompile>
898898
</ItemGroup>
899899
<!-- Define WINRT_MODULE so generated component files (.g.h, .g.cpp) use
900-
import winrt; instead of #include, and so reference projection headers
901-
skip base.h (types come from the module). Cross-namespace component deps
902-
are NOT suppressed — only WINRT_IMPL_SKIP_INCLUDES (set locally in .g.h)
903-
does that. winrt.ixx defines WINRT_BUILD_MODULE in its global module
904-
fragment for its own needs. -->
900+
import winrt;. When WINRT_MODULE is defined, namespace headers include
901+
winrt_module_namespaces.h which declares per-namespace WINRT_MODULE_NS_*
902+
macros. Cross-namespace deps are guarded by these per-namespace macros,
903+
precisely skipping only namespaces in the module while including
904+
component and other non-module deps normally.
905+
winrt.ixx defines WINRT_BUILD_MODULE in its global module fragment. -->
905906
<ItemGroup>
906907
<ClCompile>
907908
<PreprocessorDefinitions>WINRT_MODULE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -972,7 +973,7 @@ $(XamlMetaDataProviderPch)
972973
</ItemGroup>
973974

974975
<!-- Define WINRT_MODULE so generated component files (.g.h, .g.cpp) use
975-
import winrt;, and so reference projection headers skip base.h. -->
976+
import winrt;, and so namespace headers use per-namespace guards. -->
976977
<ItemGroup>
977978
<ClCompile>
978979
<PreprocessorDefinitions>WINRT_MODULE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

test/nuget/TestModuleComponent/TestModuleComponentClass.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,15 @@ namespace winrt::TestModuleComponent::implementation
1313
{
1414
return winrt::make<winrt::TestModuleComponent::Widgets::implementation::Widget>(L"FromComponent");
1515
}
16+
17+
winrt::TestModuleComponent::WidgetInfo TestModuleComponentClass::GetWidgetInfo()
18+
{
19+
auto widget = CreateWidget();
20+
return { widget.Size(), L"A test widget" };
21+
}
22+
23+
winrt::Windows::Foundation::Uri TestModuleComponentClass::GetUri()
24+
{
25+
return winrt::Windows::Foundation::Uri(L"http://aka.ms/cppwinrt");
26+
}
1627
}

test/nuget/TestModuleComponent/TestModuleComponentClass.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ namespace winrt::TestModuleComponent::implementation
88
TestModuleComponentClass() = default;
99
void Test();
1010
winrt::TestModuleComponent::Widgets::Widget CreateWidget();
11+
winrt::TestModuleComponent::WidgetInfo GetWidgetInfo();
12+
winrt::Windows::Foundation::Uri GetUri();
1113
};
1214
}
1315
namespace winrt::TestModuleComponent::factory_implementation

test/nuget/TestModuleComponent/TestModuleComponentClass.idl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@ import "TestModuleComponentWidget.idl";
22

33
namespace TestModuleComponent
44
{
5+
struct WidgetInfo
6+
{
7+
TestModuleComponent.Widgets.WidgetSize Size;
8+
String Description;
9+
};
10+
511
[default_interface]
612
runtimeclass TestModuleComponentClass
713
{
814
TestModuleComponentClass();
915
void Test();
1016
TestModuleComponent.Widgets.Widget CreateWidget();
17+
WidgetInfo GetWidgetInfo();
18+
Windows.Foundation.Uri GetUri();
1119
}
1220
}

test/nuget/TestModuleComponent/TestModuleComponentWidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace winrt::TestModuleComponent::Widgets::implementation
88
Widget() = default;
99
Widget(hstring const& name) : m_name(name) {}
1010
hstring Name() const { return m_name; }
11+
winrt::TestModuleComponent::Widgets::WidgetSize Size() const { return { 100.0f, 50.0f }; }
1112

1213
private:
1314
hstring m_name{ L"DefaultWidget" };
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
namespace TestModuleComponent.Widgets
22
{
3+
struct WidgetSize
4+
{
5+
Single Width;
6+
Single Height;
7+
};
8+
39
[default_interface]
410
runtimeclass Widget
511
{
612
Widget();
713
Widget(String name);
814
String Name{ get; };
15+
WidgetSize Size{ get; };
916
}
1017
}

0 commit comments

Comments
 (0)