如何在 c++ Autotools 项目中使用不同版本的 g++ 进行编译

Posted

技术标签:

【中文标题】如何在 c++ Autotools 项目中使用不同版本的 g++ 进行编译【英文标题】:How can I compile with different version of g++ in c++ Autotools project 【发布时间】:2018-12-25 09:18:25 【问题描述】:

我有一个大的autotools项目,子目录下一部分代码使用g++-4.9编译,其他使用g++8.2。

我的问题是如何用不同版本的g++编译整个项目。

我看到一些相关的问题是更改不同的 g++ 编译器,一般答案是设置环境变量或make 选项。

但是,我的问题是同时使用 g++8.2 和 g++4.9 进行编译。

我希望有一些解决方案可以设置 Makefile.am 像:

noinst_PROGRAMS=foo bar
foo_CXX_COMPILER=/usr/bin/g++-4.9

bar_CXX_COMPILER=/usr/bin/g++-8.2

编辑:

我尝试过的更多细节

    子项目中的第三方库在使用g++-4.9 -std=c++11编译时会显示很多警告“auto_ptr is deprecated”,但没有任何错误并且执行良好。 它编译良好,没有错误和g++-4.9 -std=c++98 警告。 当我使用g++-8.2 编译时,它会喊出许多错误“未定义的引用...”,即使我添加了标志-std=c++98.

我猜这是因为g++-8.2 编译器无法识别auto_ptr 的用法!

我更喜欢只使用一种编译器,它可以让问题变得简单!但是,如果情况不能只使用一个,我想知道如何使用不同的两个编译器设置 Makefile.am,或者解决这个编译问题的任何最佳方法!

【问题讨论】:

您需要两个不同的构建目标:一个用于您的程序(库?)和它依赖的文件(目标文件、库等),使用 g++8.2 构建,另一个用于构建g++4.9。如果您需要使用每个编译器进行构建,请设置另一个构建目标,该目标依赖于两个特定于编译器的构建。 你确定不能用 g++8.2 构建所有东西吗?也许通过为您认为需要 v4.9 的目标添加一些额外的选项?这将是一个更具前瞻性的解决方案。 @JohnBollinger : 我的子项目使用的第三方库 (Hazelcast Client c++) 应该根据这个answer 使用 g++-4.9 或更低版本。我尝试使用 g++-8.2 进行编译,它显示了很多错误,例如“未定义对 ... 的引用”。在使用 g++-4.9 时,它运行良好。那个 Hazelcast Client C++ Library 好像是个老库了! 您链接到的 Google 线程是关于 Hazelcast 无法使用太、不太新的 C++ 标准库,我在其中没有看到任何关于g++4.9 是极限。如果您自己无法弄清楚,那么提出一个关于使用 g++ 8.2 构建 Hazelcast 的(单独的)问题可能是值得的。仅仅因为您看到很多错误并不一定意味着解决方案很复杂。并且试图在同一个项目中使用不同版本的 C++ 标准库是个坏消息。 @eric_hsu:避免评论你自己的问题。 请edit您的问题以改进它。 提及问题中的所有库,并明确告诉我们它们是用什么 C++ 方言编码的(C++98、C++14、C+ +17, ...) 【参考方案1】:

我的问题是如何用不同版本的g++编译整个项目。

这是可能的,但我不建议这样做。 GNU 构建系统对此没有任何支持,但您可以看看 AX_CC_FOR_BUILD 如何实现类似的想法(为构建和主机启用编译器)。

想法#2 是@JohnBollinger 建议的——选择一个编译器并用它构建。 与设置两个编译器相比,您构建的最终用户会更喜欢这一点。这是我会采用的解决方案,因为 GNU 构建系统就是这样工作的。如果由于某种原因不能对旧代码进行现代化改造,可以告诉 g++-8.2 从以前版本的 C++ 编译代码。

想法 #3 基本上是将您的项目拆分为两个 autotools 项目——一个使用旧编译器编译,一个使用新编译器编译。也不是这个想法的真正粉丝。

【讨论】:

【参考方案2】:

我有一个大的autotools项目,子目录下一部分代码使用g++-4.9编译,其他使用g++8.2。

我的问题是如何用不同版本的g++编译整个项目。

我不建议这样做。 ABI 约定可能已更改(因此恕我直言,不建议使用不同 ABI 的两个不同 GCC 进行编译)。

实际上,我建议使用相同(最新)的 GCC 构建所有项目,即使用 g++ 8.2

如果项目的某些部分使用不同的 C++ 方言,您可以显式地将一些 -std=c++11-std=c++17 选项传递给它们。

所以只需将您的项目配置为使用相同(和最新的)GCC。如果某些 C++ 方言不同,请将特定标志传递给它。请参阅options controlling the C++ dialect 和-std= option。

最后,您可以考虑修补旧库的源代码,使其与 C++14 兼容(特别是,删除所有出现的 auto_ptr 并明智地将它们替换为 unique_ptr 等...)。在大多数情况下,这样做是值得的(也许旧库的新版本已经存在,即 C++14 或 C++17)

混合使用C++ standard library 的两个不同版本肯定很痛苦,应该避免。如果你坚持尝试,你需要痛苦地理解所有血淋淋的细节(所以我真的建议不要尝试这个)。然后阅读 Drepper 的 How to write shared libraries 论文。

另一种方法是让您的软件使用两个不同的processes(一个用于旧的 C++98 源代码,另一个用于新的 C++14 代码)并使用inter-process communication 工具。这可能是最可靠的解决方案。

出于实际目的,将旧 C++98 和新 C++14 视为两种不同且不兼容的编程语言(C++11确实不同其前身)。

【讨论】:

谢谢!我确定它应该使用标志 -std=c++11。因此,如果我想使用g++-8.2 来编译我的整个大项目,它应该添加一些 Options Controlling C++ Dialect 标志,就像您发布的那样。我只是简单地查看了一下,我应该传递的可能标志是 -fabi-version=n-fabi-compat-version=n -侘寂=n。但是,当我将 n 的值设置为 2 和 8 时,它在我的测试中不起作用。这是正确的设置方法吗? 我不知道你是否需要设置它。但可能不会。 子项目中在g++4.9中编译良好的第三方库使用已弃用的auto_ptr。当我通过修改-std=option控制方言的选项 使用g++8.2 编译时,它仍然显示很多错误“未定义对...的引用”。我猜这是因为不推荐使用的类型无法在 g++-8.2 中编译!我对吗?如果是这样,我将采用@Idav1s 的第一和第三个建议来调查解决方案。 您可能需要明智地链接(可能是两个不同的 C++ 标准库) 感谢您明智地构建 c++ 项目的建议!在一个项目中遇到两个编译器真的很痛苦。我终于克隆了第三方库的源代码,用我默认的g++(8.2)自己手动构建。这使我的项目成功构建在一个编译器中!此外,将库版本从 3.10 更新到 3.11。我不确定为什么这种方式解决了这个问题。我猜我链接的原始共享库可能会在g++4.9 中构建,这会在链接时导致g++8.2 中的编译错误。那是对的吗 ?无论如何,它解决了!

以上是关于如何在 c++ Autotools 项目中使用不同版本的 g++ 进行编译的主要内容,如果未能解决你的问题,请参考以下文章

如何在 autotools 项目中传播配置选项?

重新排序 gnu autotools 链接器标志

如何使用 autotools 与库同时构建 Python 接口

如何从现有的 C++ 源代码在 Eclipse CDT 中创建 GNU Autotool 项目?

Autotools:如何设置全局编译标志

在 AIX 上链接 Autotools 项目时避免使用 -blibpath