[Golang]当我使用Alpine Docker运行它时,错误:stdlib.h:没有这样的文件或目录,据说缺少” stdlib.h”。


golang:alpine上运行go rungo test会因Docker出现stdlib.h: No such file or directory fatal错误而被责骂。

即使我搜索了"" golang""阿尔卑斯"严重错误:stdlib.h:没有这样的文件或目录",该信息也不会以日语显示,因此具有我的可搜索性。

1
2
3
4
5
6
7
8
$ go test ./...
Testing main package
go: downloading ...
...
# runtime/cgo
exec: "gcc": executable file not found in $PATH
  FAIL  github.com/KEINOS/Sample [build failed]
  FAIL  github.com/KEINOS/Sample/hoge [build failed]
  • 图像:golang:alpine

    • 转到:v1.15.3 linux / amd64
    • 操作系统:Alpine Linux v3.12,x86_64(内核:4.19.76-linux kit)

TL; DR (今牧产业)

最低版本

1
2
# Minimum, at-least-to-install packages to run/build
apk add --no-cache gcc musl-dev

卧式服装版(含以上)

1
2
# Base meta-package to run/build (This includes the above packages as well)
apk add --no-cache build-base

在Alpine上进行开发吗?Build?如果遇到麻烦,请将其打包

1
2
# For Dev, better to be installed packages
apk add --no-cache alpine-sdk build-base

TS; DR (我从中学到的东西)

我必须从一台运行的机器上的Go语言(Golang)源中编写。但是没有安装Golang。此外,不允许单独安装它。 .. ..

幸运的是,已经安装了Docker,所以我决定尝试使用golang:alpine映像进行尝试。

在将本地当前目录装载到容器的/ go目录中时开始

1
2
3
4
5
$ # Docker でマウントを取ってみる
$ cd /path/to/the/repo
$ docker run --rm -it -v $(pwd):/go golang:alpine /bin/sh
...
/go #

$GOPATH/go.mod exists but should not错误

首先,运行测试。不知何故,它根本无法工作。

1
2
3
4
5
6
7
8
9
10
11
/go # go test main.go ./...
$GOPATH/go.mod exists but should not

/go # go mod download
$GOPATH/go.mod exists but should not

/go # go mod verify
$GOPATH/go.mod exists but should not

/go # go env
$GOPATH/go.mod exists but should not

我认为这是因为未安装

mod,但是它是exists,所以看起来有所不同。据说go.mod exists but should not具有" go.mod,但不应该"。

显然,以上错误与GOPATH模式和模块模式有关。

  • 参考

    • Go:Qiita从Dep迁移到Go Modules

当然,环境变量没有GO111MODULE

1
2
3
4
5
6
7
8
9
/go # env
HOSTNAME=xxxxxxxxxxxx
SHLVL=1
HOME=/root
TERM=xterm
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
GOPATH=/go
PWD=/go
GOLANG_VERSION=1.15.3

我想知道是否是因为它处于GOPATH模式,所以我尝试将GO111MODULE=on设置为"始终在模块兼容模式下运行",但不幸的是它没有用。

以GO111MODULE = on开头

1
2
3
4
5
6
$ docker run --rm -it -v $(pwd):/go -e GO111MODULE=on golang:alpine /bin/sh
/go #
/go # echo $GO111MODULE
on
/go # go env
$GOPATH/go.mod exists but should not

由于它是

