How do you write a makefile for both clang and gcc?
You can use CMake to achieve that. It is a better to use if you want to have portable code.
CMake allows to generate Makefile that is appropriate for your system(e.g. your system default compiler). CMake has a lot of features that can be very useful to check actual system configuration.
In this answer, you have example how do that: In cmake, how can I test if the compiler is Clang?
A reliable check is to use the CMAKE__COMPILER_ID variables. E.g., to check the C++ compiler:
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # using Clang elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # using GCC elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") # using Intel C++ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # using Visual Studio C++ endif()
If you still want to use Makefile you should check this answer: https://stackoverflow.com/a/2826178/7042963
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;
}
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