go.bbclass 解析
go.bbclass 解析
1. 全文解析
这是一个BitBake(OpenEmbedded/Yocto Project构建系统中使用的构建工具)类文件,用于构建Go语言应用程序或库的 recipe。这个 recipe 中包含了一系列指令和变量,用于配置和构建 Go 项目。下面我将逐一解释其中的关键部分:
-
inherit goarch
和inherit linuxloader
:这些是 BitBake 中的继承指令,告诉 BitBake 该 recipe 要继承哪些类,以便复用相应的构建逻辑。 -
GO_PARALLEL_BUILD
:定义了用于并行构建的参数。 -
export GODEBUG
:设置 Go 环境变量 GODEBUG,控制 Go 缓存的行为。 -
GOROOT
:设置 Go 的根目录路径。 -
export GOARCH
,export GOOS
,export GOHOSTARCH
,export GOHOSTOS
:设置与目标平台相关的 Go 构建变量。 -
GOARM
,GO386
,GOMIPS
:设置针对不同架构的特定 Go 构建参数。 -
DEPENDS_GOLANG
:定义 Go 项目的依赖关系,包括目标平台的 Go 运行时和其他依赖。 -
GO_LINKSHARED
,GO_RPATH_LINK
,GO_RPATH
:控制 Go 链接时的选项,用于处理动态链接库。 -
GO_EXTLDFLAGS
:设置与外部链接器相关的标志。 -
GOBUILDFLAGS
,GOPATH_OMIT_IN_ACTIONID
,GOPTESTBUILDFLAGS
,GOPTESTFLAGS
:设置构建 Go 项目的标志和参数。 -
GO
,GOTOOLDIR
:定义 Go 和 Go 工具的路径。 -
CGO_ENABLED
,CGO_CFLAGS
,CGO_CPPFLAGS
,CGO_CXXFLAGS
,CGO_LDFLAGS
:设置与 CGo 相关的环境变量。 -
go_do_unpack
,go_list_packages
,go_list_package_tests
,go_do_configure
,go_do_compile
,go_do_install
,go_stage_testdata
:这些是定义构建和安装过程的自定义 BitBake 函数,用于处理 Go 项目的不同阶段的任务。 -
EXPORT_FUNCTIONS
:导出了需要执行的任务函数。 -
FILES
和INSANE_SKIP
:定义了构建产物和相关的 QA 校验规则。 -
Python 函数:包含了一些自定义 Python 代码片段,用于特定情况下的处理,例如针对不支持
-buildmode=pie
的平台进行特殊处理。
这个 recipe 中的指令和变量配置了 Go 项目的构建环境和过程,以便在 BitBake 构建系统中进行自动化构建和打包。
2. 分步解析
2.1 python go_do_unpack()
这段 Python 代码是 BitBake recipe 中的自定义函数 go_do_unpack()
,用于处理 Go 项目的源代码解压过程。让我解释其中的关键部分:
-
src_uri = (d.getVar('SRC_URI') or "").split()
:从 BitBake 中获取SRC_URI
变量的值,该变量通常包含了源代码的下载链接。如果未定义SRC_URI
,则设置为空字符串,然后将其拆分成一个列表,以处理可能包含多个源代码链接的情况。 -
if len(src_uri) == 0:
:检查src_uri
列表是否为空,如果为空,就没有源代码需要解压,所以直接返回。 -
fetcher = bb.fetch2.Fetch(src_uri, d)
:创建一个bb.fetch2.Fetch
对象,用于处理下载和解压源代码的操作。这个对象使用了src_uri
列表和 BitBake 数据层对象d
。 -
for url in fetcher.urls:
:遍历fetcher
对象的urls
,这是一个包含了源代码下载链接的列表。 -
if fetcher.ud[url].type == 'git':
:检查当前下载链接的类型是否为 Git。这里使用了fetcher.ud
来获取有关下载链接的元数据信息。 -
if fetcher.ud[url].parm.get('destsuffix') is None:
:检查是否已经设置了destsuffix
。destsuffix
通常是源代码的目标子目录。 -
s_dirname = os.path.basename(d.getVar('S'))
:获取 BitBake 变量S
的值,它代表当前源代码解压后的目录。然后使用os.path.basename
函数获取该目录的基本名称。 -
fetcher.ud[url].parm['destsuffix'] = os.path.join(s_dirname, 'src', d.getVar('GO_IMPORT')) + '/'
:如果尚未设置destsuffix
,则构建一个新的目标子目录路径,其中包含了源代码解压后的目录名称、'src' 子目录以及 BitBake 变量GO_IMPORT
的值(通常是 Go 项目的导入路径),然后将这个路径赋值给fetcher.ud[url].parm['destsuffix']
,以指定解压后的源代码应该放置的位置。 -
fetcher.unpack(d.getVar('WORKDIR'))
:使用fetcher
对象的unpack
方法,将源代码解压到 BitBake 变量WORKDIR
指定的工作目录中。
总之,这段代码的主要功能是根据源代码的类型和目标子目录的设置来解压 Go 项目的源代码,并确保它们被正确地放置在 BitBake 工作目录中的指定位置。这有助于构建 Go 项目时能够在正确的源代码路径下找到所需的文件。
2.2 go_list_packages()
这段代码是一个自定义的 BitBake 函数 go_list_packages()
,用于列出 Go 项目中的包(packages)。让我逐行解释其中的关键部分:
-
${GO} list
:这是一个使用 Go 工具链来执行命令的部分。${GO}
是一个环境变量,它包含了用于构建 Go 项目的 Go 工具的路径。 -
-f '{{.ImportPath}}'
:这是go list
命令的选项,它告诉 Go 工具输出每个包的导入路径(import path)。导入路径是一个唯一标识 Go 包的字符串。 -
${GOBUILDFLAGS}
:这是一个环境变量,其中包含了用于构建 Go 项目的一些标志和参数。 -
${GO_INSTALL}
:这是一个环境变量,通常包含了要安装的 Go 包的列表。 -
egrep -v '${GO_INSTALL_FILTEROUT}'
:这是一个管道操作,将go list
命令的输出传递给egrep
命令。egrep
命令用于根据正则表达式过滤输入的行。在这里,它使用${GO_INSTALL_FILTEROUT}
的值,该值通常包含了需要过滤掉的 Go 包的正则表达式。-v
选项表示反向匹配,即排除匹配的行。
综合来说,这段代码的作用是运行 go list
命令来列出 Go 项目中的包,并通过管道操作过滤掉了 ${GO_INSTALL_FILTEROUT}
中定义的不需要的包。最终,它将列出的包的导入路径作为输出。这通常用于确定哪些 Go 包将被构建和安装。
2.3 go_list_package_tests()
这段代码是另一个自定义的 BitBake 函数 go_list_package_tests()
,用于列出 Go 项目中包含测试文件的包(packages)。以下是代码的逐行解释:
-
${GO} list
:这是使用 Go 工具链来执行命令的部分,类似前面提到的函数中。${GO}
是一个环境变量,包含了 Go 工具的路径。 -
-f '{{.ImportPath}} {{.TestGoFiles}}'
:这是go list
命令的选项,指定要输出的信息格式。{{.ImportPath}}
表示输出包的导入路径,{{.TestGoFiles}}
表示输出包中的测试文件。这样,输出将包含每个包的导入路径和其测试文件列表。 -
${GOBUILDFLAGS}
:这是一个包含了用于构建 Go 项目的标志和参数的环境变量。 -
${GO_INSTALL}
:这是一个环境变量,通常包含了要安装的 Go 包的列表。 -
grep -v '\[\]$'
:这是一个管道操作,它使用grep
命令来过滤输出的行。-v
选项表示反向匹配,\[\]$
是一个正则表达式,用于匹配不包含测试文件的包。通过这一步,它排除了那些没有测试文件的包。 -
egrep -v '${GO_INSTALL_FILTEROUT}'
:再次使用egrep
命令,根据${GO_INSTALL_FILTEROUT}
中定义的正则表达式,过滤掉不需要的包。 -
awk '{ print $1 }'
:最后,使用awk
命令提取每行的第一个字段,即包的导入路径。这样最终的输出是测试文件存在的 Go 包的导入路径列表。
综合来看,这段代码的作用是运行 go list
命令来列出包含测试文件的 Go 包,并通过一系列的管道操作过滤掉不符合条件的包,最终输出包含测试文件的包的导入路径列表。这通常用于构建和运行 Go 项目的测试套件。
2.4 go_do_configure()
go_do_configure() {
ln -snf ${S}/src ${B}/
}
do_configure[dirs] =+ "${GOTMPDIR}"
这段代码是 BitBake recipe 中的自定义函数 go_do_configure()
,用于配置 Go 项目。以下是代码的逐行解释:
-
ln -snf ${S}/src ${B}/
:这是一个符号链接操作,它使用ln
命令将${S}/src
(通常是源代码目录)符号链接到${B}/
(通常是构建目录)下。这个操作的目的是将源代码链接到构建目录,以便在构建过程中可以轻松访问源代码。符号链接是一种轻量级的文件链接,不会复制文件内容,而是创建一个指向源文件的引用。 -
do_configure[dirs] =+ "${GOTMPDIR}"
:这是 BitBake recipe 中的配置信息。它告诉 BitBake 在执行do_configure
任务时,应该包括${GOTMPDIR}
(通常是 Go 项目的临时构建目录)在需要清理的目录列表中。这意味着在清理构建目录时,BitBake 将同时清理${GOTMPDIR}
目录。
总之,这段代码的作用是在配置 Go 项目时创建一个符号链接,将源代码链接到构建目录,以便在构建过程中访问源代码。同时,它还配置了 BitBake 以包括 ${GOTMPDIR}
目录在需要清理的目录列表中,以确保在清理构建目录时也清理了临时构建目录。
2.5 go_do_compile()
这段代码是 BitBake recipe 中的自定义函数 go_do_compile()
,用于编译 Go 项目。以下是代码的逐行解释:
-
export TMPDIR="${GOTMPDIR}"
:这一行设置环境变量TMPDIR
的值为${GOTMPDIR}
,通常是 Go 项目的临时构建目录。这样可以确保在编译过程中使用正确的临时目录。 -
if [ -n "${GO_INSTALL}" ]; then
:这是一个条件语句,检查环境变量${GO_INSTALL}
是否已定义且非空。${GO_INSTALL}
通常包含了要编译的 Go 包的列表。 -
if [ -n "${GO_LINKSHARED}" ]; then
:这是另一个条件语句,检查环境变量${GO_LINKSHARED}
是否已定义且非空。${GO_LINKSHARED}
通常包含了用于链接共享库的标志。 -
${GO} install ${GOBUILDFLAGS}
go_list_packages``:如果${GO_INSTALL}
已定义且非空,并且${GO_LINKSHARED}
也已定义且非空,那么将运行${GO} install
命令来编译并安装 Go 包。${GOBUILDFLAGS}
包含了用于构建 Go 项目的标志和参数。反引号 `go_list_packages` 用于执行go_list_packages
函数,以获取要编译的包列表。 -
rm -rf ${B}/bin
:如果${GO_INSTALL}
和${GO_LINKSHARED}
已定义且非空,那么在编译完成后,将删除构建目录${B}
中的bin
子目录。 -
do_compile[dirs] =+ "${GOTMPDIR}"
:这是 BitBake recipe 的配置信息,告诉 BitBake 在执行do_compile
任务时应包括${GOTMPDIR}
(通常是 Go 项目的临时构建目录)在需要清理的目录列表中。这确保了在清理构建目录时也清理了临时构建目录。 -
do_compile[cleandirs] = "${B}/bin ${B}/pkg"
:这也是 BitBake recipe 的配置信息,定义了在执行do_compile
任务的清理步骤中需要删除的目录列表。在这里,${B}/bin
和${B}/pkg
将被删除,以确保在下一次构建时从干净的状态开始。
综合来看,这段代码的主要作用是在编译 Go 项目时运行 go install
命令,根据 ${GO_INSTALL}
中定义的要编译的包列表,同时根据 ${GO_LINKSHARED}
中定义的标志来决定是否链接共享库。同时,它还配置了 BitBake 以包括 ${GOTMPDIR}
目录在需要清理的目录列表中,并定义了需要删除的目录,以确保在下一次构建时从干净的状态开始。
2.6 go_do_install()
go_do_install() {
install -d ${D}${libdir}/go/src/${GO_IMPORT}
tar -C ${S}/src/${GO_IMPORT} -cf - --exclude-vcs --exclude '*.test' --exclude 'testdata' . | \
tar -C ${D}${libdir}/go/src/${GO_IMPORT} --no-same-owner -xf -
tar -C ${B} -cf - --exclude-vcs --exclude '*.test' --exclude 'testdata' pkg | \
tar -C ${D}${libdir}/go --no-same-owner -xf -
if [ -n "`ls ${B}/${GO_BUILD_BINDIR}/`" ]; then
install -d ${D}${bindir}
install -m 0755 ${B}/${GO_BUILD_BINDIR}/* ${D}${bindir}/
fi
}
这段代码是 BitBake recipe 中的自定义函数 go_do_install()
,用于安装 Go 项目的构建产物到目标系统。以下是代码的逐行解释:
-
install -d ${D}${libdir}/go/src/${GO_IMPORT}
:这是一个install
命令,用于创建目标系统上的目录${D}${libdir}/go/src/${GO_IMPORT}
。${D}
是 BitBake 中的一个变量,代表目标系统的根目录。${libdir}
通常包含了库文件的目录路径,${GO_IMPORT}
是 Go 项目的导入路径。这个命令的目的是创建一个目录,用于存放 Go 项目的源代码。 -
tar -C ${S}/src/${GO_IMPORT} -cf - --exclude-vcs --exclude '*.test' --exclude 'testdata' .
:这是一个tar
命令,用于创建一个压缩文件。${S}
通常是 BitBake recipe 的源代码目录,${GO_IMPORT}
是 Go 项目的导入路径。这个命令的目的是将源代码目录中的文件(不包括版本控制文件、.test
文件和testdata
目录)打包成一个压缩文件。 -
tar -C ${D}${libdir}/go/src/${GO_IMPORT} --no-same-owner -xf -
:这是另一个tar
命令,用于将前面创建的压缩文件解压到目标系统的目录${D}${libdir}/go/src/${GO_IMPORT}
中。--no-same-owner
选项用于确保解压后的文件的所有者与目标系统一致。 -
tar -C ${B} -cf - --exclude-vcs --exclude '*.test' --exclude 'testdata' pkg
:这是另一个tar
命令,用于创建一个压缩文件,包含构建目录${B}
中的pkg
目录中的文件(不包括版本控制文件、.test
文件和testdata
目录)。 -
tar -C ${D}${libdir}/go --no-same-owner -xf -
:这是另一个tar
命令,用于将前面创建的压缩文件解压到目标系统的目录${D}${libdir}/go
中,确保解压后的文件的所有者与目标系统一致。 -
if [ -n "
ls ${B}/${GO_BUILD_BINDIR}/" ]; then
:这是一个条件语句,它检查${B}/${GO_BUILD_BINDIR}/
目录下是否存在文件。 -
install -d ${D}${bindir}
:如果上面的条件成立,这个命令会在目标系统上创建目录${D}${bindir}
,${bindir}
通常包含了可执行文件的目录路径。 -
install -m 0755 ${B}/${GO_BUILD_BINDIR}/* ${D}${bindir}/
:这个命令用于将${B}/${GO_BUILD_BINDIR}
目录中的所有文件安装到目标系统的${D}${bindir}/
目录中,并设置文件的权限为0755
,以确保它们可以被执行。
综合来看,这段代码的主要作用是将 Go 项目的源代码安装到目标系统的相应目录中,同时将构建产物安装到适当的位置,以便它们可以在目标系统上使用。这通常是构建和安装 Go 项目的最后步骤。
2.7 go_stage_testdata()
go_stage_testdata() {
oldwd="$PWD"
cd ${S}/src
find ${GO_IMPORT} -depth -type d -name testdata | while read d; do
if echo "$d" | grep -q '/vendor/'; then
continue
fi
parent=`dirname $d`
install -d ${D}${PTEST_PATH}/$parent
cp --preserve=mode,timestamps -R $d ${D}${PTEST_PATH}/$parent/
done
cd "$oldwd"
}
这段代码是 BitBake recipe 中的自定义函数 go_stage_testdata()
,用于在构建目标系统时将 Go 项目的测试数据(testdata)阶段性地安装到目标系统。以下是代码的逐行解释:
-
oldwd="$PWD"
:这一行将当前工作目录的路径保存到变量oldwd
中,以便稍后可以返回到原始工作目录。 -
cd ${S}/src
:这行代码将当前工作目录切换到 BitBake recipe 的源代码目录${S}/src
。${S}
通常是 BitBake recipe 的源代码目录。 -
find ${GO_IMPORT} -depth -type d -name testdata | while read d; do
:这行代码使用find
命令来查找${GO_IMPORT}
目录及其子目录中的所有名为testdata
的目录。${GO_IMPORT}
通常是 Go 项目的导入路径。 -
if echo "$d" | grep -q '/vendor/'; then
:这是一个条件语句,用于检查目录$d
是否包含/vendor/
,如果是,则跳过该目录的处理。在 Go 项目中,/vendor/
目录通常包含第三方依赖项,这段代码可能用于排除第三方测试数据。 -
parent=
dirname $d``:这行代码获取目录$d
的父目录,并将其路径存储在变量parent
中。 -
install -d ${D}${PTEST_PATH}/$parent
:这是一个install
命令,用于创建目标系统上的目录${D}${PTEST_PATH}/$parent
。${D}
是 BitBake 中的一个变量,代表目标系统的根目录。${PTEST_PATH}
通常包含了测试数据的目标路径,${parent}
是测试数据目录在目标系统中的相对路径。 -
cp --preserve=mode,timestamps -R $d ${D}${PTEST_PATH}/$parent/
:这是一个cp
命令,用于将目录$d
中的测试数据递归地复制到目标系统中的${D}${PTEST_PATH}/$parent/
目录中,并保留文件的权限和时间戳信息。 -
cd "$oldwd"
:最后,这行代码将工作目录切换回原始工作目录,以确保在函数执行完毕后返回到正确的工作目录。
综合来看,这段代码的主要作用是查找 Go 项目中的测试数据目录,并将这些测试数据复制到目标系统的相应目录中,以供在目标系统上运行测试时使用。这有助于确保测试数据在构建和运行测试时可用。
2.8 others
EXPORT_FUNCTIONS do_unpack do_configure do_compile do_install
FILES:${PN}-dev = "${libdir}/go/src"
FILES:${PN}-staticdev = "${libdir}/go/pkg"
INSANE_SKIP:${PN} += "ldflags"
这段代码是 BitBake recipe 的配置和元数据部分,用于定义需要导出的函数、文件列表以及一些检查的设置。以下是代码的逐行解释:
-
EXPORT_FUNCTIONS do_unpack do_configure do_compile do_install
:这一行定义了需要导出的函数列表。在 BitBake recipe 中,不是所有函数都需要在构建过程中执行,有些函数可能只在构建的特定阶段执行,而这里导出的函数列表告诉 BitBake 在构建过程中哪些函数需要被执行。在这里,被导出的函数包括do_unpack
、do_configure
、do_compile
和do_install
,这些函数通常是构建一个软件包所必需的构建阶段。 -
FILES:${PN}-dev = "${libdir}/go/src"
:这一行定义了${PN}-dev
软件包的文件列表。${PN}
通常代表软件包的名称,这里指定了${PN}-dev
软件包应该包括的文件路径,通常是${libdir}/go/src
。${libdir}
通常包含了库文件的目录路径,${PN}-dev
软件包通常包含开发时所需的头文件和源代码。 -
FILES:${PN}-staticdev = "${libdir}/go/pkg"
:类似于前面的行,这一行定义了${PN}-staticdev
软件包的文件列表,通常包括库文件。${PN}-staticdev
通常包含静态库文件,供开发人员在构建其他软件时链接使用。 -
INSANE_SKIP:${PN} += "ldflags"
:这一行定义了要跳过的 QA 检查。QA 检查是 BitBake 中的一种质量检查,它用于检测潜在的问题或错误。在这里,${PN}
被添加到INSANE_SKIP
列表中,并指定了要跳过的检查是 "ldflags"。这可能意味着 BitBake 不会执行与链接标志相关的某些检查,因为在某些情况下,Go 项目可能具有特定的链接需求,因此需要禁用某些 QA 检查。
综合来看,这段代码的作用是配置 BitBake recipe 的一些元数据,包括导出函数、文件列表以及跳过特定的 QA 检查,以确保 BitBake 正确构建和打包 Go 软件包。