GO v1.15,因此默认情况下首先将GO111MODULE设置为auto,即似乎启用了"模块模式",并且根据下面的链接有两种解决方法。 ..

  • 参考

    • 从GOPATH模式转到模块兼容模式@ Qiita

    • [Golang] $ GOPATH / go.mod存在,但不应避免@ Selfnote

    • 在Ubuntu 16.04 @ StackOverflow中收到GOPATH错误"开始:无法在GOPATH模式下使用路径@version语法"

  • 将源代码挂载到/go以外的目录中并执行它。

  • export GOPATH=和环境变量设置设置为"空",并将其缓存在用户目录下。

  • go.mod exists but should not的原因

    原因是将源代码安装在容器上时的安装目标($(pwd):/go)。源代码与GOPATH处于相同的层次结构中。换句话说,将开发源代码与mod.go放在GOPATH指定的目录中时,即使它处于模块模式,也遇到了错误。

    模块模式下,该模块将缓存在GOPATH指定的目录下。因此,该错误是由该缓存目录中的诸如go.mod之类的额外文件引起的。他说,当然,"有$GOPATH/go.mod exists but should not"和" $GOPATH/go.mod,但它们被禁止。"

    暂时,我决定将其安装在/app而不是/go上。

    在将本地当前目录装载到/ app时开始

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    $ cd /path/to/the/repo
    $ docker run --rm -it -v $(pwd):/app golang:alpine /bin/sh
    /go #
    /go # # マウントしたディレクトリに移動
    /go # cd /app
    /app #
    /app # # 今度は go env が表示された。GO111MODULEは空なので auto ∴ モジュールモード
    /app # go env
    GO111MODULE=""
    GOARCH="amd64"
    GOBIN=""
    GOCACHE="/root/.cache/go-build"
    GOENV="/root/.config/go/env"
    GOEXE=""
    GOFLAGS=""
    GOHOSTARCH="amd64"
    GOHOSTOS="linux"
    GOINSECURE=""
    GOMODCACHE="/go/pkg/mod"
    GONOPROXY=""
    GONOSUMDB=""
    GOOS="linux"
    GOPATH="/go"
    GOPRIVATE=""
    GOPROXY="https://proxy.golang.org,direct"
    GOROOT="/usr/local/go"
    GOSUMDB="sum.golang.org"
    GOTMPDIR=""
    GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
    GCCGO="gccgo"
    AR="ar"
    CC="gcc"
    CXX="g++"
    CGO_ENABLED="1"
    GOMOD=""
    CGO_CFLAGS="-g -O2"
    CGO_CPPFLAGS=""
    CGO_CXXFLAGS="-g -O2"
    CGO_FFLAGS="-g -O2"
    CGO_LDFLAGS="-g -O2"
    PKG_CONFIG="pkg-config"
    GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build030913204=/tmp/go-build -gno-record-gcc-switches"

    "gcc": executable file not found in $PATH错误

    然后,再次查看并重新测试。我继续前进,但是没有用。

    运行测试

    1
    2
    3
    4
    5
    6
    7
    8
    /app # go test ./...
    go: downloading github.com/...
    go: downloading github.com/...
    ...
    # runtime/cgo
    exec: "gcc": executable file not found in $PATH
    FAIL    github.com/KEINOS/Hello-Cobra [build failed]
    FAIL    github.com/KEINOS/Hello-Cobra/hoge [build failed]

    不知何故cgo生气。没有gcc。嗯cgo我没用过。我想知道从属软件包是否正在使用它。

    • 使用cgo(1)@ Qiita在C和Go链接后面

    暂时安装gcc,然后再次进行测试。

    gcc安装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /app # # gcc 入ってない
    /app # gcc --version
    /bin/sh: gcc: not found
    /app #
    /app # # gcc 入れる
    /app # apk add --no-cache gcc
    ...
    /app # # gcc 入った
    /app # gcc --version
    gcc (Alpine 9.3.0) 9.3.0

    重新测试

    1
    2
    3
    4
    5
    6
    7
    8
    /app # go test ./...
    # runtime/cgo
    _cgo_export.c:3:10: fatal error: stdlib.h: No such file or directory
        3 | #include <stdlib.h>
          |          ^~~~~~~~~~
    compilation terminated.
    FAIL    github.com/KEINOS/Hello-Cobra [build failed]
    FAIL    github.com/KEINOS/Hello-Cobra/hoge [build failed]

    毕竟,似乎他在某处使用cgo,并且被骂了。这次,如果stdlib.h还不够,那就是C。显然,依赖包使用的是cgo

    已将问题发布到GitHub上的Golang Docker存储库中。 Alpine的cgo似乎需要musl-dev。不,我经常在阿尔卑斯问题中看到它。

    尝试添加musl-dev
    不知道为什么gcc不依赖它。
    (从CGO看来在golang上不起作用:1.6-alpine#86 @ GitHub)

    现在,让我们再次测试。有效。

    1
    2
    3
    4
    5
    6
    7
    8
    /app # # musl-dev 入れる
    /app # apk add --no-cache musl-dev
    ...
    /app # # テストする
    /app # go test ./...
    ok      github.com/KEINOS/Sample        0.003s
    ok      github.com/KEINOS/Sample/hoge   0.006s
    /app # # ??

    是的,高山图像被设计为最小化。
    (从CGO看来在golang上不起作用:1.6-alpine#86 @ GitHub)

    "是的。Alpine图像被设计为最低要求。"该文件说。

    需要注意的主要警告是,它确实使用musl libc而不是glibc和朋友,这可能导致意外行为。
    ...
    为了最小化映像大小,基于Alpine的映像中不包含其他相关工具(例如gitgccbash)。以该映像为基础,在您自己的Dockerfile中添加所需的内容(请参阅alpine图像说明,以获取有关如何在不熟悉的情况下安装软件包的示例。)
    (golang:-alpine |快速参考| Golang | docker-library @ GitHub)

    "无论如何,我建议您Alpine使用不可读的musl libc代替glibc及其有趣的同伴。并且,为了使尺寸尽可能小,不包括gitgcc甚至bash

    顺便说一句。由于Alpine是用于容器的,因此它不包含任何内容,因此我忘记了将自己需要的东西放在Dockerfile中来使用它。

    他说:"以某种方式,找到并安装apk软件包很麻烦。"如果您搜索类似Ubuntu的" build-essential"包之类的东西,"我经常将其用于构建。"有"收集所说的内容的程序包"和"收集经常用于开发的内容的程序包"。

    构建所需的常见事物包

    1
    apk add build-base

    开发所需的常见事物包

    1
    apk add alpine-sdk
    • #24 | docker-alpine | gliderlabs @ GitHub与build-essential等效吗?

    当然,我可以不用插入gccmusl-dev而完成build-base

    参考

    • 从GOPATH模式转到模块兼容模式@ Qiita

    • 使用cgo(1)@ Qiita在C和Go链接后面

    • [Golang] $ GOPATH / go.mod存在,但不应避免@ Selfnote

    • 尝试构建docker映像时,出现" gcc":在$ PATH中未找到可执行文件@StackOverflow

    • CGO在golang上似乎不起作用:1.6-alpine#86 @ GitHub

    • #24 | docker-alpine | gliderlabs @ GitHub与build-essential等效吗?

    • 在Ubuntu 16.04 @ StackOverflow中收到GOPATH错误"开始:无法在GOPATH模式下使用路径@version语法"