<div dir="ltr">(sorry for the delay, the dev meeting has been keeping me busy from sun-up to sun-down for the last two days)<br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 28, 2014 at 4:03 PM, Stephen Kelly <span dir="ltr"><<a href="mailto:steveire@gmail.com" target="_blank">steveire@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class="">Sean Silva wrote:<br>
<br>
>> I did this for Qt5Core and came up with<br>
>><br>
>>  <a href="http://www.steveire.com/Qt5Core.modulemap" target="_blank">http://www.steveire.com/Qt5Core.modulemap</a><br>
>><br>
>> What is the next step?<br>
>><br>
><br>
> It depends on what your goals are.<br>
<br>
</span>My goal is to gain experience with clang modules for C++, and possibly to be<br>
able to communicate the principles behind the design of them, the gotchas,<br>
the limitations, the requirements and the benefits. I'm learning what I'd<br>
need to know to write useful blogs of give a useful talk at a conference or<br>
meetup.<br>
<br>
So, that's why I want to get from 'this file I hacked together does not<br>
cause explosions' to 'Here are the other things you can put in a modulemap<br>
file and why you would want to'.<br></blockquote><div><br></div><div>Great question. Right now, I can think of two really useful things that clang's functionality will give you:</div><div><br></div><div>1. A possibly very significant build time speedup. You will be getting >90% of the benefit in this regard once your build "works" with modules and all the time-consuming headers end up in one of your module maps (I'll explain this a bit more below; there are many ways for it to "work"). For example, if 40% of your build time is spent parsing the QtCore headers, say 500 times total across a 700 file build, then you will end up with pretty much a 40% build time improvement (modulo Amdahl with the linker).</div><div><br></div><div>2. A way to check certain aspects of "modularity" of your headers. If you want to track down recursive dependencies, then put each header in it's own *top-level* module. If you want to verify that code that imports your headers is only relying on the thing that your header is explicitly meant to export, then you can replace `export *` with a whitelist of explicit exports.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<span class=""><br>
> Once I got an initial module map<br>
> working, the first thing I did was to analyze build time. If you are on<br>
> Mac, then the attached patch to clang and the attached DTrace script could<br>
> prove useful.<br>
<br>
</span>Cool, thanks. I'll try this at some point too for sure.<br>
<span class=""><br>
> The "toss them all in a single top-level module" approach causes *all* the<br>
> headers to be included if any of them is included.<br>
<br>
</span>Ah! Wow, that's certainly slide-worthy. So<br>
<br>
 #include <QtCore/QString><br>
<br>
 int main(int, char **)<br>
 {<br>
   QString s;<br>
   QObject o;<br>
   QStringListModel m;<br>
   return 0;<br>
 }<br>
<br>
compiles with -fmodules but not without it.<br></blockquote><div><br></div><div>Perfect slide-sized example!</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
That's weird at least.<br>
<span class=""><br>
> The `export *` just means "export declarations from any modules I depend<br>
> on", which is what you almost always want at the moment since that matches<br>
> textual inclusion semantics. I.e. if someone was including "QSubclass" and<br>
> relying on that include to bring in "QBaseclass" (or a system header or<br>
> whatever).<br>
<br>
</span>... ie<br>
<br>
 #include <QWidget><br>
<br>
 int main(int, char **)<br>
 {<br>
   QObject o;<br>
   return 0;<br>
 }<br>
<br>
compiles without -fmodules and fails with it, until I add export *.<br></blockquote><div><br></div><div>Another great slide-sized example!</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
I'll add that to my qmake patch for generating the modules for now. In that<br>
patch I can be more-exact though about what to export (qmake knows which<br>
modules are dependencies). Is there any advantage to doing that? Although I<br>
can think of a case in the QtSql module I'd have to examine for a breakage<br>
case (QSqlRelationalDelegate includes QtWidget classes, but qmake may not<br>
consider that a module-dependency).<br>
<span class=""><br>
>> I *could* include qatomic_x86.h to the modulemap, but that header is not<br>
>> designed for users to include. Users include qatomic.h instead, which<br>
>> includes the appropriate _foo header.<br>
>><br>
><br>
> This will break if multiple headers in the module map end up including<br>
> qatomic.h (whichever one comes first will include the declarations of<br>
> qatomic.h). If qatomic.h is only included from a single header in the<br>
> module map you should be fine though.<br>
<br>
</span>It is included by multiple headers. I don't understand the problem though<br>
you're bringing up though. All TUs are expected to use the same<br>
qatomic_foo.h.<br>
<br>
What is the breakage case you're warning against?<br></blockquote><div><br></div><div>The easiest way to explain this is to explain the present implementation.</div><div><br></div><div>One thing you should know at the outset is that clang generates one serialized AST file in the modules cache path for every *top-level* module and for every "configuration" (think about this as sets of compiler flags that could cause different behavior; e.g. -fno-rtti).</div><div><br></div><div>Building an AST file for a top-level module is done as follows:</div><div>1. Create a "unity build" of all the headers mentioned in this top-level module (including all submodules). Clang literally creates an in-memory file called `<module-includes>` that just does a #include of every one of the headers mentioned in the top-level module.</div><div>2. Clang parses this header and then generates a serialized AST file.</div><div><br></div><div>Now, how does clang distinguish submodules? Well, it basically does it by using the source location to include only those headers for the submodule that contains the `header` declaration. Every header mentioned in the module map essentially contributes all of the declarations within it or included by it. However, everything *not* mentioned in the module map ends up being textually included by one of the headers in the module map, and all of its declarations are "owned" by the corresponding header. Due to include guards, basically this means there is a "first one wins" situation, where during this "header unity build", whichever file includes a non-mentioned header ends up "owning" all of the declarations.</div><div><br></div><div>So basically, suppose you have:</div><div><br></div><div>module TopLevel {</div><div>  module QFoo {</div><div>    header "QFoo"</div><div>    export *</div><div>  }</div><div>  module QBar {</div><div>    header "QBar"</div><div>    export *</div><div>  }</div><div>}</div><div><br></div><div>Say both the header "QFoo" and the header "QBar" end up including `qatomic.h`. Then Clang's "unity build" will see:</div><div><br></div><div>#include <QFoo></div><div>#include <QBar></div><div><br></div><div>And clang's parsing will go something like this:</div><div><br></div><div>enter QFoo</div><div>include qatomic.h</div><div>exit QFoo</div><div>enter QBar</div><div>skip including qatomic.h due to header guard.</div><div>exit QBar</div><div><br></div><div>So now, if someone does</div><div>#include <QFoo></div><div> they will see qatomic.h, but if they do<br></div><div>#include <QBar></div><div>they will not see qatomic.h, since nothing about qatomic.h was present within the #include of QBar during the "header unity build". If qatomic.h is mentioned in a module map, then clang will make a note to itself when it sees those includes and so they will be properly exported.</div><div><br></div><div>Missing files in the module map can also cause some very cryptic errors like the following:</div><div>foo.h:10 error: redeclaration of Foo</div><div>foo.h:10 note: previous declaration here</div><div>This basically means that a non-mentioned header is being entered through two different inclusion paths (if it is mentioned in a module map, then it will only be entered once when building the module). To debug this, there is a secret clang flag `-fdiagnostics-show-note-include-stack` that will show you the inclusion path on the note. The inclusion stack that starts with the `<module-includes>` file is from the module and is as expected; you will need to place at least one of the headers in the other inclusion stack into a module map so that it gets turned into a module import. This may be able to happen between two modules (i.e. both inclusion stacks start from `<module-includes>` (but they are different top-level modules)).</div><div><br></div><div>Hope that helps. Keep the questions coming!</div><div><br></div><div>-- Sean Silva</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class=""><div class="h5"><br>
Thanks,<br>
<br>
Steve.<br>
<br>
<br>
_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@cs.uiuc.edu">cfe-dev@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev</a><br>
</div></div></blockquote></div><br></div></div>