Docker Makefile文件结构

来源:互联网 发布:unsw moodle 网络 编辑:程序博客网 时间:2024/06/14 05:40

转自:http://www.tuicool.com/articles/MNNjmiE


这里来分析下docker的Makefile作为之后对于docker实现的一个切入口。

首先是all:

all: build    $(DOCKER_RUN_DOCKER) hack/make.sh

build做的操作为:

build: bundles    docker build -t "$(DOCKER_IMAGE)" .

bundles做的操作为:

bundles:    mkdir bundles

这里有些奇怪,既然我的目的是编译docker,那么这里的docker命令又是哪里来的呢?docker在这里确实很有新意,其编译后并不是安装到本地,而是安装在一个docker container中,因此编译的时候我们得保证有docker安装了才行。

所以这里首先会建立一个bundles目录,然后会执行docker build -t “$(DOCKER_IMAGE)”,也就是生成一个image。默认这个image的名字是docker-dev,也就是这里会从仓库里下载个image。之后DOCKER_RUN_DOCKER,也就是:

DOCKER_RUN_DOCKER := docker run --rm -it --privileged $(DOCKER_ENVS) $(DOCKER_MOUNT) "$(DOCKER_IMAGE)"

会运行这个image,并在里边执行hack/make.sh。因此我们来看下make.sh。

首先是检查下是不是跑在container中:

# We're a nice, sexy, little shell script, and people might try to run us;# but really, they shouldn't. We want to be in a container!if [ "$PWD" != "/go/src/$DOCKER_PKG" ] || [ -z "$DOCKER_CROSSPLATFORMS" ]; then{   echo "# WARNING! I don't seem to be running in the Docker container."echo "# The result of this command might be an incorrect build, and will not be"echo "#   officially supported."echo "#"echo "# Try this instead: make all"echo "#"} >&2fiecho

然后是列出了默认要建立的bundle:

# List of bundles to create when no argument is passedDEFAULT_BUNDLES=(validate-dcovalidate-gofmtvalidate-testvalidate-tomlvalidate-vetbinarytest-unittest-integration-clitest-docker-pydynbinarycovercrosstgzubuntu)

接着检查是不是git上拷贝下来的源码:

VERSION=$(< ./VERSION)if command -v git &> /dev/null && git rev-parse &> /dev/null; thenGITCOMMIT=$(git rev-parse --short HEAD)if [ -n "$(git status --porcelain --untracked-files=no)" ]; thenGITCOMMIT="$GITCOMMIT-dirty"fielif [ "$DOCKER_GITCOMMIT" ]; thenGITCOMMIT="$DOCKER_GITCOMMIT"elseecho >&2 'error: .git directory missing and DOCKER_GITCOMMIT not specified'echo >&2 '  Please either build with the .git directory accessible, or specify the'echo >&2 '  exact (--short) commit hash you are building using DOCKER_GITCOMMIT for'echo >&2 '  future accountability in diagnosing build issues.  Thanks!'exit 1fi

建立GOPATH目录,我们的可执行文件会被安装到这个下面:

if [ "$AUTO_GOPATH" ]; thenrm -rf .gopathmkdir -p .gopath/src/"$(dirname "${DOCKER_PKG}")"ln -sf ../../../.. .gopath/src/"${DOCKER_PKG}"export GOPATH="${PWD}/.gopath:${PWD}/vendor"fiif [ ! "$GOPATH" ]; thenecho >&2 'error: missing GOPATH; please see https://golang.org/doc/code.html#GOPATH'echo >&2 '  alternatively, set AUTO_GOPATH=1'exit 1fi

检查DOCKER_EXPERIMENTAL是否被设置,如果设置的话打个warning:

if [ "$DOCKER_EXPERIMENTAL" ]; then    echo >&2 '# WARNING! DOCKER_EXPERIMENTAL is set: building experimental features'    echo >&2    DOCKER_BUILDTAGS+=" experimental"fi

是否要编译daemon:

if [ -z "$DOCKER_CLIENTONLY" ]; then    DOCKER_BUILDTAGS+=" daemon"fi

是否是lxc:

if [ "$DOCKER_EXECDRIVER" = 'lxc' ]; then    DOCKER_BUILDTAGS+=' test_no_exec'fi

是否能编译btrfs:

# test whether "btrfs/version.h" exists and apply btrfs_noversion appropriatelyif \    command -v gcc &> /dev/null \    && ! gcc -E - &> /dev/null <<<'#include <btrfs/version.h>' \; then    DOCKER_BUILDTAGS+=' btrfs_noversion'fi

是否支持延迟remove:

# test whether "libdevmapper.h" is new enough to support deferred remove# functionality.if \    command -v gcc &> /dev/null \    && ! ( echo -e  '#include <libdevmapper.h>\nint main() { dm_task_deferred_remove(NULL); }'| gcc -ldevmapper -xc - &> /dev/null ) \; then       DOCKER_BUILDTAGS+=' libdm_no_deferred_remove'fi

设置一些编译选项:

