Обратите внимание: поскольку этот вопрос связан с моей работой, я хотел бы дать как можно меньше информации о моей программе.
Я пытаюсь скомпилировать программу для микроконтроллера 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)
Пожалуйста, дайте мне знать, если требуется дополнительная информация. Спасибо за вашу помощь.
Вы не показываете значения для GCC
, STARTUP_FILE
и т. д. Вы используете $(TOOL_DIR)/riscv-none-embed-ar
, поэтому я ожидаю, что GCC
будет определяться аналогичным образом. Кроме того, у вас есть -MMD
в CFLAGS
, в котором создаются файлы .o/.elf
. Я могу ошибаться, но я всегда использовал -MMD
только при создании .dep
файла, а не при создании .o
файлов или .elf
файлов. Возможно, вам следует отредактировать свой вопрос и опубликовать вывод команды make
в отдельном блоке кода.
@CraigEstey Я добавил информацию о GCC и STARTUP_FILE. Что касается -MMD, должен признаться, что я не совсем понимаю, как он работает, его добавил кто-то другой. Но мы использовали этот флаг несколько раз, и до сих пор это не было проблемой.
@CraigEstey, мне пришлось поискать, но если -E
также не указано, -MMD
генерирует файлы зависимостей в дополнение к объектным файлам. Однако некоторые другие директивы -M
отличаются по этому поводу.
Поскольку жалоба находится именно на startup.S
, возможно, опубликовать ее? Поскольку вы пытаетесь построить систему на «голом железе», это будет важно. Также скрипт компоновщика. И снова вывод [работающей] make
команды? Вы можете получить больше/лучше информации от readelf -a
, чем от nm
.
Ваш make-файл слишком велик, чтобы его можно было интерпретировать в моей голове. Пожалуйста, опубликуйте точные команды в том виде, в каком они вызываются make
.
При этом линия $(OBJ): $(SRC)
выглядит очень неправильно. Все объекты зависят от всех источников, но для их сборки нужно запустить всего одну команду? Я не думаю, что это может сработать.
Правило
$(OBJ): $(SRC)
$(GCC) $(CFLAGS) -c $< -o $@
скомпилирует (только) первый исходный файл в $(SRC) и сделает это повторно для каждого объектного файла в $(OBJ). Если у вас есть несколько исходных и объектных файлов, все файлы .o в конечном итоге окажутся одинаковыми — результат компиляции первого исходного файла. Кажется, это согласуется с вашим выводом nm main.o, поскольку для его получения на самом деле компилируется какой-то другой исходный файл, а не main.c.
На самом деле вам нужно правило, больше похожее на
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(GCC) $(CFLAGS) -c $< -o $@
это правило шаблона, которое заставляет каждый файл, соответствующий шаблону слева, зависеть от шаблона справа, и компилирует каждый исходный файл для создания соответствующего объектного файла.
В этом и была проблема, теперь все работает, спасибо большое.
Установите eclipse, добавьте свою цепочку инструментов и забудьте о ручных make-файлах.