使用arm-none-eabi-ar将库相互链接时,如何避免未定义的符号

时间:2016-06-18 19:30:18

标签: c arm stm32f4discovery ar

我正在使用arm-none-eabi-gcc工具链onlinux,并且无法创建链接到其他档案的档案。作为一个具体的例子,基础档案(libstm32f4_hal.a)应该有一个函数$.ajax({ url: someUrl, method: "POST", data: "teamMemberId=" + id, statusCode: { 404: function (obj, textStatus, errorThrown) { cancel(); }, 403: function (obj, textStatus, errorThrown) { alert( //statusCodeDescription ); }, 200: cancel } }); 并使用HAL_SPI_GetState,它似乎确实

nm

然后我想制作另一个使用libstm32f4_hal.a的存档(libstm32f4_bsp.a)。第二个存档似乎构建正确,但是当我尝试链接这些库时,链接器会抛出以下错误。

$ nm libstm32f4_hal.a
stm32f4xx_hal_spi.o:
...
0000158d T HAL_SPI_GetState
00001495 T HAL_SPI_IRQHandler
00000271 T HAL_SPI_Init
...

当我使用cube/Drivers/BSP/STM32F4-Discovery/libstm32f4_bsp.a(stm32f4_discovery.o): In function `SPIx_Init': cube/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery.c:313: undefined reference to `HAL_SPI_GetState' 检查libstm32f4_bsp.a时,确实未定义函数nm

HAL_SPI_GetState

这是我用来构建第二个档案的makefile。

$ nm libstm32f4_bsp.a
stm32f4_discovery.o:
...
         U HAL_SPI_GetState
         U HAL_SPI_Init
...

有人可以解释为什么会这样吗?我很乐意提供更多详细信息,但对于我在这里尝试做的事情相对缺乏经验,我不完全确定还有什么有用的。

上下文是,我正在尝试为STM32F4-Discovery板构建演示代码。它基本上将电路板设置为USB鼠标。由于USB堆栈非常庞大,我的计划是将硬件抽象层(HAL)构建为存档,然后将特定于板的中间件构建为链接到HAL存档的存档,然后在我的最终构建链接中将演示代码构建到这两个档案。

感谢您的帮助。

编辑:

这是我用来构建项目的makefile。

CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar

HAL_DIR = ../../STM32F4xx_HAL_Driver

###########################################

vpath %.c

CFLAGS  = -g -O2 -Wall
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -ffreestanding -nostdlib

CFLAGS += -I$(HAL_DIR)/Inc
CFLAGS += -I../../CMSIS/Device/ST/STM32F4xx/Include
CFLAGS += -I../../CMSIS/Include

SRCS = stm32f4_discovery.c stm32f4_discovery_accelerometer.c stm32f4_discovery_audio.c


OBJS = $(SRCS:.c=.o)

.PHONY: all clean

all: libstm32f4_bsp.a

%.o : %.c
    $(CC) $(CFLAGS) -c -o $@ $^ -L$(HAL_DIR) -lstm32f4_hal

libstm32f4_bsp.a: $(OBJS)
    $(AR) -rvs $@ $(OBJS)

clean:
    rm -f $(OBJS) libstm32f4_bsp.a

这是失败的链接命令。

# STM32 Makefile for GNU toolchain and openocd
#
# This Makefile fetches the Cube firmware package from ST's' website.
# This includes: CMSIS, STM32 HAL, BSPs, USB drivers and examples.
#
# Usage:
#   make cube       Download and unzip Cube firmware
#   make program        Flash the board with OpenOCD
#   make openocd        Start OpenOCD
#   make debug      Start GDB and attach to OpenOCD
#   make dirs       Create subdirs like obj, dep, ..
#   make template       Prepare a simple example project in this dir
#
# Copyright 2015 Steffen Vogel
# License   http://www.gnu.org/licenses/gpl.txt GNU Public License
# Author    Steffen Vogel <post@steffenvogel.de>
# Link      http://www.steffenvogel.de
#
# edited for the STM32F4-Discovery

# A name common to all output files (elf, map, hex, bin, lst)
TARGET     = demo

# Take a look into $(CUBE_DIR)/Drivers/BSP for available BSPs
BOARD      = STM32F4-Discovery
BSP_BASE   = stm32f4_discovery

OCDFLAGS   = -f board/stm32f4discovery.cfg
GDBFLAGS   =

#EXAMPLE   = Templates
EXAMPLE    = Demonstrations

# MCU family and type in various capitalizations o_O
MCU_FAMILY = stm32f4xx
MCU_LC     = stm32f401xc
MCU_MC     = STM32F407xx
MCU_UC     = STM32F407VG




# Your C files from the /src directory
SRCS       = main.c
SRCS      += system_$(MCU_FAMILY).c
SRCS      += stm32f4xx_it.c

# Basic HAL libraries
#SRCS      += stm32f4xx_hal_rcc.c stm32f4xx_hal_rcc_ex.c stm32f4xx_hal.c stm32f4xx_hal_cortex.c stm32f4xx_hal_gpio.c $(BSP_BASE).c

# USB .c
SRCS      += usbd_conf_template.c usbd_core.c usbd_ctlreq.c usbd_ioreq.c
SRCS      += usbd_hid.c
SRCS      += usbd_desc.c
SRCS      += stm32f4xx_hal_pcd.c

SRCS      += stm32f4_discovery_accelerometer.c stm32f4xx_hal_tim.c

# Directories
OCD_DIR    = /usr/share/openocd/scripts

CUBE_DIR   = cube

BSP_DIR    = $(CUBE_DIR)/Drivers/BSP/$(BOARD)
HAL_DIR    = $(CUBE_DIR)/Drivers/STM32F4xx_HAL_Driver
CMSIS_DIR  = $(CUBE_DIR)/Drivers/CMSIS

DEV_DIR    = $(CMSIS_DIR)/Device/ST/STM32F4xx

CUBE_URL   = http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stm32cubef4.zip

# that's it, no need to change anything below this line!

###############################################################################
# Toolchain

PREFIX     = arm-none-eabi
CC         = $(PREFIX)-gcc
AR         = $(PREFIX)-ar
OBJCOPY    = $(PREFIX)-objcopy
OBJDUMP    = $(PREFIX)-objdump
SIZE       = $(PREFIX)-size
GDB        = $(PREFIX)-gdb

OCD        = openocd

###############################################################################
# Options

# Defines
DEFS       = -D$(MCU_MC) -DUSE_HAL_DRIVER

# Debug specific definitions for semihosting
DEFS       += -DUSE_DBPRINTF

# Include search paths (-I)
INCS       = -Itemplate/inc
INCS      += -I$(BSP_DIR)
INCS      += -I$(CMSIS_DIR)/Include
INCS      += -I$(DEV_DIR)/Include
INCS      += -I$(HAL_DIR)/Inc

# USB .h
INCS      += -I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Inc
INCS      += -I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Inc

# Library search paths
LIBS       = -L$(CMSIS_DIR)/Lib

# Compiler flags
CFLAGS     = -Wall -g -std=c99 -Os
CFLAGS    += -mlittle-endian -mcpu=cortex-m4 -march=armv7e-m -mthumb
CFLAGS    += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
CFLAGS    += -ffunction-sections -fdata-sections
CFLAGS    += $(INCS) $(DEFS)

CFLAGS    += -mthumb-interwork

# Linker flags
LDFLAGS    = -Wl,--gc-sections -Wl,-Map=$(TARGET).map $(LIBS) -Ttemplate/$(MCU_LC).ld

# Enable Semihosting
LDFLAGS   += --specs=rdimon.specs -lc -lrdimon

# Source search paths
VPATH      = ./template/src
VPATH     += $(BSP_DIR)
VPATH     += $(HAL_DIR)/Src
VPATH     += $(DEV_DIR)/Source/

VPATH     += $(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src
VPATH     += $(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src

OBJS       = $(addprefix template/obj/,$(SRCS:.c=.o))
DEPS       = $(addprefix template/dep/,$(SRCS:.c=.d))

# Prettify output
V = 0
    Q = @
    P = > /dev/null
endif

###################################################

.PHONY: all dirs program debug template clean

all: $(TARGET).elf

-include $(DEPS)

dirs: template/dep template/obj cube
template/dep template/obj template/src template/inc:
    @echo "[MKDIR]   $@"
    $Qmkdir -p $@

template/obj/%.o : %.c | dirs
    @echo "[CC]      $(notdir $<)"
    $Q$(CC) $(CFLAGS) -c -o $@ $< -MMD -MF template/dep/$(*F).d -L$(HAL_DIR) -lstm32f4_hal -L$(BSP_DIR) -lstm32f4_bsp

$(TARGET).elf: $(OBJS)
    @echo "[LD]      $(TARGET).elf"
    $Q$(CC) $(CFLAGS) $(LDFLAGS) template/src/startup_$(MCU_LC).s $^ -o $@ -L$(HAL_DIR) -lstm32f4_hal -L$(BSP_DIR) -lstm32f4_bsp
    @echo "[OBJDUMP] $(TARGET).lst"
    $Q$(OBJDUMP) -St $(TARGET).elf >$(TARGET).lst
    @echo "[SIZE]    $(TARGET).elf"
    $(SIZE) $(TARGET).elf

openocd:
    $(OCD) -s $(OCD_DIR) $(OCDFLAGS)

program: all
    $(OCD) -s $(OCD_DIR) $(OCDFLAGS) -c "program $(TARGET).elf verify reset"

debug:
    @if ! nc -z localhost 3333; then \
        echo "\n\t[Error] OpenOCD is not running! Start it with: 'make openocd'\n"; exit 1; \
    else \
        $(GDB)  -ex "target extended localhost:3333" \
            -ex "monitor arm semihosting enable" \
            -ex "monitor reset halt" \
            -ex "load" \
            -ex "monitor reset init" \
            $(GDBFLAGS) $(TARGET).elf; \
    fi

cube:
    rm -fr $(CUBE_DIR)
    wget -O /tmp/cube.zip $(CUBE_URL)
    unzip /tmp/cube.zip
    mv STM32Cube* $(CUBE_DIR)
    chmod -R u+w $(CUBE_DIR)
    rm -f /tmp/cube.zip

template: cube template/src template/inc
    cp -ri $(CUBE_DIR)/Projects/$(BOARD)/$(EXAMPLE)/Src/* template/src
    cp -ri $(CUBE_DIR)/Projects/$(BOARD)/$(EXAMPLE)/Inc/* template/inc
    cp -i $(DEV_DIR)/Source/Templates/gcc/startup_$(MCU_LC).s template/src
    cp -i $(CUBE_DIR)/Projects/$(BOARD)/$(EXAMPLE)/TrueSTUDIO/STM32F4-DISCO/$(MCU_UC)_FLASH.ld template/$(MCU_LC).ld

clean:
    @echo "[RM]      $(TARGET).elf"; rm -f $(TARGET).elf
    @echo "[RM]      $(TARGET).map"; rm -f $(TARGET).map
    @echo "[RM]      $(TARGET).lst"; rm -f $(TARGET).lst
    @echo "[RMDIR]   template/dep"          ; rm -fr template/dep
    @echo "[RMDIR]   template/obj"          ; rm -fr template/obj

rm:
    rm -rf template
ifeq ($V, 0)

我将项目加载到github here,以防任何人有足够的动力去尝试自己构建项目。作为旁注,我正在运行Arch linux。

1 个答案:

答案 0 :(得分:2)

您失败的命令类似于

arm-none-eabi-gcc ...-mcpu=cortex-m4 .. template/obj/main.o \
-lstm32f4_hal ... -lstm32f4_bsp

您的libstm32f4_hal.a存档已定义功能HAL_SPI_GetState,此功能由libstm32f4_bsp.a存档使用。

因此,您的链接命令中的归档顺序错误。您应该知道链接器(ld,通常由gcc调用以执行实际的链接步骤)从左到右处理输入存档(.a文件),请查看{{1}的手册页} http://linux.die.net/man/1/ld

  

通常,存档只按命令行中指定的顺序搜索一次。

您可以尝试更改hal和bsp存档(ld(1))的顺序,但如果它也失败,那么您将具有循环依赖性。您可以在链接命令(-lstm32f4_bsp ... -lstm32f4_hal)中多次提及库,或者只是指示链接器使用-lstm32f4_bsp ... -lstm32f4_hal -lstm32f4_bsp-(-)和{{1来遍历存档的子列表链接器选项,如man和https://stackoverflow.com/a/5651895/196561中所述。应该在具有循环依赖关系的库周围放置选项:--start-group

man page of ld

中选项的完整说明
  

--end-group   --start-group -lstm32f4_bsp ... -lstm32f4_hal --end-group

     

档案应该是档案文件列表。它们可以是显式文件名,也可以是-( archives -)选项。

     

重复搜索指定的存档,直到没有创建新的未定义引用。通常,只按命令行中指定的顺序搜索存档一次。如果需要该存档中的符号来解析稍后在命令行中显示的存档中的对象引用的未定义符号,则链接器将无法解析该引用。通过对存档进行分组,可以反复搜索所有存档,直到所有可能的引用都得到解决。

     

使用此选项会产生显着的性能损失。最好只在两个或多个档案之间存在不可避免的循环引用时使用它。

当您使用gcc调用链接器时,如果您的gcc不识别它们,请使用--start-group archives --end-group前缀将选项传递给链接器:-l

当您使用shell / make时,您可能需要在短选项中引用-Wl,-Wl,--start-group -lstm32f4_bsp ... -lstm32f4_hal -Wl,--end-group,例如使用单引号:(