Sdk: Homebrew formula

Created on 17 Dec 2015  ·  104Comments  ·  Source: dotnet/sdk

I would love to install .NET via homebrew. Any plans to maintain a brew formula? I think the majority of Mac developers work this way.

enhancement

Most helpful comment

I'd like to make a strong recommendation for a solution that is definitely more work up front but which would fairly nicely obviate most of the concerns around side by side installations, trying to manage things on the homebrew (and chocolatey) front, etc.

As has been mentioned a number of times in this thread, other language communities tend to support installing specific versions via homebrew… but recommend the use of other tools to actually manage it, for precisely the reasons brought up here: homebrew really doesn't offer support for side-by-side installation in any important way. So in Ruby people tend to use rubyenv or rvm; in Node it's nodenv or nvm, in Python it's pyenv or conda, and – perhaps most importantly as an example here – in Rust it's an officially supported and distributed tool, rustup, and that's what manages side-by-side installations of the tool.

For example, to install the current stable and nightly releases of Rust as well as 1.12.0 from last year, set the global default to stable and then use nightly in one directory and 1.12.0 in another:

$ rustup update stable nightly 1.12.0
$ rustup default stable
$ cd ~/to/some/directory
$ rustup override nightly
$ cd ~/to/someplace/else
$ rustup override 1.12.0

My experience with rustup and others over the past few years has me pretty well convinced that the best long-term play for dotnet is to either subsume that functionality itself, or to ship a dotnet-up that does the same kind of thing that rustup does. Then that tool can be installed and its version managed by homebrew, etc. much more easily, because you never need two versions of it installed side-by-side.

Obviously that's a non-zero amount of work, but (a) there's lots of prior art and (b) much of the packaging side of that already exists. (It seems like the biggest thing there is that it currently runs via a GUI package installer, which is not the way that Mac developers generally expect – though in principle a dotnet-up could still just pull that GUI package installer, amusingly weird though that would be.)

All 104 comments

@nathanboktae yep, we are working on that, hopefully I will have a PR for the formula this week or early next week. :)

:+1:

:+1:

Great! Looking forward to it! :beers:

This is for https://github.com/Homebrew/homebrew-devel-only or https://github.com/Homebrew/homebrew-binary homebrew main should be built from sources

class Dotnet < Formula
  desc ".NET Core command line toolchain."
  homepage "https://github.com/dotnet/cli"

  devel do
    url "https://dotnetcli.blob.core.windows.net/dotnet/dev/Binaries/Latest/dotnet-osx-x64.latest.tar.gz"
    sha256 "7002abc6f56533d6b436fb8515117c4ab47fa913707ca36c85e74a7740f1617a"
    version "1.0.0-dev"
  end

  bottle :unneeded

  def install
    libexec.mkpath
    cp_r Dir[buildpath/"*"], libexec
    bin.install_symlink libexec/"bin/dotnet"
    bin.install_symlink libexec/"bin/dotnet-compile"
    bin.install_symlink libexec/"bin/dotnet-build"
    bin.install_symlink libexec/"bin/dotnet-compile-csc"
    bin.install_symlink libexec/"bin/dotnet-compile-fsc"
    bin.install_symlink libexec/"bin/dotnet-new"
    bin.install_symlink libexec/"bin/dotnet-pack"
    bin.install_symlink libexec/"bin/dotnet-publish"
    bin.install_symlink libexec/"bin/dotnet-repl"
    bin.install_symlink libexec/"bin/dotnet-restore"
    bin.install_symlink libexec/"bin/dotnet-resgen"
    bin.install_symlink libexec/"bin/dotnet-run"
    bin.install_symlink libexec/"bin/dotnet-test"
    bin.install_symlink libexec/"bin/corehost"
  end

  test do
    system "#{bin}/dotnet"
  end

  def caveats; <<-EOS.undent
    To set DOTNET_HOME:
      export DOTNET_HOME=#{libexec}
    EOS
  end
end

@diimdeep nice one. :) I've already built one but was waiting for the beta to push it to Homebrew repo. We do have building from sources, btw, but similarly to yours, I have opted for using the built tarballs.

@diimdeep a question: why all of the bin.install_symlink calls? The brew link phase automatically links stuff properly after install, doesn't it?

@blackdwarf afaik after build, anything from formula #{prefix}/bin linked to HOMEBREW_PREFIX/bin

I looked at install script from .pkg and tried to make that formula link same and nothing more(there are much more files in bin/ inside tarball)

Note that in the context of Homebrew, libexec is reserved for private use by the formula and therefore is not symlinked into HOMEBREW_PREFIX.

Copy tarball content to #{prefix}/libexec, from #{prefix}/libexec/bin link to #{prefix}/bin, and after that link phase did trick.

@diimdeep I just coped stuff over from bin to #{prefix}/bin and brew link did the job. It will only symlink +x files as far as I was able to observe. Reagrdless, the effect is the same, the question was for my education. :)

+1

builds take 20 mins today. will homebrew main do the build server-side? Or are we talking a 20 minute install window for end-users?

@piotrpMSFT for end-users. If we want to do that. We don't have to. It is our choice as @diimdeep mentioned above. We can provide both a stable and a devel install option within a single formula.

I think the better UX would be to download on all feeds. Mostly stirring the pot to see if this is a bad thing to aspire to in the Homebrew context...

@piotrpMSFT you mean never build from source?

:+1: Any updates?

