Ошибка нескольких определений makefile проекта c

Этот вопрос представляет собой повторное выражение, созданное в соответствии с проблемой это.

В моем встроенном проекте C у меня есть две отдельные платы, и я хочу создать два файла .c (master.c и slave.c) для каждой платы, содержащие свою собственную функцию main().

Я использовал stm32cumbemx для создания проекта с main.c, makefile и другими источниками и заголовками (я хочу вручную заменить main.c на master.c и slave.c). это структура папок проекта (для простоты я удалил slave.c):

.
├── Inc
│   └── main.h
├── Makefile
├── Src
│   ├── main.c
│   └── master.c
└── STM32F103RBTx_FLASH.ld

основной.ч:

#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif


#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

основной.с:

#include "main.h"
int variable = 1;
void function(void);
int main() {
    variable += 1;
    while(1){}
}

void function(void) {
    int something = 0;
    something++;
}

мастер.с:

#include "main.h"
int variable = 1;
int variable2;
void function(void);
void function2(void);
int main() {
    variable += 1;
    while(1){
        function2();
    }
}

void function(void) {
    int something = 0;
    something++;
}

void function2(void) {
    variable2++;
}

STM32F103RBTx_FlASH.ld:

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20005000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 128K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH


  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM



  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

и makefile (части, которые я добавил в предварительно сгенерированный файл, находятся между #edit begin и #edit end комментариями:

TARGET = myproject
#edit begin
MASTER = master
SLAVE = slave
#edit end


DEBUG = 1
# optimization
OPT = -Og


BUILD_DIR = build

# C sources
C_SOURCES =  \
Src/main.c

#edint begin
SLAVE_SOURCES = \
Src/slave.c

MASTER_SOURCES = \
Src/master.c \
#edit end

PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

CPU = -mcpu=cortex-m3

# fpu
# NONE for Cortex-M0/M0+/M3

# float-abi


# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

# macros for gcc
# AS defines
AS_DEFS =

# C defines
C_DEFS =  \
-DUSE_HAL_DRIVER \
-DSTM32F103xB


# AS includes
AS_INCLUDES =

# C includes
C_INCLUDES =  \
-IInc \


# compile gcc flags
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif


# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"


# link script
LDSCRIPT = STM32F103RBTx_FLASH.ld

# libraries
LIBS = -lc -lm -lnosys
LIBDIR =
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections

# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin

#edit begin
master: $(BUILD_DIR)/$(MASTER).elf $(BUILD_DIR)/$(MASTER).hex $(BUILD_DIR)/$(MASTER).bin
slave: $(BUILD_DIR)/$(SLAVE).elf $(BUILD_DIR)/$(SLAVE).hex $(BUILD_DIR)/$(SLAVE).bin
#edit end

#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
$(info OBJECTS is $(OBJECTS))

#edit begin
MASTER_OBJ = $(addprefix $(BUILD_DIR)/,$(notdir $(MASTER_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(MASTER_SOURCES)))
$(info MASTER_OBJ is $(MASTER_OBJ))

MASTER_OBJ += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
#edit end

$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
    $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
    $(AS) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
    $(CC) $(OBJECTS) $(LDFLAGS) -o $@
    $(SZ) $@

#edit begin
$(BUILD_DIR)/$(MASTER).elf: $(MASTER_OBJ) Makefile
    $(CC) $(MASTER_OBJ) $(LDFLAGS) -o $@
    $(SZ) $@

$(BUILD_DIR)/$(SLAVE).elf: $(SLAVE_OBJ) Makefile
    $(CC) $(SLAVE_OBJ) $(LDFLAGS) -o $@
    $(SZ) $@
#edit end

$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
    $(HEX) $< $@

$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
    $(BIN) $< $@

$(BUILD_DIR):
    mkdir $@

clean:
    -rm -fR $(BUILD_DIR)

-include $(wildcard $(BUILD_DIR)/*.d)

# *** EOF ***

результат sudo make в терминале:

OBJECTS is build/main.o 
MASTER_OBJ is build/master.o
mkdir build
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb   -DUSE_HAL_DRIVER -DSTM32F103xB -IInc  -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"build/main.d" -Wa,-a,-ad,-alms=build/main.lst Src/main.c -o build/main.o
arm-none-eabi-gcc build/main.o  -mcpu=cortex-m3 -mthumb   -specs=nano.specs -TSTM32F103RBTx_FLASH.ld  -lc -lm -lnosys -Wl,-Map=build/myproject.map,--cref -Wl,--gc-sections -o build/myproject.elf
arm-none-eabi-size build/myproject.elf
   text    data     bss     dec     hex filename
     88       8    1568    1664     680 build/myproject.elf
arm-none-eabi-objcopy -O ihex build/myproject.elf build/myproject.hex
arm-none-eabi-objcopy -O binary -S build/myproject.elf build/myproject.bin

как видите, код компилируется без ошибок. и результат sudo make master (после запуска sudo make clean):

MASTER_OBJ is build/master.o
mkdir build
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb   -DUSE_HAL_DRIVER -DSTM32F103xB -IInc -IDrivers/STM32F1xx_HAL_Driver/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy -IDrivers/CMSIS/Device/ST/STM32F1xx/Include -IDrivers/CMSIS/Include -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"build/master.d" -Wa,-a,-ad,-alms=build/master.lst Src/master.c -o build/master.o
arm-none-eabi-gcc build/master.o  -mcpu=cortex-m3 -mthumb   -specs=nano.specs -TSTM32F103RBTx_FLASH.ld  -lc -lm -lnosys  -Wl,-Map=build/dual-interface.map,--cref -Wl,--gc-sections -o build/master.elf
c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: warning: cannot find entry symbol Reset_Handler; defaulting to 08000000
arm-none-eabi-size build/master.elf
   text    data     bss     dec     hex filename
     88       8    1568    1664     680 build/master.elf
arm-none-eabi-objcopy -O ihex build/master.elf build/master.hex
arm-none-eabi-objcopy -O binary -S build/master.elf build/master.bin
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb   -DUSE_HAL_DRIVER -DSTM32F103xB -IInc -IDrivers/STM32F1xx_HAL_Driver/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy -IDrivers/CMSIS/Device/ST/STM32F1xx/Include -IDrivers/CMSIS/Include -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"master"  -mcpu=cortex-m3 -mthumb   -specs=nano.specs -TSTM32F103RBTx_FLASH.ld  -lc -lm -lnosys  -Wl,-Map=build/dual-interface.map,--cref -Wl,--gc-sections  Src/master.c build/master.elf build/master.hex build/master.bin   -o master
c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: build/master.elf: in function `_init':
(.text+0x40): multiple definition of `_init'; c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/thumb/v7-m/nofp/crti.o:(.init+0x0): first defined here
c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: build/master.elf: in function `_fini':
(.text+0x4c): multiple definition of `_fini'; c:/program files (x86)/gnu arm embedded toolchain/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/thumb/v7-m/nofp/crti.o:(.fini+0x0): first defined here
build/master.bin: file not recognized: file format not recognized
collect2.exe: error: ld returned 1 exit status
make: *** [master] Error 1

Как я могу это решить?

вы можете воссоздать ошибку в Windows с помощью "gnu make" и "arm-none-eabi-gcc" в качестве компилятора. в linux и в случае ошибки stdint.h также необходимо установить один из упомянутых пакетов здесь.

Почему вы определили function() как в master.c, так и в main.c? Если вам нужны две видимые функции локально с одинаковыми именами, сделайте их static

Eugene Sh. 08.04.2022 17:50

@ЕвгенийШ. master.c и main.c не будут компилироваться одновременно. Как я уже сказал в вопросе, моя цель - получить два набора файлов .bin, .hex и .elf, специфичных для каждой платы.

mehdi 08.04.2022 18:08

Последний вызов gcc кажется плохим и, вероятно, неожиданным? Похоже, что цель master was already built before. Your master` дважды содержит зависимость $(BUILD_DIR)/$(MASTER).hex. Но не уверен, что это единственная проблема. Разве он не должен содержать только его, потому что остальные зависимости наследуются?

Eugene Sh. 08.04.2022 18:16

@ЕвгенийШ. вы правы насчет двух файлов .hex. Это опечатка, и одним из них должен был быть master.bin. и файлы .hex и .bin создаются из файла .elf в соответствии с makefile. Теперь, когда я исправил опечатку, создается и двоичный файл. Но я до сих пор не могу найти причину последнего вызова gcc.

mehdi 09.04.2022 06:40
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
45
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Последний gcc пробег...

arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb   -DUSE_HAL_DRIVER -DSTM32F103xB -IInc  -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"master"  -mcpu=cortex-m3 -mthumb   -specs=nano.specs -TSTM32F103RBTx_FLASH.ld  -lc -lm -lnosys -Wl,-Map=build/myproject.map,--cref -Wl,--gc-sections  Src/master.c build/master.elf build/master.hex   -o master

... который генерирует ошибки, сам по себе ошибочен. Откуда это взялось?

Обратите внимание на -o master в конце: в make-файле не представлено правило, рецепт которого включал бы такую ​​компиляцию, но он создает файл с тем же именем, master, что и цель. Это результат применения встроенного неявного правила для сборки исполняемого файла из исходного файла C с соответствующим именем.

Этому способствуют несколько обстоятельств.

  1. Сделан запрос на создание цели master. В данном случае это целевая цель, но также достаточно, чтобы она была предпосылкой другой цели, которую make хочет построить.

  2. Makefile не содержит рецепта сборки master.

  3. Существует исходный файл с именем master.c. Хотя он находится в подкаталоге Src, есть директива %vpath, которая говорит make обрабатывать файлы в этом каталоге, как если бы они находились в корневом каталоге проекта.

Кроме того,

  1. Встроенное правило, по-видимому, включает объявленные предварительные условия цели master (build/master.elf и build/master.hex) в команду компиляции. Это не задокументировано и не является стандартным для версий make, которые я проверял, и это причина ошибок множественного определения: gcc строит исполняемый файл, поэтому он предоставляет стандартные _init и _fini функции, но уже созданный исполняемый файл build/master.elf, который включен в ссылку также имеет эти.

Поскольку вы на самом деле не хотите, чтобы файл с именем master создавался, хорошим решением было бы объявить эту цель фальшивой:

.PHONY: master

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

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