c项目makefile多重定义错误

c project makefile multiple definitions error

这个问题是对应this问题创建的repex。

在我的嵌入式 C 项目中,我有两个独立的板,我想为每个板创建两个 .c 文件(master.c 和 slave.c),每个板包含它们自己的特定 main() 函数.

我已经使用 stm32cumbemx 生成项目,其中包含 main.c、makefile 和其他来源以及 headers(我想将 main.c 替换为 master.c 和 slave.c 手动)。 这是项目的文件夹结构(为简单起见,我删除了 slave.c):

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

main.h:

#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif


#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

main.c:

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

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

master.c:

#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(我添加到pre-generated文件的部分在#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

我该如何解决这个问题?

您可以使用“gnu make”和“arm-none-eabi-gcc”作为编译器重现 windows 中的错误。在 linux 和 stdint.h 错误的情况下,您还需要安装提到的软件包之一 here.

最后一个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:makefile 中没有规定其配方会产生这样的编译,但它正在构建一个同名的文件,master,如目标目标。 这是从 correspondingly-named C 源文件构建可执行文件的 built-in 隐式规则 练习的结果。

有几种情况导致了这一点。

  1. 请求构建目标 master。在这种情况下,它是目标目标,但它也足以成为 make 想要构建的另一个目标的先决条件。

  2. makefile 不提供构建 master 的任何方法。

  3. 有一个名为 master.c 的源文件。虽然它在子目录 Src 中,但有一个 %vpath 指令告诉 make 将该目录中的文件视为它们出现在项目根目录中。

此外,

  1. built-in 规则显然在编译命令中包含目标 masterbuild/master.elfbuild/master.hex)的声明先决条件。对于我检查过的 make 版本,这没有记录或标准,这是 multiple-definition 错误的原因:gcc 正在构建可执行文件,因此它提供标准 _init_fini 函数,但是包含在 link 中的 already-built 可执行文件 build/master.elf 也有这些。

由于您实际上并不想要构建一个名为 master 的文件,因此一个好的解决方案是声明该目标是虚假的:

.PHONY: master

这有几个有用的效果,但对于您的目的而言,关键是它会导致跳过针对该目标的隐式规则搜索。