shians
shians

Reputation: 965

How do you write a makefile for both clang and gcc?

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?

Upvotes: 15

Views: 26343

Answers (3)

Kenn Sebesta
Kenn Sebesta

Reputation: 9728

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.

Upvotes: 4

bit2shift
bit2shift

Reputation: 676

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

Upvotes: 4

PaulR
PaulR

Reputation: 3707

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;
}

Upvotes: 17

Related Questions