@vors yeah, working on that, we have some bugs that are blocking this. As soon as they are fixed, we will make a push to the Homebrew binary repo. :)

Home brew also has the 'bottles' feature for pre-built binaries. Defaults to use that unless a user wants to have it build from source. I'd go that way, it's the normal homebrew route.

Any updates on this? Not feeling very confident in downloading things that change my PATH and are opaque to me to inspect before installing, whilst a homebrew formula is easy to inspect with brew edit.

Ping, still waiting for an answer here. Reading this thread would seem to imply you need to publish at least a semi-stable release. Given the amount of press that coreclr has attracted, perhaps now would be a good time for a rc3 that can be used as stable and that you know work together with F#?

+1

+1

+1

+1

Maybe someone just goes ahead and submits the PR to Homebrew? :)

+1

+1

+1

any news? it's really nice if a formula is avaiable on osx, and the preview2 works ok.
maybe with the bottles for pre-built binaries is enough, easier to do.

Wow, very disappointed to see the ball being dropped on this. Seems like there should be some sort of communication as to why this simple feature is being delayed to 1.0.0-rtm milestone....

+1

This is available in Homebrew-Cask (Homebrew Binary is deprecated). See cask

To install:

$ brew tap caskroom/cask
$ brew cask install dotnet

I added export DYLD_LIBRARY_PATH=/usr/local/opt/openssl/lib to my ~/.zshrc file to make it all work rather than the suggested brew link --force openssl command suggested on the installation page.

@joshka just to understand, this will use the PKG installer to install the SDK? Will it just use installer under the wraps to perform a silent install?

@blackdwarf yes. The result will be the same as using the pkg (except for that fuzzy warm feeling that you get from everything being installed from homebrew ;))

How other applications could reference it in their formulas?

With analogy to how Java applications reference java and existing .NET applications reference mono now.

Probably as homebrew-cask/dotnet, but I haven't checked that a formula can require a cask. I assume it can, or can be made to trivially.

Is there any plans to do something about openssl dependency on OSX?

$ brew cask install dotnet
==> Caveats
The latest version of OpenSS is required to use .NET Core.
It was already installed, but you may need to link it

  brew link --force openssl

==> Satisfying dependencies
==> Installing Formula dependencies from Homebrew
openssl ... already installed
complete
==> Downloading https://download.microsoft.com/download/0/A/3/0A372822-205D-4A86
Already downloaded: /Users/ivanzub/Library/Caches/Homebrew/dotnet-1.0.0-preview2-003121.pkg
==> Verifying checksum for Cask dotnet
==> Running installer for dotnet; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are i
==> installer: Package name is Microsoft .NET Core 1.0.0 - SDK Preview 2 (x64)
==> installer: Installing at base path /
==> installer: The install was successful.
🍺  dotnet was successfully installed!
$ brew link --force openssl
Warning: Refusing to link: openssl
Linking keg-only openssl means you may end up linking against the insecure,
deprecated system OpenSSL while using the headers from Homebrew's openssl.
Instead, pass the full include/library paths to your compiler e.g.:
  -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib

Which will result in error when running dotnet new:

$ dotnet new

Unhandled Exception: System.TypeInitializationException: The type initializer for 'Crypto' threw an exception. ---> System.TypeInitializationException: The type initializer for 'CryptoInitializer' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'System.Security.Cryptography.Native': The specified module could not be found.
 (Exception from HRESULT: 0x8007007E)
   at Interop.CryptoInitializer.EnsureOpenSslInitialized()
   at Interop.CryptoInitializer..cctor()
   --- End of inner exception stack trace ---
   at Interop.Crypto..cctor()
   --- End of inner exception stack trace ---
   at Interop.Crypto.GetRandomBytes(Byte* buf, Int32 num)
   at System.IO.Path.GetCryptoRandomBytes(Byte* bytes, Int32 byteCount)
   at System.IO.Path.GetRandomFileName()
   at Microsoft.DotNet.InternalAbstractions.TemporaryDirectory..ctor()
   at Microsoft.Extensions.EnvironmentAbstractions.DirectoryWrapper.CreateTemporaryDirectory()
   at Microsoft.DotNet.Configurer.NuGetPackagesArchiver..ctor()
   at Microsoft.DotNet.Cli.Program.ConfigureDotNetForFirstTimeUse(INuGetCacheSentinel nugetCacheSentinel)
   at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, ITelemetry telemetryClient)
   at Microsoft.DotNet.Cli.Program.Main(String[] args)
Abort trap: 6

Hey @tmat and @jplebre – what are your plans re. this?

Added a homebrew formula. Feedback appreciated. It hasn't finished compiling yet, and so it may very well fail...

I'm thinking that it makes better sense to go with the precompiled version generally. Take note and perhaps discuss what to do about this with the cask and brew guys. They should have some perspective on dupes.

To everyone in this thread; I made the initial work towards the homebrew formula; now I would like you guys to chime in over there to make it all compile and work according to what the homebrew team demands/wants. Help out, please!

@joshka Why? brew install ... has better usability.

@haf I think either way would work, but MS has released dotnet as a "blessed" precompiled version (though slightly broken by default due to openssl library locations). Does it make sense to use that particular version of the released framework over recompiling it?

Secondly, given the cask is already done (see link above), would it be better to ensure that this is fixed rather than duplicating work?

