如何正确设置项目的 make 文件?

Posted

技术标签:

【中文标题】如何正确设置项目的 make 文件?【英文标题】:How to correctly setup a make file for a project? 【发布时间】:2020-08-30 00:48:27 【问题描述】:

Vulkan SDK 托管了一个仅包含 C++ 标头的 C 包装 库。问题是,它真的是一个沉重的头,所以它浪费了大量的编译时间。

所以我考虑为我的 Vulkan 项目使用 make 文件,这是我以前从未做过的。我决定以编程方式生成所有依赖项。可能这部分我也搞砸了,太难理解了。

它确实有点工作,可能有一种更简单的方法来做同样的事情。 这是我无法真正解决的部分:

    我为我的项目生成了所有 .o(对象)文件以及 .gch(预编译头文件) 然后我对 vulkan.hpp 和 glfw3.h 做了同样的事情。 (请记住,我的大部分编译时间都花在这上面)。

...关于这个过程,我有几个问题:

我能否以某种方式强制g++ 编译器使用.gch 文件? -I, -include 的组合似乎根本不起作用,我什至无法调试 -H/-M/-MM 的情况,因为我没有任何来自此命令的输出。

我正在使用 MSYS2 MINGW_64 版本,如果它有所作为的话。 如果有人能给我一两个关于 make 文件的提示,我会很高兴,特别是如果我对编译过程有完全误解。

# Methods

define uniq =
  $(eval seen :=)
  $(foreach _,$1,$(if $(filter $_,$seen),,$(eval seen += $_)))
  $seen
endef

# Compilation flags
_COMPILER := g++ -std=c++17
_FLAGS_WARNING := -Wall -Wextra -Wshadow
_FLAGS_COMPILE := -g -O0
_FLAGS_VULKAN := -lglfw3 -lvulkan

# Custom Flags
_FLAGS_DEBUG := -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0

# Output
_OUTPUT_NAME := test

# Directories
_TMP_DIR := _tmp
_O_DIR := $_TMP_DIR\.o
_GCH_DIR := $_TMP_DIR\.gch

_SOURCE_DIR := src
_BUILD_DIR := build
_DEBUG_DIR := $_BUILD_DIR\debug
_RELEASE_DIR := $_BUILD_DIR\release

# Files
_VULKAN_HPP := C:/VulkanSDK/1.2.148.1/Include/vulkan/vulkan.hpp
_GLFW_HPP := C:/msys64/mingw64/include/GLFW/glfw3.h

# Grouping Files
# .cpp & .o
_CPP_LIST := $wildcard $_SOURCE_DIR/*.cpp $_SOURCE_DIR/*/*.cpp
_CPP_LIST_NAME := $notdir $_CPP_LIST
_O_LIST := $addprefix $_O_DIR/, $patsubst %.cpp, %.o, $_CPP_LIST_NAME

# .hpp & .gch
_HPP_LIST := $wildcard $_SOURCE_DIR/*.hpp $_SOURCE_DIR/*/*.hpp $_VULKAN_HPP
_HPP_LIST_NAME := $notdir $_HPP_LIST
_GCH_LIST := $addprefix $_GCH_DIR/, $patsubst %.hpp, %.gch, $_HPP_LIST_NAME

# .h & .gch
_H_LIST := $_GLFW_HPP
_H_LIST_NAME := $notdir $_H_LIST
_C_GCH_LIST := $addprefix $_GCH_DIR/, $patsubst %.h, %.gch, $_H_LIST_NAME

_COMPILATION_BUNDLE_CPP = $_FLAGS_WARNING $_FLAGS_COMPILE $_FLAGS_VULKAN $_FLAGS_DEBUG -I $_GCH_DIR 
_COMPILATION_BUNDLE_HPP = $_FLAGS_COMPILE -x c++-header $_FLAGS_DEBUG -I $_GCH_DIR

$_DEBUG_DIR/$_OUTPUT_NAME: $_GCH_LIST $_C_GCH_LIST $_O_LIST 
    $_COMPILER $_COMPILATION_BUNDLE_CPP $_O_LIST $addprefix -include , $_GCH_LIST $addprefix -include , $_C_GCH_LIST -o $@ 

vpath %.cpp $(call uniq, $dir $_CPP_LIST)
$_O_DIR/%.o: %.cpp 
    $_COMPILER $_COMPILATION_BUNDLE_CPP -c $< -o $@ 

