Makefile link 步骤不正确 link obj 文件

Makefile link step doesn't properly link obj files

我在使用当前的 make 设置 link 将所有生成的 obj 文件转换为可执行文件时遇到问题。我的目录结构如下(提供参考):

如您所见,我将多个子项目存储在同一目录下,并使用对make 的递归调用来构建每个项目。首先,它从特定项目收集所有源文件和头文件,然后编译它们,将生成的 obj 文件存储在 root/bin/project/obj 中。从这里开始,我想 link 所有的 obj 文件并生成一个可执行文件,该文件将存储在 root/bin/project/bin 目录下。

问题是,通过使用当前的 Makefile 配置,我的 linker (MSVC link.exe) 只能看到 obj 目录中的第一个 obj 文件。下面提供Makefile查看编译和link命令:

# expands to root/bin/projname/bin
TARGET_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/bin
#expands to root/bin/projname/obj
OBJ_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/obj
# expands to a list of all the obj files created from the source files (a.obj, b.obj..)
OBJECTS := \
    $(notdir $(patsubst %.cpp,%.obj,$(patsubst %.c,%.obj,$(SOURCES))))
SOURCES := $(wildcard src/*.c) $(wildcard src/*.cpp)

# default target
all: dirs $(TARGET).exe

# Link
$(TARGET).exe: $(OBJ_DIR)/$(OBJECTS)
    $(LNK) $(LIB_PATH) $(LIBS) /OUT:$(TARGET_DIR)/$@ $(OBJ_DIR)/$(OBJECTS)

# Compile
$(OBJ_DIR)/$(OBJECTS): $(SOURCES)
    $(CC) /c $(CFLAGS) $(INCLUDES) /Fo$(OBJ_DIR)/ /EHsc $(SOURCES)

.PHONY: build
dirs:
    $(MKDIR) $(TARGET_DIR)
    $(MKDIR) $(OBJ_DIR)
    $(MKDIR) $(TEST_DIR)

我遇到的错误如下,在linking过程中:

"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\..\..\VC\vcvarsall.bat" x86_amd64 > NUL && link /NOLOGO /MACHINE:X64  /LIBPATH:"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib\x64"  /DEFAULTLIB:shell32.lib /OUT:../bin/project1/bin/project1.exe ../bin/project1/obj/main.obj sort.obj

如您所见,它仅针对 objdir 中的第一个 obj 文件 links,而试图 link 针对 Makefile 目录中的第二个 obj 文件,这当然会导致错误:`LINK:致命错误 LNK1181:无法打开输入文件 'sort.obj'

更新:已接受的答案中提出了解决方案。下面会留下最终版本。

# expands to root/bin/projname/bin
TARGET_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/bin
#expands to root/bin/projname/obj
OBJ_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/obj
# expands to a list of all the obj files created from the source files (a.obj, b.obj..)
OBJECTS := \
    $(notdir $(patsubst %.cpp,%.obj,$(patsubst %.c,%.obj,$(SOURCES))))
SOURCES := $(wildcard src/*.c) $(wildcard src/*.cpp)

# default target
all: dirs $(TARGET).exe

# Link
$(TARGET).exe: $(addprefix $(OBJ_DIR)/,$(OBJECTS)))
    $(LNK) $(LIB_PATH) $(LIBS) /OUT:$(TARGET_DIR)/$@ $^

# Compile
$(OBJ_DIR)/$(OBJECTS): $(SOURCES)
    $(CC) /c $(CFLAGS) $(INCLUDES) /Fo$(OBJ_DIR)/ /EHscT $(SOURCES)

.PHONY: build
dirs:
    $(MKDIR) $(TARGET_DIR)
    $(MKDIR) $(OBJ_DIR)
    $(MKDIR) $(TEST_DIR)

这是不对的:

$(OBJ_DIR)/$(OBJECTS)

这扩展到什么?假设 OBJECTSfoo.o bar.o baz.oOBJDIRobj。然后上面展开为:

obj/foo.o bar.o baz.o

这显然不是你想要的。如果您想为列表中的每个单词添加一个值作为前缀,您不能只将该值放在整个列表之前。您需要使用类似:

$(addprefix $(OBJ_DIR)/,$(OBJECTS))