我可以让我的 Makefile 自动使 GCC 使用它支持的最新标准吗?

Can I have my Makefile automatically make GCC use the most recent standard it supports?

本文关键字:支持 最新 标准 GCC 我的 Makefile 我可以      更新时间:2023-10-16

我的C++03项目需要升级到C++11,我可以保证至少在我想使用的所有GCC中都可以获得对它的实验性支持。

但是,这可能是-std=c++0x的,也可能是来自较新的 GCC 的实际-std=c++11。总有一天它会-std=c++14(当 CentOS 赶上来时......

我怎样才能形成一个 GNU Makefile,根据哪个标志会成功,将"最佳"标志添加到CXXFLAGS

我可以说"好吧,我最早使用的 GCC 仍然没有生产就绪的 C++11 支持,所以我应该坚持使用 C++03",但是嗯。

这将选择$(CXX)编译器支持的最佳选项:

CXX_MODE.42 := -std=c++98
CXX_MODE.43 := $(CXX_MODE.42)
CXX_MODE.44 := $(CXX_MODE.43)
CXX_MODE.45 := $(CXX_MODE.44)
CXX_MODE.46 := -std=c++0x
# Unnecessary, since -std=c++0x still works, but hey why not:
CXX_MODE.47 := -std=c++11
CXX_MODE.48 := $(CXX_MODE.47)
CXX_MODE.49 := $(CXX_MODE.48)
CXX_MODE.5 := -std=c++14
CXX_MODE.6 := $(CXX_MODE.5)
GXX_VERSION := $(shell $(CXX) -dumpversion | awk -F. '$$1<5{print $$1$$2} $$1>=5{print $$1}')
CXX_MODE := $(CXX_MODE.$(GXX_VERSION))
CXXFLAGS += $(CXX_MODE)

为了获得额外的乐趣,您可以根据其他变量在c++gnu++模式之间进行选择:

CXX_MODE.42 := 98
CXX_MODE.43 := $(CXX_MODE.42)
CXX_MODE.44 := $(CXX_MODE.43)
CXX_MODE.45 := $(CXX_MODE.44)
CXX_MODE.46 := 0x
# Unnecessary, since -std=c++0x still works, but hey why not:
CXX_MODE.47 := 11
CXX_MODE.48 := $(CXX_MODE.47)
CXX_MODE.49 := $(CXX_MODE.48)
CXX_MODE.5 := 14
CXX_MODE.6 := $(CXX_MODE.5)
GXX_VERSION := $(shell $(CXX) -dumpversion | awk -F. '$$1<5{print $$1$$2} $$1>=5{print $$1}')
CXX_MODE := $(CXX_MODE.$(GXX_VERSION))
ifneq($(STRICT),)
CXXFLAGS += -std=c++$(CXX_MODE) -pedantic -pedantic-errors
else
CXXFLAGS += -std=gnu++$(CXX_MODE)
endif

不完全是一个答案,因为这不提供自动选择,但我认为无论如何它都很有用。

您可以使用 make 命令行选项来选择所需的内容:

ifeq($(CPP11),Y)
    CXXFLAGS+=-std=c++11
endif
ifeq($(CPP14),Y)
    CXXFLAGS+=-std=c++14
endif

调用将按以下方式完成:

make <target> CPP11=Y

make <target> CPP14=Y
我知道

这个话题现在已经很老了,但无论如何我都想提交我的答案,因为它可能会帮助一些有同样问题的人。

我做了一个bash脚本(名为c ++ _latest_version.sh),它尝试从C++23到C++98的所有C++标准,由Makefile调用。

#!/bin/bash
# Some error handling of arguments.
echo "int main(){}" > /tmp/c++_version.cpp
if (( $? != 0 )); then
    echo "Cannot create temporary file in /tmp directory." >&2
    exit 2
fi
if [[ "$2" == "NO_WIP_STANDARD" ]]; then
    cpp_versions=(23 20 17 14 11 03 98)
else
    cpp_versions=(23 2b 20 2a 17 1z 14 1y 11 0x 03 98)
fi
for cpp_version in ${cpp_versions[@]}; do
    version_flag="-std=c++$cpp_version"
    "$1" $version_flag /tmp/c++_version.cpp -o /tmp/c++_version.out &> /dev/null
    if (( $? == 0 )); then
        echo "-std=c++$cpp_version"
        exit 0
    fi
done
echo "How in the hell your compiler can't even run c++98 code ?" >&2
exit 3

该脚本称为 './c++_latest_standard.sh [g++ 或 clang++] [NO_WIP_STANDARD]。

然后是制作文件:

# Uncomment this line if encountering compile-related issues with C++2b, C++2a, C++1z, C++1y or C++0x (C++ version is displayed by the Makefile).
# WIP_STANDARD_MODE=NO_WIP_STANDARD
# Comment those two lines if you're using another compiler than g++ and clang++, and don't forget to set yourself the C++ standard you want in CXX_VERSION (or replace it in CXX_FLAGS below).
CXX_VERSION_ERROR   =   $(shell ./c++_latest_version.sh $(CXX) $(WIP_STANDARD_MODE) 2>&1)
CXX_VERSION =   $(shell ./c++_latest_version.sh $(CXX) $(WIP_STANDARD_MODE) 2> /dev/null)
CXXFLAGS  +=  ... $(CXX_VERSION)
# write your compiling stuff here

您应该已经注意到我编写的NO_WIP_STANDARD变量,它用于禁用"正在进行中"标准,例如部分实现的 C++23 的 c++2b,因为它可能会导致编译问题。在我的机器(Arch Linux)上,我在使用clang++时遇到了问题,使用C++2b编译OpenGL(cmath标头存在潜在问题,可能兼容性设置不正确)。

如果有人希望我发布整个 bash 脚本,我可以做到(到目前为止还没有只发布绝对必要的内容。

我也同意每个编译器都应该有一个标志来编译最新的标准,而不是诉诸测试每个标志等不优雅的技巧,直到找到最新的标志。如果有人考虑改进,我愿意接受您的建议。希望我帮助:)