Make:利用 VPATH 编译 link 不同扩展名的文件
Make: Utilizing VPATH to compile and link files with a different extension
我有一个有点奇怪的 Make 案例,我正在努力弄清楚。我有一个 C++ 项目,我从一些 .cpp 文件开始,我需要从多个应用程序使用的多个远程目录编译一些源文件。这并不理想,但这是我的开发组使用的遗留 directory/compilation 结构。
其他项目利用 VPATH 来完成此任务。然而,他们最终对获得 linked 的所需对象列表进行了硬编码,这种方法对我来说似乎并不优雅或不灵活。我想动态编译和 link 中的所有内容。另一个潜在的并发症是这些远程 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)
结果是,除我的 VPATH 目录中的文件外,所有内容都得到编译和 linked。我怀疑这可能是因为一旦我的 $(OBJ) prereq 被评估,none 结果对象本身位于 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
或 /another/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_DIR)
并在末尾添加 .o
。
当然,如果您的系统中的任何地方都有两个具有相同基本名称的文件,那您就不走运了,您将不得不做一些更复杂的事情,例如保留目录结构。
我有一个有点奇怪的 Make 案例,我正在努力弄清楚。我有一个 C++ 项目,我从一些 .cpp 文件开始,我需要从多个应用程序使用的多个远程目录编译一些源文件。这并不理想,但这是我的开发组使用的遗留 directory/compilation 结构。
其他项目利用 VPATH 来完成此任务。然而,他们最终对获得 linked 的所需对象列表进行了硬编码,这种方法对我来说似乎并不优雅或不灵活。我想动态编译和 link 中的所有内容。另一个潜在的并发症是这些远程 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)
结果是,除我的 VPATH 目录中的文件外,所有内容都得到编译和 linked。我怀疑这可能是因为一旦我的 $(OBJ) prereq 被评估,none 结果对象本身位于 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
或 /another/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_DIR)
并在末尾添加 .o
。
当然,如果您的系统中的任何地方都有两个具有相同基本名称的文件,那您就不走运了,您将不得不做一些更复杂的事情,例如保留目录结构。