# Use these flags when compiling the tests and final binaryIAMSTATIC='true'source "$SCRIPTDIR/make/.go-autogen"if [ -z "$DOCKER_DEBUG" ]; thenLDFLAGS='-w'fiLDFLAGS_STATIC='-linkmode external'# Cgo -H windows is incompatible with -linkmode external.if [ "$(go env GOOS)" == 'windows' ]; thenLDFLAGS_STATIC=''fiEXTLDFLAGS_STATIC='-static'# ORIG_BUILDFLAGS is necessary for the cross target which cannot always build# with options like -race.ORIG_BUILDFLAGS=( -a -tags "netgo static_build $DOCKER_BUILDTAGS" -installsuffix netgo )# see https://github.com/golang/go/issues/9369#issuecomment-69864440 for why -installsuffix is necessary hereBUILDFLAGS=( $BUILDFLAGS "${ORIG_BUILDFLAGS[@]}" )# Test timeout.: ${TIMEOUT:=30m}TESTFLAGS+=" -test.timeout=${TIMEOUT}"# A few more flags that are specific just to building a completely-static binary (see hack/make/binary)# PLEASE do not use these anywhere else.EXTLDFLAGS_STATIC_DOCKER="$EXTLDFLAGS_STATIC -lpthread -Wl,--unresolved-symbols=ignore-in-object-files"LDFLAGS_STATIC_DOCKER="$LDFLAGS_STATIC-extldflags \"$EXTLDFLAGS_STATIC_DOCKER\""

FreeBSD做个特殊处理:

if [ "$(uname -s)" = 'FreeBSD' ]; then# Tell cgo the compiler is Clang, not GCC# https://code.google.com/p/go/source/browse/src/cmd/cgo/gcc.go?spec=svne77e74371f2340ee08622ce602e9f7b15f29d8d3&r=e6794866ebeba2bf8818b9261b54e2eef1c9e588#752export CC=clang# "-extld clang" is a workaround for# https://code.google.com/p/go/issues/detail?id=6845LDFLAGS="$LDFLAGS -extld clang"fi

处理sqlite3.h的路径问题:

# If sqlite3.h doesn't exist under /usr/include,# check /usr/local/include also just in case# (e.g. FreeBSD Ports installs it under the directory)if [ ! -e /usr/include/sqlite3.h ] && [ -e /usr/local/include/sqlite3.h ]; then    export CGO_CFLAGS='-I/usr/local/include'    export CGO_LDFLAGS='-L/usr/local/lib'fi

根据GO的支持程度设置test相关变量:

HAVE_GO_TEST_COVER=if \    go help testflag | grep -- -cover > /dev/null \    && go tool -n cover > /dev/null 2>&1 \; then    HAVE_GO_TEST_COVER=1fi

接着是一些函数定义,大部分都是根据名字就能知道功能的。我们从main开始看:

main() {# We want this to fail if the bundles already exist and cannot be removed.# This is to avoid mixing bundles from different versions of the code.mkdir -p bundlesif [ -e "bundles/$VERSION" ]; thenecho "bundles/$VERSION already exists. Removing."rm -fr "bundles/$VERSION" && mkdir "bundles/$VERSION" || exit 1echofiif [ "$(go env GOHOSTOS)" != 'windows' ]; then# Windows and symlinks don't get along wellrm -f bundles/latestln -s "$VERSION" bundles/latestfiif [ $# -lt 1 ]; thenbundles=(${DEFAULT_BUNDLES[@]})elsebundles=($@)fifor bundle in ${bundles[@]}; doexport DEST="bundles/$VERSION/$(basename "$bundle")"# Cygdrive paths don't play well with go build -o.if [[ "$(uname -s)" == CYGWIN* ]]; thenexport DEST="$(cygpath -mw "$DEST")"fimkdir -p "$DEST"ABS_DEST="$(cd "$DEST" && pwd -P)"bundle "$bundle"echodone}

这里通过for循环一次调用bundle函数,bundle的实现为:

bundle() {    local bundle="$1"; shift    echo "---> Making bundle: $(basename "$bundle") (in $DEST)"    source "$SCRIPTDIR/make/$bundle" "$@"}

bundle数组我们在一开始的时候就列出来了,这里看下binary,对应的文件为hack/make/binary,内容很短:

#!/bin/bashset -eBINARY_NAME="docker-$VERSION"BINARY_EXTENSION="$(binary_extension)"BINARY_FULLNAME="$BINARY_NAME$BINARY_EXTENSION"source "${MAKEDIR}/.go-autogen"echo "Building: $DEST/$BINARY_FULLNAME"go build \-o "$DEST/$BINARY_FULLNAME" \"${BUILDFLAGS[@]}" \-ldflags "$LDFLAGS$LDFLAGS_STATIC_DOCKER" \./dockerecho "Created binary: $DEST/$BINARY_FULLNAME"ln -sf "$BINARY_FULLNAME" "$DEST/docker$BINARY_EXTENSION。"hash_files "$DEST/$BINARY_FULLNAME"

可以看到其调用go build直接编译生成docker-$VERSION文件,并做了个软链到$DEST/docker$BINARY_EXTENSION。同时这个命令也告诉了我们编译文件的入口,也就是main文件的位置,就是docker/docker.go。下面要看代码的时候,就从这个docker.go的main开始看咯。


0 0