繁体   English   中英

Arch Linux 的 GCC 预处理器指令

[英]GCC preprocessor directives for Arch Linux

GCC(或 Clang)在为 Arch Linux OS 编译时是否定义了任何宏?

我需要检查我的软件是否限制自己在 Arch Linux 之外的任何环境下编译(这背后的原因是题外话)。 我在互联网上找不到任何相关资源。

有谁知道如何通过 GCC 预处理器指令保证我的二进制文件只能在 Arch Linux 下编译?

当然我总是可以

#ifdef __linux__
  ...
#endif

但这还不够精确。

编辑:这必须通过 C 源代码而不是任何构建系统来完成,因此,例如,通过 CMake 执行此操作将被完全丢弃。

编辑 2:用户伪造此行为不是问题,因为该软件已分发给选定的客户,因此,积极尝试“滥用”我们的源代码是“他们的决定”。

您可以列出预定义的预处理器宏

gcc -dM -E - /dev/null
clang -dM -E - /dev/null

这些都没有表明编译器在哪个操作系统下运行。 所以你不仅无法判断程序是否在 Arch Linux 下编译,甚至无法判断程序是否在 Linux 下编译。 __linux__和朋友表明该程序正在Linux 编译。 它们是在从另一个系统交叉编译到 Linux 时定义的,而不是在从 Linux 交叉编译到另一个系统时定义的。

您可以通过指定系统头文件的绝对路径并依赖不可移植的头文件(例如/usr/include/bits/foo.h )人为地使您的程序更难编译。 在不修改源代码的情况下,这几乎不可能对 Linux 以外的任何东西进行交叉编译或编译。 但是,大多数 Linux 发行版都将标头安装在同一位置,因此您不太可能确定特定的发行版。

你很可能问错了问题 与其问如何将编译限制为 Arch Linux,不如从为什么要将编译限制为 Arch Linux 开始。 如果答案是“因为生成的程序在另一个发行版下不是我想要的”,那么从那里开始并确保差异导致编译错误而不是错误执行。 如果“为什么”的答案是其他问题,那么您可能正在寻找解决社会问题的技术解决方案,而这很少有好的结果。

GCC(或 Clang)在为 Arch Linux OS 编译时是否定义了任何宏?

不,因为在二进制级别上 Arch Linux 没有任何固有的特性。 对于它的价值,在编译时你/编译器唯一需要关心的是目标架构(即它将运行什么样的 CPU)、数据类型大小和对齐以及函数调用约定。

稍后,当需要将编译后的翻译单元对象链接到最终的二进制可执行文件中时,周围的运行时库也很重要。 如果不采取特殊的预防措施,您实际上会将自己锁定在由链接器拉动的特定品牌的运行时库中(glibc 与例如 musl;libstdc++ 与 libc++)。

可以通过静态链接轻松回避后面的问题,但这限制了程序可用的系统和中级 API 的范围。 例如,在 Linux 上,纯粹的静态链接程序无法使用 OpenGL-3.x 或 Vulkan 等图形加速 API,因为它们依赖于将 GPU 驱动程序的组件加载到进程中。 但是,您仍然可以使用 X11 和间接 GLX OpenGL,因为它们使用通过套接字的有线协议工作,这些协议是使用对内核的直接系统调用来实现的。

对于每个发行版的每个 Linux 内核,这些内核系统调用在二进制级别上都是完全相同的 尽管内核内部在重新定义接口方面有很多余地,但在涉及面向用户空间的接口(即常规程序)时,有一条神圣的、教条的、铁定的规则,你永远不会破坏用户空间! 违反此规则的内核开发人员有意或无意地被 Linus Torvalds 在他的臭名昭著的咆哮中公开抨击。

最重要的是,没有“二进制级别的 Linux 发行版特定标识符”之类的东西。 归根结底,Linux 发行版就是这样:东西的发行版。 这意味着有人或更多人决定了一组文件,这些文件组成了一个工作的 Linux 系统,以某种方式将其包装起来并为其命名。 而已。 除了被称为“Arch”并且(暂时)依赖于pacman包管理器之外,“Arch”Linux 并没有什么固有的特性。 而已。 关于“Arch”或任何其他 Linux 发行版的其他一切都只是偶然的问题。

如果您真的想将不同的 Linux 发行版分类到有关二进制兼容性的某些箱中,那么您必须将以下组合归类

  • 所需的最小支持系统调用集。 这转化为所需的最低内核版本。

  • 正在使用什么 libc 变体; 并且可能是哪个版本,尽管完全有可能链接到一组最少支持的功能,但几乎“永远”存在。

  • 分发决定的 C++ 标准库的变体。 这实际上也会导致可能看起来纯粹是 C 的程序,因为某些系统级库 ( *cough* Mesa *cough* ) 会在内部拉取大量 C++ 基础架构(甚至是编译器),还会触发其他“有趣”的问题¹

我需要检查我的软件是否限制自己在 Arch Linux 之外的任何环境下运行(这背后的原因是题外话)。 我在互联网上找不到任何相关资源。

您无法在 Internet 上找到资源,因为在二进制级别上没有任何特定的东西可以制作“Arch”Arch。 对于现在的价值,我可以立即创建一个 Arch 的分支,更改其默认 XDG 骨架的选择——这样默认情况下用户目录会填充名为leechflicksbeatspics的子目录——并将其命名为“l33tz “Linux。 出于所有意图和目的,它不再是 Arch。 它的行为确实与默认的 Arch 行为有很大不同,如果你依赖任何特定的东西,这也是你所关心的,而且是最微小的。

您的雇主似乎不了解 Linux 是什么,也不了解各个发行版之间的区别。

提示:这不是二进制兼容性。 事实上,只要你停留在无聊的老glibc + libstdc++ Linux 发行版之间,就可以令人震惊地相互兼容。 除了libc.solibdl.sold-linux[-${arch}].so之外,它们放置库的位置可能略有不同,但这两个通常总是可以在/lib下找到。 一旦ld-linux[-${arch}].solibdl.so接管(这意味着拉入在运行时加载的所有库),找到共享对象和库的所有细节都被动态抽象掉了链接器。


1:就像只有在执行全局构造函数并且 libstdc++ 决定它想要成为单线程之后才成为多线程一样,因为 libpthread 没有链接到没有自己创建单线程的程序中。 那是我发现的一个非常奇怪的错误,但是yshui终于明白了https://gitlab.freedesktop.org/mesa/mesa/-/issues/3199

不,它没有。 即使这样做了,它也不会阻止任何人在 Arch Linux 发行版上编译代码,然后在不同的 Linux 上运行它。

如果您需要阻止您的软件“在 Arch Linux 之外的任何环境下运行”,则需要插入运行时检查。 虽然,老实说,我不知道检查可能包含什么,因为 linux 发行版不是单一产品。 实际检查可能与您施加限制的原因有关。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM