【问题标题】:Is there a way to create makefile that uses only required .o files?有没有办法创建只使用所需的 .o 文件的 makefile?
【发布时间】:2015-01-14 23:18:51
【问题描述】:

我想创建一个可以一次编译多个程序的makefile。可能有一些 .cpp 文件被所有人使用,而一些 .cpp 文件仅被一个人使用。我当前的makefile如下:

CPPFLAGS = -std=c++14 -MMD -pthread 
TARGETS = server.cpp client.cpp

SRC = $(wildcard *.cpp)
NON_TARGET_SRC = $(filter-out $(TARGETS),$(SRC))

all: $(TARGETS:%.cpp=%)

clean:
    rm -rf *.o
    rm -rf *.d

$(TARGETS:%.cpp=%): % : $(NON_TARGET_SRC:%.cpp=%.o) %.o ###redundant?
    g++ $(CPPFLAGS) -o $@ $^

-include $(SRC:%.cpp=%.d)

Server.cpp 和 client.cpp 是包含 main() 函数的文件的名称,应该被编译为可执行文件,而不是 .o 文件。虽然上面的 makefile 有效,但我认为它确实是多余的,因为它使用所有非目标 .o 文件进行最终编译,而它可能应该只使用需要的文件(或者链接器是否选择需要的文件就其本身而言,使这样的命令的开销可以忽略不计?)。所以,问题是:

有没有办法列出特定程序所需的 .o 文件?

编辑:

由于将所有目标文件打包到一个库文件中,以下代码似乎可以正常工作。

CPPFLAGS = -std=c++14 -MMD -pthread 
TARGETS = server.cpp client.cpp

LIBRARY_NAME=objects
LIBRARY_FILE=lib$(LIBRARY_NAME).a
SRC = $(wildcard *.cpp)
NON_TARGET_SRC = $(filter-out $(TARGETS),$(SRC))
LDFLAGS = -L.
LDLIBS = -l$(LIBRARY_NAME)

all: $(TARGETS:%.cpp=%)

clean:
    rm -rf *.o
    rm -rf *.d
    rm -rf *.a

$(TARGETS:%.cpp=%): % : $(LIBRARY_FILE) %.o
    g++ $(CPPFLAGS) -o $@ $*.o $(LDFLAGS) $(LDLIBS)

$(LIBRARY_FILE): $(NON_TARGET_SRC:%.cpp=%.o)
    ar rcu $@ $(NON_TARGET_SRC:%.cpp=%.o)
    ranlib $@

-include $(SRC:%.cpp=%.d)

【问题讨论】:

    标签: c++ makefile


    【解决方案1】:

    这样做的方法是将除具有main() 函数的对象文件之外的所有对象文件构建到库中并与库链接。建立一个库是这样的:

    libfoo.a: $(LIBOFILES)
        ar rcu $@ $(LIBOFILES)
        ranlib $@
    

    您还需要设置 Makefile 以使用该库:

    LDFLAGS = -L.
    LDLIBS  = -lfoo
    

    【讨论】:

    • 感谢您提供实际使用的代码。我会尝试运行它,看看它是否正常工作。
    • 不幸的是,它给了我很多“未定义的引用”错误。你能检查一下makefile生成的命令是否正确吗? pastebin.com/Xkri6SXb
    • 感谢您的详尽解释 - 我不知道对象的顺序很重要。我在您的帮助下创建的 makefile 现在可以正常工作。我编辑了帖子以供将来参考。
    • 我脑子里又蹦出一件事——如果链接器跳过不必要的目标文件,我原来的解决方案不是和这个一样有效吗? (最初的解决方案是使用所有目标文件调用 g++,无论是否需要)
    • 顺便说一句,如果库更改,此解决方案是否会重建可执行文件?每当任何目标文件发生变化时,库都会发生变化,所以我们回到了起点,一切都取决于每一次变化:l
    【解决方案2】:

    “有没有办法列出特定程序所需的 .o 文件?”

    是的。手动列出它们(或至少是所需的来源和替代品)。

    目录搜索功能也可以派上用场,但这取决于您的项目结构的实际外观。

    恕我直言,最简单的方法是将 .o 文件捆绑到库中,链接器将自动选择特定目标实际需要的内容。

    【讨论】:

    • 显然,我希望 makefile 尽可能不费力 - 所以我想摆脱手动输入依赖项。搜索功能不起作用,因为在这种情况下,我将所有文件放在一个目录中,每个可执行文件的 .o 文件混合在一起。最后一个解决方案 - 将所有 .o 文件打包到一个库中,也需要我重建整个项目,即使只有一个文件受到影响,对吗?
    • @akrasuski1 “我将所有文件放在一个目录中,每个可执行文件的 .o 文件混合在一起。” 这可能是您的方法的缺陷。为什么没有一个目录来存放常见的东西,而其他目录只包含几个 TARGET 可执行文件所需的东西。良好的源代码组织占租金的一半以上。 “还需要我重建整个项目,即使只有一个文件受到影响,对吗?” 取决于实际更改的内容。通常只需要重建受影响的文件,因为您已经在使用 .d 依赖项。
    • @akrasuski1:不,该库依赖于所有 .o 文件,但 makefile 仍然可以仅重建已更改的源,保留仍然有效的其他 .o 文件。与编译或链接相比,将多个 .o 文件放入库中是一项非常便宜的操作。
    • @BenVoigt 好的,我从来没有真正创建过这样的库,所以我认为它更像是一个需要完全重建而不是完全重建的“大文件”只是一个实际的单个 .o 文件包。感谢您的澄清。
    猜你喜欢
    • 1970-01-01
    • 2011-09-25
    • 2012-12-14
    • 2023-03-09
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 2020-12-25
    • 2023-01-10
    相关资源
    最近更新 更多