Skip to content

path: appending local paths to external paths#14278

Draft
Alizter wants to merge 2 commits intoocaml:mainfrom
Alizter:push-muxxuvplzrzn
Draft

path: appending local paths to external paths#14278
Alizter wants to merge 2 commits intoocaml:mainfrom
Alizter:push-muxxuvplzrzn

Conversation

@Alizter
Copy link
Copy Markdown
Collaborator

@Alizter Alizter commented Apr 21, 2026

Rather than using Filename.concat we use / as a directory separator on all platforms for paths that we construct. We already do this for local paths, so appending to external paths shouldn't be any different. This makes path behaviour homogeneous across platforms.

Importantly on Windows something like:

C:\foo\bar + ./baz/zaz

used to be

C:\foo\bar\./baz/zaz

and is now

C:\foo\bar/baz/zaz

Notice that the prefix is untouched, since we don't control it. When scrubbing prefixes with BUILD_PATH_PREFIX_MAP this will mean that $PREFIX/baz/zaz will be the same on all platforms. That will be addressed in a later PR.

We do however touch the prefix if it ends in a trailing directory separator. Before appending we make sure that this separator is stripped if it exists.

Addresses parts of

@Alizter Alizter added the windows Issues that relate to Dune on Microsoft Windows label Apr 21, 2026
@Alizter Alizter force-pushed the push-muxxuvplzrzn branch 3 times, most recently from c34687c to 9718e45 Compare April 21, 2026 11:10
Alizter added a commit that referenced this pull request Apr 21, 2026
More test cases documenting quirky path behaviour when working on
#14278.
@Alizter Alizter force-pushed the push-muxxuvplzrzn branch from 9718e45 to 86f5da9 Compare April 21, 2026 18:32
@Alizter Alizter marked this pull request as ready for review April 21, 2026 18:32
@Alizter Alizter requested a review from Copilot April 21, 2026 18:32
@Alizter Alizter requested a review from rgrinberg April 21, 2026 18:33
@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 21, 2026

@nojb You may also be interested in having a look since this relates to path constructions on Windows.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes path concatenation for external paths consistent across platforms by always using / when appending relative/local path fragments, and by normalizing away ./ and trailing separators in common cases.

Changes:

  • Update Path_external.relative to join with / and strip leading ./ plus a trailing separator on the base path.
  • Update stdune expect-tests and blackbox tests to reflect the new normalized output.
  • Add a changelog entry documenting the behavior change.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
otherlibs/stdune/src/path_external.ml Changes external path appending logic to normalize ./ and use / separators.
otherlibs/stdune/test/path_tests.ml Updates expect-tests for external-relative normalization (./ removal and trailing slash handling).
otherlibs/stdune/test/path_external_build_tests.ml Updates expectations to be platform-homogeneous for absolute filename/reach outputs.
test/blackbox-tests/test-cases/optional-executable.t Adjusts expected printed binary paths to remove ./ segment.
doc/changes/fixed/14278.md Documents the fix in the changelog.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread otherlibs/stdune/src/path_external.ml
Comment thread otherlibs/stdune/src/path_external.ml
@rgrinberg
Copy link
Copy Markdown
Member

The PR says this is a fix, but what's the bug? That we use a different separate on windows?

@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 21, 2026

The PR says this is a fix, but what's the bug? That we use a different separate on windows?

That and /foo/ + ./bar becoming /foo/./bar.

@rgrinberg
Copy link
Copy Markdown
Member

Is that a problem?

@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 21, 2026

Both choices of separator are arbitrary so strictly speaking we are not fixing anything. What we are doing however is choosing the more convenient option for dune. When BUILD_PATH_PREFIX_MAP works I would like:

  $ realdir foo
  $TESTCASE_ROOT/foo

rather than having two cases for Windows and otherwise.

@Alizter Alizter changed the title fix(path): appending local paths to external paths refactor(path): appending local paths to external paths Apr 21, 2026
@Alizter Alizter force-pushed the push-muxxuvplzrzn branch from 86f5da9 to f879433 Compare April 21, 2026 22:10
@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 21, 2026