Third, you're now in the position of creating a formula that duplicates a cask and the onus is upon you to suggest that the cask should be dropped in favor of the formula. I'd encourage you to provide some input on this. I'm not saying the cask is the correct approach, but I'm leaning to that perspective right now. What are your thoughts on this?

Regarding the commit itself, it would be good to add some comments around why the git stuff is patched out.

@joshka Well, first of all, it's not just a little broken, it doesn't work, since this one does the onus is on them to show why it would be better to deviate from the cask-preferred way of bundling software. (using the same argument)

Secondly, MSFT has shown that it's not the best judge of how to use its software in other ecosystems than Windows, so I need their blessing just as much as I need the pope's blessing. This thread should show that people want something they can install from homebrew.

Thirdly, not providing a normal homebrew install will make people who are not used to MSFT's greatness and wisdom, to question why they didn't provide a normal installation. It will make them suspicious of what the package contains and why they can't just compile it as a part of homebrew's build process, like everyone else does.

@haf by "blessed", I meant only in the sense that it's the released version ;)

When I say "a little broken", the dotnet cask worked at the time it was created. The homebrew guys made a breaking change (which was correct IMO) that broke the cask. Setting the rpath on the Crypto lib currently makes this work. It doesn't however work for the cask as it requires sudo due to the default folder permissions on the installation folders.

On the third point, I really think this comes down to expectations. I guess my expectation is that dotnet stuff is released as a binary release rather than a source release, and for this to just work. This kind of aligns with the idea that we pull Nuget packages with binary DLLs. Why would the core framework be compiled from source while everything else is delivered pre-baked?

The divide between homebrew and cask really is a source vs binary thing. To understand the viewpoints on duplication across the two projects have a read of https://github.com/caskroom/homebrew-cask/issues/15603 and https://github.com/caskroom/homebrew-cask/issues/14384.

I'm certainly not against this, it's just I'm more for distributing dotnet as a binary package. I'd like to hear others opinions though.

@joshka I think that tools that require dotnet should be able to install via homebrew instead of also having a dependency on cask.

@laktak that's a pretty reasonable point. Thanks.

Many homebrew formulas are precompiled.
Think that is a great experience and for something like .Net, would be preferred for me.
(but I still install them via something like brew install dotnet)

Thanks all for considering this.

@blackdwarf where are we here?

Any updates on this issue?

Here is where we are at. At this point, it seems that the Homebrew formula for Core is some ways off and will be coming later than we hoped. This post will go into details on why this is proving to be more difficult than we anticipated.

TL;DR

The way we do side-by-side (SxS) in .NET Core is not compatible with the way Homebrew expects formulas to provide the same functionality. We are looking for an approach to handle this but it will be some time before we can get to it because we are all heads down on shipping v1 of the .NET Core tooling. In the meantime, the PKG installer and dotnet-install.sh script are options that can be used to acquire the CLI and/or the shared runtime.

Longer version

Let me explain where the problem lies in more depth. When you install the .NET Core SDK, you get several things:

  1. A version of the runtime (or, in the case of the MSBuild-based SDKs 2 of them, LTS and Current)
  2. A version of the command-line tools (CLI)
  3. A host binary
  4. A host policy (fxr) file

All of these components have their own versions that are installed side-by-side. We use the model where we have a root directory where all of the the bits are installed and each of the components above gets a sub-directory in that root. Different versions go into those sub-directories. Here is a sample layout of the installation on one of my machines:

├───host
│ └───fxr
│ └───1.1.0
├───sdk
│ ├───1.0.0-preview2-003121
│ ├───1.0.0-preview2-003131
│ ├───1.0.0-preview4-004079
│ ├───1.0.0-preview5-004232
│ ├───1.0.0-rc3-004517
│ └───1.0.0-rc4-004769
├───shared
│ └───Microsoft.NETCore.App
│ ├───1.0.0
│ ├───1.0.1
│ ├───1.0.3
│ └───1.1.0

This layout is very important because it drives the way both the SDK and the runtime resolution work. For example, if you have aglobal.json file and you specify a version of the SDK you want to use for a given project, the host will know to go into the sdk directory that is right next to it and try to resolve the version you asked for. This similar process happens when you run an application against the shared framework, but the shared directory is used and a framework is found.

Homebrew, on the other hand, expects that each formula is a separate version and places them on disk as such. This model would break our side-by-side story. Following the example with the SDK, even if you have the correct versions installed, you would not be able to multiplex between them because the host would not be able to find the SDK folder it needs, unless you keep unlinking and re-linking the correct version you need. This would not be optimal and we believe would confuse a lot of our users.

This post hopefully explained some of the problems that we've encountered trying to get a brew formula working. We will continue figuring out how to get it out, but for now we are busy finishing the v1 release so we are focusing all our energies into that. Therefore, this work will have to come in post release, unfortunately.

Of course, the PKG installer and the dotnet-install.sh script still work so you can use them to acquire the CLI and/or the shared framework.

@blackdwarf Thanks a lot for the (very) detailed response! Great to see you reply so soon and so in-depth. Obviously, gettting the tooling right is most important now, but hopefully you'll be able to figure this out later. Would it help if I posted this problem on the homebrew repro? They might have some suggestions on how to handle this. I saw some other formulas use symlinks to map the homebrew enforced structure to their own structure. Would that be a possible solution?

@ErikSchierboom by all means, feel free to post. I wanted to do that myself after we ship v1 and I was able to get back to this. Would be good to see if the Homebrew maintainers have some input as to how this could be solved.

