Docker Makefile文件结构

转自: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 "#"
	} >&2
fi
echo

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

# List of bundles to create when no argument is passed
DEFAULT_BUNDLES=(
	validate-dco
	validate-gofmt
	validate-test
	validate-toml
	validate-vet
	binary
	test-unit
	test-integration-cli
	test-docker-py
	dynbinary
	cover
	cross
	tgz
	ubuntu
)

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

VERSION=$(< ./VERSION)
if command -v git &> /dev/null && git rev-parse &> /dev/null; then
	GITCOMMIT=$(git rev-parse --short HEAD)
	if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
		GITCOMMIT="$GITCOMMIT-dirty"
	fi
elif [ "$DOCKER_GITCOMMIT" ]; then
	GITCOMMIT="$DOCKER_GITCOMMIT"
else
	echo >&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 1
fi

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

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

检查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 appropriately
if \
    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 binary
IAMSTATIC='true'
source "$SCRIPTDIR/make/.go-autogen"
if [ -z "$DOCKER_DEBUG" ]; then
	LDFLAGS='-w'
fi
LDFLAGS_STATIC='-linkmode external'
# Cgo -H windows is incompatible with -linkmode external.
if [ "$(go env GOOS)" == 'windows' ]; then
	LDFLAGS_STATIC=''
fi
EXTLDFLAGS_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 here
BUILDFLAGS=( $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#752
	export CC=clang
	# "-extld clang" is a workaround for
	# https://code.google.com/p/go/issues/detail?id=6845
	LDFLAGS="$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=1
fi

接着是一些函数定义,大部分都是根据名字就能知道功能的。我们从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 bundles
	if [ -e "bundles/$VERSION" ]; then
		echo "bundles/$VERSION already exists. Removing."
		rm -fr "bundles/$VERSION" && mkdir "bundles/$VERSION" || exit 1
		echo
	fi
	if [ "$(go env GOHOSTOS)" != 'windows' ]; then
		# Windows and symlinks don't get along well
		rm -f bundles/latest
		ln -s "$VERSION" bundles/latest
	fi
	if [ $# -lt 1 ]; then
		bundles=(${DEFAULT_BUNDLES[@]})
	else
		bundles=($@)
	fi
	for bundle in ${bundles[@]}; do
		export DEST="bundles/$VERSION/$(basename "$bundle")"
		# Cygdrive paths don't play well with go build -o.
		if [[ "$(uname -s)" == CYGWIN* ]]; then
			export DEST="$(cygpath -mw "$DEST")"
		fi
		mkdir -p "$DEST"
		ABS_DEST="$(cd "$DEST" && pwd -P)"
		bundle "$bundle"
		echo
	done
}

这里通过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/bash
set -e
BINARY_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
	" \
	./docker
echo "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开始看咯。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值