[clang] [docs] [C++20] [Modules] Ideas for transitioning to modules (PR #80687)
David Blaikie via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 5 08:38:12 PST 2024
================
@@ -610,6 +610,345 @@ the following style significantly:
The key part of the tip is to reduce the duplications from the text includes.
+Ideas for converting to modules
+-------------------------------
+
+For new libraries, we encourage them to use modules completely from day one if possible.
+This will be pretty helpful to make the whole ecosystems to get ready.
+
+For many existing libraries, it may be a breaking change to refactor themselves
+into modules completely. So that many existing libraries need to provide headers and module
+interfaces for a while to not break existing users.
+Here we provide some ideas to ease the transition process for existing libraries.
+**Note that the this section is only about helping ideas instead of requirement from clang**.
+
+Let's start with the case that there is no dependency or no dependent libraries providing
+modules for your library.
+
+ABI non-breaking styles
+~~~~~~~~~~~~~~~~~~~~~~~
+
+export-using style
+^^^^^^^^^^^^^^^^^^
+
+.. code-block:: c++
+
+ module;
+ #include "header_1.h"
+ #include "header_2.h"
+ ...
+ #include "header_n.h"
+ export module your_library;
+ export namespace your_namespace {
+ using decl_1;
+ using decl_2;
+ ...
+ using decl_n;
+ }
+
+As the example shows, you need to include all the headers containing declarations needs
+to be exported and `using` such declarations in an `export` block. Then, basically,
+we're done.
+
+export extern-C++ style
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: c++
+
+ module;
+ #include "third_party/A/headers.h"
+ #include "third_party/B/headers.h"
+ ...
+ #include "third_party/Z/headers.h"
+ export module your_library;
+ #define IN_MODULE_INTERFACE
+ extern "C++" {
+ #include "header_1.h"
+ #include "header_2.h"
+ ...
+ #include "header_n.h"
+ }
+
+Then in your headers (from ``header_1.h`` to ``header_n.h``), you need to define the macro:
+
+.. code-block:: c++
+
+ #ifdef IN_MODULE_INTERFACE
+ #define EXPORT export
+ #else
+ #define EXPORT
+ #endif
+
+And you should put ``EXPORT`` to the beginning of the declarations you want to export.
+
+Also it is suggested to refactor your headers to include thirdparty headers conditionally:
+
+.. code-block:: c++
+
+ + #ifndef IN_MODULE_INTERFACE
+ #include "third_party/A/headers.h"
+ + #endif
+
+ #include "header_x.h"
+
+ ...
+
+This may be helpful to get better diagnostic messages if you forgot to update your module
+interface unit file during maintaining.
+
+The reasoning for the practice is that the declarations in the language linkage are considered
+to be attached to the global module. So the ABI of your library in the modular version
+wouldn't change.
+
+While this style looks not as convenient as the export-using style, it is easier to convert
+to other styles.
+
+ABI breaking style
+~~~~~~~~~~~~~~~~~~
+
+The term ``ABI breaking`` sounds terrifying generally. But you may want it here if you want
+to force your users to introduce your library in a consistent way. E.g., they either include
+your headers all the way or import your modules all the way.
+The style prevents the users to include your headers and import your modules at the same time
+in the same repo.
+
+The pattern for ABI breaking style is similar with export extern-C++ style.
+
+.. code-block:: c++
+
+ module;
+ #include "third_party/A/headers.h"
+ #include "third_party/B/headers.h"
+ ...
+ #include "third_party/Z/headers.h"
+ export module your_library;
+ #define IN_MODULE_INTERFACE
+ #include "header_1.h"
+ #include "header_2.h"
+ ...
+ #include "header_n.h"
+
+ #if the number of .cpp files in your project are small
+ module :private;
+ #include "source_1.cpp"
+ #include "source_2.cpp"
+ ...
+ #include "source_n.cpp"
+ #else // the number of .cpp files in your project are a lot
+ // Using all the declarations from thirdparty libraries which are
+ // used in the .cpp files.
+ namespace third_party_namespace {
+ using third_party_decl_used_in_cpp_1;
+ using third_party_decl_used_in_cpp_2;
+ ...
+ using third_party_decl_used_in_cpp_n;
+ }
+ #endif
+
+(And add `EXPORT` and conditional include to the headers as suggested in the export
+extern-C++ style section)
+
+Remember that the ABI get changed and we need to compile our source files into the
+new ABI format. This is the job of the additional part of the interface unit:
+
+.. code-block:: c++
+
+ #if the number of .cpp files in your project are small
+ module :private;
+ #include "source_1.cpp"
+ #include "source_2.cpp"
+ ...
+ #include "source_n.cpp"
+ #else // the number of .cpp files in your project are a lot
+ // Using all the declarations from thirdparty libraries which are
+ // used in the .cpp files.
+ namespace third_party_namespace {
+ using third_party_decl_used_in_cpp_1;
+ using third_party_decl_used_in_cpp_2;
+ ...
+ using third_party_decl_used_in_cpp_n;
+ }
+ #endif
+
+In case the number of your source files are small, we may put everything in the private
+module fragment directly. (it is suggested to add conditional include to the source
+files too). But it will make the compilation of the module interface unit to be slow
+when the number of the source files are not small enough.
+
+**Note that the private module fragment can only be in the primary module interface unit
+and the primary module interface unit containing private module fragment should be the only
+module unit of the corresponding module.**
+
+In that case, you need to convert your source files (.cpp files) to module implementation units:
+
+.. code-block:: c++
+
+ + #ifndef IN_MODULE_INTERFACE
+ // List all the includes here.
+ #include "third_party/A/headers.h"
+ ...
+ #include "header.h"
+ + #endif
+
+ + module your_library;
+
+ // Following off should be unchanged.
+ ...
+
+The module implementation unit will import the primary module implicitly.
+We don't include any headers in the module implementation units
+here since we want to avoid duplicated declarations between translation units.
+This is the reason why we add non-exported using declarations from the third
----------------
dwblaikie wrote:
```suggestion
This is the reason why we add non-exported using declarations from third
```
https://github.com/llvm/llvm-project/pull/80687
More information about the cfe-commits
mailing list