go.bbclass 解析

发布时间 2023-10-08 11:37:21作者: 我家有只江小白

go.bbclass 解析

1. 全文解析

这是一个BitBake(OpenEmbedded/Yocto Project构建系统中使用的构建工具)类文件,用于构建Go语言应用程序或库的 recipe。这个 recipe 中包含了一系列指令和变量,用于配置和构建 Go 项目。下面我将逐一解释其中的关键部分:

  1. inherit goarchinherit linuxloader:这些是 BitBake 中的继承指令,告诉 BitBake 该 recipe 要继承哪些类,以便复用相应的构建逻辑。

  2. GO_PARALLEL_BUILD:定义了用于并行构建的参数。

  3. export GODEBUG:设置 Go 环境变量 GODEBUG,控制 Go 缓存的行为。

  4. GOROOT:设置 Go 的根目录路径。

  5. export GOARCH, export GOOS, export GOHOSTARCH, export GOHOSTOS:设置与目标平台相关的 Go 构建变量。

  6. GOARM, GO386, GOMIPS:设置针对不同架构的特定 Go 构建参数。

  7. DEPENDS_GOLANG:定义 Go 项目的依赖关系,包括目标平台的 Go 运行时和其他依赖。

  8. GO_LINKSHARED, GO_RPATH_LINK, GO_RPATH:控制 Go 链接时的选项,用于处理动态链接库。

  9. GO_EXTLDFLAGS:设置与外部链接器相关的标志。

  10. GOBUILDFLAGS, GOPATH_OMIT_IN_ACTIONID, GOPTESTBUILDFLAGS, GOPTESTFLAGS:设置构建 Go 项目的标志和参数。

  11. GO, GOTOOLDIR:定义 Go 和 Go 工具的路径。

  12. CGO_ENABLED, CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_LDFLAGS:设置与 CGo 相关的环境变量。

  13. go_do_unpack, go_list_packages, go_list_package_tests, go_do_configure, go_do_compile, go_do_install, go_stage_testdata:这些是定义构建和安装过程的自定义 BitBake 函数,用于处理 Go 项目的不同阶段的任务。

  14. EXPORT_FUNCTIONS:导出了需要执行的任务函数。

  15. FILESINSANE_SKIP:定义了构建产物和相关的 QA 校验规则。

  16. Python 函数:包含了一些自定义 Python 代码片段,用于特定情况下的处理,例如针对不支持 -buildmode=pie 的平台进行特殊处理。

这个 recipe 中的指令和变量配置了 Go 项目的构建环境和过程,以便在 BitBake 构建系统中进行自动化构建和打包。

2. 分步解析

2.1

python go_do_unpack() {src_uri = (d.getVar('SRC_URI') or "").split() if len(src_uri) == 0: return fetcher = bb.fetch2.Fetch(src_uri, d) for url in fetcher.urls: if fetcher.ud[url].type == 'git': if fetcher.ud[url].parm.get('destsuffix') is None: s_dirname = os.path.basename(d.getVar('S')) fetcher.ud[url].parm['destsuffix'] = os.path.join(s_dirname, 'src', d.getVar('GO_IMPORT')) + '/' fetcher.unpack(d.getVar('WORKDIR')) }
 

这段 Python 代码是 BitBake recipe 中的自定义函数 go_do_unpack(),用于处理 Go 项目的源代码解压过程。让我解释其中的关键部分:

  1. src_uri = (d.getVar('SRC_URI') or "").split():从 BitBake 中获取 SRC_URI 变量的值,该变量通常包含了源代码的下载链接。如果未定义 SRC_URI,则设置为空字符串,然后将其拆分成一个列表,以处理可能包含多个源代码链接的情况。

  2. if len(src_uri) == 0::检查 src_uri 列表是否为空,如果为空,就没有源代码需要解压,所以直接返回。

  3. fetcher = bb.fetch2.Fetch(src_uri, d):创建一个 bb.fetch2.Fetch 对象,用于处理下载和解压源代码的操作。这个对象使用了 src_uri 列表和 BitBake 数据层对象 d

  4. for url in fetcher.urls::遍历 fetcher 对象的 urls,这是一个包含了源代码下载链接的列表。

  5. if fetcher.ud[url].type == 'git'::检查当前下载链接的类型是否为 Git。这里使用了 fetcher.ud 来获取有关下载链接的元数据信息。

  6. if fetcher.ud[url].parm.get('destsuffix') is None::检查是否已经设置了 destsuffixdestsuffix 通常是源代码的目标子目录。

  7. s_dirname = os.path.basename(d.getVar('S')):获取 BitBake 变量 S 的值,它代表当前源代码解压后的目录。然后使用 os.path.basename 函数获取该目录的基本名称。

  8. 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'],以指定解压后的源代码应该放置的位置。

  9. fetcher.unpack(d.getVar('WORKDIR')):使用 fetcher 对象的 unpack 方法,将源代码解压到 BitBake 变量 WORKDIR 指定的工作目录中。

