4

The problem:

2 version of g++ installed on a computer running Ubuntu 12.04. They are the versions 4.6 and 5.2.

I have to compile a C++11 program using a Makefile. If I use g++ as compiler it calls automatically the version 4.6, it does not support c++11 so the compilation fails. I've followed a tutorial online, so that now if I call g++ it calls automatically the version 5.2 and now it works.

I find this solution not so good, since it works only on my PC. Is there a way to recognize in the Makefile if the default g++ version support C++11 and, in case not, switch to a more recent version?

Thank you!

stefano1
  • 161
  • 10
  • 2
    I'd set my CC and CXX environment variables before invoking make on the command line. You can then use CC and CXX in your makefile to make it work. The shell scripts cc and cxx ( / c++ ) use those environment variables. – bash0r Feb 04 '16 at 10:28
  • 1
    Have you considered configuring the makefiles with autotools? [This answer](http://stackoverflow.com/questions/11909347/autotools-check-for-c11) tells you how to create a check for C++11 capabilities. – Henrik Feb 04 '16 at 10:33
  • 1
    Another great option is CMake. It checks for different compiler capabilities by attempting to compile small test programs. – Vorac Feb 04 '16 at 10:43

6 Answers6

6

Is there a way to recognize in the Makefile if the default g++ version support C++11 and, in case not, switch to a more recent version?

You can certainly detect the version of the default compiler available in PATH in your makefile. However, where do you search for another version?

The standard approach is to let the user specify the C compiler through CC and C++ compiler through CXX make variables, e.g.: make CC=/path/to/my/gcc CXX=/path/to/my/g++.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • In this way the user, before calling `make`, should call `make CC=/path/to/my/gcc CXX=/path/to/my/g++` right? – stefano1 Feb 04 '16 at 10:46
  • 1
    Not _before_ calling `make`. _When_ calling make pass extra variables to it, see https://www.gnu.org/software/make/manual/make.html#Overriding – Maxim Egorushkin Feb 04 '16 at 10:49
  • I have to say that, if it's possible and not too complicated for you to pass custom arguments to make calls on different platforms, then this is the answer you want. It's the least intrusive, and most flexible. – Yam Marcovic Feb 04 '16 at 10:52
4

You can always select which gcc to use while invoking make

make CXX=/gcc/path/of/your/choice

otherwise you can detect gcc version using

ifdef CXX
     GCC_VERSION = $(shell $(CXX) -dumpversion)                                                                                               
else
     GCC_VERSION = $(shell g++ -dumpversion)
endif

in Makefile and while using, you can test if your gcc is >=4.6

ifeq ($(shell expr $(GCC_VERSION) '>=' 4.6), 1)

UPDATE: newer gcc needs -dumpfullversion together (icx is the CC from Intel OneAPI)

$ icx -dumpversion
  14.0.0
$ gcc -dumpversion
  9    
$ icx -dumpfullversion -dumpversion
  14.0.0
$ gcc -dumpfullversion -dumpversion
  9.3.1
fchen
  • 781
  • 7
  • 15
dlmeetei
  • 9,905
  • 3
  • 31
  • 38
  • You should assign default value `CXX=g++` in the makefile. `make CXX=...` overrides your assignment. This way you do not need this conditional at all. Just `GCC_VERSION = $(shell $(CXX) -dumpversion)` one-liner. – Maxim Egorushkin Feb 04 '16 at 15:23
2

One very simple way is to use conditional statements in your makefile, and go for versions which you know are compatible, and only use the default gcc as a fallback. Here's a basic example:

CXX=g++

ifeq (/usr/bin/g++-4.9,$(wildcard /usr/bin/g++-4.9*))
    CXX=g++-4.9
# else if... (a list of known-to-be-ok versions)
endif

The other, more robust method, is to generate your makefile using a script that checks for capabilities using test compilations, kind of like what ./configure usually does. I really don't mean to recommend autotools, though.

Yam Marcovic
  • 7,953
  • 1
  • 28
  • 38
  • Thank you! I think that this will solve the problem! Why don't you recommend autotools? – stefano1 Feb 04 '16 at 10:41
  • @stefano1 It's a lot of boilerplate. Not all projects need it, and most can do with a much simpler (and often better) build system. By the way, google "tup". – Yam Marcovic Feb 04 '16 at 10:49
  • @YamMarcovic make is simple and powerful, but has got a steep learning curve, IMO. I have seen different build systems over the years based on CMake, tup, premake, ninja, etc.. They were not better or faster than my non-recursive makes. – Maxim Egorushkin Feb 04 '16 at 10:52
  • @MaximEgorushkin I work with the AOSP, which uses a non-recursive make. It's horrible at such large scales. For small to medium-sized projects I also used a non-recursive make, but once I switched to tup (and learned how to use it idiomatically) I didn't look back. P.S. CMake and ninja aren't really comparable to make or tup. – Yam Marcovic Feb 04 '16 at 10:53
  • @MaximEgorushkin At any rate, however, I talked about `autotools`, not make. – Yam Marcovic Feb 04 '16 at 10:56
  • @YamMarcovic I am not going to argue, that is a battle one cannot win :) – Maxim Egorushkin Feb 04 '16 at 10:59
