Makefile Make:利用VPATH编译和链接具有不同扩展名的文件

Makefile Make:利用VPATH编译和链接具有不同扩展名的文件,makefile,gnu-make,vpath,Makefile,Gnu Make,Vpath,我有一个有点奇怪的制造案例,我正在努力弄清楚。我有一个C++项目,我从一些.CPP文件开始,我需要从多个应用程序中使用的多个远程目录编译一些源文件。这并不理想,但这是我的开发组使用的传统目录/编译结构 其他项目利用VPATH来实现这一点。然而,他们最终硬编码了需要链接的对象列表,这种方法在我看来既不优雅也不灵活。我想动态编译和链接中的所有内容。另一个潜在的复杂性是,这些远程VPATH目录中的某些目录的文件扩展名为.c(即使这些目录编译为c++),而不是.cpp 我当前的解决方案: # Direc

我有一个有点奇怪的制造案例,我正在努力弄清楚。我有一个C++项目,我从一些.CPP文件开始,我需要从多个应用程序中使用的多个远程目录编译一些源文件。这并不理想,但这是我的开发组使用的传统目录/编译结构

其他项目利用VPATH来实现这一点。然而,他们最终硬编码了需要链接的对象列表,这种方法在我看来既不优雅也不灵活。我想动态编译和链接中的所有内容。另一个潜在的复杂性是,这些远程VPATH目录中的某些目录的文件扩展名为.c(即使这些目录编译为c++),而不是.cpp

我当前的解决方案:

# Directory for object files 
OBJ_DIR = build

CPPSRC := $(wildcard *.cpp)
CSRC   := $(wildcard *.c)
OBJ    := $(CSRC:%.c=$(OBJ_DIR)/%.o) $(CPPSRC:%.cpp=$(OBJ_DIR)/%.o)

# Directory for output binaries
BIN_DIR = bin

# Name of binary executable
OUTPUT = foo

# VPATH allows you to specify other directories to search for prereqs in
VPATH = /one/remote/dir /another/remote/dir

# 'make all'
all: $(BIN_DIR)/$(OUTPUT)

# 'make clean'
clean: 
    @rm -rf $(BIN_DIR)
    @rm -rf $(OBJ_DIR)

$(OBJ_DIR)/%.o: %.cpp
    @mkdir -p $(OBJ_DIR)
    $(CXX) -c $< -o $@

$(OBJ_DIR)/%.o: %.c
    @mkdir -p $(OBJ_DIR)
    $(CXX) -c $< -o $@

$(BIN_DIR)/$(OUTPUT): $(OBJ)
    @mkdir -p $(BIN_DIR)
    $(CXX) -g -ansi -Wall -Werror -o $@ $(OBJ)
对象文件的目录 OBJ_DIR=构建 CPPSRC:=$(通配符*.cpp) 中国证监会:=$(通配符*.c) OBJ:=$(证监会:%.c=$(OBJ\U目录)/%.o)$(CPPSRC:%.cpp=$(OBJ\U目录)/%.o) #输出二进制文件的目录 BIN_DIR=BIN #二进制可执行文件的名称 输出=foo #VPATH允许您指定要在中搜索prereq的其他目录 VPATH=/one/remote/dir/other/remote/dir #“全做” 全部:$(BIN_DIR)/$(输出) #“打扫干净” 清洁: @rm-rf$(本部目录) @rm-rf$(OBJ_DIR) $(对象目录)/%.o:%.cpp @mkdir-p$(OBJ_DIR) $(CXX)-c$<-o$@ $(OBJ_DIR)/%.o:%.c @mkdir-p$(OBJ_DIR) $(CXX)-c$<-o$@ $(BIN_DIR)/$(输出):$(OBJ) @mkdir-p$(BIN_DIR) $(CXX)-g-ansi-Wall-Werror-o$@$(OBJ) 结果是,除了我的VPATH目录中的文件外,所有内容都被编译和链接。我怀疑这可能是因为一旦计算了我的$(OBJ)prereq,结果对象本身就没有一个位于VPATH中,只有源文件

