GLEP 47:创建“安全”的环境变量

作者 Diego Pettenò,Fabian Groffen
类型 标准跟踪
状态 已拒绝
版本 1
创建日期 2005-10-14
最后修改日期 2014-01-23
发布历史 2006-02-09
GLEP 源码 glep-0047.rst

致谢

本 GLEP 的文本是以下人员讨论和输入的结果,不分特定顺序:Mike Frysinger、Diego Pettenò、Fabian Groffen 和 Finn Thain。

摘要

为了使 ebuild 和 eclass 能够做出特定于宿主的决策,需要有一系列环境变量来允许此类决策。此 GLEP 引入了一些需要采取的措施,以使这些决策“安全”,方法是确保决策所依据的变量是“安全”的。与 GLEP 22 [1] 有少量重叠,本 GLEP 中将保留使用 2 元组关键字,而不是 4 元组关键字。此外,ELIBC, KERNELARCHCHOST开始自动填充,以及 2 元组关键字,而不是像 GLEP 22 中提议的那样仅从 4 元组关键字填充。

的命运USERLAND变量不在本 GLEP 的范围内。根据其在树中的存在情况,可以决定以我们提议设置ELIBC, KERNELARCH相同的方式设置此变量,或者,例如,通过配置文件设置。

动机

Gentoo/Alt 项目正处于发展初期,准备为大量“替代”配置提供服务,例如 FreeBSD、NetBSD、DragonflyBSD、GNU/kFreeBSD、Mac OS X、(Open)Darwin、(Open)Solaris 等。因此,该项目需要更好地掌握正在构建的实际主机。有关主机环境的信息对于在高度依赖于构建环境的设置(如平台或 C 库实现)上做出正确的(自动)决策至关重要。

基本原理

Gentoo 独有的 Portage 系统允许从源代码包轻松安装应用程序。编译源代码容易受到许多环境设置和某些工具可用性的影响。最近,Gentoo for FreeBSD 项目已启动,这是第二个在使用外部(非 GNU)C 库和用户空间实用程序的外部主机操作系统上运行的 Gentoo 项目。此类项目受 Gentoo Portage 的 ebuild 中当前的隐式假设的影响,即存在单一类型的操作系统、C 库和系统实用程序。为了使 ebuild(以及 eclass)能够了解这些环境差异,应提供有关这些差异的信息。由于基于此信息做出的决策可能至关重要,因此,此信息的可信度以及值可以被视为“安全”和正确至关重要。

向后兼容性

本 GLEP 中提出的关键字方案与 Portage 树的当前情况完全兼容,这与 GLEP 22 形成对比。GLEP 22 提供的变量无法从新的关键字中提取,但由于 GLEP 22 样式的关键字目前不在树中,因此这不是问题。如有必要,可以从 CHOST 变量中提取相同的信息。无需对 ebuild 进行任何修改。

规范

与 GLEP 22 不同,当前使用的关键字方案没有改变。对于需要它们的体系结构,选择 2 元组关键字,而不是提议使用 4 元组 [2] 关键字。对于 1 元组关键字就足够了的体系结构,可以保留该关键字。由于这不会改变树中当前的情况,因此与 GLEP 22 中的 4 元组关键字相比,这被认为是一个很大的优势。此 GLEP 是关键字语法的正式规范。

关键字将由连字符(“-”)分隔的两部分组成。关键字 2 元组左侧第一个连字符之前的部分是体系结构,例如 ppc64、sparc 和 x86。体系结构名称允许的字符在a-z0-9中。左侧第一个连字符右侧的其余部分表示操作系统或发行版,例如 linux、macos、darwin、obsd 等。如果省略了右侧部分,则表示操作系统/发行版类型为 Gentoo GNU/Linux。在这种情况下,连字符也会被省略,关键字仅由体系结构组成。操作系统或发行版名称可以由a-zA-Z0-9_+:-中的字符组成。请注意,连字符是允许的字符,因此关键字中两个字段的分隔仅可以通过从关键字字符串开头扫描第一个连字符来确定。遵循此规范的关键字示例为 ppc-darwin 和 x86。这与树中当前关键字的使用完全兼容。

变量ELIBC, KERNELARCH当前在配置文件中设置,除非它们是 GNU/Linux 系统的默认值。因此,用户可以轻松地覆盖和定义它们。为了防止这种情况发生,变量应由 Portage 本身根据CHOST变量自动填充。虽然CHOST变量可以像用户设置的其他变量一样简单,但它仍然被认为是“安全”的。这一假设基于以下事实:该变量本身在其他许多地方以相同的意图使用,并且无效的CHOST将导致系统出现重大故障。更改CHOST为系统无效值的用户的警告,这可能会导致系统无法使用。总之,CHOST变量的“安全性”基于外部假设的“安全性”,该讨论不在本 GLEP 的范围内。

