编辑:这是最后一个Makefile,它在构建目录中构建所有.o文件,并生成一个可执行文件。
CXX = g++
CXXFLAGS = -g -Wall
SRC_DIR = ./src
BUILD_DIR = ./build
SRC = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(SRC:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
LIBS = -lusb-1.0 -lpulse-simple -lpulse
EXEC = AndroidMicLinux
all: $(EXEC)
$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -o $@ -c $<
$(EXEC) : $(OBJS)
$(CXX) -o $(EXEC) $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(EXEC)
这个生成文件有很多问题。其中大多数都与变量的展开有关。如果你简单地想象变量的扩展,你很可能会看到问题。请记住,make只是进行文本替换以展开变量。没有";魔术;发生在这里。
例如:
SRC = $(wildcard $(SRC_DIR)/*.cpp)
假设您有文件./src/foo.cpp
和./src/bar.cpp
。这意味着$(SRC)
将扩展到这两个文件。好的然后你有:
OBJS = $(BUILD_DIR)/$(notdir $(SRC:.cpp=.o))
这是怎么回事?首先我们扩展BUILD_DIR
:
OBJS = ./build/$(notdir $(SRC:.cpp=.o))
然后对CCD_ 5进行扩展,得到CCD_。然后应用CCD_ 7,得到CCD_。这被替换为函数,所以结果是:
OBJS = ./build/foo.o bar.o
你可以看出这是错误的。你不能只是把一个字符串放在函数之前,然后期望这个字符串附加到函数的每个单词!你需要明确告诉make你想这么做。也许你想要这样的东西:
OBJS = $(SRCS:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
下一条规则:
%.o : %.c
$(CC) -o $(OBJS) -c $(SRC)
首先,配方是错误的。这会扩展到什么?
g++ -o ./build/foo.o ./build/bar.o -c ./src/foo.cpp ./src/bar.cpp
很明显,这是一个完全无效的编译行。您只需要一个对象文件和源文件,而不是所有。这就是自动变量的用途:
%.o : %.c
$(CC) -o $@ -c $<
然而,这仍然是错误的:这种模式规则永远不会匹配。为什么?因为当make尝试构建./build/foo.o
时,%
模式与字符串./build/foo
匹配。因此,当make查看先决条件%.c
是否存在时,它将检查./build/foo.c
。首先,文件名以.cpp
结尾,而不是以.c
结尾,所以应该是%.cpp
。但除此之外,源文件与目标文件位于不同的目录中,因此不能仅使用%
。你必须这样写:
$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
$(CC) -o $@ -c $<
我还将指出,约定使用CC
作为C编译器;如果您正在编译C++,则应该使用CXX
变量。此外,您设置了一个FLAGS
变量,但您的编译规则实际上并没有使用它;你不能只把它放在链接规则中。而且,对于C++编译器标志,约定是使用CXXFLAGS
作为变量。