Nixpkgs: go 1.11 fails with crypto/x509 and cgo

Created on 25 Feb 2019  路  19Comments  路  Source: NixOS/nixpkgs

Issue description

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.

Steps to reproduce

$ 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)

Technical details

  • system: "x86_64-darwin"
  • host os: Darwin 18.2.0, macOS 10.14.3
  • multi-user?: no
  • sandbox: no
  • version: nix-env (Nix) 2.1.3
  • channels(rob): "nixpkgs-19.03pre170546.0f43790d2ce"
  • nixpkgs: /Users/rob/.nix-defexpr/channels/nixpkgs
darwin golang

Most helpful comment

env CC=clang gometalinter seems to work around the problem.

All 19 comments

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rzetterberg picture rzetterberg  路  3Comments

matthiasbeyer picture matthiasbeyer  路  3Comments

yawnt picture yawnt  路  3Comments

edolstra picture edolstra  路  3Comments

langston-barrett picture langston-barrett  路  3Comments