Thanks!

@blackdwarf I've logged an issue on the Homebrew repository.

@blackdwarf There was a response, which basically states that it should be possible, but that submitting a PR would be the best way to engage in any discussion.

@ErikSchierboom interesting. Thanks for doing this. I will see about opening a PR on the Homebrew repo and seeing what happens.

@blackdwarf Good luck!

Any update on this?

He refers to http://docs.brew.sh/Versions.html – so perhaps making formulae of { runtime, cli, binary, fxr } files and then having a meta-package that depends on the versions of these? Note that .Net Core needs to follow semver.

You all have obviously been super busy the last few months – and congrats to everyone involved in getting .NET Core 2.0 out the door and all that. This seemed like a good time to check in and see if there is a status update or even a roadmap status update on this – being able to brew install dotnet would be ✨

fyi there already is a cask available (both dotnet and dotnet-sdk):

$ brew tap caskroom/cask #if you haven't already
$ brew cask install dotnet-sdk

I might be missing something and didn't find any helpful documentation so I'm asking here.

I've

$ brew tap caskroom/cask #if you haven't already
$ brew cask install dotnet-sdk

got

==> Satisfying dependencies
==> Downloading https://download.microsoft.com/download/0/F/D/0FD852A4-7EA1-4E2A
######################################################################## 100.0%
==> Verifying checksum for Cask dotnet-sdk
==> Installing Cask dotnet-sdk
==> Running installer for dotnet-sdk; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are i
Password:
allo? anyo==> installer: Package name is Microsoft .NET Core SDK - 2.0.0 (x64)
==> installer: Installing at base path /
==> installer: The install was successful.
🍺  dotnet-sdk was successfully installed!

and then tried

$ dotnet
Unknown command 'dotnet'

User feedback:

  • I was wondering what's the difference between dotnet-runtime and dotnet-sdk (respectively formulae dotnet and dotnet-sdk). Do I need both? Is one of them including dotnet-cli?
  • From my experience (coming from nodejs/osx world), I think it might be relevant to suggest directly on your README.md how to install and start developing on _whatever your os is_. I'm expecting an experience such as
$ brew install dotnet
$ dotnet new myproject
$ code myproject

Hope this helps.

@Maximebpro Your $PATH is modified by the installer, so you need to open a new terminal before dotnet will work. dotnet-sdk includes both the SDK and runtime, so you only need one.

@spencerhakim thanks for your help 👍 (kinda felt stupid on that $PATH issue, thank you for your time)

Path modifications are tricky. A new terminal should get it automatically.
For the current one, there's this trick:

eval $(/usr/libexec/path_helper -s)

The casks are maintained by 3rd parties but it just downloads and silently installs the official installer package.
You could open a PR to add a post-install message (e.g. via caveat) to alert the users of the PATH modification.

Isn't it pretty stupid to modify PATH from the installer on OS X? It's not Windows we're talking about here; people have their own PATH construction logic in bash_profile or zshrc or .... Why not create a real brew instead of downloading an opaque installer?

Packaging custom installer under the cask doesn't make it a Homebrew package.
Please make a conventional Homebrew package instead.

To those pushing for a formula and being kinda rude about it, homebrew is open source. Feel free to step up and contribute...

Isn't it pretty stupid to modify PATH from the installer on OS X?

@haf Do you think that this is what the installer is doing? You have jumped to a conclusion that's not supported by reality. Read man path_helper.

@joshka That's not true and you know it (see https://github.com/dotnet/cli/issues/533#issuecomment-280559084). This issue is about changes being required to .Net Core to support homebrew/side-by-side installations. Alternatively a side-by-side script, like pyenv, nvm, rbenv, etc, all which are packaged on homebrew.

@haf you're missing the point that dotnet has a side-by-side story already that works. Perhaps you could articulate why this not being on homebrew is a blocker for you right now? I'm in agreement that it would be ideal to see this as formula/ae.

