From 6df808e96ebaaf72b1c96573ec93fb6ab53efb98 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Tue, 12 Sep 2023 15:15:02 +0200 Subject: [PATCH] Update module implementation status and fix errors Fixes: #487 --- talk/expert/modules.tex | 202 ++++++++++++++++++++++------------------ 1 file changed, 112 insertions(+), 90 deletions(-) diff --git a/talk/expert/modules.tex b/talk/expert/modules.tex index 56dddd65..b3850b68 100644 --- a/talk/expert/modules.tex +++ b/talk/expert/modules.tex @@ -9,7 +9,7 @@ \begin{itemize} \item Better isolation. No cross-talk between multiple pieces of included code, and also not between included code and your code. \item Better control over public interface of your library. Avoid leaking library dependencies into user code. - \item Faster compilation + \item Faster compilation (\href{https://youtu.be/DJTEUFRslbI?si=ZRvH1wx0sVJVriLh&t=3259}{import fmt; \textgreater1500x faster}) \end{itemize} \end{itemize} \end{block} @@ -121,12 +121,12 @@ import math; import ; int main() { - Ratio r = golden(); // error (Ratio not visible) - auto r = golden(); // ok: (Ratio is reachable) - std::cout << r.num; // ok: members of reachable - // class types become visible + Ratio r = golden(); // error: Ratio not visible + auto r = golden(); // OK: Ratio is reachable + std::cout << r.num; // OK: members of reachable + // types are visible using R = decltype(r); - R r2{1.f, 3.f}; // ok + R r2{1.f, 3.f}; // OK } \end{cppcode*} \end{exampleblock} @@ -135,20 +135,24 @@ \begin{frame}[fragile] \frametitlecpp[20]{Module structure} \begin{exampleblock}{} + \small \begin{cppcode*}{gobble=2} - module; - #include // global module fragment - // ... // only preprocessor - // statements allowed - - export module math; // exported module name - - import ; // module preamble - // ... // only imports allowed - - export struct S { ... }; // module purview - export S f() { ... } // starts at first - std::string h() { ... } // non-import + module; // global module fragment (opt.) + #include // only preprocessor + // ... // statements allowed + + export module math; // module preamble starts with + // exported module name. + import ; // only imports allowed + // ... // + + export struct S { ... }; // module purview started + export S f(); // at first non-import + std::string h() { ... } + + module :private // private module fragment (opt.) + S f() { ... } // changes here trigger + // no recompilation of BMI \end{cppcode*} \end{exampleblock} \end{frame} @@ -206,10 +210,64 @@ \end{exampleblock} \end{frame} +\begin{frame}[fragile,shrink=5] + \frametitlecpp[20]{Submodules and re-exporting} + \begin{block}{} + Modules can (re-)export other modules using \cppinline{export import}: + \end{block} + \vspace{-5mm} + \begin{columns}[t] + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module one} + \begin{cppcode*}{gobble=6} + export module one; + + export struct S { ... }; + \end{cppcode*} + \end{exampleblock} + \end{column} + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module two} + \begin{cppcode*}{gobble=6} + export module two; + import ; + + export std::string b() + { ... } + \end{cppcode*} + \end{exampleblock} + \end{column} + \end{columns} + \begin{columns}[t] + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module three} + \begin{cppcode*}{gobble=6} + export module three; + import one; + export import two; + + export S f() { ... } + \end{cppcode*} + \end{exampleblock} + \end{column} + \begin{column}{.45\textwidth} + \begin{exampleblock}{Module four} + \begin{cppcode*}{gobble=6} + export module four; + import three; + // b and f visible + // S and std::string only + // reachable + \end{cppcode*} + \end{exampleblock} + \end{column} + \end{columns} +\end{frame} + \begin{frame}[fragile,shrink=5] \frametitlecpp[20]{Module partitions} \begin{block}{} - We can split a module's interface into multiple files: + We can split a module's \emph{interface} into multiple files: \end{block} \vspace{-5mm} \begin{columns}[t] @@ -248,7 +306,7 @@ \begin{frame}[fragile,shrink=5] \frametitlecpp[20]{Module implementation units} \begin{block}{} - We can split a module's implementation into multiple files: + We can split a module's \emph{implementation} into multiple files: \end{block} \begin{exampleblock}{Interface} \begin{cppcode*}{gobble=2} @@ -285,57 +343,6 @@ \end{columns} \end{frame} -\begin{frame}[fragile,shrink=5] - \frametitlecpp[20]{Submodules and re-exporting} - \begin{block}{} - Modules can (re-)export other modules: - \end{block} - \vspace{-5mm} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module base} - \begin{cppcode*}{gobble=6} - export module base; - - export struct S { ... }; - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module bar} - \begin{cppcode*}{gobble=6} - export module bar; - import ; - - export std::string b() - { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module foo} - \begin{cppcode*}{gobble=6} - export module foo; - import export module base; - import bar; - - export S f() { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module math} - \begin{cppcode*}{gobble=6} - export module math; - export import foo; - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} -\end{frame} - \begin{frame}[fragile] \frametitlecpp[23]{Standard library modules} % see: Minimal module support for the standard library http://wg21.link/P2412 @@ -343,7 +350,7 @@ \begin{itemize} \item Use \cppinline|import std;| for the entire C++ standard library. Basically everything in namespace \cppinline|std|. \begin{itemize} - \item E.g.\ \cppinline{memcpy(a, b, n);}, \cppinline{sqrt(val);}, \cppinline{uint32_t i;} will not compile. You need to prefix \cppinline{std::}. + \item E.g.\ \cppinline{memcpy(a, b, n)}, \cppinline{sqrt(val)}, \cppinline{uint32_t i} will not compile. You need to prefix \cppinline{std::}. \end{itemize} \item Use \cppinline|import std.compat;| for the entire C and C++ standard library \item No macros are exported. For these, you still need to include the corresponding headers. @@ -525,7 +532,7 @@ very thick ] \draw [-Latex](7,10) -- (7,0) node [midway,right] {t}; - \draw[thick] node at(3, 10) [fill=white,rounded rectangle] {build dependencies}; + \draw[thick] node at(3, 10) [fill=white,rounded rectangle] {scan dependencies}; \path[thick] node (vec) at(5,9) [rectangle,draw] {\textless{}vector\textgreater{}} node (vecbmi) at(4,7.5) [rectangle,draw] {vector.bmi} @@ -572,16 +579,22 @@ \item Translation units no longer independent \begin{itemize} \item Extra tool needs to infer dependency graph before building - \item This graph needs to be communicated to the build system - \item We will likely need a \href{https://wg21.link/P1689}{standard dependency file format} + \begin{itemize} + \item Called a ``dependency scanner'' + \item Needs to be communicated to the build system + \item Using a new \href{https://wg21.link/P1689}{standard dependency file format} + \end{itemize} \item Parallel and distributed builds need synchronization \end{itemize} - \item Compilation of module translation units produces binary module interface (BMI) and object file + \item Compilation of module translation units produces a binary module interface (BMI) \emph{and} an object file \begin{itemize} - \item BMIs need to be maintained/shared between multiple compiler instances + \item Need to manage BMIs between multiple compiler invocations \end{itemize} - \item Tools beside the compiler need to build/read binary module interface (static analysis, auto completion, etc.) - \item The C++ standard specifies very little on how this works + \item Tools beside the compiler need to build/read BMIs + \begin{itemize} + \item E.g. static analysis, language servers for auto completion, etc. + \end{itemize} + \item The \cpp standard specifies very little on how this works \begin{itemize} \item We may experience large implementation divergence \end{itemize} @@ -593,12 +606,16 @@ \frametitlecpp[20]{Build system} \begin{block}{Status} \begin{itemize} - \item build2 supports everything g++ does - \item MSBuild figures out dependencies and build order automatically (Windows/Visual Studio only) + \item Dependency scanner since clang 16: \texttt{clang-scan-deps} + \item Experimental module support in cmake since 3.26, uses \texttt{clang-scan-deps}, many fixes in later versions % see: https://discourse.cmake.org/t/c-20-modules-update/7330/24 and https://youtu.be/c563KgO-uf4?si=HUpnSivtDxvBoTr3&t=3592 + \item MSBuild (Windows) fully handles dependency scanning \item \cppinline{g++ a.cpp b.cpp ...} ``just works'', must be one line though - \item GCC uses a \href{https://wg21.link/P1184}{module mapper} to resolve imports, which specifies a protocol and uses a central server for module maintenance \item \href{https://wg21.link/p1602}{Experimental extensions to GNU make} exist to grow dependency graph on the fly while modules are discovered - \item No support in cmake (3.23) yet + \item Header units unsupported in all build systems (May 2023) % See talk: https://youtu.be/_LGR0U5Opdg?si=yQoCYD2yGFhi_vs6&t=3768 + \item C++23: \cppinline{import std;} supported in MSVC, partially in clang + \begin{itemize} + \item GCC/clang/MSVC also plan support in C++20 % see: https://github.com/microsoft/STL/issues/3945 + \end{itemize} \end{itemize} \end{block} \end{frame} @@ -607,7 +624,9 @@ \frametitlecpp[20]{Building modules (g++)} \begin{block}{Case study: g++} \begin{itemize} - \item By default, g++ caches compiled module interfaces (CMI, i.e.\ BMI) in subdirectory \texttt{./gcm.cache} + \item BMI is called CMI (compiled module interfaces) + \item By default, g++ caches CMIs in subdirectory \texttt{./gcm.cache} + \item Uses a \href{https://wg21.link/P1184}{module mapper} to resolve imports, which specifies a protocol and uses a central server for module maintenance \item Each module needs to be built before it can be imported \begin{itemize} \item {\footnotesize \cppinline{g++ -std=c++20 -fmodules-ts -c ratio.cpp -o ratio.o}} @@ -630,16 +649,17 @@ \begin{itemize} \item Start writing importable headers (no macro dependencies) \begin{itemize} - \item This allows dual use: \cppinline{#include} before \cpp20 and \cppinline{import} with \cpp20 + \item Dual use: \cppinline{#include} before \cpp20 and \cppinline{import} with \cpp20 \end{itemize} \item Watch progress on module support in your build system \end{itemize} \end{exampleblock} \begin{exampleblock}{Guidance for tomorrow} \begin{itemize} - \item Start importing headers when \cpp20 is available - \item Start writing modules when all users of your code have \cpp20 - \item Start using \cppinline{import std;} when \cpp23 is available + \item Start writing modules when your users have \cpp20 + \item Maybe import standard headers when \cpp20 is available + \item Start using \cppinline{import std;} when available + \item Future of header units unclear (implementation difficulties) \end{itemize} \end{exampleblock} \end{frame} @@ -647,10 +667,12 @@ \begin{frame}[fragile] \frametitlecpp[20]{Modules} \begin{block}{Resources} + \small \begin{itemize} - \item \href{https://www.youtube.com/watch?v=szHV6RdQdg8}{Practical C++ Modules - Boris Kolpackov - CppCon 2019} \item \href{https://www.youtube.com/watch?v=nP8QcvPpGeM}{A (Short) Tour of C++ Modules - Daniela Engert - CppCon 2021} (very technical) \item Understanding C++ Modules: \href{https://vector-of-bool.github.io/2019/03/10/modules-1.html}{Part1}, \href{https://vector-of-bool.github.io/2019/03/31/modules-2.html}{Part2} and \href{https://vector-of-bool.github.io/2019/10/07/modules-3.html}{Part3}. + \item \href{https://www.youtube.com/watch?v=DJTEUFRslbI}{So, You Want to Use C++ Modules … Cross-Platform? - Daniela Engert - C++ on Sea 2023} + \item \href{https://www.youtube.com/watch?v=c563KgO-uf4&t=686s}{import CMake: 2023 State of C++20 modules in CMake - Bill Hoffman - CppNow 2023} \end{itemize} \end{block} \end{frame}