为什么make不会在我的源文件中进行迭代?

时间:2019-06-09 20:25:45

标签: makefile ubuntu-18.04

我为项目创建了一个makefile,但是make不会遍历我的源文件。我不知道该怎么办。

我的atm目录中有2个源文件

Makefile:

LIBNAME=hazelicious
FLIBNAME=lib$(LIBNAME).so
VERSION=
CC=g++
CXXFLAGS=-W -Wall -O2 -std=c++17 -fPIC -I./vendor/spdlog/include/
LDFLAGS=-shared -Wl,-soname,$(FLIBNAME)
DSRC=src/
DTGT=
DOBJ=$(DTGT)obj/
DOUT=$(DTGT)bin/
EXEC=$(DOUT)$(APPNAME)
SRC= $(wildcard $(DSRC)**/*.cpp)
OBJ= $(subst $(DSRC), $(DOBJ), $(patsubst %.cpp, %.o, $(SRC)))

all: $(FLIBNAME)

install: 
    @sudo cp $(DOUT)$(FLIBNAME) /usr/local/lib/
    @sudo cp $(DSRC)Hazelicious.h /usr/local/include/
    @echo "Library and header files copied!"

$(FLIBNAME): $(OBJ)
    @mkdir -p $(DOUT)
    @$(CC) -o $(DOUT)$@ $^ $(LDFLAGS)

$(OBJ): $(SRC)
    mkdir -p $(DOBJ)
    mkdir -p $(@D)
    $(CC) -o $@ -c $< $(CXXFLAGS)

checkvar:
    @echo $(SRC)
    @echo $(OBJ)

clean:
    @rm -rf $(DOBJ)
    @rm -rf $(EXEC)

run:
    @./$(EXEC)

输出:

g++ -o obj/Hazelicious/Log.o -c src/Hazelicious/Log.cpp -W -Wall -O2 -std=c++17 -fPIC -I./vendor/spdlog/include/
g++ -o obj/Hazelicious/Application.o -c src/Hazelicious/Log.cpp -W -Wall -O2 -std=c++17 -fPIC -I./vendor/spdlog/include/

您会看到第二行使用相同的Log.cpp文件

我的目录结构:

/src
  /Hazelicious
    Application.cpp
    Log.cpp
    ...
/obj
  /Hazelicicous
/bin

1 个答案:

答案 0 :(得分:0)

如果您期望这样:

SRC= $(wildcard $(DSRC)**/*.cpp)

要在.cpp的所有子目录中找到所有$(DSRC)文件,您会很失望的。 **特殊的globbing序列是非标准的,并且仅受某些shell支持(如zsh或bash(如果启用了特殊选项))。它不是POSIX标准通配符的一部分,并且不受GNU make的wildcard函数支持。您必须使用标准的实现,例如:

SRC := $(shell find $(DSRC) -name \*.cpp)

(此处使用简单的变量分配(:=,而不是递归变量分配(=),以大大提高效率)。

也是这样:

OBJ= $(subst $(DSRC), $(DOBJ), $(patsubst %.cpp, %.o, $(SRC)))

可能会惹上麻烦,因为subst会替换 all 个实例,即使在单词中间,即使一个单词中有多个实例也是如此。更好(更简单)的只是:

OBJ := $(patsubst $(DSRC)/%.cpp,$(DOBJ)/%.o,$(SRC))

看到相同源文件的原因是您的配方错误:

$(OBJ): $(SRC)
        mkdir -p $(DOBJ)
        mkdir -p $(@D)
        $(CC) -o $@ -c $< $(CXXFLAGS)

假设SRC解析为src/foo.cpp src/bar.cpp src/biz.cpp。然后OBJ解析为obj/foo.o obj/bar.o obj/biz.o。因此,在扩展了以上规则的目标和前提条件之后,make将获得以下信息:

obj/foo.o obj/bar.o obj/biz.o : src/foo.cpp src/bar.cpp src/biz.cpp
        mkdir -p $(DOBJ)
        mkdir -p $(@D)
        $(CC) -o $@ -c $< $(CXXFLAGS)

当make在一个显式规则中看到多个目标时,它将视为多个显式规则,每个目标一个,如下所示:

obj/foo.o : src/foo.cpp src/bar.cpp src/biz.cpp
        mkdir -p $(DOBJ)
        mkdir -p $(@D)
        $(CC) -o $@ -c $< $(CXXFLAGS)
obj/bar.o : src/foo.cpp src/bar.cpp src/biz.cpp
        mkdir -p $(DOBJ)
        mkdir -p $(@D)
        $(CC) -o $@ -c $< $(CXXFLAGS)
obj/biz.o : src/foo.cpp src/bar.cpp src/biz.cpp
        mkdir -p $(DOBJ)
        mkdir -p $(@D)
        $(CC) -o $@ -c $< $(CXXFLAGS)

您可以看到,在所有规则中,第一个必备条件(即$<扩展到的前提)将是src/foo.cpp,这正是您所观察到的行为。

Make不会以某种方式神奇地遍历所有目标和先决条件并为您匹配它们。

在in中,您始终会从该目标的先决条件列表中编写一个构建单个目标的规则。在您的情况下,您可能想要编写如下的 pattern规则

$(DOBJ)/%.o : $(DSRC)/%.cpp
        mkdir -p $(@D)
        $(CC) -o $@ -c $< $(CXXFLAGS)

代替上面的明确规则。这为make提供了一种模式,可用于构建与其匹配的任何目标,并列出了关联的.cpp文件的先决条件。