【问题标题】:Issue with Make file with files in multiple directories使用多个目录中的文件生成文件的问题
【发布时间】:2015-02-03 22:08:48
【问题描述】:

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

我将在 SRCDIR 中执行 makefile。

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:SOURCEOBJECTS 符合预期并列出了 SOURCEDIR 中的所有目标文件。然而,PROTOOBJECTS 只列出 *.cc 文件而不是 *.o 文件。我希望它在与 patsubst 一起使用后拥有 PROTOOBJECTS 中的所有目标文件列表。顺便说一句,SOURCEDIR 有 *.cpp 文件,而 PROTOSRCDIR 有 .pb.cc 文件。这些是由 Google Protocol Buffer 编译器生成的。

问题 2:
这将是我的 make 文件的最终目标。
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 做哪些修改?

【问题讨论】:

  • 我不确定这是否与这些变量有关。这可能与您没有将$(SRCOBJECTS) $(PROTOOBJECTS) 列为$(LIBRARY) 的先决条件有关。
  • 与您的问题无关,但您不需要在$(patsubst) 调用中使用$(SOURCEDIR)$(PROTOSRCDIR),您可以将它们作为% 通配符的一部分吞下。以SRCOBJECTS = $(patsubst %.cpp, $%.o, $(SOURCES)) 为例。
  • 不要使用~ 使用$HOME~ 是一个外壳,外壳不涉及在任何地方扩展 $(PROTOSRCDIR)
  • 同样,您对LDFLAGS 的分配在您分配时不会被执行。 (它将在配方行中使用时执行,因为 shell 会看到反引号并运行命令,但这不一定是您希望发生的情况。)对于命令的 make-parse-time 运行,您需要使用$(shell)(和 := 简单扩展的变量赋值让 make 只在解析时执行一次,而不是每次使用变量时执行一次)。
  • 并且支持@user657267 在他们的评论中所说的$(LIBRARY) 目标并没有告诉make 构建它需要链接的对象,所以make 不会为你这样做。因此,即使您以前的 makefile 也只有在您预先构建了所有 .o 文件时才能正常工作。删除它们,它应该无法链接。

标签: c++ makefile


【解决方案1】:

我建议使用 make 的 VPATH 功能。这告诉 make 也在其他目录中寻找“源”。所有的目标文件都将与共享库一起在构建目录中结束。

# 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 内置了这些。您只需填写CPPFLAGSCXXFLAGS 的值

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

这是如何工作的:

假设 SOURCEDIR 中有 s1.cpp 和 s2.cpp,PROTOSRCDIR 中有 p1.pb.cc、p2.pb.cc,libprotoinf.so 取决于 s1.o、s2.o、p1.pb.o、p2 .pb.o

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-25
    相关资源
    最近更新 更多