You seem quite passionate for getting this into homebrew, and I'd like to hope that you can translate this passion into a contribution. Mike suggested that it's possible to do this (in https://github.com/Homebrew/brew/issues/2052). I'll add some more detail that might help. This does not require changes to dotnet to achieve.

  1. Create a main dotnet formula that manages the root folder setup.
  2. Create an @ version of a dotnet-runtime formula for each version you care about that depends on the dotnet formula. Install symlinks to the runtime files in the Cellar in the right place in the main package folder.

I bet you could probably do it in less than a couple of hours.

@joshka The first problem is that the installer doesn't update PATH correctly; it just doesn't work for me. I'm not interested in learning about how to decompile installers and debug them. If it was a script in homebrew I could fix it. Core doesn't provide a means of managing things on the command line, so it does not have a working side-by-side story. I literally had to curl a GUID-based link and then untar and move the files to the right locations, just to install v2 the other day. That was NOT user-friendly. Not to mention the umpteen times the Core team has moved the "offical" installer scripts, breaking my projects. Then it broke anyway, because OS X support had been removed prematurely (in favour of Sierra), I had to upgrade and that broke Haskell, which I had to fix, and that was that day.

The second problem is that all other things, than .Net are bootstrapped with homebrew. I'm talking this list:

ant         influxdb        pango
apr         isl         pcre
apr-util        jpeg            perl
asciidoc        jq          pixman
autoconf        kafka           pkg-config
autoconf-archive    keybase         poppler
automake        keychain        postgresql
autossh         kops            protobuf
bazel           kubernetes-cli      py2cairo
cabal-install       leptonica       py3cairo
cairo           libcroco        pyenv
cfssl           libevent        pyenv-pip-rehash
cmake           libexif         pygobject3
colordiff       libffi          python
consul          libgsf          python3
consul-backinator   libmpc          r
ctags           libpgm          rbenv
diff-so-fancy       libpng          readline
dnsmasq         librdkafka      redis
docbook         librsvg         ruby-build
docbook-xsl     libsodium       s-lang
editorconfig        libssh2         sbt
eigen           libtiff         scala
erlang          libtool         shared-mime-info
fftw            libuv           siege
fontconfig      little-cms2     sphinx-doc
forge           lua         sqlite
freetype        lz4         sqlmap
fswatch         lzlib           ssh-copy-id
gcc         mesos           sslyze
gd          midnight-commander  subversion
gdbm            minisign        swi-prolog
gdk-pixbuf      mobile-shell        swig
gettext         mono            tbb
ghc         mono-libgdiplus     telegraf
giflib          mpfr            terraform
git         mr          tesseract
glib            mvnvm           tmux
gmp         nginx           tree
gnu-getopt      ngrep           tsung
gnuplot         nmap            ucspi-tcp
go          node            unixodbc
gobject-introspection   numpy           vault
grafana         nvm         vcsh
graphviz        oniguruma       vips
harfbuzz        opencv3         watch
haskell-stack       openexr         webp
heroku          openjpeg        wrk
heroku-toolbelt     openssh         wxmac
htop            openssl         xmlto
hugo            [email protected]     xz
icu4c           orc         yarn
ilmbase         osslsigncode        zeromq
imagemagick     packer          zookeeper

Obviously dotnet should be in there with the other language runtimes of the world.

Thirdly, I don't have time to cater to the whims of the homebrew authors https://github.com/Homebrew/legacy-homebrew/pulls?q=is%3Apr+author%3Ahaf+is%3Aclosed – as you can see all my PRs have been closed because I'm not there day and night to respond to their smallest whim of how it should be. MSFT are the authors of .Net and have paid people to work on it – they have the time to fix this. Not I. If you have problems with this, then you're also saying that my time is worth nothing and that the packages I've published on Nuget aren't worth anything.

As for your "this should be possible because Mike hinted something", you have obviously never tried to get anything merged into homebrew. Mike likes to hint, but doesn't like to help out when it matters/you get stuck.

So given that you're so clearly wrong @joshka, how about you spend those hours and prove that you're not?

PS; a wrapper script like rbenv, installable via homebrew, is enough;

 ~ rbenv
rbenv 1.1.0
Usage: rbenv <command> [<args>]

Some useful rbenv commands are:
   commands    List all available rbenv commands
   local       Set or show the local application-specific Ruby version
   global      Set or show the global Ruby version
   shell       Set or show the shell-specific Ruby version
   install     Install a Ruby version using ruby-build
   uninstall   Uninstall a specific Ruby version
   rehash      Rehash rbenv shims (run this after installing executables)
   version     Show the current Ruby version and its origin
   versions    List all Ruby versions available to rbenv
   which       Display the full path to an executable
   whence      List all Ruby versions that contain the given executable

See `rbenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/rbenv/rbenv#readme

It's the complete lack of command line tools and faulty installers, that makes it hard to bootstrap a complete and working environment that's a problem.

PSS; a month back I had a newbie come up to me after my talk looking for advice on how to get started with F# on OSX/Ubuntu. He said he'd spent two full-time days just trying to get things installed and was wondering if there even existed a platform where things worked. Even after showing him how to get some things working, I had to advice him against mono 5.0 (which was the latest on homebrew) because they broke dynamic interface generation for F# and .Net core didn't have a way to be installed that worked. In the end, I could say; try docker run fsharp and it'll just work, because that I had QA'd myself. But what about the dev environment? What about latest mono? What about .Net Core? I had no response to that.

I think it's easy for people like @joshka, with years of experience on Windows, sitting in Visual Studio (generalising a bit here, it may not apply to him in particular, but it seems to from his LinkedIn), to be like "What's the problem?". There is a problem. It's part tooling and part fact that MSFT's employees don't respond constructively in threads like this. Often I regret not moving away from .Net sooner because of how bad the MSFT employees manage their community.

PSSS; or shit-storms like https://github.com/NuGet/NuGetGallery/pull/4437 – it's completely brain-dead by the .Net team/Nuget not to merge things the community builds. Closing that PR without discussion fully showcases what a lie "it's open source, just send a PR", is.

Just wanted to mention rbenv too.
Absolutely the same case.

@haf

@joshka The first problem is that the installer doesn't update PATH correctly; it just doesn't work for me.

Works for me, what doesn't work for you? Can you be more precise?

$ ls -l /etc/paths.d/dotnet
-rw-r--r--  1 root  wheel  24 Aug 20 22:14 /etc/paths.d/dotnet

$ cat /etc/paths.d/dotnet
/usr/local/share/dotnet

$ echo $PATH
/Users/joshka/.nvm/versions/node/v7.5.0/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/share/dotnet:/usr/local/MacGPG2/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Users/joshka/bin:/usr/local/opt/go/libexec/bin:/Users/joshka/Code/go/bin:/Users/joshka/.rvm/bin

I'm guessing you're possibly doing something like overwriting your PATH in a startup script. Show me where you're setting this. An easy mistake is to hard set the PATH rather than append / prepend desired paths.

As for your "this should be possible because Mike hinted something", you have obviously never tried to get anything merged into homebrew. Mike likes to hint, but doesn't like to help out when it matters/you get stuck.

Mike's pretty busy, and homebrew isn't his day job. It looks to me like you got a bunch of PRs merged after necessary revisions. You can check that I've also contributed to homebrew and homebrew cask and at times faced similar push back on things. Regardless I like that Mike and the homebrew team keep a high standard of software that's installed on many machines all around the world. I'd recommend that you take a read of https://docs.brew.sh/Maintainers-Avoiding-Burnout.html for more info on the tenets that are core to working well with the homebrew team. It covers some of the issues you seem to be at odds with in your interactions. Perhaps you have the misconception that it's the responsibility of the homebrew team to test your software contribution rather than enforcing just the installation process. It really isn't, and for the most part you'll be lucky if you find someone that uses the software that you're trying to add. In addition, the best homebrew formulas are written and maintained by the eventual users rather than the software makers. I'd honestly prefer to use a package written by you with your significant experience with homebrew than one that's written by an MS dev that's never used it before and may lack context.

So given that you're so clearly wrong @joshka, how about you spend those hours and prove that you're not?

A pretty good way to dis-incentivize someone to work on your behalf is to tell them from the outset that they're wrong. Thanks, but no thanks.

Re: the paket issue. Install a greasemonkey userscript and move on with your life.

I'm far from an expert on Homebrew, but I have made a number of contributions and would be glad to help write one for .NET Core 😄

I work at Microsoft, so feel free to ping me here or offline if there's anything I can do to help! 🙂

Is it ever possible to uninstall dotnet from Mac "officially"?
Or current official installer is one way only?

There is a provided shell script to uninstall what the official package installers install here. I can't 100 percent vouch for it, but I have used it and it seemed to work okay.

any updates on this?

+1

@daften The primary difference between a Caskroom version of .NET Core and a Homebrew version is that the latter is built from source, which would allow other open-source packages that depend on Core to also be eligible for Homebrew. As it is now, any apps written that take a dependency on Core (e.g. PowerShell) can never be in Homebrew proper :(

When I worked on CLI, I had an experimental homebrew formula for preview2 here:

https://github.com/brthor/homebrew-dotnet-cli/blob/master/Formula/dotnetcli.rb

For anyone interested, this is a good starting place, and I think will just work if you replace the preview2 url in the formula with whatever release you are targetting.

IIRC there were several issues with building a proper homebrew formula, that would be officially supported. The first is that homebrew would require feature work to properly support side-by-side dotnet sdk installations. Otherwise devs will break their old projects every time they upgrade via homebrew.

EDIT: the formula solves SxS, there's some other edge case issue I can no longer recall.

The caskcroom version even isn't able to install side-by-side. you can do a brew cask install dotnet-sdk --force to install the newest version while keeping old ones or do a re-install deleting the old version and installing the newest. Due to the problem of the asp.net core runtime store not rolling forward (2.1 asp.net core runtime fixes this for 2.1) this may leave some apps non-functional.

Some side-by-side issues could in theory be resolved via metapackages and a huge number of dotnet-sdk-2.1.103/dotnet-sdk-2.1.104/* packages (which I find quite ugly but that's not the point).

Now that there seems to be a push behind the source build effort, this could also be used by homebrew. but some parts aren't source buildable yet (asp.net core runtime IIRC?).

It'd be ugly, but it could be supported via Homebrew's versioning story. For instance, PowerShell could declare a dependency on an older minor release that it no longer receiving patch updates (e.g. :depends_on "[email protected]".

Sidenote: why is SxS an issue? Not to derail the thread, but when I write :depends_on "node", all packages will just use whatever is available at /usr/local/bin/node with no issue.

@cglong

IIRC Homebrew side by side was an issue for the developer usability story of CLI. Upgrading your homebrew version shouldn't break your local apps that targetted the previous version of the shared runtime. Roll-forward between patch versions partially solves that, but rolling forward on greater version changes is unsafe.

EDIT: I might not be understanding your question about SxS correctly.

@dasMulli

Taking a look at the formula I provided, it actually solves side by side by copying formulas over top of one another in the {opt_share}. It builds from source too. I don't recall what the issues with it were, but there was at least one show-stopper from the perspective of official support.

Off the top of my head, it looks like the root dotnet binary is from whatever the last version installed was, and not the latest version, which breaks some backcompat. That could probably be fixed with a clever semaphore file somewhere.

I guess what I meant is just: Why is this an issue for .NET Core but not Node, Python or Ruby? TypeScript, IPython and Lolcat (formulae I wrote) all just use whatever happens to be the latest version of their respective runtimes at runtime. I've installed major point updates to Node without TypeScript being affected at all.

If a formula takes a dependency on [email protected], then that formula's dependency is snapped to version 2.0.x, which sounds like it might address the concern here.

Why is this an issue for .NET Core but not Node, Python or Ruby?

.NET Core solves the SxS problem in a different way (more robustly IMO).

Python for example solves it by naming one of your binaries python and the other python3. Alternatively you can use 3rd party tools like virtualenv to get a version specific to a project. But realistically having one project that depends on behavior in python 2.5 and another in 2.7 will be difficult to manage on the same machine.

I assume ruby is similar but am not a big ruby person. No idea how node.js works.

I've installed major point updates to Node without TypeScript being affected at all.

This is probably because of an effort to retain backcompat, which is one alternative to a robust SxS strategy, but is very limiting in the long term.

If a formula takes a dependency on [email protected] ...

With the formula I provided this will work, but the issue currently is that if the dotnet 1.0 formula is installed afterwards you will get the 1.0 version of the host multiplexer on the PATH, which could break the 2.0 installation.

I'd like to make a strong recommendation for a solution that is definitely more work up front but which would fairly nicely obviate most of the concerns around side by side installations, trying to manage things on the homebrew (and chocolatey) front, etc.

As has been mentioned a number of times in this thread, other language communities tend to support installing specific versions via homebrew… but recommend the use of other tools to actually manage it, for precisely the reasons brought up here: homebrew really doesn't offer support for side-by-side installation in any important way. So in Ruby people tend to use rubyenv or rvm; in Node it's nodenv or nvm, in Python it's pyenv or conda, and – perhaps most importantly as an example here – in Rust it's an officially supported and distributed tool, rustup, and that's what manages side-by-side installations of the tool.

For example, to install the current stable and nightly releases of Rust as well as 1.12.0 from last year, set the global default to stable and then use nightly in one directory and 1.12.0 in another:

$ rustup update stable nightly 1.12.0
$ rustup default stable
$ cd ~/to/some/directory
$ rustup override nightly
$ cd ~/to/someplace/else
$ rustup override 1.12.0

My experience with rustup and others over the past few years has me pretty well convinced that the best long-term play for dotnet is to either subsume that functionality itself, or to ship a dotnet-up that does the same kind of thing that rustup does. Then that tool can be installed and its version managed by homebrew, etc. much more easily, because you never need two versions of it installed side-by-side.

Obviously that's a non-zero amount of work, but (a) there's lots of prior art and (b) much of the packaging side of that already exists. (It seems like the biggest thing there is that it currently runs via a GUI package installer, which is not the way that Mac developers generally expect – though in principle a dotnet-up could still just pull that GUI package installer, amusingly weird though that would be.)

I'm also a Microsoft employee, and I'm willing to spend some (non-core) time on this. Here's my take, I would appreciate any feedback.

In my experience, many popular languages support two different compatibility models via Homebrew:

  1. Versioned formulae for backwards-incompatible versions - it's up to the project to determine whether this means major versions (e.g. python@2), minor versions (e.g. [email protected]), or potentially something else. Homebrew users are used to these packages being updated to newer versions within those defined constraints (python@2 should always be the most recent version of Python 2.x, [email protected] should be the most recent Ruby 2.3.x). I've been a Homebrew user and very occasional contributor for the last many years, and I've certainly experienced the occasional issue with a newer point release - but nowadays it's relatively trivial to revert to the older formula version and brew pin, and continue on your merry way.

  2. Version managers - rbenv, nodenv, pyenv, and the like. These are fantastic projects in their own right, which permit you to be very specific about which exact version of the language you want, to easily keep multiple versions on your machine, and to use different versions for different projects. The above version managers all basically use shims to detect, based on your environment or a configuration file, which of the installed versions to actually use when you type, e.g. ruby. Rust is a little bit of a special snowflake in this respect. It does all of the above, but in addition many of Rust's tools natively understand the concept of a toolchain - I can tell cargo to use a specific installed version of Rust just by specifying it as a parameter.

Not all languages have a version manager, but most of the common ones seem to - either a bespoke tool (rustup, sbt) or a lightweight shim manager (rbenv and its clones). It seems to me that some sort of version manager should eventually be created for .NET Core as well. Even granting that .NET Core SDKs can be installed side-by-side with no problem, there's still a problem - the user has no easy way to select which version is actually used when they run dotnet. Whether this version manager gets built into dotnet (which would involve some refactoring to separate the dotnet tool from the rest of the runtime / SDK and version it separately), or whether there's a separate environment manager in the vein of rbenv, something like that will eventually be needed for people to be able to easily build production-ready applications on .NET Core (at least on non-Windows platforms).

HOWEVER, the above is really tangential to what we're talking about here, which is getting .NET Core into Homebrew. We don't have to solve the version management problem to make that happen. If people need a specific point release of .NET Core in order to build their production-ready apps, they can do that today by following the official installation steps and downloading the appropriate .pkg installer directly from Microsoft. I don't think there's an expectation that people should be able to install a .NET Core package from homebrew and -not- have it upgraded for them.

I propose we focus our effort around maintaining minor-versioned Homebrew formulae for dotnet, and let the version management discussion happen somewhere else (I could probably get a clone of rbenv going pretty quick, but that's another topic). I also propose that we focus on brewing the full SDK package, without adding extra complexity of also supporting the runtime package. Other languages mentioned above don't have this distinction (Java is an exception, but it doesn't support being installed by plain Homebrew - it's Cask-only).

I have a modernized version of the dotnet-cli formula working for the 2.1.300 RC build. It looks like the build system is a bit different for the 2.1.200 release build, so I am working through that now.

The CLI is being built from scratch, but in order to do that the build script downloads appropriately versioned, prebuilt SDK and runtime packages. I'm not sure it would be feasible to try to build our own SDK / runtime from scratch, and the versioning dance that happens between the CLI, SDK, and runtime is hardcoded into the CLI's build script. There are other languages that do things in a similar fashion (I would guess Erlang and Smalltalk need to download a prebuilt image or VM, at least), but just something to be aware of.

@bsiegel does that build from the cli repo or use https://github.com/dotnet/source-build?

@dasMulli It doesn't currently. I'll investigate the source-build project next. It looks like it should be able to produce everything we need (it doesn't explicitly mention that it builds the CLI, but it looks like it does) and I assume that matching up the correct versions of each component are handled there too. It looks like some things are still in flux wrt/ the 2.1 release, based on the documentation I read, but it's definitely a good place to start. Thanks!

From what I know the problem with dotnet/source-build at the moment is that a lot of asp.net core components are missing - the global tools and shared framework which would have to be downloaded separately.
But I think this is definitely a good strategy for the future to use the same build infrastructure that linux distributions will use for macOS/Homebrew.
(Though personally, I prefer the cask since that's just a quick download)

as far as I am aware of there are 3 things make dotnet core version story different. And it causes existing solution from other ecosystem cannot directly apply.

  1. global.json : it can pin a project to a specific version depends on a file on project side.
  2. multi-level look up. It can find the version on program files(several known location) even if you try to run a just zipped file.
  3. run time policy. When run a portable app. Depends on the runtimeconfig.json, it could run on a different runtime you have on your machine.

@wli3 All three of those scenarios would need to be handled by some sort of dotnet version manager - whether this is ultimately shipped within the dotnet CLI itself, or written as a separate utility in the vein of rbenv and its clones. The problem you mention isn't unique to .NET - for example, plenty of Ruby projects specify a Ruby version in their .ruby-version, but the version of Ruby you get when you brew install ruby doesn't know or care about this file - you need to use a version manager for this. I feel pretty safe taking the same path with respect to versioning a future dotnet formula - brew install dotnet will always get you the latest stable version of .NET core, as will brew upgrade. If you need to stick with a specific version for awhile, brew pin it.

If I wanted a specific version of dotnet (e.g. in a production server), I would have used Docker to pin dotnet version (as well as all other dependencies). A version manager would still be awesome for use-cases not covered by Docker. I would prefer a self-contained .NET Core binary for that.

It's been almost a year since the last update here... is there a way to install dotnet via Homebrew yet?

@jonathancross brew cask install dotnet-sdk

brew cask install dotnet-sdk

This removes your old version and installs the current latest version. For users of Global.json (which in itself needs greater-than/lesser-than operators as well as wildcarding), this can be a bane.

There should be a tap available for users to install different versions of the dotnet-sdk side-by-side. The good thing is that dotnet-sdk already supports this (see dotnet --list-sdks), and the only work that needs to be done is to provide the tap.

this might be helpful: https://stackoverflow.com/a/57880964/3380951

Haha, I went there and discovered that it's a cask tap written by the commenter above you. Thanks @isen-ng! 😉

I would just like to add my vote to getting a dotnet formula into Homebrew "proper". As @cglong writes in https://github.com/dotnet/sdk/issues/4600#issuecomment-378855545:

The primary difference between a Caskroom version of .NET Core and a Homebrew version is that the latter is built from source, which would allow other open-source packages that depend on Core to also be eligible for Homebrew. As it is now, any apps written that take a dependency on Core (e.g. PowerShell) can never be in Homebrew proper :(

This is precisely the situation we're in with GitVersion. We already have a gitversion formula, but it is currently dependent on Mono, which keeps us from updating it, since such an update would require us to declare a dependency on dotnet which does not exist. We do not want to move our formula to a Cask.

So an important part of solving GitTools/GitVersion#2374 for us would be to solve this issue first by getting a source-built dotnet formula into Homebrew. Effort was made in Homebrew/homebrew-core#3691, but .NET Core was at such an early stage back then that it eventually was rejected.

We should be in a much better state with .NET Core now, though I'm having tremendous problems getting .NET Core to build on macOS, as outlined in #11795. Documentation on how to actually build .NET Core from source seems to be mostly non-existent.

Lastly, I'd like to echo what @bsiegel writes in https://github.com/dotnet/sdk/issues/4600#issuecomment-387492022:

HOWEVER, the above is really tangential to what we're talking about here, which is getting .NET Core into Homebrew. We don't have to solve the version management problem to make that happen. If people need a specific point release of .NET Core in order to build their production-ready apps, they can do that today by following the official installation steps and downloading the appropriate .pkg installer directly from Microsoft. I don't think there's an expectation that people should be able to install a .NET Core package from homebrew and -not- have it upgraded for them.

💯 to this. Homebrew is a simple, low barrier to entry way to install packages. Hard-core .NET developers won't rely on Homebrew to manage their SDK's anymore than hard-core Ruby developers depend on Homebrew (directly) to manage their Ruby versions.

Getting a build-from-source version of .NET Core into Homebrew is not only or primarily about getting .NET Core itself installed on a system. For that, a Cask formula is good enough. The main point is that through the availability of a dotnet formula in proper Homebrew, other formulae can declare their dependence on dotnet and still be available in proper Homebrew. When other tools depending on .NET Core can be built from source, it's a huge let-down that .NET Core itself can't be. That needs to be fixed so dotnet can finally become a proper Homebrew formula once and for all.

Homebrew/homebrew-core#60929 is merged and brew install dotnet now works. 🎉

Was this page helpful?
0 / 5 - 0 ratings