Makefile - .o: 文件无法识别:文件被截断了吗?

Makefile - .o: file not recognized: File truncated?

我刚开始学习 GNU make,但在使用 .d(依赖项)文件时遇到链接问题。谁能用这个 error:

给我指出正确的方向

...../part1.o: file not recognized: File truncated recipe for target 'bin/target/prog' failed

这是一个简单的程序,包含:main.cpp、part1.cpp、part1.h、part2.cpp、part2.h

第 1 部分和第 2 部分有打印内容的方法。

这是在 运行 make:

时来自终端

我不明白为什么我会收到使用 #pragma once?

的警告
stud@GoldenImageASE:~/Desktop/ISU/L1/2$ make ARCH=target -f Makefile.th
Compiling...part2.cpp
arm-devkit-g++ -MTbuild/target/part2.o -MM -I. part2.cpp > build/target/part2.d
Compiling...part1.cpp
arm-devkit-g++ -MTbuild/target/part1.o -MM -I. part1.cpp > build/target/part1.d
Compiling...main.cpp
arm-devkit-g++ -MTbuild/target/main.o -MM -I. main.cpp > build/target/main.d
object file....main.o
arm-devkit-g++ -I. -c main.cpp part1.h part2.h > build/target/main.o
part1.h:1:9: warning: #pragma once in main file
 #pragma once
         ^
part2.h:1:9: warning: #pragma once in main file
 #pragma once
         ^
object file....part1.o
arm-devkit-g++ -I. -c part1.cpp > build/target/part1.o
object file....part2.o
arm-devkit-g++ -I. -c part2.cpp > build/target/part2.o
arm-devkit-g++ -I. -o build/target/main.o build/target/part1.o build/target/part2.o -o prog
build/target/part1.o: file not recognized: File truncated
collect2: error: ld returned 1 exit status
Makefile.th:27: recipe for target 'bin/target/prog' failed
make: *** [bin/target/prog] Error 1

我的 Makefile 如下:

# Variables
SOURCES=main.cpp part1.cpp part2.cpp
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)
EXE=prog
CXXFLAGS =-I.


# Making for host
# > make ARCH=host
ifeq (${ARCH},host)
CXX=g++
BUILD_DIR=build/host
EXE_DIR=bin/host
endif

# Making for target
# > make ARCH= target
ifeq (${ARCH},target)
CXX=arm-devkit-g++
BUILD_DIR=build/target
EXE_DIR=bin/target
endif

$(addprefix ${EXE_DIR}/,$(EXE)): $(addprefix ${BUILD_DIR}/,$(DEPS)) $(addprefix ${BUILD_DIR}/,$(OBJECTS))
# << Check the $(DEPS) new dependency
    @mkdir -p $(dir $@)
    $(CXX) $(CXXFLAGS) -o $(addprefix ${BUILD_DIR}/,$(OBJECTS))

$(addprefix $(BUILD_DIR)/, %.o): %.cpp
    @echo "object file...."$*.o
    $(CXX) $(CXXFLAGS) -c $^ > $@


# Rule that describes how a .d ( dependency ) file is created from a .cpp
# Similar to the assigment %. cpp -> %.o
${BUILD_DIR}/%.d: %.cpp
    @mkdir -p $(dir $@)
    @echo "Compiling..."$<
    $(CXX) -MT$(@:.d=.o) -MM $(CXXFLAGS) $^ > $@

debug:
    @echo "DEPS: "$(DEPS)"\n"
    @echo "OBJ: " $(addprefix ${BUILD_DIR}/,$(OBJECTS))"\n"
    @echo "EXE: " $(addprefix ${EXE_DIR}/,$(EXE))"\n"


.PHONY:clean
clean: 
    rm -f $(EXE) $(addprefix ${BUILD_DIR}/,$(DEPS)) $(addprefix ${BUILD_DIR}/,$(OBJECTS))

ifneq ($(MAKECMDGOALS),clean)
-include $(addprefix ${BUILD_DIR}/,$(DEPS))
endif

你有两个不相关的问题。第一个是链接时有两个相互冲突的 -o 选项。

您询问的实际问题有所不同,但仍与 -o 选项有关:即您在尝试创建目标文件时没有。

创建对象文件时,生成的对象文件不会写入标准输出,因此您的重定向不会导致gcc前端程序创建对象用你想的名字归档。

例如:

arm-devkit-g++ -I. -c part1.cpp > build/target/part1.o

上述命令将在当前目录中创建一个名为part1.o的目标文件,并将(空)标准输出写入文件build/target/part1.o .这将使 build/target/part1.o 为空,这就是链接器所抱怨的(这就是它说文件被截断时的意思)。

该命令应该看起来像

arm-devkit-g++ -I. -c part1.cpp -o build/target/part1.o

注意使用 -o 选项命名输出文件。

您需要修改 makefile 以在构建目标文件时不使用重定向。


此外,构建目标文件时不应列出头文件,只列出要构建的源文件,因此命令

arm-devkit-g++ -I. -c main.cpp part1.h part2.h > build/target/main.o

真的应该

arm-devkit-g++ -I. -c main.cpp -o build/target/main.o

您没有正确编译目标文件。 g++ 不输出文件到stdout,直接写到本地。如果要将目标文件放在特定目录下,需要使用-o选项:

$(BUILD_DIR)/%.o: %.cpp | $(BUILD_DIR)
    $(CXX) $(CXXFLAGS) -c $^ -o $@
                            ^^^^^^

$(BUILD_DIR):
    @mkdir -p $@

此外,您构建的可执行文件不正确。依赖项不足,您没有列出目标。你会想要这个:

$(EXE_DIR)/$(EXE) : $(addprefix $(BUILD_DIR),$(OBJECTS)) | $(EXE_DIR)
    $(CXX) $(CXXFLAGS) -o $@ $^

$(EXE_DIR):
    @mkdir -p $@

这将从您的二进制文件在目录上创建一个仅顺序依赖项,并正确构建二进制文件。请注意,您的目标不应依赖于 .d 文件。这没什么意义。相反,您构建 .os 的规则也应该简单地构建 .ds(该规则当前遇到与您的 .o 规则相同的问题):

# build the .o and the .d in one go
$(BUILD_DIR)/%.o : %.cpp | $(BUILD_DIR)
    $(CXX) $(CXXFLAGS) -o $@ -c $< -MP -MMD -MF $(@:.o=.d)

作为社论旁白,在 SHOUTY_CAPS 中编写 MAKEFILES 中的所有变量是一种普遍的趋势。事实证明,这比仅使用 snake_case 更难阅读。小写字母工作得很好。