如何防止基于我的 g++ 编译器版本的不同编译?

Posted

技术标签:

【中文标题】如何防止基于我的 g++ 编译器版本的不同编译?【英文标题】:How do I prevent different compilation based on the version of my g++ compiler? 【发布时间】:2015-06-23 18:44:41 【问题描述】:

场景: 我正在两台不同的机器上构建软件。 其中一台机器具有完全符合 C++11 版本的 g++。 另一个没有。

机器 1(Linux):

$ g++ --version
g++ (Ubuntu 5.1.0-0ubuntu11~14.04.1) 5.1.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

机器 2(带有 Cygwin 的 Windows):

$ g++ --version
g++ (GCC) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

我在这两台机器上构建的 C++ 软件一直支持到 C++98。

但是,如果 C++ 的新功能可用,我们将使用它们。 (有问题的软件是C++ Catch 用于单元测试)。

问题: 我有一个通用的 makefile 可以构建这个软件。在Cygwin 上,它成功构建了软件。在 Linux 上,使用较新的编译器无法构建,因为我假设它检测到编译器的版本并尝试使用更现代的 C++ 功能。

这里是错误的转储,以供一目了然。大多数只是nullptr_t 相关。也许与模板推导的新规则有关(不完全确定):

catch.hpp:833:17: error: ‘nullptr_t’ in namespace ‘std’ does not name a type
     inline std::nullptr_t opCast(std::nullptr_t)  return nullptr; 
                 ^
catch.hpp:954:58: error: ‘template<Catch::Internal::Operator Op, class T> bool Catch::Internal::compare’ conflicts with a previous declaration
     template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) 
                                                          ^
catch.hpp:948:44: note: previous declaration ‘namespace Catch::Internal  ::compare’
     template<Operator Op, typename T> bool compare( T* lhs, int rhs ) 
                                            ^
catch.hpp:954:53: error: ‘nullptr_t’ is not a member of ‘std’
     template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) 
                                                     ^
catch.hpp:954:70: error: expected primary-expression before ‘*’ token
     template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) 
                                                                      ^
catch.hpp:954:72: error: ‘rhs’ was not declared in this scope
     template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) 
                                                                        ^
catch.hpp:954:76: error: expression list treated as compound expression in initializer [-fpermissive]
     template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) 
                                                                            ^
catch.hpp:954:44: warning: variable templates only available with -std=c++14 or -std=gnu++14
     template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) 
                                            ^
catch.hpp:954:78: error: expected ‘;’ before ‘’ token
     template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) 
                                                                              ^
catch.hpp:957:66: error: ‘std::nullptr_t’ has not been declared
     template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) 
                                                                  ^
catch.hpp:957:44: error: redefinition of ‘template<Catch::Internal::Operator Op, class T> bool Catch::Internal::compare(T*, int)’
     template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) 
                                            ^
catch.hpp:948:44: note: ‘template<Catch::Internal::Operator Op, class T> bool Catch::Internal::compare(T*, int)’ previously declared here
     template<Operator Op, typename T> bool compare( T* lhs, int rhs ) 
                                            ^
In file included from main.cpp:2:0:
catch.hpp:1088:38: error: ‘std::string Catch::toString’ redeclared as different kind of symbol
 std::string toString( std::nullptr_t );
                                      ^
catch.hpp:1085:13: note: previous declaration ‘std::string Catch::toString(unsigned char)’
 std::string toString( unsigned char value );
             ^
catch.hpp:1088:23: error: ‘nullptr_t’ is not a member of ‘std’
 std::string toString( std::nullptr_t );
                       ^
In file included from main.cpp:2:0:
catch.hpp:7336:38: error: ‘std::string Catch::toString’ redeclared as different kind of symbol
 std::string toString( std::nullptr_t ) 
                                      ^
In file included from main.cpp:2:0:
catch.hpp:1232:13: note: previous declaration ‘template<class T, class Allocator> std::string Catch::toString(const std::vector<_Tp, _Alloc>&)’
 std::string toString( std::vector<T,Allocator> const& v ) 
             ^
In file included from main.cpp:2:0:
catch.hpp:7336:23: error: ‘nullptr_t’ is not a member of ‘std’
 std::string toString( std::nullptr_t ) 

通过确保使用--std=c++11 标志编译g++,可以在Linux 机器上轻松修复此问题。但是,我不希望两台机器上有两个单独的 makefile。我不能将--std=c++11 标志添加到两个版本中,因为版本4.9 还没有那个标志。

问题: 如何在不同版本的g++ 上使用相同的命令启用交叉编译?代码根据g++ 的版本构建不同——在这种情况下,有时需要传递std 标志。

补充: 我已经尝试为两个版本提供g++ 标志--std=c++98,但在Linux 版本上仍然失败。这里的目标是在两台机器上使用相同类型的命令。

【问题讨论】:

在 Windows 上可以使用 MinGW 64。它支持 std=c++11 选项。 --std=c++11 已添加回 GCC 4.7。 在 Makefile 中使用条件保护有什么问题? @MSalters 我错了。我一定是在尝试时打错了标志。我实际上可以用这个标志在 Cygwin 下构建。 【参考方案1】:

在 Windows 平台上,我推荐使用 Stephan Lavavej 的Nuwen Distro。唯一的障碍是您不能使用std::thread 设施,但boost::thread 提供了几乎无缝的替代方案。

【讨论】:

【参考方案2】:

在 Windows 上,我建议切换到 MSYS2,特别是如果您需要 c++11 支持。最新版本有 mingw64 g++4.9.2。我能够成功地使用 c++11/boost/python 大量构建我的 Ubuntu 项目,而我无法在 Cygwin 或 MSVC2015 RC 上做到这一点。 MSYS2 的包管理器名为pacman,相当于apt-get/yum

有相当多的预建内容可供您查看here。

非常简洁的介绍here

【讨论】:

以上是关于如何防止基于我的 g++ 编译器版本的不同编译?的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的g ++编译器中满足C ++标准版本?

防止.NET版本更改[重复]

g++ 只为 linux 编译跨平台

#ifdef 标志来区分 gcc 和 g++ 编译器? [复制]

如何在 Visual Studio 中混合不同编译器版本的程序:?

如何将 c、c++ 和 python 代码编译为“Released/Final”版本? [关闭]