当前变量的 USE 展开将得到维护,因为这将带来完全的向后兼容性。由于变量本身在其表示的内容方面没有变化,只是其分配方式发生了变化,因此在维护它们方面应该没有问题。使用 USE 展开,可以在 ebuild 中编写条件代码,这与任何现有方法都没有区别。

...
RDEPEND="elibc_FreeBSD? ( sys-libs/com_err )"
...
src_compile() {
    ...
    use elibc_FreeBSD && myconf="${myconf} -Dlibc=/usr/lib/libc.a"
    ...
}

或者,变量ELIBC, KERNELARCH在 ebuild 环境中可用,并且可以使用它们来代替调用xxx_Xxxx或在实际上需要的 switch 语句中。

可以使用映射文件将各种CHOST值转换为四个变量的正确值。此更改对 ebuild 和 eclass 是不可见的,但允许依赖这些变量,因为它们基于“安全”值——CHOST变量。Ebuild 不应对关键字值敏感,而应使用上述四个变量。它们允许对属性进行特定测试。如果这是不可取的,则可以使用完整的CHOST变量来匹配完整操作系统。

变量赋值

ELIBC, KERNEL, ARCH变量从配置文件中填充。可以覆盖该文件,以便映射文件中的以下条目(箭头左侧)将导致右侧分配的变量

*-*-linux-*      -> KERNEL="linux"
*-*-*-gnu        -> ELIBC="glibc"
*-*-kfreebsd-gnu -> KERNEL="FreeBSD" ELIBC="glibc"
*-*-freebsd*     -> KERNEL="FreeBSD" ELIBC="FreeBSD"
*-*-darwin*      -> KERNEL="Darwin" ELIBC="Darwin"
*-*-netbsd*      -> KERNEL="NetBSD" ELIBC="NetBSD"
*-*-solaris*     -> KERNEL="Solaris" ELIBC="Solaris"

Mike Frysinger 提出了一种实现此目的的方法,建议使用一个 env-map 文件,例如,其中填充了

% cat env-map
*-linux-* KERNEL=linux
*-gnu ELIBC=glibc
x86_64-* ARCH=amd64

然后可以使用以下 bash 脚本将四个变量设置为正确的值

% cat readmap
#!/bin/bash

CBUILD=${CBUILD:-${CHOST=${CHOST:-$1}}}
[[ -z ${CHOST} ]] && echo need chost

unset KERNEL ELIBC ARCH

while read LINE ; do
    set -- ${LINE}
    targ=$1
    shift
    [[ ${CBUILD} == ${targ} ]] && eval $@
done < env-map

echo ARCH=${ARCH} KERNEL=${KERNEL} ELIBC=${ELIBC}

给定 env-map 文件示例,此脚本将导致

% ./readmap x86_64-pc-linux-gnu
ARCH=amd64 KERNEL=linux ELIBC=glibc

中的条目env-map文件将以正向线性完整扫描的方式进行评估。此详尽搜索的一个副作用是,如果多个条目匹配给定的CHOST,则可以重新分配变量。因此,条目的顺序很重要。因为env-map文件的大小假定不超过文件系统的块大小,所以完整扫描与“首次命中停止技术”相比的性能损失被认为是最小的。

但是,应该注意的是,上述 bash 脚本是概念验证实现。由于 Portage 大部分是用 Python 编写的,因此用 Python 编写此代码的等效代码效率更高。在编码方面,这被认为不是问题,但env-map文件的格式,尤其是其通配符,可能不是与 Python 最佳匹配。为此,env-map文件的格式规范将推迟到 Python 实现,此处仅给出要求。

env-map文件应能够编码, 对,其中是一个与 chost 字符串匹配的(正则)表达式,并且包含至少一个变量对变量ARCH, KERNELELIBC的唯一赋值。的解释器env-map文件必须线性扫描文件,并继续尝试匹配并根据需要分配变量,直到文件结束。

由于 Portage 将使用env-map文件,因此该文件的位置不在本 GLEP 的范围内,由 Portage 实现者决定。

参考文献

[1]GLEP 22,新的“关键字”系统,用于整合各种用户空间/内核/体系结构,Goodyear,(https://gentoolinux.cn/glep/glep-0022.html)
[2]为了便于阅读,我们将引用 1 元组、2 元组和 4 元组,即使元组本身暗示一个包含两个值的字段。为清楚起见:1 元组描述一个单值字段,而 4 元组描述一个包含四个值的字段。