«неопределенная ссылка на 'main'»: файл main.o создан, но основная функция не скомпилирована

Обратите внимание: поскольку этот вопрос связан с моей работой, я хотел бы дать как можно меньше информации о моей программе.

Я пытаюсь скомпилировать программу для микроконтроллера RISC-V. Я использую инструменты компиляции GCC RISC-V.

Проект содержит несколько файлов вместе с файлом main.c, который содержит базовую функцию main (пока пустую):

int main(void)
{
    return 0;
}

Во время компиляции я получаю следующее сообщение от компоновщика:

riscv-none-embed/bin/ld.exe: при запуске.S: неопределенная ссылка на 'основной'

Я проверил, и компилятор создал объектный файл для файла main.c: main.o . Но внутри него не появляется «основная» функция; при запуске инструмента nm на main.o я получаю такой вывод:

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)

Пожалуйста, дайте мне знать, если требуется дополнительная информация. Спасибо за вашу помощь.

Установите eclipse, добавьте свою цепочку инструментов и забудьте о ручных make-файлах.

gulpr 21.03.2024 18:06

Вы не показываете значения для GCC, STARTUP_FILE и т. д. Вы используете $(TOOL_DIR)/riscv-none-embed-ar, поэтому я ожидаю, что GCC будет определяться аналогичным образом. Кроме того, у вас есть -MMD в CFLAGS, в котором создаются файлы .o/.elf. Я могу ошибаться, но я всегда использовал -MMD только при создании .dep файла, а не при создании .o файлов или .elf файлов. Возможно, вам следует отредактировать свой вопрос и опубликовать вывод команды make в отдельном блоке кода.

Craig Estey 21.03.2024 18:08

@CraigEstey Я добавил информацию о GCC и STARTUP_FILE. Что касается -MMD, должен признаться, что я не совсем понимаю, как он работает, его добавил кто-то другой. Но мы использовали этот флаг несколько раз, и до сих пор это не было проблемой.

Wheatley 21.03.2024 18:26

@CraigEstey, мне пришлось поискать, но если -E также не указано, -MMD генерирует файлы зависимостей в дополнение к объектным файлам. Однако некоторые другие директивы -M отличаются по этому поводу.

John Bollinger 21.03.2024 18:46

Поскольку жалоба находится именно на startup.S, возможно, опубликовать ее? Поскольку вы пытаетесь построить систему на «голом железе», это будет важно. Также скрипт компоновщика. И снова вывод [работающей] make команды? Вы можете получить больше/лучше информации от readelf -a, чем от nm.

Craig Estey 21.03.2024 19:02

Ваш make-файл слишком велик, чтобы его можно было интерпретировать в моей голове. Пожалуйста, опубликуйте точные команды в том виде, в каком они вызываются make.

n. m. could be an AI 21.03.2024 19:13

При этом линия $(OBJ): $(SRC) выглядит очень неправильно. Все объекты зависят от всех источников, но для их сборки нужно запустить всего одну команду? Я не думаю, что это может сработать.

n. m. could be an AI 21.03.2024 19:26
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Правило

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

скомпилирует (только) первый исходный файл в $(SRC) и сделает это повторно для каждого объектного файла в $(OBJ). Если у вас есть несколько исходных и объектных файлов, все файлы .o в конечном итоге окажутся одинаковыми — результат компиляции первого исходного файла. Кажется, это согласуется с вашим выводом nm main.o, поскольку для его получения на самом деле компилируется какой-то другой исходный файл, а не main.c.

На самом деле вам нужно правило, больше похожее на

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

это правило шаблона, которое заставляет каждый файл, соответствующий шаблону слева, зависеть от шаблона справа, и компилирует каждый исходный файл для создания соответствующего объектного файла.

В этом и была проблема, теперь все работает, спасибо большое.

Wheatley 28.03.2024 10:45

Другие вопросы по теме