跳过正文

代码生成过程

·329 字·2 分钟
K8s-Codegen - 这篇文章属于一个选集。
§ 4: 本文

代码生成过程
#

本节以 deepcopy-gen 为例,介绍代码生成器生成代码的全流程。其他代码生成器的生成过程与 deepcopy-gen 基本一致。

Kubernetes 代码生成器包括 deepcopy-gen、defaulter-gen、conversion-gen、openapi-gen、prerelease-lifecycle-gen、client-gen、lister-gen、informer-gen、applyconfiguration-gen 等。其中最常用的 5 种生成代码的过程如图 13-3 所示。

deepcopy-gen、defaulter-gen、conversion-gen、openapi-gen、prerelease-lifecycle-gen、client-gen、lister-gen、informer-gen、applyconfiguration-gen 代码生成器生成代码的流程基本类似,以 deepcopy-gen 代码生成器为例,生成代码的过程可分为以下 3 步:

  • 构建 deepcopy-gen 二进制文件。
  • 生成 .todo 文件。
  • 生成 DeepCopy 相关函数。
image-20260516014113953

下面分别进行介绍。

构建 deepcopy-gen 二进制文件
#

为方便读者理解 Makefile.generated_files 的生成代码的过程,下面将 Makefile.generated_files 中的代码和重要的调试信息一并展示。以 deepcopy-gen 代码生成器为例,代码示例如下。

$(DEEPCOPY_GEN):
	$(GODEPS k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/deepcopy-gen)
	KUBE_BUILD_PLATFORMS="" \
	hack/make-rules/build.sh k8s.io/code-generator/cmd/deepcopy-gen
	touch $@

重要的调试信息如下:

KUBE_BUILD_PLATFORMS="" hack/make-rules/build.sh k8s.io/code-generator/cmd/deepcopy-gen
touch _output/bin/deepcopy-gen

hack/make-rules/build.sh 构建脚本根据传入的代码生成器的 main 入口文件路径,构建二进制文件。touch $@ 则更新 deepcopy-gen 代码生成器二进制文件的 atime/mtime/ctime 时间戳。

生成 .todo 文件
#

.todo 文件相当于临时文件,用来存放被 Tags 标记过的包。通过 shell 的 grep 命令将所有代码包中 Tags 标记过的包目录记录在 .todo 文件中,方便记录哪些包需要使用代码生成功能,代码示例如下。

ALL_K8S_TAG_FILES := $(shell find $(ALL_GO_DIRS) -maxdepth 1 -type f -name \*.go | xargs grep --color=never -l '^// *+k8s:')
DEEPCOPY_DIRS := $(shell grep --color=never -l '+k8s:deepcopy-gen=' $(ALL_K8S_TAG_FILES) | xargs -n1 dirname | LC_ALL=C sort -u)

$(DEEPCOPY_FILES): $(DEEPCOPY_GEN)
	if [ "$(DBG_CODEGEN)" == 1 ]; then \
		echo "DBG: deepcopy needed in $(@D):"; \
		ls -lft --full-time $@ || true; \
		ls -lft --full-time $? || true; \
	fi
	echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(DEEPCOPY_GEN).todo

重要的调试信息如下:

echo k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config>>.make/_output/bin/deepcopy-gen.todo

Makefile.generated_files 中定义了 ALL_K8S_TAG_FILES 变量,用于获取代码中使用“// +k8s:”Tags 标记过的包,DEEPCOPY_DIRS 变量用于从 ALL_K8S_TAG_FILES 变量中筛选出使用“+k8s:deepcopy-gen”Tag 标记过的包。最终将筛选出的包路径输出到 .todo 文件中。deepcopy-gen.todo 文件中的部分内容如下。

$ head .make/_output/bin/deepcopy-gen.todo
k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config
k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config/v1alpha1
k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm
k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1
k8s.io/kubernetes/pkg/apis/abac
k8s.io/kubernetes/pkg/apis/abac/v0
k8s.io/kubernetes/pkg/apis/abac/v1beta1
k8s.io/kubernetes/pkg/apis/admission
k8s.io/kubernetes/pkg/apis/admissionregistration
k8s.io/kubernetes/pkg/apis/apps

生成 DeepCopy 相关函数
#

.PHONY: gen_deepcopy
gen_deepcopy: $(DEEPCOPY_GEN) $(META_DIR)/$(DEEPCOPY_GEN).todo
	if [ -s $(META_DIR)/$(DEEPCOPY_GEN).todo ]; then \
		pkgs=$$(cat $(META_DIR)/$(DEEPCOPY_GEN).todo | paste -sd, -); \
		if [ "$(DBG_CODEGEN)" == 1 ]; then \
			echo "DBG: running $(DEEPCOPY_GEN) for $$pkgs"; \
		fi; \
		N=$$(cat $(META_DIR)/$(DEEPCOPY_GEN).todo | wc -l); \
		kube::log::status "Generating deepcopy code for $$N targets"; \
		./hack/run-in-gopath.sh $(DEEPCOPY_GEN) \
			--v $(KUBE_VERBOSE) \
			--logtostderr \
			-i "$$pkgs" \
			--bounding-dirs $(PRJ_SRC_PATH),"k8s.io/api" \
			-O $(DEEPCOPY_BASENAME) \
			"$$@"; \
	fi

重要的调试信息如下:

./hack/run-in-gopath.sh _output/bin/deepcopy-gen \
  --v 1 \
  --logtostderr \
  -i "$pkgs" \
  --bounding-dirs k8s.io/kubernetes,"k8s.io/api" \
  -O zz_generated.deepcopy

./hack/run-in-gopath.sh 脚本用于设置临时 Kubernetes GOPATH 环境并在其中运行命令。

deepcopy-gen 代码生成器参数说明如表所示。

参数参数说明
--v指定日志级别
--logtostderr将日志输出到标准错误输出
-i, --input-dirs输入源,即 .todo 文件中的目录列表,以逗号分隔
--bounding-dirs依赖的包及为其生成 DeepCopy 的类型
-O, --output-filebase输出文件的命名

deepcopy-gen 代码生成器将 .todo 文件的内容作为输入源,生成 DeepCopy 相关函数,并输出到 zz_generated.deepcopy.go 文件中。以 k8s.io/kubernetes/pkg/apis/abac/v1beta1 作为输入源手动进行测试,执行以下命令。

./hack/run-in-gopath.sh _output/bin/deepcopy-gen \
  --v 1 \
  --logtostderr \
  -i "k8s.io/kubernetes/pkg/apis/abac/v1beta1" \
  --bounding-dirs k8s.io/kubernetes,"k8s.io/api" \
  -O zz_generated.deepcopy

最终,我们在 pkg/apis/abac/v1beta1/ 目录下得到新生成的 zz_generated.deepcopy.go 代码文件。

凉柠
作者
凉柠
专注于 Kubernetes、分布式系统与 AI Agent 架构探索。
K8s-Codegen - 这篇文章属于一个选集。
§ 4: 本文