roxk / idlgen

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Need to include namespace, `BlankPage`, `IBlankPage`, `IBlankPageProtected` etc possible self-referencing projection types when replacing `.g.h` for clean build

roxk opened this issue · comments

commented

Namespace can be grabbed by regex. Make it support only 1 namespace per file is a good default.

commented

Encountered an issue in test data which in essence is the same problem as #71: creating dummy projection types would produce redefinition error if the header include other implementation type. Those implementation type headers are still referencing .g.h, which includes all those existing types in the projection. Don't even need that. Just #include <winrt/$RootNamespace.h> should be enough to trigger this issue.

In theory, since during bootstrap midl content would be replaced with a dummy namespace, in a clean build this issues shouldn't exist. But a long term solution is to duplicate cppwinrt's work and generate a single header which include all these types...It seems forking cppwinrt to add a generation mode without class body is easier?

...Modifying cppwinrt only fixes definition removal issue. Adding runtime class in header file requires a pure idlgen solution as the core issue is idlgen needs both bootstrapped projection and fake projection, and currently there is not a complete model in how these two could be mixed.

For starters, projection isn't guarded per class so using ifdef to prevent redefinition is impossible. But it seems to indicate this problem is similar to header inclusion problem.

commented

Tested in sample app, generating fake projected types is indeed OK. But also encountered another systematic issues where authored enum etc don't have their projected types generated yet.

A complete solution likely involve:

  1. For all in-project component types, generate fake-projected types in .idlgen.h during bootstrap
  2. For library types, keep using CppWinRTMake(Static|Ref)Projection (just skip component projection)
  3. Since idlgen cannot easily modify included headers' .g.h, replacing actual content of all existing .g.h during bootstrap
  4. After IdlgenCppGenerateIDL, replace .g.h to the original content

Conceptually, this is just extending what idlgen currently does to a single file in memory, to all files in a pre-pass in .idlgen.h.

  • Make StripImplementationProjectionFromHeader an action triggered via a cli option --generate-fake-projection so that idlgen can generate .idlgen.h
  • Generate idlgen.h during bootstrap
    • test
    • nuget
  • add build task to rename .g.h (if any) to .g.h.bak, and .idlgen.h to g.h
    • test
    • nuget
  • add post-generate build task to rename .g.h back
    • test
    • nuget
  • Recognize authored types in idlgen.h
    • enum
    • interface
    • struct
    • delegate

...another solution is to fork clang to add the ability to keep parsing (and saves the names as if its forward declaration) even when it sees unrecognized entities.

commented
  1. Should just create $(IntDir)idlgen/Generated Files and put everything there and pass this dir to idlgen when generating IDL instead of renaming back and forth.
  2. Just like cppwinrt works by (a) midl -> mdmerge, we work by generating (Class|Enum|other).g.h for both projected and impl types -> merge in $RootNamespace.h for projected types
commented

Even better, we could generate fake projection by generating initial idl, and rely on cppwinrt to generate the projection. The problem of modifying the projection thus becomes a problem of modifying idl. This also eliminates the problem of mixing real projection and fake projection - there is simply no fake projection anymore. We only have bootstrapping idl.

We still have --gen-fake-projection option, but it

  1. would be renamed to --gen-bootstrap-idl
  2. supersede IdlgenCppGenerateBootstrap supercede IdlgenCppClearMidl
  3. generates midl entites with empty body (e.g. runtime class definition without any properties/methods/events)
commented

Encountered the following limitation:

  1. IProtected and IStatics cannot be generated, and any attempt to generate them would reproduce definition removal issue. Workaround is to declare protected member with [[idlgen::protected]]
  2. Projected types have to be treated like incomplete type - they cannot be referenced directly in header. Any existing members are just dummy. It's kind of fine as WinRT properties/methods cannot be inlined anyways (from a projection. This is indeed a limitation if devs can access the implementation type).
  3. Xaml generated header *.xaml.g.h isn't generated

Almost there. Almost there...

commented

Good news is defining multiple class in the same header indeed just works™️ (provided that you included all the boilerplate of factory impl, include .g.cpp, etc).

So if I found the build task for generating xaml.g.h and add that as dependency before IdlgenCppGenerateIDL, we should be all set. I wonder if vanilla XAML project works here?

commented

So the target to generate .xaml.g.h etc is actually MarkupCompilePass1, adding that target to generate xaml.g.h and clean build for sample-app is fixed 🎉

...But then I encountered the same "building from cli doesn't work" issue 🤦 Already using VS 2022 dev shell. Investigating...