-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
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
Feature Request: Preventing formulae updates from breaking their dependencies #60
Comments
This is a difficult problem because we are unable to test all combinations of all formulas with all options. Formulas with fewer options are inherently less fragile. We do test the default configurations where we have tests available. If the broken formulas lack tests, adding a Of course, we do not want to break packages. I think there is not a generic solution but maybe you have some ideas. |
As peculiar as it may sound, this is basically by design. If you need something more stable, I'd suggest maintaining your own tap with the working set of tools pegged to a particular version and backing up older bottles and build-time resources that you need. Note that you can also generate your own bottles using
Cf. Homebrew/homebrew-bundle#162 (Another option is to use virtualization and/or file-system level snapshotting). |
Yeah, adding tests will help in some cases. And minimizing options in the first place will help. TL;DR: Add Details: The Homebrew/homebrew-science#3454 Homebrew/homebrew-science#3512 PCL doesn't have a I'm not sure what happens in The full solution of testing all combinations of options is prohibitively expensive. (Testing N options takes N or 2^N runs, depending on how thorough you are.) We could do a smaller version where we just test the option combinations which are used in We could also detect dylib versions by interrogating files with The best immediate approach is probably "make sure all your formulae have Open to other suggestions. I may have blinders on for this issue since I'm so used to looking at (EDIT: Note that this ability is currently limited because we're not using |
@tdsmith Maybe it is possible to compile once with the default and once with all options? I know mutually exclusive options won't work there but it would probably eliminate a large subset of these problems while only requiring 1 additional continuous integration run. |
A pull request implementing a |
Would it? What's the goal here? Reopened for now; I'm not sure the discussion is over. |
I'm not sure doubling the CI load is acceptable either; we haven't found a way to move our CI infrastructure into the cloud and right now we aren't willing to invest in the capital costs or the maintenance burden of additional CI builders. We could maybe do some heuristics about whether it looks like dylib names are likely to change, but that seems less effective than adding tests to formulas. |
We would probably have to alter the formula DSL to express option conflicts, too, or explicitly specify |
maybe an "advanced build" command where the rb script can specify a second reasonable configuration to test with extra options set? that's something I'd know enough to submit pull requests for as an occasional, very minor contributor. @ilovezfs thanks for the link, I'd be sad if there were no options because I'd be back to compiling from source all the time... I'm using stuff like cuda and image tools. For one data point I'd say about 90% of the time I type |
There's no way this'll fly on Homebrew's current CI. It's an outlier of an example but doing Qt5 per option (which is the safest way to handle possible conflicting options) would take ~10 hours of CI time, per VM. You're talking 30 hours of CI time total, for a single formula. Doing it in a way where we do an initial run and then one with all options afterwards (potentially risking conflict) would still take upwards of ~4 hours per CI time, per VM. Short of someone providing Homebrew with a large enough donation to enable us to buy, run and maintain a significantly larger number of hardware we're limited on what we can reasonably do. We tried to farm out some of the CI load to Travis but have ended up pulling back on that for various reasons. CI is a struggle for us, and it chews up a lot of hours behind-the-scenes keeping it going. The answer here to an extent is that people need to be careful which options are added and only add the ones with community demand and value. Every option added to an official Homebrew formulae is more or less a promise that we'll keep trying to support it, as removing options is always treated as more or less a last resort.
For reasons stated by others above and myself before I still consider this a "fairly bad idea" ™️. |
Options in Homebrew are inherently fragile, because the options are not tested by the test-bot, and the interactions between options are definitely not tested. Using any option basically puts you into uncharted territory. Within the current constraints of not testing options with CI, the only way to avoid breakage is not to use options. If there's an option that you use frequently, you could open an issue to discuss making that option the default behaviour for the formula, and then it would be tested by CI. |
Increasingly we're asking the question if an option is popular/valuable enough to merit inclusion is it popular/valuable to merit being turned on by default. We haven't come up with a firm answer yet, but on a case-by-case basis it's worth considering. |
@sjackman an "advanced build" option could reduce the surface area that is untested while keeping compile times lower than the full combinatorial explosion of possibilities. Or, perhaps more options should generally be included by default? I'd be happy to add some pull requests adding |
This is a good point and options should be considered "dangerous" by anyone relying on CI to test formulae. Really, I think on most formulae they add more user pain than they save... CC @Homebrew/science here. This is a reason
I'm fairly keen to keep formulae's default options on the stuff that's useful for 99% of users. This has made me remember that we should be making a note with our new analytics of what options are used for formulae so we can consider making commonly used ones the default.
You'll learn. I'd never used Ruby before I started working on Homebrew and now I do Ruby development full-time 😉 |
Yes tests are absolutely necessary. We insist on tests now, but there was a time when we didn't, and some formula haven't changed since that time. Currently 486/581 (84%) have tests.
Ditto. Homebrew was my first Ruby project as well. I quite like the language now. |
I've wondered how this system works. If app depends on lib, and lib is rebuilt changing the dylib name (or soname), and the |
@sjackman A classic example are |
Ah, I see. Thanks for the explanation. Do you modify the original formula and bump the revisions of the dependents all in the same commit? |
Ideally one commit per formula bump, with the following style:
And so on. |
We haven't been entirely consistent with this, unfortunately. I think the preferred style is to have one commit per formula. But you can also find instances of
in the recent Git history of |
@ahundt: Do you have a list of some other homebrew/science formulae which tend to get broken dependencies like this? It would be helpful to have some more concrete examples. And we can make sure they are testable so they're at least taking advantage of Homebrew's current QA process. |
I think While having the repos all separate is great for separation of concerns, it's a little troublesome to update a library in Dealing with the Dealing with the other repos' dependents is harder. CI currently does detect the breaks in the other repos. While we can immediately issue pull requests on those repos as soon as the version bump is merged into I'm not sure about the right way to solve this. One option would be to somehow coordinate between the repositories so that all of the library-version-bump-related PRs are merged (nearly) simultaneously. This seems hard to do, though, since unpredictable CI errors do happen (something builds just fine locally, but not on e.g. a different OS X version). Another option would be to have the formulae that list |
The one vs many commits is more a stylistic issue. Regardless of how many commits it is, for formulae in the same repo, all the commits go in the same PR which is merged all-or-nothing, so they're tested and committed as a unit, and users will pick up all of them in the same But for formulae in separate repos, skystrife hits it on the head:
We do not have a mechanism for linking PRs across repos, testing them together, or making sure they get tested and deployed as a unit. So the current mechanism actually requires this out-of-sync window, because the PRs for dependent repos' revision bumps can only be run in CI after the version bumps to I don't know how to solve this currently. I think that "coordinating between repositories" would require adding some special metadata in PRs that The limiting factor here is again whether the dependent formulae are testable. Right now, that means having a Perhaps we could also add an automatic dylib linkage test that's done regardless of whether a Both of these are probably necessary to get to a "perfect" state, because they're independent sources of possible breakage. (Plus restoring
IIRC, This doesn't cover the case of keeping bottles in sync, though: the case that breaks more often is when you do a fresh installation of |
That brings up another question, @ahundt: Are you seeing this breakage on systems where these things are already installed, and a |
@apjanke: If on a fresh system after the icu4c 56.1 bump you installed the php56-intl package, you received icu4c 56.1 as well as binaries for php56-intl that were compiled against icu4c 55.1. So yes, this applies to newly installing packages as well. |
@scpeters In that case the formula should depend on whatever is the newest version of |
@MikeMcQuaid thanks for the clarification. What would happen when trying to install both packages at the same time? Would the older version of boost be installed as keg-only for the sake of the package that requires it? Also, if there was a 3rd package that depended on packages that have varying support for the latest versions of boost, they might run into a conflict.
Would the same version of boost be used when installing |
@scpeters They would both be installed either side-by-side or keg-only depending on conflicts and if we're able to resolve them. In that case it'd be up to the author of C to resolve the issue. Currently that formula would not work at all or have the same problem with homebrew/versions. I'd rather focus on known issues with formulae rather than speculative issues; we can always iterated and improve any approach we take. |
Since |
Thanks for the responses. I spend a big part of my time maintaining software for Ubuntu/debian, which define distributions with specific versions of each package, which is a different model than homebrew, which generally uses the latest version of everything. In my head, the example about packages A,B,C seemed relevant, but maybe it's more relevant to the Ubuntu/debian model. I'll see if I can think of a concrete example for which it would impact homebrew. |
@scpeters At this point it's probably worth critiquing implementations rather than theory so let's hold off until we have that. |
Sorry for my lack of responses, I've been traveling the last two weeks. I like the ideas that have been discussed, is there something that can be put into effect? @MikeMcQuaid I've actually encountered the "theoretical" problem mentioned by @scpeters in real use cases. Particularly with libraries that support OpenCV 2.x vs OpenCV 3.x, vtk 5 vs 6 and 6 vs 7, Qt 4.x vs Qt 5.x, and a variety of boost versions, particularly around the introduction of new boost libraries (boost.geometry in my case) between 1.4x and 1.5x, and compilation of libraries during the transition between cmake versions 2.8.x with x<10 to 3.x. I don't think this situation is uncommon as different libraries take different amounts of time to support newer versions of their dependencies, particularly widely used ones. Here is a specific comment on the effects of version transitions from another user: PointCloudLibrary/pcl#1563 (comment) |
Regarding #62 where I'd sometimes like to remap dependencies, could there be a command line command like |
A couple of the smaller ones are now in effect.
Don't know about the others. And this thread has gotten long enough that I've kind of lost track of all the items which were proposed. |
I can 100% guarantee we won't support something like that that will make things extremely hard to debug.
I think in this case it's on the packager to avoid such conflicts. |
@apjanke I tried to add a summary of proposals and additional problems to the very top of this. here is the tl;dr Key problems
Solutions with most backingThese are reasonably easy, well liked ideas that will mitigate (but may not completely solve) the above
|
I don't actually think this is a problem; it's something that blocks package D from being packaged in pretty much any package manager and is a problem with their development process. Otherwise: yeh, I agree 👍 |
I just stumbled across this issue and I have been frustrated with version incompatibilities before (reverting QT5.6 to 5.5 for the capybara-webkit gem was annoying and isn't going to be fixed so now qt5 has to be pinned forever, and I can never build anything that requires QT5.6+ at build time without remembering to install the new version and then switch the links back when I'm done so that the next time I bundle update everything's not broken again). However I'd rather deal with that migraine than this bit: I think there's a lot of good that could come from versioning some libraries but please please please don't do it to the databases. |
We will version databases in some form, just not sure what that will be yet. As a counterpoint under the current system if you have MySQL 5.6 data and upgrade to 5.7 temporarily then getting your data 5.6 compatible again is a non-trivial process. |
You're right. Thinking about it more, I guess I mostly run into this when adding new dependencies which supply new functionality to software I'm developing myself, or when porting software from another OS or package management system like ubuntu. I guess I was just thinking of "things that would be nice to avoid" and not "things a package manager can actually do anything about", haha. |
I'm probably going to catch some shit for even mentioning this, but for several years now I've been using a personal fork of homebrew which does not use dynamic linkage at all. Its a pretty simple hack, just replacing every instance of This (obviously) takes care of this issue (and most other linkage headaches) for 95% of the formulae I use, and (in most likelihood) at least half of all formulae in general. For the rest I use There are so many reasons to do this, the most important of which, for me, as I'm developing my own software, is to avoid things like this; but when developing an app/program that will be distributed in binary form, I actually don't really understand how anyone would be able to use homebrew without doing something like this. |
@geoff-codes The opposite: I'm pretty interested in learning more about that and what it would take to make your fork a bit easier. |
Oh! In the past I've had several unpleasant run-ins with some homebrew maintainers who vociferously advocated for dynamically linking as much as possible (that issue I linked above doesn't address this exact idea per se, but I trust you can gather my meaning). I have thus largely avoided proposing anything related to what is now the "brew" repo, for some time now. I have even avoided putting anything in a public fork: my worry was someone might come across it, adopt it, and suddenly a few weeks I'd be maintaining a fork to which the upstream maintainers were diametrically opposed. But I know there's been a significant "changing of the guard" since that period, so, if you're serious: There are actually several "side-advantages" of doing this as well, namely,
I get faster code and great compatibility across systems. All it costs me is a few kb's in my executables.
Presently, the code I have is pretty crude, and mostly consists of shell scripts that copy formulae to a temporary directory, 'grep-and-sed's as appropriate; then installs the formula using a So, if indeed this is something you'd want to consider experimenting with, I'd be happy to clean it all up and implement it in Ruby for something you could pull into a topic branch...? |
Linuxbrew bottles can run on any distro. The bottles target |
As an alternative to static linking, you can copy all the shared executables that an executable depends upon into its |
If the executable is installed in |
@geoff-codes the static linking idea sounds to me a bit like Ubuntu snappy, which I think is great for leaf applications. If you want to build a framework to use in other applications, my impression is that static linking would be less helpful. I wonder what percentage of homebrew installs are for leaf applications vs. frameworks. |
It's both. That is, one goal is to be able to compile executables that can be distributed completely outside/without brew, while still being able to use brew handle building libraries, dependencies, as well as building utilities, toolchain, etc.
Yeah, I'm just going to have to disagree with you there. @scpeters Yes, I agree its a bit like snappy, but it is exactly sta.li. In fact, their FAQ makes all the points I would make on this argument. |
Closing in favour of #620. Thanks for all the discussion, folks. |
Key problems
Solutions with most backing
These are reasonably easy, well liked ideas that will mitigate (but may not completely solve) the above
proposed solutions
This is the full list of proposals (not definite upcoming features). Check marks indicate they are implemented
brew audit
output formatbrew install mypackage --override-dep boost ahundt/boost155
. could be a normal brew command or perhaps an easy way to change the formula files?posed problems without solutions
these are from the ongoing conversation beyond the initial request posed above
Original Feature Request
I keep having libraries I depend on get broken because those dependencies' own dependencies are changed out from under them. In particular, this happens most frequently when flags other than the default are needed.
Two examples:
https://github.com/Homebrew/homebrew-science/issues/3454
https://github.com/Homebrew/homebrew-science/pull/3512
Perhaps there is a way to avoid these problems that also meets the crucial criteria of the homebrew team being willing to put it into practice? :-)
Thanks for your thoughts and considering my request!
The text was updated successfully, but these errors were encountered: