使用多个目录中的文件生成文件的问题

Issue with Make file with files in multiple directories

本文关键字:文件 问题      更新时间:2023-10-16

我有下面的制作文件。当我只有一个目录(即 SOURCEDIR)中的文件时,这工作正常。现在我添加了 PROTOSOURCES 和 PROTOSRCDIR。

我将在 SRCDIR 中执行生成文件。

VERSION = 0.0.1
CC      = /usr/bin/g++
CFLAGS  = -Wall
LDFLAGS = `pkg-config --cflags --libs protobuf`
SHFLAGS = -shared
SOURCEDIR = .
PROTOSRCDIR = ~/depot/Projects/src1/obj/cpp
SOURCES = $(wildcard $(SOURCEDIR)/*.cpp)
PROTOSOURCES = $(wildcard $(PROTOSRCDIR)/*.cc)
SRCOBJECTS = $(patsubst $(SOURCEDIR)/%.cpp, $(SOURCEDIR)/%.o, $(SOURCES))
PROTOOBJECTS = $(patsubst $(PROTOSRCDIR)/%.cc, $(PROTOSRCDIR)/%.o, $(PROTOSOURCES))
LIBRARY = libprotointf.so
.PHONY: all clean
all: $(LIBRARY)
$(LIBRARY): 
    $(CC) $(SHFLAGS) $(CFLAGS) $(LDFLAGS) $(SRCOBJECTS) $(PROTOOBJECTS) -o    $(LIBRARY)
$(SOURCEDIR)/%.o: $(SOURCEDIR)/%.cpp
    $(CC) $(CFLAGS) $(LDFLAGS) -c -fPIC $< -o $@
$(PROTOSRCDIR)/%.o: $(PROTOSRCDIR)/%.cc
    $(CC) $(CFLAGS) $(LDFLAGS) -c -fPIC $< -o $@
clean:
    rm -f libprotointf.so

我有以下问题。

问题 1:源对象符合预期,并列出了 SOURCEDIR 中的所有对象文件。但是,原型对象只列出 *.cc 文件而不是 *.o 文件。我希望它在与 patsubst 一起使用后拥有 PROTOOBJECTS 中的所有对象文件列表。顺便说一句,SOURCEDIR 有 *.cpp 个文件,而 PROTOSRCDIR 有 .pb.cc 个文件。这些是由谷歌协议缓冲区编译器生成的。

问题 2:
这将是我的制作文件的最终目标。
1)在SRCDIR中编译文件并生成.o文件
2)在PROTOSRCDIR中编译文件并生成.o文件
3) 生成一个共享库 libprotointf.so 文件,其中包含上述两个步骤中的所有对象文件。

当我只在 SRCDIR 中有文件时,我的库链接和编译命令如下所示,工作正常。

$(LIBRARY): 
    $(CC) $(SHFLAGS) $(CFLAGS) $(LDFLAGS) $(SRCOBJECTS) -o $(LIBRARY)
$(SOURCEDIR)/%.o: $(SOURCEDIR)/%.cpp
    $(CC) $(CFLAGS) $(LDFLAGS) -c -fPIC $< -o $@

我需要对我的 Makefile 进行哪些修改才能创建共享库?

我建议使用make的VPATH功能。这也告诉人们在其他目录中寻找"来源"。所有目标文件最终都将与共享库一起出现在构建目录中。

# Note: GNU make syntax
VERSION := 0.0.1
CXX     := /usr/bin/g++
CXXFLAGS:= -Wall -fPIC
LDFLAGS := $(shell pkg-config --cflags --libs protobuf)
SHFLAGS := -shared
SOURCEDIR := .
PROTOSRCDIR := ~/depot/Projects/src1/obj/cpp
VPATH := $(SOURCEDIR):$(PROTOSRCDIR)
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp) # full paths
SOURCEFILES := $(notdir $(SOURCES)) # just (source) filenames
OBJECTS := $(SOURCEFILES:.cpp=.o) # all in the current dir
PROTOSOURCES = $(wildcard $(PROTOSRCDIR)/*.cc) # full paths
PROTOSOURCEFILES := $(notdir $(PROTOSOURCES)) # just (source) filenames
PROTOOBJECTS := $(PROTOSOURCEFILES:.cpp=.o) # all in the current dir
LIBRARY = libprotointf.so
.PHONY: all clean
all: $(LIBRARY)
$(LIBRARY): $(OBJECTS) $(PROTOOBJECTS)
    $(CC) $(SHFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^

注意:没有%.o: %.cc%.o: %.cpp规则。GNU make内置了这些。您所需要做的就是填写 CPPFLAGS 的值,CXXFLAGS

请注意,按照惯例,CC 是包含 C 编译器的变量。C++编译器的变量为 CXX 。同样,CFLAGS适用于 C 编译器; CXXFLAGS 是包含C++编译器标志的变量。

工作原理:

假设你在 SOURCEDIR 和 p1.pb.cc 中有 s1.cpp 和 s2.cpp,p2.pb.cc 在 PROTOSRCDIR 中,libprotoinf.so 依赖于 s1.o、s2.o、p1.pb.o、p2.pb.o

Make 可以使用其内置的%.o: %.cpp规则轻松地从 s1.cpp 构建 s1.o,从 s2 构建 s2.o.cpp。当它尝试构建 p1.pb.o 时,它不会在当前目录中找到 p1.pb.cc,但 VPATH 变量告诉它也在 PROTOSRCDIR 中查找。然后make将从$(PROTOSRCDIR)/p1.pb.cc构建p1.pb.o,就好像cc文件存在于当前目录中一样。

使用这种技术,您甚至可以在与 SOURCEDIR 不同的单独构建目录中构建。