简体   繁体   中英

How do I prevent different compilation based on the version of my g++ compiler?

Scenario:
I'm building software across two different machines.
One of these machines has a fully compliant C++11 version of g++ .
The other does not.

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

Machine 2 (Windows with Cygwin):

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

The C++ software I'm building across these two machines supports all the way back to C++98.

However, newer features of C++ will be used if they are available.
(The software in question, is C++ Catch for unit testing).

Problem:
I have a generic makefile that will build this software. On Cygwin it builds the software successfully. On Linux , with the newer compiler, it fails to build, because I assume it detects the version of the compiler and attempts to use more modern C++ features.

Here is a dump of the errors for glancing purposes. Mostly just nullptr_t related. Maybe something to do with newer rules on template deduction(not entirely sure):

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 ) {

This can be easily fixed on the Linux machine by ensuring that g++ gets compiled with the --std=c++11 flag. However, I don't want two separate makefiles across the two machines. I can't add the --std=c++11 flag to both builds, because version 4.9 doesn't have that flag yet.

Question:
How can I enable cross-compilation using the same command on different versions of g++ ? The code builds differently based on the versions of g++ -- in which case, sometimes the std flag needs to be passed.

Additional:
I've tried giving g++ the flag --std=c++98 for both builds, but it still fails on the Linux build. The goal here is to use the same kind of command across both machines.

On Windows platforms, I recommend to use Stephan Lavavej's Nuwen Distro . The only snag is that you can't use the std::thread facilities, but boost::thread provides an almost seamless alternative.

On Windows I would recommend switching to MSYS2 especially if you need c++11 support. Latest release has got mingw64 g++4.9.2. I was able to successfully built my Ubuntu project heavily using c++11/boost/python whereas I wasn't able to do that on Cygwin or MSVC2015 RC. MSYS2 has got it's package manager called pacman which is kind of apt-get/yum equivalent.

There is quite large number of prebuilt stuff which availibility you can check here .

Very compact introduction here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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