【问题标题】:My desired automatic make file我想要的自动生成文件
【发布时间】:2015-02-19 08:57:47
【问题描述】:

我是 make 文件的新手。

我有一个程序由

main.cpp
types.hpp
application/coordinator.hpp
application/correlation.hpp
application/handler.hpp
application/settings.hpp
libraries/basket.hpp
libraries/config.hpp
libraries/graphics.hpp
...

我有很多文件,我的文件列表会更新很多次。我希望 make 文件自动识别要生成或更新的 .o 文件。我不想在每次创建和包含新文件时更新我的​​ make 文件。输出必须在名为bin的目录中生成

main.cpp 是我唯一的 cpp 文件,其余文件是 hpp

直到现在,这个link 启发了我编写这段代码:

CC=g++
CFLAGS= -g -Wfatal-errors 

CFLAGS+= -std=c++11
LIBS= -lboost_filesystem -lboost_system

all: run

run: $(OBJS)
    $(CC) $(CFLAGS) $^ main.cpp -o $@

$(OBJS): bin/%.o : bin/%.hpp

如何将其改进为工作代码和我想要的?

【问题讨论】:

  • 通常的方法是让编译器为.h/.hpp 文件生成一个依赖列表(使用-Mx 选项系列),并包含生成的.d (文件)与您的 makefile。
  • 由于您只有一个cpp 文件,因此您将只有一个.o 文件
  • @barej “你认为从hpp文件中制作.o文件吗”你不认为,.o是从.cpp/.c 文件。这些包含标题。你的意思是你在头文件中有内联代码吗?这样做的编译时间没有区别。
  • @barej 如果将 .hpp 包含到 main.cpp 中,则不能同时从 .hpp 生成 .o,因为它将包含相同类/对象/方法的定义,并且您'会得到链接错误(重复定义)。您需要考虑分离软件的接口(进入标头)和实现(进入 cpp 文件)。然后,您可以将标头包含在实现源和使用它的源中。然后你需要将生成的目标文件链接在一起。

标签: c++ makefile gnu-make


【解决方案1】:

如果您打算只拥有一个cpp 文件,您可以按以下方式编写makefile:

CXX := g++
CXXFLAGS := -g -Wall -pedantic -Wextra

HEADERS := types.hpp $(wildcard application/*.hpp) $(wildcard libraries/*.hpp)

all: run

run: main.cpp $(HEADERS)
    $(CXX) $(CXXFLAGS) $< -o $@

$(wildcard) 将在应用程序和库中找到所有标头。可执行文件将依赖于所有头文件和main.cpp,因此如果其中任何一个发生更改,二进制文件将被重建。

$&lt; 表示“第一个依赖项”。这样,只有 cpp 文件被传递给编译器。

注意:在 GNU make 约定中,CC 和 CFLAGS 指的是 C 编译器。对于 C++,变量名为 CXX 和 CXXFLAGS。

【讨论】:

  • 加1用于添加-Wextra
  • 仍然担心不添加所有 hpp 文件。我有很多文件,例如trash_old.hpp 等。你能告诉我在这种情况下如何使用$^吗?
  • $(wilcard) 是一个生硬的工具,它假定您要使用这些目录中的每个标题。如果您想要更精确的列表,可以手写HEADERS:= 行。或者你可以使用$(filter) / $(filter-out) 来输出$(wildcard)
  • @Bulletmagnet “您可以手动编写HEADERS:= 行” 或使用编译器的-MM 选项生成上述的头依赖文件。
  • @Bulletmagnet 您对this 有何看法?抱歉之前的乱码。
【解决方案2】:

这是一个不同的方案:在构建软件时生成依赖信息。这适用于创建多个目标文件的多个 cpp 文件。

CXX := g++
#CPPFLAGS := preprocessor flags, e.g. -I and -D
CXXFLAGS := -g -Wall -pedantic -Wextra -Wfatal-errors -std=c++11 -MD -MP

SOURCES := main.cpp
OBJECTS := $(SOURCES:.cpp=.o)
DEPFILES:= $(OBJECTS:.o=.d)

all: run

# Link the executable
run: $(OBJECTS)
    $(CXX) $(LDFLAGS) $^ -o $@ $(LIBS)

-include $(DEPFILES)

.o 文件被构建时,-MD -MP 标志告诉编译器生成依赖文件作为副作用。如果存在,这些依赖文件将包含在 makefile 中。

这使用了 GNU make 的内置 %.o : %.cpp 规则。我们只是为其提供参数(CXXCPPFLAGSCXXFLAGS)。

如果对应的.cpp 文件较新(GNU make 的内置规则或手写规则),Make 已经知道要重建 .o 文件。将 .d 文件包含在 makefile 中,我们告诉 make 目标文件也依赖于头文件,并且应该在其中一个文件更改时重新构建。但重建.o 的规则始终是%.o : %.cpp

【讨论】:

  • 非常感谢。它非常接近我的需要。你能告诉我为什么我试图把main.dmain.o和bin目录中的执行文件失败给我错误:make: *** No rule to make target 'bin/main.o', needed by 'run'. Stop.我的代码here
  • @barej 那是因为 make 无法将 bin/ 文件夹与您的源路径匹配。一种解决方法是使用$(vpath) make 变量并将路径放在您的.cpp 所在的位置。
  • vpath 最简单的用法是将makefile 放在bin 文件夹中,这样所有的目标文件和可执行文件都可以在没有路径的情况下引用。 vpath 将使 make 能够找到其他地方的源。
  • @Bulletmagnet "... 将 makefile 放入 bin 文件夹中..." 在 build 文件夹中保留 makefile 非常不方便(例如,我通常不这样做)没有使用 SCCS 管理的构建文件夹)。我不得不承认$(vpath) 可能不是最好的解决方案,但是按照您的建议编写明确的规则会更好。我实际上是使用 make 模板和路径替换来生成这些。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-03
  • 2011-05-29
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多