我可以采取更好的方法吗?我无法轻松更改这些远程VPATH目录的内容,因为它们由不同所有者的许多不同应用程序使用。

查看:

CPPSRC := $(wildcard *.cpp)
CSRC   := $(wildcard *.c)
OBJ    := $(CSRC:%.c=$(OBJ_DIR)/%.o) $(CPPSRC:%.cpp=$(OBJ_DIR)/%.o)

$(BIN_DIR)/$(OUTPUT): $(OBJ)
第一行表示,获取我当前目录中与模式
*.cpp
匹配的所有文件。第二行表示,获取我当前目录中与模式
*.c
匹配的所有文件。第三行表示,将所有这些源文件转换为
$(OBJ_DIR)
目录中的对象文件名

最后一行说,当您想要构建
$(BIN_DIR)/$(OUTPUT)
时,请确保首先构建所有这些对象文件

您没有告诉make它应该为其他地方可能找到的源构建任何对象文件(例如,
/one/remote/dir
/other/remote/dir
)。那么,它为什么要尝试建造它们呢

你必须去寻找那些文件,并将它们添加到你的对象列表中

您可以尝试以下方法:

VPATH = /one/remote/dir /another/remote/dir
OBJ += $(patsubst %,$(OBJ_DIR)/%.o,$(notdir $(basename $(wildcard $(addsuffix /*.cpp,$(VPATH)) $(addsuffix /*.c,$(VPATH))))))
这会将
/*.cpp
/*.c
后缀添加到
$(VPATH)
中的每个目录中,然后执行通配符以获取所有匹配的文件,然后获取基本名称(删除
.cpp
.c
后缀),然后删除目录路径,然后将每个基本文件名转换为前缀
$(OBJ\u DIR)
并在末尾添加
.o

当然,如果系统中的任何位置都有两个基名称相同的文件,那么您就倒霉了,您将不得不做一些更复杂的事情,例如保留目录结构。

查看:

CPPSRC := $(wildcard *.cpp)
CSRC   := $(wildcard *.c)
OBJ    := $(CSRC:%.c=$(OBJ_DIR)/%.o) $(CPPSRC:%.cpp=$(OBJ_DIR)/%.o)

$(BIN_DIR)/$(OUTPUT): $(OBJ)
第一行表示,获取我当前目录中与模式
*.cpp
匹配的所有文件。第二行表示,获取我当前目录中与模式
*.c
匹配的所有文件。第三行表示,将所有这些源文件转换为
$(OBJ_DIR)
目录中的对象文件名

最后一行说,当您想要构建
$(BIN_DIR)/$(OUTPUT)
时,请确保首先构建所有这些对象文件

您没有告诉make它应该为其他地方可能找到的源构建任何对象文件(例如,
/one/remote/dir
/other/remote/dir
)。那么,它为什么要尝试建造它们呢

你必须去寻找那些文件,并将它们添加到你的对象列表中

您可以尝试以下方法:

VPATH = /one/remote/dir /another/remote/dir
OBJ += $(patsubst %,$(OBJ_DIR)/%.o,$(notdir $(basename $(wildcard $(addsuffix /*.cpp,$(VPATH)) $(addsuffix /*.c,$(VPATH))))))
这会将
/*.cpp
/*.c
后缀添加到
$(VPATH)
中的每个目录中,然后执行通配符以获取所有匹配的文件,然后获取基本名称(删除
.cpp
.c
后缀),然后删除目录路径,然后将每个基本文件名转换为前缀
$(OBJ\u DIR)
并在末尾添加
.o


当然,如果系统中的任何位置都有两个基名称相同的文件,那么你就不走运了,你必须做一些更复杂的事情,例如保留目录结构。

MadScientist的解决方案正是我所需要的,但他提到的警告将使我在未来远离这类事情……疯狂科学家的解决方案正是我所需要的,但他提到的警告将使我在未来远离这类事情。。。