【问题标题】:linking succeeds with arm-none-eabi-g++ but not arm-none-eabi-gcc使用 arm-none-eabi-g++ 链接成功,但没有 arm-none-eabi-gcc
【发布时间】:2016-05-01 20:14:05
【问题描述】:

我正在使用 Launchpad Arm 编译器工具。具体来说,

arm-none-eabi-g++ 和 arm-none-eabi-gcc 来自:

(用于 ARM 嵌入式处理器的 GNU 工具)5.2.1 20151202(发布)[ARM/embedded-5-branch 修订版 231848]

我有一个针对 STM32F103 处理器的简单程序,除了证明我可以编写硬件并调用数学库中的函数之外,没有其他目的。就是这样:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "stm32f10x.h"

void hardwareTest(void){
   // Turn on the clock for PortB
   RCC->APB2ENR = RCC_APB2ENR_IOPBEN; // Turn on IO Port B
   // Put PB0 into push pull 50 MHz mode
   GPIOB->CRL = 0x03;
   // Turn PB0 on
   GPIOB->ODR = 1;
}

volatile int x; // force call to sqrt() later

int main(void) {
   x = sqrt(100.0f);
   x = sqrt(x);
   hardwareTest();
   return (x);
}

当我尝试构建它时,我收到一个链接器错误,告诉我有一个未定义的对 sqrt 的引用。构建是使用 arm-none-eabi-gcc 完成的。偶然我发现,如果使用 arm-none-eabi-g++ 完成构建,使用相同的命令行参数,则链接会成功执行。

我写了一个 Makefile 来演示区别:

PROJECT = minimal
SOURCES = src/startup_stm32f10x_hd.s \
          src/system_stm32f10x.c \
          src/main.c
OUTPUT = ./out
print-%:
    @echo '$*=$($*)'

TOOLCHAIN = arm-none-eabi-

CXX = $(TOOLCHAIN)g++
CC = $(TOOLCHAIN)gcc
AR = $(TOOLCHAIN)ar
AS = $(TOOLCHAIN)gcc -c -x assembler-with-cpp
LD =  $(TOOLCHAIN)gcc
OBJCOPY = $(TOOLCHAIN)objcopy
OBJDUMP = $(TOOLCHAIN)objdump
SIZE = $(TOOLCHAIN)size
RM = rm -f

CFLAGS  = -O
CFLAGS += -nostartfiles

CXXFLAGS  = -O
CXXFLAGS += -nostartfiles

ARCH = -mcpu=cortex-m3 -mthumb -DSTM32F10X_HD 
LDFLAGS = 

all: clean $(PROJECT).elf $(PROJECT).gcc $(PROJECT).bin

$(PROJECT).bin: $(PROJECT).elf 
    @echo ' ======== '
    @echo ' Generating binaries'
    $(OBJCOPY) -O binary $(OUTPUT)/$< $(OUTPUT)/$(PROJECT).bin
    $(OBJCOPY) -O ihex   $(OUTPUT)/$< $(OUTPUT)/$(PROJECT).hex
    @echo ' ======== '

$(PROJECT).elf: $(SOURCES)
    @echo ' ======== '
    @echo ' Successful build uses g++'
    @echo ' CXXFLAGS = $(CXXFLAGS)'
    @echo ' LDFLAGS = $(LDFLAGS)'
    @echo ' ARCH = $(ARCH)'
    $(CXX) -o $(OUTPUT)/$@ $(ARCH)  $(CXXFLAGS) $(LDFLAGS) -Wl,-Tld_script/stm32.ld,-lm  $^
    @echo ' ======== '

$(PROJECT).gcc: $(SOURCES)
    @echo ' ======== '
    @echo ' Broken build uses gcc'
    @echo ' CFLAGS = $(CFLAGS)'
    @echo ' LDFLAGS = $(LDFLAGS)'
    @echo ' ARCH = $(ARCH)'
    $(CC) -o $(OUTPUT)/$@ $(ARCH)   $(CFLAGS) $(LDFLAGS) -Wl,-Tld_script/stm32.ld,-lm  $^
    @echo ' ======== '

$(PROJECT).gxx: $(SOURCES)
    @echo ' ======== '
    @echo ' build with g++'
    $(CXX) -o $(OUTPUT)/$@ $(ARCH)  $(CXXFLAGS) $(LDFLAGS) -Wl,-Tld_script/stm32.ld  $^
    @echo ' ======== '

