你如何为 clang 和 gcc 编写一个 makefile?

Posted

技术标签:

【中文标题】你如何为 clang 和 gcc 编写一个 makefile?【英文标题】:How do you write a makefile for both clang and gcc? 【发布时间】:2018-11-29 04:08:27 【问题描述】:

我想在我的代码中使用 std::experimental::filesystem,这需要我使用带有 GCC 的 -lstdc++fs 和带有 Clang 的 -lc++experimental 进行编译。目前我有一个 makefilemakefile.clang 反映编译的差异,或者我考虑过使用 clang 构建目标,以便我可以运行 build clang

是否有一些规范的方法可以在 makefile 中设置特定于编译器的标志?

【问题讨论】:

无关:您应该可以通过升级到支持 C++17 的编译器来避免这种情况 你能发布你当前使用的makefile吗? 假设您使用 GNU Make(或一些兼容的 make 程序),您可以使用 conditions 设置某些标志。或者您可以使用另一个构建系统来为您生成正确的 makefile。 请edit您的问题提供有用的附加文本信息(作为文本)。 我知道这是旧的,但这个网站对任何寻找答案的人都有帮助:hiltmon.com/blog/2015/09/28/… ...我已经使用这种方法很长时间没有问题 【参考方案1】:

您可以使用 CMake 来实现。如果您想拥有可移植的代码,最好使用它。

CMake 允许生成适合您系统的 Makefile(例如您的系统默认编译器)。 CMake 有很多功能对于检查实际系统配置非常有用。

在这个答案中,您有示例:In cmake, how can I test if the compiler is Clang?

一个可靠的检查是使用 CMAKE__COMPILER_ID 变量。例如,检查 C++ 编译器:

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

如果你仍然想使用 Makefile,你应该检查这个答案:https://***.com/a/2826178/7042963

【讨论】:

【参考方案2】:

正如用户“一些程序员老兄”所提到的,GNU make 中有conditionals。您可以通过这种方式轻松检查编译器版本:

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

给定以下源文件test.cpp,您可以使用make CXX=g++ testmake CXX=clang test 对其进行编译,它应该将适当的标志传递给每个编译器。

#include <iostream>

int main() 
  std::cout << "Hello World " << MESSAGE << std::endl;
  return 0;

【讨论】:

我会接受这个作为答案,因为它可能是你只使用 make 时能得到的最接近的东西。它存在别名问题,例如 MacOS 将 g++ 别名为 clang,而像 g++-7 这样的版本化编译器可能无法正常工作。【参考方案3】:

为了处理版本化编译器,就像您在接受答案的评论中提到的那样,您需要使用 $(findstring find,in)

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

这里需要注意的是,您不能使用$(findstring g++,$(CXX)),因为它会无意中匹配clang++

更精确地处理事情的更深入的替代方法是:

# 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

【讨论】:

以上是关于你如何为 clang 和 gcc 编写一个 makefile?的主要内容,如果未能解决你的问题,请参考以下文章

你如何为 getInitialProps 编写 Jest 测试?

你如何为 IE 开发插件?

为啥 clang 无法展开循环(即 gcc 展开)?

用于解释自定义 c++11 属性的 Clang/GCC 插件

你如何为 Seam / JPA (hibernate) 创建一个 DAO 类?

你如何为 Cobol 字帖生成 java~jrecord 代码