Hi,
Do you think it will be useful if SPM could install package on the system(in /usr/local/bin
for exemple)?
This project GitHub - swiftbrew/Swiftbrew: Homebrew for Swift packages actually make it possible.
Thank you,
Hi,
Do you think it will be useful if SPM could install package on the system(in /usr/local/bin
for exemple)?
This project GitHub - swiftbrew/Swiftbrew: Homebrew for Swift packages actually make it possible.
Thank you,
It has been in the Evolution Ideas document in SwiftPM since the beginning.
There are several tools and scripts in the wild that attempt to do this. Mint is the most popular that I have seen.
But to actually do it right is far more complicated than most of those tools admit. Despite having tried many such tools, I still find myself having to clumsily use my own script, because each tool inevitably neglects some SwiftPM feature, such as dynamic libraries. The arrival of resources (SEâ0271), will make it even more complicated.
There are several major design hurdles:
You cannot just dump the executable into /usr/local/bin
(which is roughly what Mint did last I checked), because you will loose any dependencies and resources. Neither can you dump all the products into a global location, because a dependency might overlap with a different package, but at a different version.
You cannot install a binary built elsewhere (which is what Swiftbrew appears to be doing), because the matching Swift toolchain isnât guaranteed to be in the same location. macOS can safely assume consistency with some stable system libraries like Foundation
and Dispatch
. But XCTest
and SwiftSyntax
â implicit toolchain dependencies are another story. Outside Darwin, not even Foundation
is reliable unless you build from source on the destination machine.
Those are all things that âjust workâ with swift build
and would need to also âjust workâ with a hypothetical swift install
command.
I definitely think it'll be valuable to have a swift install
command. @SDGGiesbrecht laid out many of the problems that we need to address for implementing such a command in a cross-platform manner. It would be great if someone wants to drive a pitch/proposal for adding the install command.
cc @Yonas_Kolb
Whatâs the value of SPM doing this? Iâd rather keep my system installs in one place, like brew
.
A few reasons I can think of:
brew switch <formula> <version>
to move between them, they can't be used side by side easily.The flip side of this is that if we push the work onto SwiftPM that the complexity still exists, but it is now SwiftPM's problem. There's a lot of historical baggage here: for example, Python's pip
tool has had to bend over backwards to behave well alongside tools like apt-get
. There are many Linux package managers, each with a package format different from the others, and if Linux ever starts packaging Swift packages then SwiftPM and the system package manager will have to learn to get along.
On the other hand, if SwiftPM simply decides not to do this, then we can have a clear separation of worlds: SwiftPM is for development, not distribution.
An alternative might be to directly integrate with various official system package managers:
$ swift package export apt-get
> swift package export PackageManagment
...
But I for one donât like managing multiple redundant manifests side by side, so I consider the status quo to be unsatisfactory.
+1 for an install command that all it does is copy the statically linked binary to /usr/local/bin
and any associated resources to /usr/local/share
(or any prefix).
â1 for an install command that can update/upgrade/manage installations
â1 if the idea is to install dynamic libraries and manage the resulting dependency hell.
SwiftPM is good as a resolution and build tool, and should be careful (IMO) to stay focused on that. I +1 a limited install function because it will increase adoption of minor tools before they become popular enough to warrant being packaged by the big-kids (eg. brew/apt).
No one (that I know of) is suggesting installing libraries for shared use. Dynamic libraries only come up because an executable can have one in its dependency graph and it still needs to work. Putting all the products in an isolated directory somewhere and then only symlinking the executables in /usr/local/bin
would be one way to make sure multiple executables can have incompatible dependencies and still live sideâbyâside without a problem.
As for prior art, there's $ npm install --global package-name
which installs a binary globally, and is a very useful and popular feature in the Node.js community. I have made lots of Node.js command-line tools that can be easily installed with a single command. I would love to be able to also distribute Swift command-line tools this easily.
No one (that I know of) is suggesting installing libraries for shared use. Dynamic libraries only come up because an executable can have one in its dependency graph and it still needs to work. Putting all the products in an isolated directory somewhere and then only symlinking the executables in
/usr/local/bin
would be one way to make sure multiple executables can have incompatible dependencies and still live sideâbyâside without a problem.
K cool, I mentioned it since that it was most of the âequivalentsâ do (pip, gem, npm (less so)), they have their equivalent of âdylibsâ installed in the prefix and manage the dependency hell. I feel this is outside the scope of SwiftPM and itâs notable that system packagers usually end up installing the more popular tools themselves since managing large amounts of software (where that software is more than just a single binary) is best served by a central committee that knows all the caveats.
This would be especially useful if we get package support in scripts. Otherwise, consider a simple Vapor microservice - it would take a good 5 minutes or more to start! It would have to download and build everything from scratch, including dependencies like SwiftNIO.
You could call it "installing", or you could call it a "shared cache of prebuilt products" - either way, it would be nice if all my locally-running packages had access to it.
A shared cache would be a separate feature, though it is also on SwiftPMâs general wish list. master
already supports some aspects of crossâmodule optimization, and as that grows, SwiftPM will want to take advantage of it. To that end, instead of only the final products, a shared cache will probably contain the results of each build phaseâdependency clones, object files, etc. SwiftPM would then reach as far back as useful for optimization, but no further.
An install feature would be good, but I donât want it installing in /usr/local/bin. Maybe ~/bin, or maybe ~/.spm/package.bundle.name/version/bin, with a path updated that adds all those folders â or something like that.
Itâs pointless if it doesnât install somewhere in PATH
.
...
No package manager installs into the default path (on macOS at least). Is it even possible anymore? So since it needs to be added to the path anyway, what does it matter?
brew installs to /usr/local/bin
, which is also in the default PATH on macOS. If youâre referring to SIP, then /usr/local
is not SIP protected.
This is also the default path for gem, pip and node. The only PM that doesnât install to /usr/local/bin
that I know of is MacPortsâand I get some people consider it the only real package manager, but thereâs no accounting for taste.
Ah, right. I guess I was thinking of the other directories brew warns about. Is it a good idea to have multiple managers writing into the same directory? I could see /usr/local/bin/spm/
, but I'm still not sure it's a good idea.
Itâs not ideal, but it already happens. /usr/local
is a free for all, you get no guarantees about it.
I maintain I donât see the point of an install command if it doesnât âjust workâ, nobody will be able to say just: [sudo] swift install https://githhub.com/foo/bar && bar --help
in their project README.
Really this is all you need to do right now:
git clone foo
swift build -C foo
sudo cp foo/.build/foo /usr/local/bin
foo
What the theoretical install
command saves is:
If a README also has to instruct a user on how to edit their PATH
thenâbelieve meâyou have created a useless command.
There seem to be several potentially related features for Swift PM that I could see affecting how a feature like this would be implemented.
The last one I'm not sure has been explicitly brought up yet:
I'd personally love to be able for my project to have a devDependencies
section or something like that that would specify the version of an executable that project uses, and be able to install and run those tools (different versions, in parallel on a machine) using something like swift run <my tool> <command>
A lot of our tools for iOS development, for example, are written in ruby or javascript (ex: Fastlane or Apollo CLI), both which let you run the command line utilities using bundle exec <the tool>
or npx <the tool>
so that you run the correct version of that tool for the project you are in.
I don't bring this up to really gauge interest in that feature, but I think it would be useful to understand what the overall vision of Swift PM is when we talk about it managing executables.