Should SPM allow installation of package on the system

A few reasons I can think of:

  • The workflow to publish packages for Homebrew is a little cumbersome. You need to make and maintain a formulae and most likely your own tap in a separate repo.
  • While Homebrew is very widely used on macOS, on Linux that's not necessarily true, so publishing for multiple platforms may require more than putting it on Homebrew.
  • Running multiple versions of a package is a little tricky in Homebrew. You have to explicitly call brew switch <formula> <version> to move between them, they can't be used side by side easily.
3 Likes

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.

8 Likes

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 Like

+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).

9 Likes

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.

1 Like

:+1: 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.

1 Like

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.

2 Likes

It’s pointless if it doesn’t install somewhere in PATH.

3 Likes

...

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.

1 Like

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:

  1. temporary directory
  2. clean up
  3. remembering where the build output goes

If a README also has to instruct a user on how to edit their PATH then—believe me—you have created a useless command.

2 Likes

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 idea from this thread of installing a single executable globally
  • Shared cache as Karl brought up. I understand this could be a separate feature, and perhaps it is unrelated completely.

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.

From what I understand, the intent for this use case is to simply add a dependency on said tool at whatever version in your package manifest. Dependencies not actually used by your products will be ignored by your clients in a future version of Swift (SE‐0226 is already implemented on master). But such dependencies will still be available during development to swift run whichever of them you want. That covers the fetching and version locking side. The separately desired shared cache feature would end up automatically persisting the built tool.

1 Like

I didn't know that already worked :man_facepalming: , thanks!

I'm curious why not /usr/local/bin ?

I think it should do both things:

  • Install it on ~/.swiftpm/package-name/version/bin/package-tool.
  • Create a symbolic link in /usr/local/bin/package-tool so it is easily accessible.
1 Like