【问题标题】:c++ makefile with multiple program, autodetection of source filesc++ makefile与多个程序,源文件的自动检测
【发布时间】:2014-03-04 07:32:11
【问题描述】:

我最近花了 5 个小时来弄清楚如何编写我需要的 makefile。我不是信息学家或程序员,所以我想要一些关于我设法做的事情的 cmet。我已经在不同的网站上看了很多,但仍然......

我需要一个可以创建不同可执行文件的 makefile:prog1prog2...

要创建.o 文件,因为我有许多具有许多依赖项的文件,我不想全部指定它们。所以我想/需要使用带有模式规则的自动变量。为了加快编译速度,我还注意只重新编译修改后的文件。我通过使用-MD 标志实现了这一点,该标志创建了一个保存在$(BUILD) 目录中的.d 文件。

我仍然无法自动检测.o 文件prog1 需要哪些。所以现在我必须自动指定它们......如果你知道如何自动指定它们......

我也想将.o 文件保存在$(BUILD) 目录中,但我无法成功。

欢迎任何建议! 谢谢

CXX = g++

ERRORS = -Wall -Wextra -pedantic
LAPACK = -llapack -lblas
OPTION = -O3 -fopenmp

CXXFLAGS = $(LAPACK) $(ERRORS) $(OPTION)
LDFLAGS  = $(LAPACK) $(ERRORS) $(OPTION)

BUILD=build
SRCS=(wildcard *.cpp)

all:prog1 prog2 ...

prog1:prog1.o dep_only_for_prog_1.o dep_for_all_progs.o dep_for_some_progs.o
    $(CXX) -o $@ $^ $(LDFLAGS) $(NOASSERT)

prog2:prog2.o dep_only_for_prog_2.o dep_for_all_progs.o dep_for_some_progs.o
    $(CXX) -o $@ $^ $(LDFLAGS) $(NOASSERT)

...

%.o:%.cpp
    $(CXX) -MD -c $(CXXFLAGS) $(NOASSERT)  $< -o $@
    mv $(<:.cpp=.d) $(BUILD)

-include $(addprefix $(BUILD)/$(SRCS:.cpp=.d))

clean:
    rm -f *.o $(BUILD)/*

【问题讨论】:

  • Makefile 应该如何知道哪些文件用于 prog1,哪些用于 prog2?如果你把这个任务交给一个人,你会告诉他/她什么规则,以便他/她知道哪些文件属于哪个程序?
  • @Cornstalks:让链接器解决它。它理解内容;没有。 (这就是为什么你首先需要像.d文件这样的黑客)
  • @Cornstalks:我会对人类说,看看主文件中的包含,如果有'dep1.hpp',看看是否有'dep1.o',如果有,包括'dep1.o'。重复此操作,直到检查了所有递归包含的文件...但也许我做错了...
  • @MSalters:链接器如何对其进行排序?
  • 没有规定每个dep1.hpp 都必须有一个源文件。一些头文件(尤其是在 C++ 中)没有任何源文件。有时源文件没有头文件。有时源文件的前缀与标头不同。这些都是完全合法的。 MSalters:链接器无法对其进行排序。假设您链接两个不同的目标文件,它们都包含符号main。链接器将如何选择正确的?简而言之,对不起 PinkFloyd 但你不走运。你必须在你的 makefile 中明确写出哪些源属于哪些程序。

标签: c++ makefile detect


【解决方案1】:

您无法让 make 以某种方式推断哪些文件属于哪些程序,但您可以使您的 makefile 更易于阅读和更新。这里还有一些不好的地方,例如将$(LAPACK)(包含链接器标志)添加到$(CXXFLAGS)(传递给编译器)。

试试:

PROGRAMS = prog1 prog2

prog1_SOURCES = prog1.cpp dep_only_for_prog_1.cpp \
                dep_for_all_progs.cpp dep_for_some_progs.cpp

prog2_SOURCES = prog2.cpp dep_only_for_prog_2.cpp \
                dep_for_all_progs.cpp dep_for_some_progs.cpp

#----- Don't need to change below here

CXX = g++

ERRORS = -Wall -Wextra -pedantic
LAPACK = -llapack -lblas
OPTION = -O3 -fopenmp

CXXFLAGS = $(ERRORS) $(OPTION)
LDFLAGS  = $(LAPACK) $(ERRORS) $(OPTION)

BUILD=build
SRCS := $(wildcard *.cpp)

all: $(PROGRAMS)

.SECONDEXPANSION:
$(PROGRAMS): $$($$@_SOURCES:%.cpp=%.o)
        $(CXX) -o $@ $^ $(LDFLAGS) $(NOASSERT)

%.o : %.cpp
        $(CXX) -MD -c $(CXXFLAGS) $(NOASSERT)  $< -o $@
        mv $(<:.cpp=.d) $(BUILD)

-include $(addprefix $(BUILD)/$(SRCS:.cpp=.d))

clean:
        rm -f *.o $(BUILD)/*

如果你愿意,也可以使用 eval。

【讨论】:

  • 我当然会使用您的建议来简化我的代码,但我想知道您为什么要为 prog_SOURCES 使用 .cpp 扩展名?我会寻找eval,因为我不明白你的意思......
  • 我只是更喜欢列出源文件。它更具体。如果您列出一个目标文件,您不知道原始源文件是什么(它可能是.c.cpp,甚至是.f90 或其他)。因此,如果您的 makefile 列出了源文件,您可以轻松地将它们转换为目标文件。但是,如果您列出目标文件,则在需要时无法取回源文件。在这里,你没有,所以没关系。 eval 是 make 的高级主题。我建议你避免使用它,除非你绝对必须拥有它,因为它可能很难让你头晕目眩。
  • 我尝试了您的解决方案,但由于某种原因,该行:$(PROGRAMS): $$($$@_SOURCES:%.cpp=%.o) 有问题,我不得不将其替换为$(PROGRAMS): $$(patsubst %.cpp, %.o, $$($$@_SOURCES))。但它有效,谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多