# Program the binary to the board using the builtin serial bootloader
program:
    stm32loader.py -p /dev/ttyUSB0 -ewv $(OUTPUT)/$(PROJECT).bin

# Remove the temporary files
clean:
    @echo ' '
    @echo ' Cleaning up: '
    $(RM) $(OUTPUT)/* *.o *.elf *.bin *.hex *.gcc *.gxx *.g++
    @echo ' ======== '

它给出以下结果:

Cleaning up: 
rm -f ./out/* *.o *.elf *.bin *.hex *.gcc *.gxx *.g++
======== 
======== 
 Successful build uses g++
 CXXFLAGS = -O -nostartfiles
 LDFLAGS = 
 ARCH = -mcpu=cortex-m3 -mthumb -DSTM32F10X_HD 
arm-none-eabi-g++ -o ./out/minimal.elf -mcpu=cortex-m3 -mthumb -DSTM32F10X_HD   -O -nostartfiles  -Wl,-Tld_script/stm32.ld,-lm  src/startup_stm32f10x_hd.s src/system_stm32f10x.c src/main.c
 ======== 
 ======== 
 Broken build uses gcc
 CFLAGS = -O -nostartfiles
 LDFLAGS = 
 ARCH = -mcpu=cortex-m3 -mthumb -DSTM32F10X_HD 
arm-none-eabi-gcc -o ./out/minimal.gcc -mcpu=cortex-m3 -mthumb -DSTM32F10X_HD    -O -nostartfiles  -Wl,-Tld_script/stm32.ld,-lm  src/startup_stm32f10x_hd.s src/system_stm32f10x.c src/main.c
/var/folders/t4/dv7b46055cjgknp4nndn1_zr0000gn/T//ccbl4swG.o: In function `main':
main.c:(.text+0x28): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
make: *** [minimal.gcc] Error 1
 ======== 
 Generating binaries
arm-none-eabi-objcopy -O binary ./out/minimal.elf ./out/minimal.bin
arm-none-eabi-objcopy -O ihex   ./out/minimal.elf ./out/minimal.hex
make: Target `all' not remade because of errors.

那么谁能告诉我为什么这两个编译器的行为不同?我忽略了什么简单的事情?如果我想使用 arm-none-eabi-gcc,我应该如何确保与 libm 和其他人的正确链接?

我查看了 Freddie Chopin 的 makefile,但它们太复杂了,我无法解开。

【问题讨论】:

  • C 和 C++ 是不同的语言。您希望 Java 编译器的行为相同吗?相同的句法和语法并不意味着相同的语义。
  • -lm 指定为gcc 的链接器标志的问题在哪里?行为符合预期,afaics。
  • 使用 -lm 标志对此处的结果没有影响

标签: c++ c gcc arm libm


【解决方案1】:

C++ 要求数学函数是基本运行时的一部分,而 C 允许它们在库中。 GCC 实现通过在 C++ 构建中自动链接 libm 来实现这一点。

链接阶段还有很多其他的不同;如果使用 C 链接器,C++ 链接将始终失败。

对于 C 链接,使用 C 链接器并指定 -lm 以使 libm 可用。

【讨论】:

  • 使用 -lm 对结果没有影响
  • 顺序很重要。 -lm 必须出现在 gcc 的参数中所有需要该库的目标文件之后。顺便说一句,gcc 接受-lm 作为选项;您无需将其隐藏在 -Wl
  • 太棒了!我确信我之前读过一些关于链接器对象顺序的东西,但它并没有深入人心。在这个例子中,我只是将对象列表移动到 LDFLAGS 条目之前,然后将 -lm 添加到 LDFLAGS 并且一切正常。
  • @peter:把 LDFLAGS 放在最后也不总是正确的,这也是为什么很多 makefile(包括 gmake 的内置规则)同时具有 LDFLAGS 和 LDLIBS 的原因。
  • 好的。好点子。谢谢你。我忽略了 orderin,假设如果排序很重要,相互依赖的目标文件将无法链接。但是,我现在认为它们会很好,但静态库是另一个问题。
猜你喜欢
  • 1970-01-01
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 2017-10-10
  • 1970-01-01
相关资源
最近更新 更多