总之,这段代码的主要功能是根据源代码的类型和目标子目录的设置来解压 Go 项目的源代码,并确保它们被正确地放置在 BitBake 工作目录中的指定位置。这有助于构建 Go 项目时能够在正确的源代码路径下找到所需的文件。

2.2

请帮忙分析以下code go_list_packages() { ${GO} list -f '{{.ImportPath}}' ${GOBUILDFLAGS} ${GO_INSTALL} | \ egrep -v '${GO_INSTALL_FILTEROUT}' }

这段代码是一个自定义的 BitBake 函数 go_list_packages(),用于列出 Go 项目中的包(packages)。让我逐行解释其中的关键部分:

  1. ${GO} list:这是一个使用 Go 工具链来执行命令的部分。${GO} 是一个环境变量,它包含了用于构建 Go 项目的 Go 工具的路径。

  2. -f '{{.ImportPath}}':这是 go list 命令的选项,它告诉 Go 工具输出每个包的导入路径(import path)。导入路径是一个唯一标识 Go 包的字符串。

  3. ${GOBUILDFLAGS}:这是一个环境变量,其中包含了用于构建 Go 项目的一些标志和参数。

  4. ${GO_INSTALL}:这是一个环境变量,通常包含了要安装的 Go 包的列表。

  5. egrep -v '${GO_INSTALL_FILTEROUT}':这是一个管道操作,将 go list 命令的输出传递给 egrep 命令。egrep 命令用于根据正则表达式过滤输入的行。在这里,它使用 ${GO_INSTALL_FILTEROUT} 的值,该值通常包含了需要过滤掉的 Go 包的正则表达式。-v 选项表示反向匹配,即排除匹配的行。

综合来说,这段代码的作用是运行 go list 命令来列出 Go 项目中的包,并通过管道操作过滤掉了 ${GO_INSTALL_FILTEROUT} 中定义的不需要的包。最终,它将列出的包的导入路径作为输出。这通常用于确定哪些 Go 包将被构建和安装。

2.3

请帮忙分析以下code go_list_package_tests() { ${GO} list -f '{{.ImportPath}} {{.TestGoFiles}}' ${GOBUILDFLAGS} ${GO_INSTALL} | \ grep -v '\[\]$' | \ egrep -v '${GO_INSTALL_FILTEROUT}' | \ awk '{ print $1 }' }

这段代码是另一个自定义的 BitBake 函数 go_list_package_tests(),用于列出 Go 项目中包含测试文件的包(packages)。以下是代码的逐行解释:

  1. ${GO} list:这是使用 Go 工具链来执行命令的部分,类似前面提到的函数中。${GO} 是一个环境变量,包含了 Go 工具的路径。

  2. -f '{{.ImportPath}} {{.TestGoFiles}}':这是 go list 命令的选项,指定要输出的信息格式。{{.ImportPath}} 表示输出包的导入路径,{{.TestGoFiles}} 表示输出包中的测试文件。这样,输出将包含每个包的导入路径和其测试文件列表。

  3. ${GOBUILDFLAGS}:这是一个包含了用于构建 Go 项目的标志和参数的环境变量。

  4. ${GO_INSTALL}:这是一个环境变量,通常包含了要安装的 Go 包的列表。

  5. grep -v '\[\]$':这是一个管道操作,它使用 grep 命令来过滤输出的行。-v 选项表示反向匹配,\[\]$ 是一个正则表达式,用于匹配不包含测试文件的包。通过这一步,它排除了那些没有测试文件的包。

  6. egrep -v '${GO_INSTALL_FILTEROUT}':再次使用 egrep 命令,根据 ${GO_INSTALL_FILTEROUT} 中定义的正则表达式,过滤掉不需要的包。

  7. awk '{ print $1 }':最后,使用 awk 命令提取每行的第一个字段,即包的导入路径。这样最终的输出是测试文件存在的 Go 包的导入路径列表。

