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

Building a specific target can cause bad state #2904

Closed
spikefoo opened this Issue Jan 8, 2017 · 7 comments

Comments

Projects
None yet
4 participants
@spikefoo
Contributor

spikefoo commented Jan 8, 2017

(Using stack-1.3.2 on Arch Linux)

Steps to reproduce

Clone this sample project with two libraries: LibA, and LibB which depends on LibA.

$ ls
lib-a lib-b stack.yaml

Build with stack build, and run with stack exec lib-a-exe and stack exec lib-b-exe.

Next, change a function (named value) in LibA, and rebuild LibA only using stack build lib-a. Now lib-a-exe uses the updated function, but lib-b-exe still uses the old one, as expected.

Now try to rebuild LibB with stack build lib-b or stack build.

Expected

stack should update (relink?) LibB to use the new version of LibA.

Actual

stack never rebuilds LibB, causing it to forever use the old LibA.

This was suprising for me, because I thought stack build lib-a && stack build lib-b was equivalent to stack build. Instead, I found out it can result in a bad state where LibB is never rebuilt, forcing me to use one of these workarounds:

Workaround

After making a change in LibA and running stack build lib-a, either:

  • Change a source file in LibB, forcing a rebuild. Or:
  • Remove lib-b/.stack-work.

Alternatively, never build a specific target (e.g. stack build lib-a) in the first place. Always run stack build to build all targets.

@lwm

This comment has been minimized.

Member

lwm commented Jan 20, 2017

I believe this use case was covered with stack build --force-dirty ?

  --[no-]force-dirty       Enable/disable Force treating all local packages as
                           having dirty files (useful for cases where stack
                           can't detect a file change
@spikefoo

This comment has been minimized.

Contributor

spikefoo commented Jan 23, 2017

It looks like stack build --force-dirty is a nicer alternative to the workaround of manually removing .stack-work.

But the issue still exists: stack build fails to rebuild a package after a dependency is updated and built using stack build $DEPENDENCY.

@mgsloan mgsloan added this to the P1: Must milestone Feb 1, 2017

@mgsloan

This comment has been minimized.

Collaborator

mgsloan commented Feb 1, 2017

I can indeed reproduce this, and I agree that it's a bug. Marking it as a P1 issue since it violates consistency that ought to be there.

@snoyberg

This comment has been minimized.

Contributor

snoyberg commented Mar 7, 2017

This reminds me of haskell/cabal#2830. And in fact I'm seeing something very similar. When I do the initial stack build, I end up with the following package IDs:

id: lib-a-0.1.0.0-AeObfw0jAOe7kZzV2FkbDJ
key: lib-a-0.1.0.0-AeObfw0jAOe7kZzV2FkbDJ
id: lib-b-0.1.0.0-xc7uosuJA3EKtusB0zBjI
key: lib-b-0.1.0.0-xc7uosuJA3EKtusB0zBjI

If I modified the LibA.hs file and rebuild, I get exactly the same id and key. This is the cause of the problem here. When you run stack build lib-a, Stack unregisters lib-a, rebuilds it, and registers it. When you run stack build lib-b, the package looks valid, because its dependency (lib-a) is still present in the database with the same ID.

This is really a Cabal or GHC bug (it should generate unique package IDs if the package contents change). A simple workaround would be to aggressively unregister all users of a package when unregistering the dependency.

snoyberg added a commit that referenced this issue Mar 7, 2017

snoyberg added a commit that referenced this issue Mar 7, 2017

Switch unregister reason from Maybe Text to Text
The previous commit (fixing #2904) made the Maybe layer confusing and
error-prone. It was too easy to end up accidentally skipping an
unregister based on the two levels of Maybe wrapping. This simplifies
the codebase, without any change in behavior.

It would be even nicer to be able to prove statically that we always
generate a dirty reason.

@snoyberg snoyberg referenced this issue Mar 7, 2017

Merged

Aggressive unregister for #2904 #3047

2 of 2 tasks complete
@snoyberg

This comment has been minimized.

Contributor

snoyberg commented Mar 7, 2017

Please see #3047, which should fix this.

@snoyberg

This comment has been minimized.

Contributor

snoyberg commented Mar 7, 2017

It looks like Cabal is using the package key as the package id as well. The key depends only on the dependencies of the build, not the output, which would explain this bug. I'll try to repro against latest cabal and report upstream.

snoyberg added a commit that referenced this issue Mar 8, 2017

@snoyberg

This comment has been minimized.

Contributor

snoyberg commented Mar 8, 2017

Fixed by #3047. Cabal is saying what I thought they would: the meaning of package IDs has changed. I'm not too happy with that, but as usual we have no control over such things.

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