With go 1.11 installed via nix on darwin, compiling simple commands that import crypto/x509 via net/http fail to compile due to problems with darwin core header imports.
Error message: 'CoreFoundation/CoreFoundation.h' file not found
For the record, go itself builds fine via nix. xcode command line tools seem to be installed ok, at least xcode-select --install
claims they're installed already.
$ cat x.go
package main
import (
"net/http"
)
func main() {
print("hello")
}
$ go build -o x x.go
# crypto/x509
/nix/store/mkcsimqjfw9s2b9rn77yvx5bpfgavpp2-go-1.11.5/share/go/src/crypto/x509/root_cgo_darwin.go:16:10: fatal error: 'CoreFoundation/CoreFoundation.h' file not found
#include <CoreFoundation/CoreFoundation.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
$ CGO_ENABLED=0 go build -o x x.go
# command-line-arguments
./x.go:4:2: imported and not used: "net/http"
(changing x.go to make proper use of the http package results in a working binary)
"x86_64-darwin"
Darwin 18.2.0, macOS 10.14.3
no
no
nix-env (Nix) 2.1.3
"nixpkgs-19.03pre170546.0f43790d2ce"
/Users/rob/.nix-defexpr/channels/nixpkgs
Later edit: By changing $PATH
my coworker ended up using the 1.12
version installed through Brew instead of the NixOS
version, so you can probably disregard what I wrote below.
Someone ran into this at work (also 1.11
on OS X)... this is what fixed it for him:
Changing
$PATH
so that/usr/local/bin/
comes before$HOME/.nix-profile/bin
Did anyone find a fix for this? I'm seeing the same thing with go-1.12 and have tried a few things, but no luck so far.
Here's what I've tried so far (none of this worked):
open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg
(See https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes)export CGO_LDFLAGS="-g -O2 -L/usr/include"
export CGO_LDFLAGS="-g -O2 -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks"
Some diagnostics..
$ nix-env -q go
go-1.12
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/sam/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/sam"
GOPROXY=""
GORACE=""
GOROOT="/nix/store/g72v3zdzn5m0i1bggk35shjvgyak9h6f-go-1.12/share/go"
GOTMPDIR=""
GOTOOLDIR="/nix/store/g72v3zdzn5m0i1bggk35shjvgyak9h6f-go-1.12/share/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="/nix/store/c64nivj8qwfx6cy5x6a8gbh6nx9m7vpk-clang-wrapper-5.0.2/bin/cc"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2 -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/bg/jmsytq956jb8bk8z0p21k3vc0000gp/T/go-build067383024=/tmp/go-build -gno-record-gcc-switches -fno-common"
I've got it working by creating a nix shell using this file shell.nix
:
with import <nixpkgs> {}; {
devEnv = stdenv.mkDerivation {
name = "dev";
buildInputs = [ stdenv go ];
CFLAGS="-I/usr/include";
LDFLAGS="-L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks";
};
}
Then running nix-shell shell.nix
and re-running my go build.
This bugs me as well. Everything works fine in nix-shell, but running go vet
outside always fails with this error - I can no longer lint my code in Vim :(
env CC=clang gometalinter
seems to work around the problem.
I've a feeling this is partially related to the CC
setting when compiled with Nix.
I'm not quite sure why this differs c.f CXX
BTW.
% go env
[...]
GCCGO="gccgo"
CC="/nix/store/2p5k5g7byv3vnswwlj5gramgrh31zdgm-clang-wrapper-7.1.0/bin/cc"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
[...]
Overriding with export CC=clang
fixes this, but making that work for GUI apps is trickier under macOS.
This does work on Darwin 18.2.0, macOS 10.14.2
cd /System/Library/Frameworks/CoreFoundation.framework
ln -s /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers Headers
ln -s /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreFoundation.framework/Modules Modules
cd /System/Library/Frameworks/Security.framework
ln -s /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers Headers
ln -s /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Modules Modules
Just to note that by upgrading go, it now works fine for me:
upgrading 'go-1.11.5' to 'go-1.12.6'
I still get this error with go-1.12.6 on darwin.
Here's how I can produce the error. Create a file named x.go
:
package test
/*
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
*/
import "C"
Build fails with go from nixpkgs, but works with CC=clang
.
$ go build x.go
# command-line-arguments
./x.go:9:10: fatal error: 'CoreFoundation/CoreFoundation.h' file not found
#include <CoreFoundation/CoreFoundation.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
$ CC=clang go build x.go
$
I also get similar results calling go's CC directly:
$ cat xx.c
#include <CoreFoundation/CoreFoundation.h>
int main(){ return 0; }
$ go env | grep ^CC
CC="/nix/store/p9xdhw6viqrypbr09l7ng7g5065kpdm1-clang-wrapper-7.1.0/bin/cc"
$ /nix/store/p9xdhw6viqrypbr09l7ng7g5065kpdm1-clang-wrapper-7.1.0/bin/cc -framework CoreFoundation xx.c
xx.c:1:10: fatal error: 'CoreFoundation/CoreFoundation.h' file not found
#include <CoreFoundation/CoreFoundation.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
$ /usr/bin/clang -framework CoreFoundation xx.c
$
Just to note that by upgrading go, it now works fine for me:
upgrading 'go-1.11.5' to 'go-1.12.6'
Interestingly, this is what I had thought when I originally updated, but seems like I wasn't using anything that needed crypto (e.g. SSL).
Not sure if anyone else here has checked-in on IRC, but I had some help from abarthur
and teto
:
(also)
To paraphrase, for those that aren't familiar:
Nix uses headers downloaded from Apple, rather than the Xcode ones:
... which fits the Nix ethos around encapsulated/isolated builds and not leaving headers as droppings in the "real" f/s.
The Nix-provided clang
doesn't know about system headers, and (rightly) doesn't have access to the above headers by default.
Adding the right CGO_CFLAGS
/CGO_LDFLAGS
/etc or overriding CC
bypasses this.
The technically correct thing to do is to drop into a nix-shell
with the right compilation targets as per https://nixos.wiki/wiki/Go now makes a lot more sense with the additional context.
It doesn't (yet) help me when VSCode spits the dummy because it doesn't know how to leverage nix-shell
instead 鈥斅燽ut I'm slowly looking into what config I can adjust.
People (including myself) still struggle with this issue, see https://github.com/NixOS/nixpkgs/issues/80177.
The technically correct thing to do is to drop into a nix-shell with the right compilation targets as per https://nixos.wiki/wiki/Go now makes a lot more sense with the additional context.
@mexisme Could you please elaborate what exactly you did to solve the problem so we can reproduce it?
@mexisme Could you please elaborate what exactly you did to solve the problem so we can reproduce it?
If you're talking about using nix-shell
, then is that not working for you?
I haven't tried that for a fair while.
If you're talking about building as "normal" (e.g. from VSCode, or on a terminal) then I usually cheat by building in a terminal:
CC=/usr/bin/cc go # (etc)
(can also do CC=/usr/bin/clang ...
)
That works every time, so far.
I also have to do this with compiler wrappers like ginkgo
.
In VSCode, I've tried setting some Go-lang settings, like:
"go.testEnvVars": {
"CC": "/usr/bin/cc"
},
"go.toolsEnvVars": {
"CC": "/usr/bin/cc"
},
... but it seems like neither are used when running go
directly?
When trying to produce a minimal example it turned out that the problem I have is actually https://github.com/NixOS/nixpkgs/issues/69401, which has something to do with permissions on $GOPATH
. So this issue does not apply - which is good, I guess.
For posterity: What I was really trying to do was using github.com/stretchr/testify
in my tests, and that needs hashing somewhere in its dependencies. But for simplicity let us take @svend's minimal example:
$ cat main.go
package main
/*
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
*/
import "C"
func main() {}
$ cat go.mod
module example.com/x
$ cat default.nix
let
nixpkgs = builtins.fetchGit {
name = "nixpkgs";
url = "https://github.com/NixOS/nixpkgs-channels";
ref = "nixos-19.09";
rev = "b9cb3b2fb2f45ac8f3a8f670c90739eb34207b0e";
};
pkgs = import (nixpkgs) {};
in
pkgs.buildGoModule {
pname = "x";
version = "0";
modSha256 = "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5";
src = ./.;
}
Then we try to build the thing inside nix-shell
:
$ nix-shell
$ go build
go: failed to create cache directory /nix/store/3702mrbj6jc9vry6m9bdcl2qany7892r-go-1.12.16/share/go/pkg/mod/cache: mkdir /nix/store/3702mrbj6jc9vry6m9bdcl2qany7892r-go-1.12.16/share/go/pkg/mod: permission denied
This is what happens in the above issue. Let us work around it with sudo:
$ sudo go build
# example.com/x
./x.go:7:10: fatal error: 'CoreFoundation/CoreFoundation.h' file not found
#include <CoreFoundation/CoreFoundation.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Here I got stuck yesterday, but then I remembered that sudo
spawns a new environment. We need to carry over the one from nix-shell
with sudo -E
:
$ sudo -E go build
$ ls
default.nix go.mod x x.go
So that worked. Unfortunately go.mod
and the x
binary are now owned by root
. As noted in https://github.com/NixOS/nixpkgs/issues/69401#issue-498086212, unsetting $GOPATH
fixes the initial permission problem. Let us fix this in default.nix
:
$ cat default.nix
# ...
pkgs.buildGoModule {
# ...
shellHook = ''
unset GOPATH
'';
}
Interestingly the issue does not occur when running nix-build
, so this really is a problem with the Go environment, and has nothing to do with buildGoModule
.
Hi people, I've made a PR that should address this: https://github.com/NixOS/nixpkgs/pull/90592
Please give it a try and leave some comments if you run into issues!
And for those who want an overlay, here you go:
(self: super: {
go = super.go.overrideAttrs (oldAttrs: {
buildInputs = oldAttrs.buildInputs ++ [ self.makeWrapper ];
postInstall = with self.darwin.apple_sdk.frameworks; ''
wrapProgram $out/share/go/bin/go \
--suffix CGO_CFLAGS ' ' '-iframework ${CoreFoundation}/Library/Frameworks -iframework ${Security}/Library/Frameworks' \
--suffix CGO_LDFLAGS ' ' '-F${CoreFoundation}/Library/Frameworks -F${Security}/Library/Frameworks'
'';
});
})
Looking into this more, I think the underlying problem is actually this: https://github.com/NixOS/nixpkgs/blob/e41ea6b5b2d6727a733e66d4d641fa533df1e4a1/pkgs/development/compilers/go/1.14.nix#L197
The problem is that this causes the CC to be hardcoded, as go env CC
will show. If you're just using the xcode clang (which you should) then you can do go env -w CC=clang
and this will fix the issue as well. Alternatively you can add environment.variables.CC = "clang"
to your nix-darwin config.
I have a PR to fix this CC override from the compilation process: https://github.com/NixOS/nixpkgs/pull/91347
This will bring Go to match the default behavior, so it will be as env CC=clang go
I just rebuilt my environment with a nix-channel --update
then a darwin-rebuild switch
and I'm now able to build the Go code I couldn't before. Thanks!
Most helpful comment
env CC=clang gometalinter
seems to work around the problem.