14

I would like to use std::experimental::filesystem in my code, this requires me to compile using -lstdc++fs with GCC and -lc++experimental with Clang. At the moment I have a makefile and makefile.clang reflecting the difference in compilation, alternatively I've thought about using a clang build target so I can run build clang.

Is there some canonical way to set compiler-specific flags in a makefile?

shians
  • 955
  • 1
  • 6
  • 21
  • 1
    Unrelated: You should be able to avoid this by upgrading to a compiler that supports C++17 – user4581301 Jun 20 '18 at 05:58
  • Can you post makefiles you are currently using? – VLL Jun 20 '18 at 06:00
  • 1
    Assuming you use GNU Make (or some compatible `make` program) you can use [conditions](https://www.gnu.org/software/make/manual/make.html#Conditionals) to set certain flags. Or you could use another build-system which generates the correct makefiles for you. – Some programmer dude Jun 20 '18 at 06:01
  • @Ville-Valtteri Here's a trimmed down version of the current makefile: https://pastebin.com/CvAvTdrd – shians Jun 20 '18 at 06:08
  • 1
    Please [edit] your question to provide helpful additional textual information (as text). – Yunnosch Jun 20 '18 at 06:14
  • You can use cmake: https://stackoverflow.com/questions/10046114/in-cmake-how-can-i-test-if-the-compiler-is-clang – BartekPL Jun 20 '18 at 06:45
  • 1
    I know this is old, but this site is helpful for anyone looking for an answer: https://hiltmon.com/blog/2015/09/28/the-simple-c-plus-plus-makefile-executable-edition/ ... I have used this method for a long time without issue – nvanwyen Dec 27 '19 at 14:13

3 Answers3

17

As the user "Some programmer dude" mentioned, there are conditionals in GNU make. You could easily check for the compiler version this way:

CXXFLAGS = -Og -Wall -Wextra

GCC_CXXFLAGS = -DMESSAGE='"Compiled with GCC"'
CLANG_CXXFLAGS = -DMESSAGE='"Compiled with Clang"'
UNKNOWN_CXXFLAGS = -DMESSAGE='"Compiled with an unknown compiler"'

ifeq ($(CXX),g++)
  CXXFLAGS += $(GCC_CXXFLAGS)
else ifeq ($(CXX),clang)
  CXXFLAGS += $(CLANG_CXXFLAGS)
else
  CXXFLAGS += $(UNKNOWN_CXXFLAGS)
endif

Given the following source file test.cpp you can compile it with make CXX=g++ test or make CXX=clang test and it should pass the appropriate flags to each compiler.

#include <iostream>

int main() {
  std::cout << "Hello World " << MESSAGE << std::endl;
  return 0;
}
PaulR
  • 3,587
  • 14
  • 24
  • 1
    I will accept this as an answer because it's probably the closest thing you can get when only using make. It suffers from aliasing issues since for example MacOS have `g++` aliased to `clang` and versioned compilers like `g++-7` would presumably not work. – shians Jun 21 '18 at 03:53
4

In order to handle versioned compilers, like you mentioned in the comment to the accepted answer, you need to use $(findstring find,in) as such:

# Detect if CXX is g++ or clang++, in this order.
ifeq '' '$(findstring clang++,$(CXX))'
  LDLIBS = -lstdc++fs
else
  LDLIBS = -lc++experimental
endif

The caveat here is that you cannot use $(findstring g++,$(CXX)) since it'll match clang++ unintentionally.

A more in-depth alternative to handle things more precisely would be:

# Detect if CXX is clang++ or g++, in this order.
ifneq '' '$(findstring clang++,$(CXX))'
  LDLIBS = -lc++experimental
else ifneq '' '$(findstring g++,$(CXX))'
  LDLIBS = -lstdc++fs
endif
bit2shift
  • 656
  • 1
  • 9
  • 17
3

This approach parses the compiler's version string looking for clang. If it doesn't find clang then it looks for g++ in order to resolve an issue with macOS, where g++ is aliased to clang.

# Set compiler-specific flags
GCC_CXXFLAGS = -DMESSAGE='"Compiled with GCC"'
CLANG_CXXFLAGS = -DMESSAGE='"Compiled with Clang"'
UNKNOWN_CXXFLAGS = -DMESSAGE='"Compiled with an unknown compiler"'

# Detect if CXX is clang++ or g++, in this order.
COMPILER_VERSION := $(shell $(CXX) --version)
ifneq '' '$(findstring clang,$(COMPILER_VERSION))'
  CFLAGS += $(CLANG_CXXFLAGS)
else ifneq '' '$(findstring g++,$(COMPILER_VERSION))'
  CFLAGS += $(GCC_CXXFLAGS)
else
  $(warning Unknown compiler)
  CFLAGS += $(UNKNOWN_CXXFLAGS)
endif

Credit to @bit2shift's answer, which inspired this one.

Kenn Sebesta
  • 7,485
  • 1
  • 19
  • 21