综合来看,这段代码的作用是运行 go list 命令来列出包含测试文件的 Go 包,并通过一系列的管道操作过滤掉不符合条件的包,最终输出包含测试文件的包的导入路径列表。这通常用于构建和运行 Go 项目的测试套件。

2.4

请帮忙分析以下code go_do_configure() { ln -snf ${S}/src ${B}/ } do_configure[dirs] =+ "${GOTMPDIR}"

这段代码是 BitBake recipe 中的自定义函数 go_do_configure(),用于配置 Go 项目。以下是代码的逐行解释:

  1. ln -snf ${S}/src ${B}/:这是一个符号链接操作,它使用 ln 命令将 ${S}/src(通常是源代码目录)符号链接到 ${B}/(通常是构建目录)下。这个操作的目的是将源代码链接到构建目录,以便在构建过程中可以轻松访问源代码。符号链接是一种轻量级的文件链接,不会复制文件内容,而是创建一个指向源文件的引用。

  2. do_configure[dirs] =+ "${GOTMPDIR}":这是 BitBake recipe 中的配置信息。它告诉 BitBake 在执行 do_configure 任务时,应该包括 ${GOTMPDIR}(通常是 Go 项目的临时构建目录)在需要清理的目录列表中。这意味着在清理构建目录时,BitBake 将同时清理 ${GOTMPDIR} 目录。

总之,这段代码的作用是在配置 Go 项目时创建一个符号链接,将源代码链接到构建目录,以便在构建过程中访问源代码。同时,它还配置了 BitBake 以包括 ${GOTMPDIR} 目录在需要清理的目录列表中,以确保在清理构建目录时也清理了临时构建目录。

2.5

请帮忙分析以下code go_do_compile() { export TMPDIR="${GOTMPDIR}" if [ -n "${GO_INSTALL}" ]; then if [ -n "${GO_LINKSHARED}" ]; then ${GO} install ${GOBUILDFLAGS} `go_list_packages` rm -rf ${B}/bin fi ${GO} install ${GO_LINKSHARED} ${GOBUILDFLAGS} `go_list_packages` fi } do_compile[dirs] =+ "${GOTMPDIR}" do_compile[cleandirs] = "${B}/bin ${B}/pkg"
 

这段代码是 BitBake recipe 中的自定义函数 go_do_compile(),用于编译 Go 项目。以下是代码的逐行解释:

  1. export TMPDIR="${GOTMPDIR}":这一行设置环境变量 TMPDIR 的值为 ${GOTMPDIR},通常是 Go 项目的临时构建目录。这样可以确保在编译过程中使用正确的临时目录。

  2. if [ -n "${GO_INSTALL}" ]; then:这是一个条件语句,检查环境变量 ${GO_INSTALL} 是否已定义且非空。${GO_INSTALL} 通常包含了要编译的 Go 包的列表。

  3. if [ -n "${GO_LINKSHARED}" ]; then:这是另一个条件语句,检查环境变量 ${GO_LINKSHARED} 是否已定义且非空。${GO_LINKSHARED} 通常包含了用于链接共享库的标志。

  4. ${GO} install ${GOBUILDFLAGS} go_list_packages``:如果 ${GO_INSTALL} 已定义且非空,并且 ${GO_LINKSHARED} 也已定义且非空,那么将运行 ${GO} install 命令来编译并安装 Go 包。${GOBUILDFLAGS} 包含了用于构建 Go 项目的标志和参数。反引号 `go_list_packages` 用于执行 go_list_packages 函数,以获取要编译的包列表。

  5. rm -rf ${B}/bin:如果 ${GO_INSTALL}${GO_LINKSHARED} 已定义且非空,那么在编译完成后,将删除构建目录 ${B} 中的 bin 子目录。

  6. do_compile[dirs] =+ "${GOTMPDIR}":这是 BitBake recipe 的配置信息,告诉 BitBake 在执行 do_compile 任务时应包括 ${GOTMPDIR}(通常是 Go 项目的临时构建目录)在需要清理的目录列表中。这确保了在清理构建目录时也清理了临时构建目录。

  7. 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

2.7

2.8