我有以下项目结构:
lib/
Makefile
src/...
inc/...
build/
inc/...
lib/libmylib.a
subproj1/
src/main.cpp
Makefile
Makefile
文件夹中的lib
用于创建文件libmylib.a
,并将相关的头文件复制到build/inc
文件夹。
我希望Makefile
中的subproj1
始终调用make -C ../lib
,但只有在标题发生更改时才重新编译文件,并且仅在必要时重新链接(一个目标文件或{ {1}}较新)。
我有以下内容(libmylib.a
等未定义的变量在另一个文件中定义):
CC
即使lib文件夹中没有任何更改,上面的内容也会重新编译LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS) $(LIBDIR)/build/lib/libmylib.a
$(CC) $^ -o $@ $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(LIBDIR)/build/lib/libmylib.a
mkdir -p $(OBJDIR)
$(CC) -c -o $@ $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $@) $<
$(LIBDIR)/build/lib/libmylib.a:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean $(LIBDIR)/build/lib/libmylib.a
clean:
$(RM) obj/* $(MAIN)
。如果我从main.cpp
规则中删除$(LIBDIR)/build/lib/libmylib.a
,则如果标题已更改,则不会重新编译$(OBJDIR)/%.o
文件(我需要运行.cpp
两次)。
只有在make
中的标头文件发生更改(或者.cpp
文件本身已更改时)才能编译subproj1
中的lib
个文件),只有在.cpp
之一被重新编译(较新的myexe
)或.cpp
较新的情况下才能构建.o
?
答案 0 :(得分:1)
使用递归makefile,您需要以正确的顺序执行子项目makefile,因为依赖关系树不完整(例如,此makefile不知道更新$(LIBDIR)/build/lib/libmylib.a
也会更新这些标头)。使用shell脚本或顶级makefile很容易做到这一点。
或者,您的makefile必须以正确的顺序无条件地执行子makefile,这可以使用shell
函数来完成,例如:
LIBDIR := ../lib
pid := $(shell ps -o ppid= $$$$)
$(shell ${MAKE} -C ${LIBDIR} >/proc/$(pid)/fd/1 2>/proc/$(pid)/fd/2)
应删除$(LIBDIR)/build/lib/libmylib.a
规则,目标文件不应取决于.a
,也不应将其标记为.PHONY
。
这可以确保在${LIBDIR}
中构建此makefile之前在${LIBDIR}
中分析文件时间戳。
现在,您自动生成的标头依赖项应该可以正常工作。
答案 1 :(得分:0)
这可能会更清洁。
LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: makelib
$(MAKE) $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $^ -o $@ $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
mkdir -p $(OBJDIR)
$(CC) -c -o $@ $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $@) $<
makelib:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean makelib
clean:
$(RM) obj/* $(MAIN)
主要目标all
需要构建makelib
,然后以递归方式为目标$(MAIN)
调用自身(因此将重新计算所有$(MAIN)
的依赖项makelib
完成建设后。)