Reputation: 355
This question is a repex created corresponding to this problem.
In my embedded C project I have two separate boards and I want to create two .c files (master.c and slave.c) for each board containing their own specific main()
function.
I've used stm32cumbemx to generate the project with main.c, makefile and other sources and headers (I want to replace main.c with master.c and slave.c manually). this is the folder structure of the project (I deleted slave.c for simplicity):
.
├── 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) }
}
and makefile (the parts I added to pre-generated file are between #edit begin
and #edit end
comments:
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 ***
resutlt of sudo make
in terminal:
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
as you see the code compiles with no errors.
and result of sudo make master
(after running 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
How can I solve this?
you can recreate the error in windows with "gnu make" and "arm-none-eabi-gcc" as compiler. in linux and in case of stdint.h error, you also need to install one of the packages mentioned here.
Upvotes: 1
Views: 1140
Reputation: 180171
The last gcc
run ...
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
... that generates the errors, is itself erroneous. Where does it come from?
Note the -o master
at the end: there is no rule presented in the makefile whose recipe would produce such a compilation, but it is building a file with the same name, master
, as the goal target. This is the result of the exercise of a built-in implicit rule for building an executable from a correspondingly-named C source file.
Several circumstances contribute to this.
A request is made to build target master
. It is the goal target in this case, but it would also suffice for it to be a prerequisite of another target that make
wants to build.
The makefile does not provide any recipe for building master
.
There is a source file named master.c
. Although it is in subdirectory Src
, there is a %vpath
directive that tells make
to treat files in that directory as if they appeared in the project root directory.
Additionally,
master
(build/master.elf
and build/master.hex
) in the compilation command. This is not documented or standard for versions of make
I've checked, and it is the reason for the multiple-definition errors: gcc is building an executable, so it provides standard _init
and _fini
functions, but the already-built executable build/master.elf
that is included in the link also has these.Since you don't actually want a file named master
built, a good solution would be to declare that target phony:
.PHONY: master
That has several useful effects, but key for your purposes is that it causes the implicit rule search for that target to be skipped.
Upvotes: 1