[Development] Using '#pragma once' instead of include guards?
Marc Mutz
marc.mutz at qt.io
Thu Feb 29 11:02:29 CET 2024
Hi,
DL;DR: Use #pragma once in all non-installed headers
The question recently came up "what is a private header". And the answer
isn't just "_p.h, of course". We have tons of headers that are "private"
without being marked as such with _p.h and "We mean it." comment.
The first realization is that there are degrees of privateness: We have
the installed private headers, and then we have non-installed/able
headers, e.g. in plugins, or tools.
So we have
- public installed headers (subject to SC and BC, syncqt and
headerscheck runs on them)
- semi-public installed headers (like above, but not subject to SC (but
BC) (_impl.h, stuff in QtPrivate namespaces, qNN, ...)
- private installed headers (not subject to SC/BC/headersclean, but
syncqt runs on them, must have "We mean it." comment)
- private non-installed headers (not subject to any constraint, not even
syncqt runs on them)
We can now look at what signs we currently have available that guide a
reader to learn which kind of header he's looking at.
For the first, we have only location in $SRCDIR.
For the second, we have _impl.h and/or "We mean it." comment.
For the third, which is easiest to distinguish, we have _p.h and "We
mean it." comment. This is enforced by syncqt, which is why we can rely
on it 100%.
For the last one, we again have just the location in $SRCDIR.
The problem is, obviously, that the first and last cases are nearly
indistinguishable and require non-local reasoning to answer.
I think we have improve on this.
With Volker's email we gave ourselves permission to use #pragma once for
"non-SDK" (= non-installed) headers, and banned it for installed
headers. So if we could make syncqt complain if a processed (=
installable) header contains #praga once, we could then flip the coin
and use an actual #pragma once as a static assertion that the header is
not installed/able.
If we do this going forward, we can then easily distinguish the four
header kinds:
- public installed headers have a traditional header guard
- semi-public installed headers ditto, except that have _impl.h suffix
or "We mean it" comment
- private installed headers ditto, _p.h suffix and "We mean it" comment
- non-installed/able headers have #pragma once
I've implemented the check in syncqt.cpp and ported xcb over, see
https://codereview.qt-project.org/q/topic:pragma-once
I'm not suggesting to do such a port for all plugins. XCB is just a test
balloon, but we might want to apply the #pragma once trick for new code
going forward.
Thanks,
Marc
On 12.10.22 12:35, Volker Hilsheimer via Development wrote:
>
>> On 11 Oct 2022, at 22:11, Thiago Macieira <thiago.macieira at intel.com> wrote:
>>
>> On Tuesday, 11 October 2022 12:25:13 PDT Kyle Edwards via Development wrote:
>>> Speaking as co-maintainer of CMake, we have effectively required #pragma
>>> once to build CMake itself since August 2017, we officially codified
>>> this as policy in September 2020, and we will soon be writing a
>>> clang-tidy plugin to enforce this in our CI. We have not received any
>>> complaints about it. Just my $0.02.
>>
>> Thanks for the information. This confirms what we already knew that all systems
>> and compilers where Qt would be compiled do support it.
>>
>> However, neither Qt Creator nor CMake are libraries. They are not comparable.
>
>
> Thanks all for sharing your insights and digging up the previous discussions as well.
>
> The summary of all this then seems to be:
>
> - ok to use '#pragma once’ in headers that are not designed to be included by Qt users, i.e. in tools, applications, examples and demos, tests
> - for everything else, in particular for public and, for consistency’s sake - private headers in Qt, we continue to use conventional include guards
>
> Rationale: #pragma once is not well enough defined and not part of the standard, and we cannot make any assumptions about how Qt is installed, used as part of a larger SDK etc. So best to stay conservative.
>
> If that’s not entirely off, then I’d like to put this into https://wiki.qt.io/Coding_Conventions [1], preempting perhaps a new thread on this topic in a few years.
>
> Volker
>
> [1]: And since that page seems rather outdated - e.g. we do use dynamic_cast in Qt today, and the suggestion to normalize signals and slots should rather suggest to make connections via PMF syntax - perhaps it’s time to move this to a QUIP where we can discuss and review such changes in gerrit. I won’t have time to do that for a while (perhaps ditto for https://wiki.qt.io/Qt_Coding_Style), but perhaps someone else wants to give this a shot.
>
> _______________________________________________
> Development mailing list
> Development at qt-project.org
> https://lists.qt-project.org/listinfo/development
--
Marc Mutz <marc.mutz at qt.io>
Principal Software Engineer
The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io
Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B
More information about the Development
mailing list