“对‘main’的未定义引用”:创建了 main.o 但未编译 main 函数

问题描述 投票:0回答:1

请注意,由于这个问题与我的工作有关,我想提供尽可能少的有关我的程序的必要信息。

我正在尝试为 RISC-V 微控制器编译程序。我正在使用 GCC RISC-V 编译工具。

该项目包含多个文件以及一个“main.c”文件,其中包含一个基本的“main”函数(目前为空):

int main(void)
{
    return 0;
}

在编译过程中,我从链接器收到以下消息:

riscv-none-embed/bin/ld.exe:在startup.S中:未定义的引用 ‘主要’

我已经检查过,编译器已经为 main.c 文件生成了一个目标文件: main.o 。但是 'main' 函数并没有出现在里面;在 main.o 上运行 nm 工具时,我得到以下输出:

0000018e t .L0
00000196 t .L0
0000019c t .L0
000001a4 t .L0
000001aa t .L0
000001c2 t .L0
000001c4 t .L0
000001c8 t .L0
000001ce t .L0
000001ce t .L0
00000076 t .L4
00000104 t .L5
000001e7 N .LASF0
000001ac N .LASF1
00000224 N .LASF10
000000e1 N .LASF11
.
.
.
00000469 N .LASF57
000000e9 N .LASF58
00000151 N .LASF59
0000008a N .LASF6
000004a2 N .LASF60
0000026c N .LASF61
00000000 d some_global_variable
00000000 T some_function0
0000017c T some_function1
00000110 T some_function2
00000050 T some_function3
         U some_function4
         U some_function5

请注意,所有 'some_functionX' 和全局变量均未在 main.c 中定义,而是在其他 C 文件中定义。

这是我的 Makefile(正确地说:它的主要部分,我已经删除了机密部分):

STARTUP_FILE := $(ROOT_DIR)/../startup.S
STARTUP_OBJ := $(ROOT_DIR)/../startup.o

TOOL_DIR := $(ROOT_DIR)/../../riscv_gcc/riscv-none-embed-gcc/bin
GCC         := $(TOOL_DIR)/riscv-none-embed-gcc-10.2.0
LD          := $(TOOL_DIR)/riscv-none-embed-ld
GDB         := $(TOOL_DIR)/riscv-none-embed-gdb
OBJCOPY     := $(TOOL_DIR)/riscv-none-embed-objcopy
OBJDUMP     := $(TOOL_DIR)/riscv-none-embed-objdump
READELF     := $(TOOL_DIR)/riscv-none-embed-readelf
CODESIZE    := $(TOOL_DIR)/riscv-none-embed-size 
NMINFO      := $(TOOL_DIR)/riscv-none-embed-nm


LIB := $(LIB_DIR)/lib$(TARGET).a
ELF := $(BIN_DIR)/$(TARGET).elf
BIN := $(BIN_DIR)/$(TARGET).bin
HEX := $(BIN_DIR)/$(TARGET).hex
DASM := $(BIN_DIR)/$(TARGET).dasm

EN_OPTIMIZE = -O0
OPTFLAGS    := -march=rv32imc -mabi=ilp32 -mno-strict-align --specs=nano.specs $(EN_OPTIMIZE)
AFLAGS      := -D__STACK_SIZE=$(STACK_SIZE) -nostartfiles --entry Reset_Handler
LDFLAGS     := $(LINKER_FILE) -Xlinker -Map=$(BIN_DIR)/$(TARGET).map -L$(LIB_DIR)
LDFLAGS     += -falign-functions=4 -falign-jumps -falign-loops -falign-labels
# The -MMD flags additionaly creates a .d file as header dependency with the same name as the .o file.
CFLAGS      := -g -Wall -MMD -Wtype-limits -Woverflow -Wabsolute-value -Wno-unused-label $(INC_DIR) $(EN_OPTIMIZE)
CFLAGS      += -falign-functions=4 -falign-jumps -falign-loops -falign-labels -mno-relax




.PHONY: all
all: $(ELF) $(BIN) $(HEX) $(DASM)


# build object files
$(OBJ): $(SRC)
ifeq ($(wildcard $(OBJ_DIR)),)
    mkdir -p $(OBJ_DIR)
endif
    $(GCC) $(CFLAGS) -c $< -o $@



# Build the library .a 
$(LIB): $(OBJ)
ifeq ($(wildcard $(LIB_DIR)),)
    mkdir -p $(LIB_DIR)
endif
    $(TOOL_DIR)/riscv-none-embed-ar -crs $@ $(OBJ)


# Build .elf
$(ELF): $(LIB) $(OBJ)
ifeq ($(wildcard $(BIN_DIR)),)
    mkdir -p $(BIN_DIR)
endif
    $(GCC) $(CFLAGS) $(STARTUP_FILE) $(LDFLAGS) $(AFLAGS) -l$(TARGET) -o $@


# Build .bin
$(BIN): $(ELF)
ifeq ($(wildcard $(BIN_DIR)),)
    mkdir -p $(BIN_DIR)
endif
    $(OBJCOPY) -O binary $< $@


# Build .hex
$(HEX): $(ELF)
ifeq ($(wildcard $(BIN_DIR)),)
    mkdir -p $(BIN_DIR)
endif
    $(OBJCOPY) -O ihex $< $@


#Build disassembly file .dasm
$(DASM): $(ELF)
ifeq ($(wildcard $(BIN_DIR)),)
    mkdir -p $(BIN_DIR)
endif
    $(OBJDUMP) -d -S $< > $@



.PHONY: clean
clean:
    rm -rf $(OUTPUT_DIR)

如果需要更多信息,请告诉我。 感谢您的帮助。

c gcc linker
1个回答
0
投票

规则

$(OBJ): $(SRC)
        $(GCC) $(CFLAGS) -c $< -o $@

将(仅)编译 $(SRC) 中的第一个源文件,并对 $(OBJ) 中的每个目标文件重复执行此操作。假设您有多个源文件和目标文件,则所有 .o 文件最终都将是相同的 - 编译第一个源文件的结果。这似乎与 main.o 的 nm 输出一致——实际上是编译了其他一些源文件来获得它,而不是 main.c

你真正想要的是一个更像的规则

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
        $(GCC) $(CFLAGS) -c $< -o $@

这是一个模式规则,使与左侧模式匹配的每个文件都依赖于右侧模式,并将编译每个源文件以生成相应的目标文件。

© www.soinside.com 2019 - 2024. All rights reserved.