vpath %.hpp $(call uniq, $dir $_HPP_LIST)
$_GCH_DIR/%.gch: %.hpp 
    $_COMPILER $_COMPILATION_BUNDLE_HPP $< -o $@

vpath %.h $(call uniq, $dir $_H_LIST)
$_GCH_DIR/%.gch: %.h
    $_COMPILER $_COMPILATION_BUNDLE_HPP $< -o $@

干净项目的执行(因此更容易理解):

g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch src/helper/helper.hpp -o _tmp\.gch/helper.gch
g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch src/renderer/renderer.hpp -o _tmp\.gch/renderer.gch
g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch C:/VulkanSDK/1.2.148.1/Include/vulkan/vulkan.hpp -o _tmp\.gch/vulkan.gch
g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch C:/msys64/mingw64/include/GLFW/glfw3.h -o _tmp\.gch/glfw3.gch 
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch  -c src/main.cpp -o _tmp\.o/main.o  
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch  -c src/helper/helper.cpp -o _tmp\.o/helper.o
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch  -c src/renderer/renderer.cpp -o _tmp\.o/renderer.o
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch  _tmp\.o/main.o _tmp\.o/helper.o _tmp\.o/renderer.o -include _tmp\.gch/helper.gch -include _tmp\.gch/renderer.gch -include _tmp\.gch/vulkan.gch -include _tmp\.gch/glfw3.gch -o build\debug/test

【问题讨论】:

相关:Precompiled headers with GCC 【参考方案1】:

使用预编译的头文件实际上相当简单。将其分解为手动步骤可能是最简单的。您甚至可以很容易地对现有项目进行改造。步骤可能是:

创建一个 PCH 文件,包括一堆标准库或其他要预编译的头文件。注意:编译您的 PCH 时使用 same 标志作为编译其他 c++ 代码时使用的标志,否则可能无法正常工作。 在您的 makefile 中添加 PCH 的包含标志...基本上就是这样。

让我们尝试一个实际的例子:

    从源文件 src1.cpp 开始并编译它:g++ -I. &lt;other flags&gt; src1.cpp -o src1.o 创建您的 pch 文件,将其命名为 pch.hpp(或其他名称) 编译您的 PCH 文件:g++ -I. &lt;other flags&gt; pch.hpp(与之前编译的标志相同)。这会生成 pch.hpp.gch 文件。 现在您可以在原始编译行中使用您的 PCH 文件:g++ -I. &lt;other flags&gt; src1.cpp -o src1.o -Winvalid-pch -include pch.hpp

需要注意的几点:

如果您使用 -Winvalid-pch 警告标志,这通常会为您提供足够的信息来找出未使用 pch 的原因(例如丢失、错误路径、错误选项等...)。 使用-include pch.hpp 而不是-include pch.hpp.gch,因为g++ 会解决这个问题。您可以看到改装很容易 - 因为您只需将包含标志附加到您的编译器行。 如果您的 .gch 文件未生成,则代码仍应直接使用 pch.hpp 标头进行编译...

【讨论】:

所以你建议我把它们都写在一个.hpp文件中,然后把这个文件编译成它的预编译版本,然后在链接编译过程中-include @DrKGD 不,一点也不。但只是以这种方式进行调试。首先以更简单/更小(可能更手动)的方式完全运行它,然后返回并修复您的 makefile。我只是建议你可以这样做 - 你甚至不需要更改现有的源文件。例如,如果文件src1.cpp 包含 ,并且您的 PCH 也包含 并且它是预编译的,那么当您将 pch.hpp 包含标志添加到 gcc/g++ 编译命令中时,将使用预编译版本。 我已经对此进行了大量测试以确保它可以正常工作 - 我的一些示例代码的构建时间快了 4 倍。尽管它们包含简单的示例源文件... 我会尝试一段时间,我会告诉你,谢谢你的建议!

以上是关于如何正确设置项目的 make 文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何设置 VSCode Flutter 项目以正确解析 Android 文件夹中的 Java 代码?

如何使用 GNU make 编译多个简单项目

Linux项目自动化构建工具-make/Makefile

如何设置正确的 Ruby 版本以在 Aptana 3 中与我的 Rails 5 项目一起使用?

如何写 makefile

如何在 CSS 中正确设置网格以实现移动友好视图? (Python Dash 项目)