我正在尝试创建一个顶级递归makefile,想法是创建makefile后,在项目中添加或删除文件时几乎不需要维护。
我遇到的问题是,当存在具有相同名称但位于不同目录中的文件时,GNU make将使用第一个目录中的.cpp文件在整个构建的其余部分中看到,并且当链接器运行时,它抱怨函数的多个定义,因为生成的.o文件都基于相同的源文件。
我在下面引用的代码不是我实际项目的代码,但它在尝试构建我的主项目时表现出同样的问题。这是我的顶级目录的布局,源代码驻留在子目录中。
async.waterfall([
function(callback) {
console.log("Step 1");
// fetch data from DB
callback(null);
},
function(callback) {
console.log("Step 2");
// FTP to remote location using a third party library
ftp.on('error', function(error) {
callback(error);
});
ftp.put(__dirname + '/data/myFile', '', function(err) {
if (!err){
callback(null, "File transferred successfully!")
}else {
callback(err, null)
}
});
}],
function(err, result){
if(err){
console.log("Step 2.5")
console.log(err);
}else{
console.log("Step 3");
}
});
这个例子很简单 - hello / hello.cpp打印“Hello”,world / hello.cpp打印“World !!”。 main.cpp调用每个函数来打印“HelloWorld !!”
这是每个文件。
EXEC / main.cpp中
otter@ubuntu:~/work/temp/maketest$ tree
.
├── exec
│ └── main.cpp
├── hello
│ ├── hello.cpp
│ └── hello.h
├── makefile
└── world
├── hello.cpp
└── hello.h
您好/ HELLO.CPP
#include <iostream>
#include "../hello/hello.h"
#include "../world/hello.h"
int main()
{
print_hello();
print_world();
return 0;
}
世界/ HELLO.CPP
#include "hello.h"
void print_hello()
{
std::cout << "Hello";
}
这是我的makefile
#include "hello.h"
void print_world()
{
std::cout << "World!!\n";
}
当我尝试构建这个小项目时,我得到以下内容。注意./world/hello.cpp在构建.o文件时使用两次 - 第一次输出到build / world / hello.o,第二次输出到/build/hello/hello.o然后链接器失败,因为.o文件是一样的。
#Specify modules to include in the build - corresponds to source code locations.
MODULES := exec \
world \
hello
CXX := g++
RM := rm -rf
#Create a list of the source directories
SRC_DIR := $(addprefix ./,$(MODULES))
#Create a variable for the build output directory
BUILD_DIR := $(addprefix ./build/,$(MODULES))
#C++ Compiler flags
CPPFLAGS := -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c
#Flags for generating dependency files.
DEPFLAGS := -MMD -MP -MT "$$@" -MF "$$(@:%.o=%.d)"
#Creates a list of all the source files that we wish to include in the build
CPP_SRCS := $(foreach sdir, $(SRC_DIR), $(wildcard $(sdir)/*.cpp))
#Creates a list of all the object files that we need to build based off source files
OBJ_TARGET := $(foreach sdir, $(MODULES), $(wildcard $(sdir)/*.cpp))
OBJS := $(patsubst %.cpp, ./build/%.o, $(OBJ_TARGET))
#Specify directories to search
vpath %.cpp $(SRC_DIR) $(BUILD_DIR)
#"function" that contains the rule to make the .o files that exist within a source director and sub-directory
define make-goal
$1/%.o: %.cpp
@echo 'Building file: $$<'
@echo 'Invoking: Linux G++ Compiler'
$(CXX) $(CPPFLAGS) "$$<" -o "$$@" $(DEPFLAGS)
@echo 'Finished building: $$<'
@echo ' '
endef
.PHONY: all checkdirs clean build/HelloWorld
all: checkdirs build/HelloWorld
build/HelloWorld: $(OBJS)
@echo 'Building Target: $@'
@echo 'Invoking: G++ Linker'
$(CXX) -L/usr/local/lib $^ -o $@
@echo 'Finished building target: $@'
@echo ' '
clean:
-$(RM) $(BUILD_DIR)
#Makes sure that the output directory exists
checkdirs: $(BUILD_DIR)
#Creates the output directory, build, if it doesn't exist
$(BUILD_DIR):
@mkdir -p $@
#This is the important "recursive" part - this will loop through all source directories and call 'make-goal', which contains the rule to make the associated .o file.
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))
所以有人知道为什么./world/hello.cpp在构建.o文件时被使用了两次?即使.cpp文件具有相同的名称,它们也位于不同的目录中,我认为make会足够智能将它们视为不同的文件,并且每次看到具有相同名称的后续文件时都不会重复使用第一个文件。
答案 0 :(得分:1)
我不确定为什么你的方法不起作用 - 如果我有时间的话,我会尝试解决这个问题 - 但是这样做的方法更简单:
build/HelloWorld: $(OBJS)
@echo 'Building Target: $@'
@echo 'Invoking: G++ Linker'
$(CXX) -L/usr/local/lib $^ -o $@
@echo 'Finished building target: $@'
@echo ' '
$(OBJS): build/%.o: %.cpp
@echo building $@ from $<
mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $< -o $@
编辑: user657267找到了您的方法无效的原因。