C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Revising #pragma once

From: Tiago Freire <tmiguelf_at_[hidden]>
Date: Wed, 28 Aug 2024 05:15:06 +0000

I don't know about you but when I "#include<someheader.h>", I don't actually mean "please just give me a file named someheader.h, any file with that name will do, the contents don't actually matter, I don't really care where it comes from".
What I usually mean is "I want this header file that I know it comes from this specific library, because it serves a very specific purpose I'm interested in"
This doesn't mean that I know exactly from which path in my filesystem it will always come from, but I expect it to come from somewhere very narrowly specific.

And I have worked with complex projects with complex dependencies with files coming from very different repositories and with very different relative paths depending on how you build it.
The first thing your build needs to do is curate the project selection, once you have selected all the specific versions of your dependencies, the build should be fully determined. And I don't mean where on your filesystems the files are, I mean when I do an include I know exactly which file you mean, that usually means in practice putting files in a filesystem but it doesn't have to be. Paths may usually be floating, but I expect the information of where my libraries are located to be fed to the build system so that in turn it can tell the compiler where to find it when the include directive is hit.

The only situation where just looking at the file path is not sufficient to resolve a pragma once but an include guard would save you the following must be true:
* An include A is indirectly trying to include itself through a different header, or file B indirectly includes A multiple times trough different headers
* There are different paths to get to A
* There are multiple definitions of paths to get to A and different headers can't resolve the same.

If 2 paths are being resolved for the same header, how would you even know it's the same thing? If you had multiple versions of the same library being used by different modules on the same build environment, I could understand that it would be hard to manage, either that environment is even coherent is a different story. But we are not talking about different files being used for different modules in the same build, we are talking about multiple paths in the exact same translation unit!
This is a code smell. It has poor hygiene.

Resolving symbolic or hard links? Looking at file times?Hashing? Why? Totally overkill. How did you end up not being able to resolve the same file canonically in the same translation unit?
That's the problem.
If you need those things to save you, your build is already borked either you realize it or not.

It ain't the pragma once or include guard that is the problem at that point.

And I also get your point, I've worked with such borked projects before. The best you can hope for is that your setup somehow works, and this seems to do it, and nobody is going to take that away from you. But I wouldn't recommend it as a practice.
I call it having good build hygiene, and a lot of companies struggle with that. It's not for everybody, but I have solved that problem with what I have worked with, and so did a lot of other people.


________________________________
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of Ville Voutilainen via Std-Proposals <std-proposals_at_[hidden]>
Sent: Wednesday, August 28, 2024 2:12:01 AM
To: std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Cc: Ville Voutilainen <ville.voutilainen_at_[hidden]>
Subject: Re: [std-proposals] Revising #pragma once

On Wed, 28 Aug 2024 at 02:54, Arthur O'Dwyer via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> On Tue, Aug 27, 2024 at 6:27 PM Henry Miller via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>>
>> On Tue, Aug 27, 2024, at 15:36, Ville Voutilainen via Std-Proposals wrote:
>> > On Tue, 27 Aug 2024 at 23:29, Tiago Freire via Std-Proposals
>> > <std-proposals_at_[hidden]> wrote:
>> >>
>> >> It's a clear-cut case of a feature that industry pretty much converged on, and the standard lagged behind.
>> >
>> > The industry refuses to use it because it doesn't work.
>> >
>> > Depending on the definition of "the industry" through a particular lens.
>>
>> Large portions of the industry uses it and find it works great in practice. Large portions of the industry refuse to use it, because there are significant edge cases where it doesn't work.
>>
>> I take the above facts as evidence that we should put something like #pragma once in the standard, but only if we either make it work in all cases; or understand and mitigate the edge cases. There are many options with trade offs. Some of the proposed mitigations I'm fine with, but others I'm not. [...]
>
>
> Here's a thought.
> My experience matches Tiago's: #pragma once Just Works, in every environment I have access to.
> But Gašper has said that his experience, in his environment, is different: #pragma once doesn't Just Work there. That is, to be precise, GCC handles the `#pragma once` syntax differently from how customers on that particular environment want it to be handled.
>
> It might be actually, practically useful, if someone with access to an environment like Gašper's, and GCC-hacking experience, would combine these to produce a compiler switch — something like `gcc -fpragma-once-hash-based`, or `-fpragma-once-timestamp-based`, or `-fpragma-once-something-else` — so that we could see what they are actually asking for. And then the GCC maintainers could consider whether to adopt an opt-in command-line switch like that. Then the few people in environments that require it, would put the switch into their build scripts, and then they could switch over to using `#pragma once` even in their environment.
>
> Right now I'm just seeing (a few) people saying "GCC's handling of #pragma once Doesn't Work for my environment," but with no concrete suggestions for how GCC ought to handle `#pragma once` in their environment.

Well, we don't have such suggestions. We don't know whether they
exist. Or, to phrase it differently, based on what we know, they
don't.
We are looking at a situation where you include the same header
multiple times via different paths, but those paths involve bind or
overlay mounts, and then the paths are different, the inodes are
different, mtimes may be
slightly different, and a #pragma once fails to recognize that we are
looking at a header that's already been seen. You can then fall back
on
content hashing if you like, but that's much slower than parsing an
include guard and skipping the file.

In other words, the quick and efficient "is it the same file?" checks
don't work, and the fallback that can give the correct answer is
prohibitively
expensive.

The solution to the problem is the use of include guards, and
avoidance of #pragma once.

So, the response to your request to implement what such users need is
that no implementation of #pragma once can do that because all data
that
it can look at is fallible and causes false negatives for the "is it
the same file?" checks. What is needed is an additional bit of
information, and that information
is an identifier for the header that is unique and not subject to such
fallibility. That identifier is what is used for an include guard.

Glad we sorted this out.
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-08-28 05:15:11