1

The thing to do is build your Makefile to use as many implicit rules as possible. By default compilation uses various environment variables.

The variable $(CXX) is the C++ compiler command and defaults to g++ on Linux systems. So clanging CXX to a different compiler executable will change the compiler for all implicit compile commands.

When you write explicit rules use the same variable that the implicit rules use. So instead of this:

program: program.cpp
    g++ -o program program.cpp

Do this:

program: program.cpp
    $(CXX) -o program program.cpp

Other variables you should use are:

CPPFLAGS = -Iinclude
CXXFLAGS = -std=c++14 -g3 -O0

Those are for pre-processing flags CPPFLAGS and compiler flags CXXFLAGS and library linking flags LDLIBS.

Using the default environment variables allows the person compiling the project the freedom to control the compilation for their desired environment.

See the GNU make manual

Galik
  • 47,303
  • 4
  • 80
  • 117
0

You can check in your source code the gcc version and abort compilation if you don't like it. Here is how it works:

/* Test for GCC > 4.6 */
#if !(__GNUC__ > 3 && __GNUC_MINOR__ > 6)
#error gcc above version 4.6 required!
#endif
Vorac
  • 8,726
  • 11
  • 58
  • 101
  • He is looking for a way to detect in makefile, Your answer will work on c/c++ files – dlmeetei Feb 04 '16 at 10:31
  • @Deleisha, indeed. Yet, most users have only one - the latest possible - gcc version installed and "selecting" a gcc installation isn't a really good idea. Drop the compilation and let the user handle the situation. – Vorac Feb 04 '16 at 10:33
  • Yes, What I was trying to say was, He is asking for a way to do in `Makefile`. Your approach is for detecting in c/c++ files – dlmeetei Feb 04 '16 at 10:50
  • 1
    @Vorac Can you edit your answer. There is missing enclosing bracket and second exclamation mark before minor version check. – Radek Feb 04 '16 at 13:50
0

This works for me:

cmake_minimum_required(VERSION 2.8.11)
project(test)

if (${CMAKE_CXX_COMPILER_VERSION} LESS 5.0)
    message(FATAL_ERROR "You need a version of gcc > 5.0")
endif (${CMAKE_CXX_COMPILER_VERSION} LESS 5.0)

add_executable(test test.cpp)
cauchi
  • 1,463
  • 2
  • 17
  • 45
  • I guess, He is looking for a way in `makefile`, your is `cmake` recipe – dlmeetei Feb 04 '16 at 10:56
  • 1
    You are right. I didn't read correctly and thought he was using cmake. who uses makefile without cmake or some other building tool these days? – cauchi Feb 04 '16 at 10:58
  • The reason is that the compilation is really really simple. It would suffice a simple `g++ main.cpp -O3 -std=c++11` since all the classes are templates. Do you think that it's better to use cmake also in this case? – stefano1 Feb 04 '16 at 20:24
  • No you are right. If it's that simple is an overkill to use cmake to generate a makefile. I was just being sarcastic. – cauchi Feb 05 '16 at 09:19