Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate correct relative paths from fsatrace output. #656

Merged
merged 1 commit into from
Mar 17, 2019

Conversation

DavidEichmann
Copy link
Contributor

I've adding this PR in relation to GHC trac issue 16400.

@@ -145,7 +145,8 @@ commandExplicit funcName oopts results exe args = do
shelled = runShell (unwords $ exe : args)

ignore = map (?==) shakeLintIgnore
ham cwd xs = [makeRelative cwd x | x <- map toStandard xs
ham cwd xs = liftIO $ sequence [fromMaybe x <$> makeRelativeEx cwd x
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm concerned with performance here. Thoughts?

Copy link
Owner

Choose a reason for hiding this comment

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

We only call this after spawning a process. Hard to do much that has a performance impact relative to that.

@@ -145,7 +145,8 @@ commandExplicit funcName oopts results exe args = do
shelled = runShell (unwords $ exe : args)

ignore = map (?==) shakeLintIgnore
ham cwd xs = [makeRelative cwd x | x <- map toStandard xs
ham cwd xs = liftIO $ sequence [fromMaybe x <$> makeRelativeEx cwd x
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What does ham actually mean?
There is an underlying assumption here that track uses relative paths as keys. Is that correct? It's troubling to me that there may be many ways to refer to the same file (relative, absolute, via different symlinks or indirections), yet there doesn't seem to be any mechanism to enforce a canonical usage.

@ndmitchell
Copy link
Owner

Thanks for the patch. Can you explain the output you get before this patch? e.g. when running you see XXX, and we're relative to YYY, and you hoped to make it ZZZ but it failed? We should generally in Shake be referring to things by relative paths. If you have symlinks, you are going to have problems with build systems. If you use absolute paths its much harder to be portable for features like cloud shake. Relative paths everywhere solves these problems nicely.

@DavidEichmann
Copy link
Contributor Author

I've added a bit of documentation to the commit message and the makeRelativeEx function. To summarize: fsatrace gives absolute paths and makeRelative fails to convert to a relative path. Hence shake marks e.g. "/root/a/file.out" (absolute path) as written to by a command, then we may need "../a/file.out" (relative path), but since these strings are not equal (absolute vs relative path) the linting fails to give an error.

@DavidEichmann DavidEichmann force-pushed the fsatrace-lint branch 3 times, most recently from 32b28fa to 708bfd6 Compare March 11, 2019 14:54
@DavidEichmann
Copy link
Contributor Author

Neil, I wanted to add some tests for the new makeRelativeEx function, but when I run cabal new-run shake-test -- filepath it simply passes without error (even when I e.g. add True === False) and says Warning: No want/action statements, nothing to do. What am I doing wrong here?

@ndmitchell
Copy link
Owner

Hopefully https://github.com/ndmitchell/shake/blob/master/docs/Developing.md answers your questions. Simple answer is add the word test at the end. Just reviewing now...

@ndmitchell
Copy link
Owner

Sorry, I should have clarified what I was looking for. It's clear what makeRelativeEx does. What I still don't understand is why GHC is producing files that need it. What GHC rule is it building? What files does it produce? What does it canonicalise them to without makeRelative? How can we write a test case that calls cmd and reproduces the error?

@DavidEichmann
Copy link
Contributor Author

BEFORE this MR

(*) I get the following when building my local GHC branch (includes changes to enable fsatrace linting over the build directory) :

$ ./boot && ./configure
$ ./hadrian/build.sh -o../.build/T-16400_default --lint-fsatrace
...
Lint checking error - 36 values were used but not depended upon:
  Used:  /home/david/MEGA/File_Dump/Well-Typed/GHC/_nosync_git/.build/T-16400_default/stage1/libffi/build/configure
  ...
  Used:  /home/david/MEGA/File_Dump/Well-Typed/GHC/_nosync_git/.build/T-16400_default/stage1/libffi/build/missing
  ...

In particular, note that I am using a build directory outside of the source tree: ../.build/T-16400_default. Also note that the lint error gives abosolute paths: the "bad" result of makeRelative e.g.:

makeRelative "/home/david/MEGA/File_Dump/Well-Typed/GHC/_nosync_git/ghc" "/home/david/MEGA/File_Dump/Well-Typed/GHC/_nosync_git/.build/T-16400_default/stage1/libffi/build/missing"

(**) Now if I correctly add a need statement in the corresponding rule (using a relative path as is the convention):

need ["../.build/T-16400_default/stage1/libffi/build/missing"]

The BUG surfaces: this does not fix the linting error. Needing the absolute path does fix the linting error, but is not a satisfactory solution.

AFTER this MR

With Hadrian as in (*) I do:

$ ./boot && ./configure
$ ./hadrian/build.sh -o../.build/T-16400_default --lint-fsatrace
Lint checking error - 31 values were used but not depended upon:
  Used:  ../.build/T-16400_default/stage1/libffi/build/missing
  ...

The number of errors decreased from 36 to 31. This is because Hadrian already correctly needs some of the files (using relative paths). Note also that the linting error gives relative paths thanks to makeRelativeEx.
Adding the need as in (**) also fixes the linting error (both relative and absolute paths work).

To Summarize

fsatrace linting fails when the accessed files are not under the current working directory even if the dependency is coded correctly in the build system (using a relative path).

Does this answer your question?

With fsatrace linting, a command that writes a file, unknown to
the build system, should then cause a linting error if that file
is later `need`ed. Previously, shake would fail to give this
expected linting error when the file in question if not under
the current working directory.

The reason for this is fsatrace gives absolute file paths and
`makeRelative` will often fail to convert to a relative path e.g:

    > makeRelative "/root/a/" "/root/b/file.out"
    "/root/b/file.out"

This is because `makeRelative` is pure and cannot guarantee a
correct relative path incase "a" is a symlink (i.e.
"/root/a/../b/file.out" is not necessarily equal to
"/root/b/file.out"). This commit fixes the bug by introducing the
function `makeRelativeEx` that guarantees a relative path is found
when one exists (at the cost of being impure).

    > -- Given that "/root/a/" is not a symlink
    > makeRelativeEx "/root/a/" "/root/b/file.out"
    Just "../b/file.out"

    > -- Given that "/root/c/" is a symlink to "/root/e/f/g/"
    > makeRelativeEx "/root/c/" "/root/b/file.out"
    Just "../../../b/file.out"
@DavidEichmann
Copy link
Contributor Author

DavidEichmann commented Mar 13, 2019

I've added some test cases now. Ready for review.

@ndmitchell ndmitchell merged commit f58458e into ndmitchell:master Mar 17, 2019
@ndmitchell
Copy link
Owner

OK, so the magic ingredient is that you are using a relative path outside the current directory for the build. That's not something I ever really consider - but no reason it shouldn't work. Thanks for the patch!

@DavidEichmann DavidEichmann deleted the fsatrace-lint branch March 18, 2019 10:44
@ndmitchell
Copy link
Owner

I followed up with a pile of tests and fixes that means it should work robustly now. I'll also write proper docs for this lint mode!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants