【问题标题】:Makefile for shared library that only compiles changed files?仅编译更改文件的共享库的 Makefile?
【发布时间】:2013-09-26 15:14:11
【问题描述】:

我正在做一个项目,我正在创建一个 .so 对象作为我的输出,其中包含几个用于另一个程序的运算符。我得到了一个运行良好的 Makefile,但它总是在我运行 make 时重新编译每个文件。最初这不是问题,但现在库中有超过 5 个或更多运算符,运行 make 非常慢。问题是,对于我的生活,我无法弄清楚如何将这个 Makefile 更改为我想要的行为方式,因为我以前从未处理过这种格式的 Makefile:

BOOST_LOCATION=/usr/local/boost_1_54_0

CFLAGS=-pedantic -W -Wextra -Wall -Wno-strict-aliasing -Wno-long-long -Wno-unused-parameter -fPIC -D__STDC_FORMAT_MACROS -Wno-system-headers -isystem -O2 -g -DNDEBUG -ggdb3  -D__STDC_LIMIT_MACROS
INC=-I. -DPROJECT_ROOT="\"$(IN_SOURCE_DIR)\"" -I"$(IN_SOURCE_DIR)/include" -I"$(BOOST_LOCATION)"
LIBS=-L"$(IN_SOURCE_DIR)/lib" -shared -Wl,-soname,libname.so -L. -lm

all:
    @if test ! -d "$(IN_SOURCE_DIR)"; then echo  "Error. Try:\n\nmake IN_SOURCE_DIR=<PATH TO SOURCE TRUNK>"; exit 1; fi 
    $(CXX) $(CFLAGS) $(INC) -o plugin.cpp.o -c plugin.cpp

    $(CXX) $(CFLAGS) $(INC) -o LogicalFile1.cpp.o -c File1/LogicalFile1.cpp
    $(CXX) $(CFLAGS) $(INC) -o PhysicalFile1.cpp.o -c File1/PhysicalFile1.cpp

    $(CXX) $(CFLAGS) $(INC) -o LogicalFile2.cpp.o -c File2/LogicalFile2.cpp
    $(CXX) $(CFLAGS) $(INC) -o PhysicalFile2.cpp.o -c File2/PhysicalFile2.cpp

    ### etc.

    $(CXX) $(CFLAGS) $(INC) -o libname.so \
                               plugin.cpp.o \
                               LogicalFile1.cpp.o \
                               PhysicalFile1.cpp.o \
                               LogicalFile2.cpp.o \
                               PhysicalFile2.cpp.o \
                               ### etc \
                               $(LIBS)

clean:
    rm -f *.o *.so

我遇到的最大问题是只有一个规则(全部),我找不到执行此操作的 Makefile 示例或如何将其拆分为多个规则。

【问题讨论】:

  • 这不是真正的makefile。它只是一个用 makefile 格式编写的 shell 脚本。您的整个“makefile”是一个调用编译所有内容的 shell 命令的规则。您不妨把它写成一个实际的 shell 脚本。我很难相信您找不到一次构建一个对象的 makefile 示例,因为您找到的每个示例 makefile 都会这样做。这就是使用 make 而不是 shell 脚本的全部点。
  • 使用 autoconf/automake/libtool 来生成你的 makefile。最初的学习曲线有点痛苦(真的没有那么多),但回报是值得的。例如看那些教程:Building libs with autotools - Building with autotools - Using libs with autotools

标签: c++ makefile shared-libraries


【解决方案1】:

在这种情况下,它实际上非常简单。现在,你只有一个 all 目标,它正在完成所有的构建。你需要打破编译器调用并将步骤链接到它们自己的规则中,你应该参加比赛:

BOOST_LOCATION=/usr/local/boost_1_54_0

CFLAGS=-pedantic -W -Wextra -Wall -Wno-strict-aliasing -Wno-long-long -Wno-unused-parameter -fPIC -D__STDC_FORMAT_MACROS -Wno-system-headers -isystem -O2 -g -DNDEBUG -ggdb3  -D__STDC_LIMIT_MACROS
INC=-I. -DPROJECT_ROOT="\"$(IN_SOURCE_DIR)\"" -I"$(IN_SOURCE_DIR)/include" -I"$(BOOST_LOCATION)"
LIBS=-L"$(IN_SOURCE_DIR)/lib" -shared -Wl,-soname,libname.so -L. -lm

all: plugin.cpp.o LogicalFile1.cpp.o PhysicalFile1.cpp.o LogicalFile2.cpp.o PhysicalFile2.cpp.o
    $(CXX) $(CFLAGS) $(INC) -o libname.so \
                               plugin.cpp.o \
                               LogicalFile1.cpp.o \
                               PhysicalFile1.cpp.o \
                               LogicalFile2.cpp.o \
                               PhysicalFile2.cpp.o \
                               ### etc \
                               $(LIBS)

plugin.cpp.o: plugin.cpp | test
    $(CXX) $(CFLAGS) $(INC) -o plugin.cpp.o -c plugin.cpp

LogicalFile1.cpp.o: File1/LogicalFile1.cpp | test
    $(CXX) $(CFLAGS) $(INC) -o LogicalFile1.cpp.o -c File1/LogicalFile1.cpp

PhysicalFile1.cpp.o: File1/PhysicalFile1.cpp | test
    $(CXX) $(CFLAGS) $(INC) -o PhysicalFile1.cpp.o -c File1/PhysicalFile1.cpp

LogicalFile2.cpp.o: File2/LogicalFile2.cpp | test
    $(CXX) $(CFLAGS) $(INC) -o LogicalFile2.cpp.o -c File2/LogicalFile2.cpp

PhysicalFile2.cpp.o: File2/PhysicalFile2.cpp | test
    $(CXX) $(CFLAGS) $(INC) -o PhysicalFile2.cpp.o -c File2/PhysicalFile2.cpp

test:
    @if test ! -d "$(IN_SOURCE_DIR)"; then echo  "Error. Try:\n\nmake IN_SOURCE_DIR=<PATH TO SOURCE TRUNK>"; exit 1; fi 

clean:
    rm -f *.o *.so

.PHONY:全清测试

从这一点开始,您也可以进一步简化。例如,您可以将所有编译行合并到一个模式规则中。

【讨论】:

  • 我不会在这里使用像test 这样的通用名称,或者至少将其标记为.PHONY
  • @user2820044 尝试更改标题并再次调用 make。它可能不会重新编译,因为这个 makefile 忽略了头依赖。
  • 我只是想对 OP 的文件进行最小的更改。但添加.PHONY 可能是个好主意。
【解决方案2】:

如果您愿意为 make 使用标准格式和内置规则,您可以像这样轻松编写整个 makefile:

ifeq (,$(wildcard $(IN_SOURCE_DIR)/.))
    $(error Try: make IN_SOURCE_DIR=<PATH TO SOURCE TRUNK>)
endif

OBJECTS = plugin.o LogicalFile1.o PhysicalFile1.o LogicalFile2.o PhysicalFile2.o  ### etc
BOOST_LOCATION = /usr/local/boost_1_54_0

CPPFLAGS = -DNDEBUG -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I. -DPROJECT_ROOT="\"$(IN_SOURCE_DIR)\"" -I"$(IN_SOURCE_DIR)/include" -I"$(BOOST_LOCATION)"
CXXFLAGS = -pedantic -W -Wextra -Wall -Wno-strict-aliasing -Wno-long-long -Wno-unused-parameter -fPIC -Wno-system-headers -isystem -O2 -g -ggdb3
LDFLAGS = -L"$(IN_SOURCE_DIR)/lib" -L.
LDLIBS = -shared -Wl,-soname,libname.so -lm

all: libname.so

libname.so: $(OBJECTS)
        $(LINK.cc) $^ $(LDLIBS) -o $@

clean:
        rm -f *.o *.so

.PHONY: all clean

【讨论】:

  • 如果它也能自动构建和包含依赖关系就好了。
  • 最好包含头文件依赖项。我认为您只需要在标志中使用-MMD 来生成依赖文件,并使用-include $(OBJECTS:.o=.d) 来包含它们。对于奖励积分,空规则%.h : ; 将在删除标头时强制重新编译。 (其中一些可能特定于 gcc/gnumake。)
  • @MikeSeymour -MP 也很有用。
  • @MaximYegorushkin:谢谢,我不知道。这看起来不像我的虚拟规则那么老套。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
  • 1970-01-01
  • 2015-11-02
  • 2011-12-10
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多