title: How can I avoid undefined symbols when linking libraries against each other with arm-none-eabi-ar
body: <p>I'm using the arm-none-eabi-gcc toolchain onlinux and am having trouble creating archives that link to other archives. As a specific example, the base archive (libstm32f4_hal.a) should have a function <code>HAL_SPI_GetState</code> and using <code>nm</code>, it seems that it does </p>
  
  <pre><code>$ nm libstm32f4_hal.a
  stm32f4xx_hal_spi.o:
  ...
  0000158d T HAL_SPI_GetState
  00001495 T HAL_SPI_IRQHandler
  00000271 T HAL_SPI_Init
  ...
  </code></pre>
  
  <p>I then want to make another archive (libstm32f4_bsp.a) which makes use of libstm32f4_hal.a. The second archive seems to build correctly, but when I try and link against these libraries, the linker throws the following error.</p>
  
  <pre><code>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'
  </code></pre>
  
  <p>When I check libstm32f4_bsp.a using <code>nm</code>, indeed the function <code>HAL_SPI_GetState</code> is not defined.</p>
  
  <pre><code>$ nm libstm32f4_bsp.a
  stm32f4_discovery.o:
  ...
           U HAL_SPI_GetState
           U HAL_SPI_Init
  ...
  </code></pre>
  
  <p>Here is the makefile I'm using to build the second archive.</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Could someone explain why this might be happening? I'd be happy to provide more details but am relatively inexperienced with what I'm trying to do here and am not completely sure what else would be helpful.</p>
  
  <p>The context is, I'm trying to build the demonstration code for the STM32F4-Discovery board. It basically sets up the board to act as a USB mouse. Since the USB stack is huge, my plan is to build the hardware abstraction layer (HAL) as an archive, then build the board-specific middleware as an archive linked to the HAL archive, and then in my final build link the demonstration code to these two archives.</p>
  
  <p>Thanks for the help.</p>
  
  <p>EDIT:</p>
  
  <p>Here is the makefile I'm using to build the project.</p>
  
  <pre><code># 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 &lt;post@steffenvogel.de&gt;
  # 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 = &gt; /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 $&lt;)"
      $Q$(CC) $(CFLAGS) -c -o $@ $&lt; -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 &gt;$(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)
  </code></pre>
  
  <p>Here is the failed linking command.</p>
  
  <pre><code>`arm-none-eabi-gcc -Wall -g -std=c99 -Os -mlittle-endian -mcpu=cortex-m4 -march=armv7e-m -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Itemplate/inc -Icube/Drivers/BSP/STM32F4-Discovery -Icube/Drivers/CMSIS/Include -Icube/Drivers/CMSIS/Device/ST/STM32F4xx/Include -Icube/Drivers/STM32F4xx_HAL_Driver/Inc -Icube/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -Icube/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Inc -DSTM32F407xx -DUSE_HAL_DRIVER -DUSE_DBPRINTF -mthumb-interwork -Wl,--gc-sections -Wl,-Map=demo.map -Lcube/Drivers/CMSIS/Lib -Ttemplate/stm32f401xc.ld --specs=rdimon.specs -lc -lrdimon template/src/startup_stm32f401xc.s template/obj/main.o template/obj/system_stm32f4xx.o template/obj/stm32f4xx_it.o template/obj/usbd_conf_template.o template/obj/usbd_core.o template/obj/usbd_ctlreq.o template/obj/usbd_ioreq.o template/obj/usbd_hid.o template/obj/usbd_desc.o template/obj/stm32f4xx_hal_pcd.o template/obj/stm32f4_discovery_accelerometer.o template/obj/stm32f4xx_hal_tim.o -o demo.elf -Lcube/Drivers/STM32F4xx_HAL_Driver -lstm32f4_hal -Lcube/Drivers/BSP/STM32F4-Discovery -lstm32f4_bsp'
  </code></pre>
  
  <p>I loaded the project to github <a href="https://github.com/hobenkr88/ArmUsb" rel="nofollow">here</a> in case anyone is motivated enough to try and build the project themselves. As a side note, I am running Arch linux.</p>