I've updated the PR title and commit message to say refactor now.

@rgrinberg
Copy link
Copy Markdown
Member

Let's wait for @nojb or @dra27 to look this over.I don't know enough about windows to know whether this change is OK.

@Alizter Alizter marked this pull request as draft April 22, 2026 13:17
@Leonidas-from-XIV Leonidas-from-XIV requested review from dra27 and nojb April 23, 2026 08:18
Copy link
Copy Markdown
Collaborator

@nojb nojb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not tested, but LGTM from a distance.

Of course, the logic remains a heuristic: if y starts with ././foo, we are still left with unnecessary components in the path, but if this behaviour matches between Windows and Unix, then that's already an improvement.

let len = String.length x in
if len > 0 && is_dir_sep x.[len - 1] then String.take x (len - 1) else x
in
x ^ "/" ^ y)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure about this suggestion, but I always wonder if it isn't better (potentially less allocation) to use String.concat here:

Suggested change
x ^ "/" ^ y)
String.concat ~sep:"/" [x; y])

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems better thanks.

@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 23, 2026

This remains a draft until I can work out what is going wrong with promotion on Windows. It seems the entries haven't been added to the promotion database correctly.

@Alizter Alizter changed the title refactor(path): appending local paths to external paths path: appending local paths to external paths Apr 23, 2026
Rather than using `Filename.concat` we use `/` as a directory separator on all
platforms for paths that we construct. We already do this for local paths, so
appending to external paths shouldn't be any different. This makes path
behaviour homogeneous across platforms.

Importantly on Windows something like:

  C:\foo\bar + ./baz/zaz

used to be

  C:\foo\bar\./baz/zaz

and is now

  C:\foo\bar/baz/zaz

Notice that the prefix is untouched, since we don't control it. When scrubbing
prefixes with `BUILD_PATH_PREFIX_MAP` this will mean that `$PREFIX/baz/zaz`
will be the same on all platforms. That will be addressed in a later PR.

We do however touch the prefix if it ends in a trailing directory separator.
Before appending we make sure that this separator is stripped if it exists.

The motivation is that both choices of separator are arbitrary, so strictly
speaking we are not fixing a bug. What we are doing however is choosing the
more convenient option for dune. When `BUILD_PATH_PREFIX_MAP` works we would
like scrubbed paths like `$TESTCASE_ROOT/foo` to be the same on all platforms,
rather than having two cases for Windows and otherwise.

Addresses parts of ocaml#10176

Signed-off-by: Ali Caglayan <alizter@gmail.com>
@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 23, 2026

Fun! So Windows' CreateProcessW accepts forward slashes in paths, but when constructing a valid path such as C:\WINDOWS\system32/cmd.exe which is what Bin.which ends up with, we get an interesting situation. There is a bug with cmd.exe so that it checks all the command arguments, including "arg[0]" for its /c flag. The /cmd.exe confuses it and it fails. This happens only with (system) on Windows.

I will add special sanitation for paths involving cmd.exe since it only affect it.

Signed-off-by: Ali Caglayan <alizter@gmail.com>
@Alizter Alizter force-pushed the push-muxxuvplzrzn branch from f879433 to 68f660f Compare April 23, 2026 11:07
@Alizter Alizter marked this pull request as ready for review April 23, 2026 11:11
@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 23, 2026

I'm still uncertain if we should be passing mixed paths to CreateProcessW even though it accepts it. Perhaps the correct thing to do would be to make sure all forward slashes are blackslashes before handing off to Spawn.

@nojb any recommendation?

@nojb
Copy link
Copy Markdown
Collaborator

nojb commented Apr 23, 2026

I'm still uncertain if we should be passing mixed paths to CreateProcessW even though it accepts it. Perhaps the correct thing to do would be to make sure all forward slashes are blackslashes before handing off to Spawn.

@nojb any recommendation?

I think this makes sense. Backslashes are the native thing on Windows, so from a distance it indeed looks like a more principled approach.

@Alizter
Copy link
Copy Markdown
Collaborator Author

Alizter commented Apr 30, 2026

TODO:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

windows Issues that relate to Dune on Microsoft Windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants