Fix includes normalize win32#2552
Conversation
|
Have you created a bug report for Microsoft? I think we should try to avoid working around bugs in Windows as much as possible, so that the underlying issue can be fixed and everyone benefits. |
0d08963 to
0e706ed
Compare
|
So I actually tried to file a bug, which requires registering a Microsoft account (don't have one, don't want one), and from what I can gather on various Internet comments, essentially goes into a /dev/null bucket most of the time. Even if they fixed this, existing Vista / Windows 10 / whatever installs would never get the fix, so I think we'll have to just work-around this here. |
|
I think someone who wants to keep this moving probably has an account and could do it for us. Until then let's merge the |
|
@jhasse After reading the Maximum File Path Limitation documentation again from my understanding this section states that only the *W functions don't have any MAX_PATH limitations, which is in line with @digit-google observation that GetFullPathNameA() fails for long paths even when the system option is set in the registry and during build. Therefore I don't understand how working with GetFullPathNameA() can fix the problem. Thanks to the both of you for looking into this. |
|
The fact that only the W versions don't have the MAX_PATH limitation is a bug on Microsoft's side which I don't want to work around. |
|
@jhasse While I agree with you about this being a bug on Microsoft's side (I would say the whole existence of a MAX_PATH in 2025 is a bug), i strongly doubt that this is something they will likely fix. The implications of such a change could be quite big from Microsoft's perspective, because potentially people will depend on the current (documented) behavior. Just to clarify:
Thank you. |
|
It's even crazier than that:
I would not be surprised if a bug filed for this "issue" would be closed as "working as intended". We can try, but I don't have high hopes it will work. |
Well, not for the normalization of long paths at least. There is a subset of features where we support long paths already.
No, if someone builds from source anyway, they can checkout one of the PRs that use the *W function.
That depends on Microsoft's answer.
The best thing to make them not break it, is to rely on it ;)
We're using A functions for UTF-8, not for long path support. |
|
As a data point, I managed to build a large Qt codebase that previously failed to compile because of moc-generated long relative include paths; it works with the ninja from this branch. |
|
@jhasse To also reflect on the discussion above: from its inception, long path support was documented to only be supported with the |
|
The fact that Microsoft documented their bug does not make it not a bug. |
|
@jhasse On the other hand (and I say this with no malice), your judgement does not make it a bug. It is not documented as a bug, there is simply a list of functions on MSDN that support long paths if the setting is enabled in the registry and the application manifest, and they happen to be the Whether or not it is a bug, boils down to what the intention of Microsoft was while introducing long paths. It is a valid choice to only add a new feature to the |
|
Well, I disagree. |
|
I filed a bug a report: https://aka.ms/AAvdklt (unfortunately there is no way to view it in a browser, it will try to open the awful Feedback Hub app on desktop). I'll update this thread if I get any kind of feedback.
|
|
No reaction after a month from Microsoft. |
|
This behavior is intentional on Microsoft's part, for backward compat reasons (the same reason why the A/W split was introduced alongside macros mapping to one or the other to begin with). Their assumption is that the only apps using the A versions are older apps, for whom the APIs must not change behavior, even for arguable "bugfix" reasons. So this will never be implemented in the A versions. From Chromium's perspective, we no longer care, since we no longer build with ninja. However, as a neutral third party, this is something where ninja should change its behavior (to use the W versions, not because it wants UCS-2 or because it wants this bug fix per se, but because that is what "apps which support more modern conventions such as Unicode and long paths" are assumed to use). |
Even the A versions absolutely change behavior, that's what manifests are for. UCS-2 was a mistake and that's why the A API is the future (with the introduction of UTF-8). It's true that there was a time where the programming community thought that wide charsets are more modern but that has definitely shifted in recent years. |
|
In theory, yes, Microsoft could have made these changes to the A APIs under the manifest gating. But in practice that's not how these specific APIs work. The A ones do not change at all, and the W ones change under manifest gates. I consider this overly cautious, and I understand where you're coming from in principle. It is certainly how some of their APIs work, after all. But it is what it is. I could be missing something about how AppCompat and future planned registry tweaks affect this that makes Microsoft's behavior sane; either way, i think the future is not the A APIs (which are often not so much UTF-8 as ASCII or 1252, but it varies by function), but something entirely different. Until then, the change here seems like the best course to me. |
0e706ed to
864c812
Compare
|
(See also https://learn.microsoft.com/en-us/windows/win32/intl/conventions-for-function-prototypes, especially the highlighted note: "New Windows applications should use Unicode...They should be written with generic functions, and should define UNICODE to compile the functions into Unicode functions." The "A" versions are for ANSI, i.e. the old Windows code pages, and may have arbitrary functional gaps; they most definitely do not guarantee UTF-8 input/output will always work.) |
|
Of course Microsoft wants to shift the blame on the developers instead of fixing their shit. As I have said here and in other issues/PRs: It's a bug on Microsoft's side which I don't want to work-around. |
|
Shrug; you can believe what you want. They have stated reasons, they don't consider it buggy but a principled compromise, they believe changing this is worse than not changing it. Regardless of the truth of their position, the only practical impact refusing to accept the PR here has at this point is that ninja is unusable for certain users and projects, punishing users for something they didn't cause and can't control. As I said, I don't personally care. Chromium has ditched ninja and now Valve has too, so it doesn't affect me. Cheers, |
|
How come long paths issue is not fixed? I remember seeing a manifest embedded in the executable in one of the latest releases of ninja (1.12.1). |
|
@mummynobbit you are commenting on the exact issue that needs fixing. I personally encountered this when building a large-ish Qt project. @jhasse I would argue that the question of this being a bug on Microsoft's end or not is completely orthogonal to the issue. Currently this bug is present on this platform and there is a valid, documented fix for it. ninja is broken without the fix. I can see in the repo history that you are willing to merge workarounds for compatibility with other external software, so why not Windows? (even though I disagree with calling this a workaround, but whatever, let's call it that). It seems like you are letting whatever feelings you may have towards this platform or Microsoft cloud your judgement. And I'm saying this as someone who has strong feelings and opinions regarding Microsoft, Windows and their role in our society. That doesn't change the fact that they exist and widely used, so we need to live with them. |
|
@jhasse Is some other fix for Windows builder without this PR fix? |
The flag in the manifest only results in some of Microsoft's APIs to support long paths. This results in some cases being fixed, but other still not working.
We don't know, the bug reports haven't been a lot more detailed than "works" or "doesn't work".
Sorry, what do you mean? |
|
I agree with @pkasting and others here that. Independently from what you may think about Microsoft and the decisions they've made, they have been consistent about documenting that only the W functions are compatible with long path support, and that applications should be modified to drop usage of the A functions for this. The fact that some, but not all, A functions do work when the manifest includes the right attribute cannot even be relied upon. In theory, though unlikely, it could break in any future Windows update. Plus the A functions that do not work, as shown in this PR, and which already create issues. In other words, Ninja should use the documented and supported way to support long paths. Moreover, the current, incomplete, state of long path support leads to situations where failures are confusing to developers, and not easily reproducible between different setups. @jhasse, can you reconsider your position for the benefit of Ninja users on Windows and, to be frank, the sanity of Ninja maintainers (you included) since this issue pops up frequently in the issue tracker? |
|
Yes. The discussion drifted a bit away from this PR on to the general issue, let's focus again. Would it be possible to add a test for this? Also if you would create a PR with the (I also think that putting <> includes over "" includes is completely wrong, did clang-format do this?) |
Actually, the tests were changed to check the new behavior (but I failed to update the comments in them, so this wasn't obvious, I'll fix it).
I assume you mean just removing the use of fixed-size buffers, right? Yes I can, but the function will still fail due to the GetFullPathNameA() failure. Please confirm if this is what you really want (I see little benefit in this).
Indeed, this is what |
Do not use fixed-size buffers in order to better support long file paths. This does *not* get rid of the failure described at [1], because GetFullPathNameA() will fail with long paths, even when the feature is enabled in the application's manifest. Insteead, using GetFullPathNameW() is required to completely fix this issue. [1] ninja-build#2442 (comment)
These will be used by functions that need to use Unicode Win32 APIS, like GetFullPathNameW() which supports long paths, instead of GetFullPathNameA() which does not, even when long paths are enabled on the system!
Use GetFullPathNameW() instead of GetFullPathNameA() to ensure that normalization works for all long paths on Windows. Adjust unit tests accordingly. Fixes ninja-build#2442
864c812 to
842fca0
Compare
|
I have refactored the PR into four commits for clarity:
Both adjust the unit-tests accordingly. |
|
@digit-google hi, i tried your ninja (1.14.0.git) and my build always end with full rebuild "warning: premature end of file; recovering" |
That means your Maybe what you are seeing is incidental, what happens if you remove the |
|
@digit-google It's clear build, builds commands are: # fresh repo/dir
# ...
ninja -C out/x64 electron
# ... full build
# ... done
ninja -C out/x64 electron:electron_dist_zip
# ninja: warning: premature end of file; recovering
# ... full build again |
|
That doesn't seem related to this PR at all, why are you asking this here? Also what do you mean exactly by "your ninja" here? If you are talking about the tip-of-tree of github.com/ninja-build/ninja, then please file a different Github issue with reproduction steps to carry the conversation there. If you are talking about the Fuchsia Ninja program instead, report that through the Fuchsia public tracker instead. Please do not pollute upstream issues with unrelated content. |
|
I only say, that ninja v1.31.1 works properly, but "1.14.0.git" from |
|
Thanks for the clarification. In that case what about 1.14.0.git tip-of-tree (i.e. without the |
|
I tried 1.14.0 from master, and I think, that works properly. |
|
I can confirm that a Ninja compiled from this branch was able to build our CMake code base on Windows 11, which consists of over 6,000 steps, including various third-party tools such as Qt, protobuf/gRPC, ActiveX, etc. @jhasse Are more changes required? We would be very happy to see this in an offical release. |
|
@jhasse ping |
|
Do I understand it correctly that @panther7 found a regression? |
|
Sorry for the long answer.
This is unclear, @panther7 , can you clarify exactly what you are seeing? As I wrote previously, it looks like you are trigerring another Ninja bug that may be unrelated to this PR. Exact repro steps would thus be very welcomed here. |
|
I am also facing this issue, don't know if its another Ninja bug |
unsigned checksum = *reinterpret_cast<unsigned*>(buf + size - 4);
int expected_id = ~checksum;
int id = static_cast<int>(nodes_.size());
if (id != expected_id || node->id() >= 0) {
read_failed = true;
break;
}anything wrong with this? I found |
I am verfied the issue is triggered this MR, I redo this mr at #2723, and now it's fine |

Remove the use of fixed-size buffers in
src/includes_normalize-win32.ccin order to support long file paths.This also requires using GetFullPathNameW() as, surprisingly, GetFullPathNameA() would fail with long paths even when long paths are enabled on the host system running the tests.
To achieve this, introduce ConvertWin32UnicodeToUTF8() and ConvertUTF8ToWin32Unicode() functions to perform conversions properly in
src/util.cc.