链接多个静态库
Linking multiple static libraries
首先要说的是,这是我第一次真正接触 GCC,如果这个问题不是很有建设性或之前有人回答过,我深表歉意。
我有两个静态库:
"L1.h"
void __attribute__((weak)) Logger_Init(void) { // Invalid... }
"L2.h"
void Logger_Init(void);
"L2.c"
void Logger_Init(void)
{
// Do stuff...
}
我的目标是让某些可执行文件将“L2”包含到编译过程中并覆盖“L1”的 Logger_Init
实现。
我读到 here 你不能 link 两个静态库,但我会检查是否在 运行 时甚至调用 Logger_Init
,所以我需要编译期间函数的声明。
在可执行项目中,有一个添加库路径和名称的选项,我在其中添加了这两个库。我的第一个问题是,这里的顺序重要吗?我在下面使用了这两个命令,但没有任何区别(它们被修剪了很多,但我认为这是相关的部分)。
gcc -L(L1_PATH) -L(L2_PATH) -l(L1_NAME) -l(L2_NAME)
gcc -L(L2_PATH) -L(L1_PATH) -l(L2_NAME) -l(L1_NAME)
我的主要问题是,如何告诉 linker(?) 在另一个静态库中有一个函数的强定义,或者类似的东西?
我还读到使用 __attribute__((weak))
对静态库不是很有帮助,但我不太明白为什么,它似乎完全符合我想要实现的目标。
我可以编译 运行 这里的所有内容,但是 Logger_Init
的“L2”实现不会被调用。
我在嵌入式环境中工作,所以使用 dynamic/shared 库是不可能的。
编辑:
根据请求,Bodo,这是完整的命令列表。这些命令不是我写的,它们都是 Vitis 自动生成的。这是我 运行 编写代码的地方。我打开详细并让它撕裂。超过一半的东西对我来说是胡言乱语,我很抱歉膨胀。最底部是有用的东西。
make all
make --no-print-directory pre-build
a9-linaro-pre-build-step
' '
make --no-print-directory main-build
'Building file: ../src/main.c'
'Invoking: ARM v7 gcc compiler'
arm-none-eabi-gcc -Wall -O0 -g3 -c -fmessage-length=0 -MT"src/main.o"
-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -v -IC:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-MMD -MP -MF"src/main.d" -MT"src/main.o" -o "src/main.o" "../src/main.c"
Using built-in specs.
COLLECT_GCC=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\arm-xilinx-eabi-gcc.exe
Target: arm-xilinx-eabi
Configured with: ../../../../../../work-shared/gcc-9.2.0-r0/gcc-9.2.0/configure
--build=x86_64-linux --host=x86_64-oesdk-mingw32 --target=arm-xilinx-eabi --prefix=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr --exec_prefix=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr
--bindir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi
--sbindir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi
--libexecdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/libexec/arm-xilinx-eabi
--datadir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share
--sysconfdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/etc --sharedstatedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/com
--localstatedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/var
--libdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi
--includedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/us r/include
--oldincludedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/include
--infodir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share/info --mandir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share/man
--disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot
--enable-clocale=generic --with-gnu-ld --enable-shared --enable-languages=c,c++ --enable-threads=posix --enable-multilib --enable-c99 --enable-long-long --enable-libstdcxx-pch --program-prefix=arm-xilinx-eabi- --without-local-prefix --enable-lto --disable-libssp --enable-libitm --disable-bootstrap --disable-libmudflap --with-system-zlib --enable-linker-build-id --with-ppl=no --with-cloog=no --enable-checking=release --enable-cheaders=c_global --without-isl --with-gxx-include-dir=/not/exist/usr/include/c++/9.2.0 --wi th-build-time-tools=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot-native/usr/arm-xilinx-eabi/bin
--with-build-sysroot=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot
--enable-poison-system-directories --disable-nls --enable-initfini-array --without-headers --with-newlib --disable-libstdcxx-pch --with-newlib --disable-threads --enable-plugins --with-gnu-as --disable-libitm --with-multilib-list=aprofile --enable-multilib --disable-nls --enable-mingw-wildcard --with-sysroot=/not/exist
Thread model: single
gcc version 9.2.0 (GCC)
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/cc1.exe
-quiet -v -I C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-imultilib thumb/v7-a+fp/hard -iprefix c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/
-isysroot C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi
-MMD src/main.d -MF src/main.d -MP -MT src/main.o -MT src/main.o -dD -D__USES_INITFINI__ ../src/main.c -quiet -dumpbase main.c -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -marm -march=armv7-a+mp+sec+vfpv3 -auxbase-strip src/main.o -g3 -O0 -Wall -version -fmessage-length=0 -o C:\Users\M257B~1.BLA\AppData\Local\Temp\ccOuqloW.s
GNU C17 (GCC) version 9.2.0 (arm-xilinx-eabi)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version
4.0.2, MPC version 1.1.0, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../../arm-xilinx-eabi/include"
ignoring duplicate directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include"
ignoring nonexistent directory "C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi/usr/lib/arm-xilinx-eabi/9.2.0/include"
ignoring nonexistent directory "C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../include"
ignoring duplicate directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include-fixed"
ignoring nonexistent directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../../arm-xilinx-eabi/include"
#include "..." search starts here:
#include <...> search starts here:
C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include
c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include-fixed
C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi/usr/include
End of search list.
GNU C17 (GCC) version 9.2.0 (arm-xilinx-eabi)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version
4.0.2, MPC version 1.1.0, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 2516cb1a757555b312b0344a413e7d9c
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/as.exe
-v -I C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-march=armv7-a+mp+sec -mfloat-abi=hard -mfpu=vfpv3 -meabi=5 -o src/main.o C:\Users\M257B~1.BLA\AppData\Local\Temp\ccOuqloW.s
GNU assembler version 2.32.0 (arm-xilinx-eabi) using BFD version (GNU Binutils) 2.32.0.20190204
COMPILER_PATH=c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/
LIBRARY_PATH=C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/thumb/v7-a+fp/hard/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../lib/arm-xilinx-eabi/gcc/;C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/arm-xilinx-eabi/9.2.0/;C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
'Finished building: ../src/main.c'
' '
'Building target: PicoZed_Main.elf'
'Invoking: ARM v7 gcc linker'
arm-none-eabi-gcc
-L"C:\Projects\Xilinx\Experiment\PicoZed\PicoZed.vitis\Library1\Debug" -L"C:\Projects\Xilinx\Experiment\PicoZed\PicoZed.vitis\Library2\Debug" -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -Wl,-build-id=none -specs=Xilinx.spec -Wl,-T -Wl,../src/lscript.ld -LC:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bsplib/lib
-o "PicoZed_Main.elf" ./src/main.o -lLibrary1 -lLibrary2 -Wl,--start-group,-lxil,-lgcc,-lc,--end-group
'Finished building target: PicoZed_Main.elf'
' '
'Invoking: ARM v7 Print Size'
arm-none-eabi-size PicoZed_Main.elf |tee "PicoZed_Main.elf.size"
text data bss dec hex filename
18736 1144 22568 42448 a5d0 PicoZed_Main.elf
'Finished building: PicoZed_Main.elf.size'
' '
My first question is, does the order matter here?
是的,字面上来自gcc documentation:
-l library
...
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o. If bar.o refers to functions in ‘z’, those functions may not be loaded.
how to tell the linker(?) that there is a strong definition of the function in another static library, or something along those lines?
通常在现代嵌入式中:
-Wl,--whole-archive -l(L1_NAME) -l(L2_NAME) -Wl,--no-whole-archive
另一种方法是解压两个库并将目标文件传递给 gcc。
but I'm not really understanding why
链接器搜索直到 库中的第一个 符号,按顺序。因此,无论您先放哪个 - 带有 weak 或 strong 的库 - 都会使用该符号,而所有后续相同的符号都将被忽略。
I can compile and run everything here, however "L2" implementation of Logger_Init doesn't get called.
这很奇怪,因为您的 post 中的 -l(L2_NAME) -l(L1_NAME)
应该会调用 l2 实现。一个 MCVE:
cat >Makefile <<EOF
all: l1.a l2.a main.o
gcc main.o l1.a l2.a
./a.out
gcc main.o l2.a l1.a
./a.out
l2.a: l2.o
ar rcs $@ $<
l1.a: l1.o
ar rcs $@ $<
EOF
cat >main.c <<EOF
int main() {
void Logger_Init();
Logger_Init();
}
EOF
cat >l1.c <<EOF
void __attribute__((weak)) Logger_Init(void) {
puts("I am weak");
}
EOF
cat >l2.c <<EOF
void Logger_Init(void)
{
puts("I am strong");
}
EOF
结果:
$ make
...
gcc main.o l1.a l2.a
./a.out
I am weak
gcc main.o l2.a l1.a
./a.out
I am strong
即。以先到者为先。我还使用 -L. -ll2 -ll1
对其进行了测试,并将库重命名为 libl*.a
- 结果相同。我怀疑你的检查方法有问题。
Make已经44岁了,是个留着长胡子的爷爷了。使用现代的东西,比如 cmake。
使用 weak
属性可能会导致非常糟糕的意大利面条代码,以后很难修复和重构。考虑只使用带有 get/set 访问器的函数指针。
Can you tell us more about why you think weak functions are bad? @Bktero
基于意见:
缺点:
- 编译器特定语法,非 portable 代码,非标准。
- 如果不可重入,则很难修补以允许传递用户指定的上下文。
- 您可以在代码中的任何地方覆盖函数。它基本上是你的意大利面代码的辣酱。
- IDE一头雾水,不知道跳转到哪里定义,因为有两个。
- 很难进行单元测试,因为:
- 一个executable可以提供一个函数重载,所以:
- 使用多个 executable 进行单元测试需要更多的编写
- 这使得使用 IDE“转到定义”功能变得非常糟糕,因为那样你会得到越来越多的相同功能的定义
- 使用带有 settable 函数指针的包装器进行单元测试是解决方案,它...它可以作为回调本身实现。
- 如果它是 library/subsystem 的回调:
- 基本上允许该库的一个实例
- 随着编程的发展,需要同一个库的多个实例
- 这需要 writing/merging 来自多个代码位置的单个入口点。
- 合并多个项目很难,因为:
- 想象一个带有弱回调的库
- 两个库正在使用该库并覆盖该弱回调
- 那么你不能同时使用这两个库,你只会得到一个函数的重复定义。
- 它需要对这些库进行修补或选择性编译。
- 它需要一个 单个 入口点和一个调用它的库 table。
- 意大利面条代码。
- 如 OP 所述 - 与顺序相关的静态库链接问题,需要使用编译器特定语法解决
--whole-archive
。因为它取决于顺序,所以它可能会令人惊讶,有时有效,有时无效,从而导致令人惊讶和意想不到的错误,因为您仅更改库和 oops 的顺序 - 您的应用程序无法正常工作。
与全局变量类似的问题。基本上与信号相同的问题。与信号相同的解决方案 - 使用函数指针。就像将 SA_SIGINFO
与 sigaction
一起使用允许使用自定义 void *context
指针传递自定义函数指针一样。
优点:
- 更快的代码
- 减少打字
Any experience to share?
好吧,我使用并研究了弱(或未定义)函数作为库的回调,它导致代码难以合并和重构。
STM32 HAL 库是用弱函数实现的,它们稍后可选择启用函数指针,现在它们的源代码中有 #if (USE_HAL_*_REGISTER_CALLBACKS == 1)
东西,参见前 stm32l0xx_hal_uart.h#L248
首先要说的是,这是我第一次真正接触 GCC,如果这个问题不是很有建设性或之前有人回答过,我深表歉意。
我有两个静态库:
"L1.h"
void __attribute__((weak)) Logger_Init(void) { // Invalid... }
"L2.h"
void Logger_Init(void);
"L2.c"
void Logger_Init(void)
{
// Do stuff...
}
我的目标是让某些可执行文件将“L2”包含到编译过程中并覆盖“L1”的 Logger_Init
实现。
我读到 here 你不能 link 两个静态库,但我会检查是否在 运行 时甚至调用 Logger_Init
,所以我需要编译期间函数的声明。
在可执行项目中,有一个添加库路径和名称的选项,我在其中添加了这两个库。我的第一个问题是,这里的顺序重要吗?我在下面使用了这两个命令,但没有任何区别(它们被修剪了很多,但我认为这是相关的部分)。
gcc -L(L1_PATH) -L(L2_PATH) -l(L1_NAME) -l(L2_NAME)
gcc -L(L2_PATH) -L(L1_PATH) -l(L2_NAME) -l(L1_NAME)
我的主要问题是,如何告诉 linker(?) 在另一个静态库中有一个函数的强定义,或者类似的东西?
我还读到使用 __attribute__((weak))
对静态库不是很有帮助,但我不太明白为什么,它似乎完全符合我想要实现的目标。
我可以编译 运行 这里的所有内容,但是 Logger_Init
的“L2”实现不会被调用。
我在嵌入式环境中工作,所以使用 dynamic/shared 库是不可能的。
编辑:
根据请求,Bodo,这是完整的命令列表。这些命令不是我写的,它们都是 Vitis 自动生成的。这是我 运行 编写代码的地方。我打开详细并让它撕裂。超过一半的东西对我来说是胡言乱语,我很抱歉膨胀。最底部是有用的东西。
make all
make --no-print-directory pre-build
a9-linaro-pre-build-step
' '
make --no-print-directory main-build
'Building file: ../src/main.c'
'Invoking: ARM v7 gcc compiler'
arm-none-eabi-gcc -Wall -O0 -g3 -c -fmessage-length=0 -MT"src/main.o"
-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -v -IC:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-MMD -MP -MF"src/main.d" -MT"src/main.o" -o "src/main.o" "../src/main.c"
Using built-in specs.
COLLECT_GCC=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\arm-xilinx-eabi-gcc.exe
Target: arm-xilinx-eabi
Configured with: ../../../../../../work-shared/gcc-9.2.0-r0/gcc-9.2.0/configure
--build=x86_64-linux --host=x86_64-oesdk-mingw32 --target=arm-xilinx-eabi --prefix=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr --exec_prefix=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr
--bindir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi
--sbindir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi
--libexecdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/libexec/arm-xilinx-eabi
--datadir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share
--sysconfdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/etc --sharedstatedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/com
--localstatedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/var
--libdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi
--includedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/us r/include
--oldincludedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/include
--infodir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share/info --mandir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share/man
--disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot
--enable-clocale=generic --with-gnu-ld --enable-shared --enable-languages=c,c++ --enable-threads=posix --enable-multilib --enable-c99 --enable-long-long --enable-libstdcxx-pch --program-prefix=arm-xilinx-eabi- --without-local-prefix --enable-lto --disable-libssp --enable-libitm --disable-bootstrap --disable-libmudflap --with-system-zlib --enable-linker-build-id --with-ppl=no --with-cloog=no --enable-checking=release --enable-cheaders=c_global --without-isl --with-gxx-include-dir=/not/exist/usr/include/c++/9.2.0 --wi th-build-time-tools=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot-native/usr/arm-xilinx-eabi/bin
--with-build-sysroot=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot
--enable-poison-system-directories --disable-nls --enable-initfini-array --without-headers --with-newlib --disable-libstdcxx-pch --with-newlib --disable-threads --enable-plugins --with-gnu-as --disable-libitm --with-multilib-list=aprofile --enable-multilib --disable-nls --enable-mingw-wildcard --with-sysroot=/not/exist
Thread model: single
gcc version 9.2.0 (GCC)
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/cc1.exe
-quiet -v -I C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-imultilib thumb/v7-a+fp/hard -iprefix c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/
-isysroot C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi
-MMD src/main.d -MF src/main.d -MP -MT src/main.o -MT src/main.o -dD -D__USES_INITFINI__ ../src/main.c -quiet -dumpbase main.c -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -marm -march=armv7-a+mp+sec+vfpv3 -auxbase-strip src/main.o -g3 -O0 -Wall -version -fmessage-length=0 -o C:\Users\M257B~1.BLA\AppData\Local\Temp\ccOuqloW.s
GNU C17 (GCC) version 9.2.0 (arm-xilinx-eabi)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version
4.0.2, MPC version 1.1.0, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../../arm-xilinx-eabi/include"
ignoring duplicate directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include"
ignoring nonexistent directory "C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi/usr/lib/arm-xilinx-eabi/9.2.0/include"
ignoring nonexistent directory "C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../include"
ignoring duplicate directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include-fixed"
ignoring nonexistent directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../../arm-xilinx-eabi/include"
#include "..." search starts here:
#include <...> search starts here:
C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include
c:\xilinx\vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include-fixed
C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi/usr/include
End of search list.
GNU C17 (GCC) version 9.2.0 (arm-xilinx-eabi)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version
4.0.2, MPC version 1.1.0, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 2516cb1a757555b312b0344a413e7d9c
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/as.exe
-v -I C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-march=armv7-a+mp+sec -mfloat-abi=hard -mfpu=vfpv3 -meabi=5 -o src/main.o C:\Users\M257B~1.BLA\AppData\Local\Temp\ccOuqloW.s
GNU assembler version 2.32.0 (arm-xilinx-eabi) using BFD version (GNU Binutils) 2.32.0.20190204
COMPILER_PATH=c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/
LIBRARY_PATH=C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/thumb/v7-a+fp/hard/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../lib/arm-xilinx-eabi/gcc/;C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/arm-xilinx-eabi/9.2.0/;C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis20.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
'Finished building: ../src/main.c'
' '
'Building target: PicoZed_Main.elf'
'Invoking: ARM v7 gcc linker'
arm-none-eabi-gcc
-L"C:\Projects\Xilinx\Experiment\PicoZed\PicoZed.vitis\Library1\Debug" -L"C:\Projects\Xilinx\Experiment\PicoZed\PicoZed.vitis\Library2\Debug" -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -Wl,-build-id=none -specs=Xilinx.spec -Wl,-T -Wl,../src/lscript.ld -LC:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bsplib/lib
-o "PicoZed_Main.elf" ./src/main.o -lLibrary1 -lLibrary2 -Wl,--start-group,-lxil,-lgcc,-lc,--end-group
'Finished building target: PicoZed_Main.elf'
' '
'Invoking: ARM v7 Print Size'
arm-none-eabi-size PicoZed_Main.elf |tee "PicoZed_Main.elf.size"
text data bss dec hex filename
18736 1144 22568 42448 a5d0 PicoZed_Main.elf
'Finished building: PicoZed_Main.elf.size'
' '
My first question is, does the order matter here?
是的,字面上来自gcc documentation:
-l library
...
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o. If bar.o refers to functions in ‘z’, those functions may not be loaded.
how to tell the linker(?) that there is a strong definition of the function in another static library, or something along those lines?
通常在现代嵌入式中:
-Wl,--whole-archive -l(L1_NAME) -l(L2_NAME) -Wl,--no-whole-archive
另一种方法是解压两个库并将目标文件传递给 gcc。
but I'm not really understanding why
链接器搜索直到 库中的第一个 符号,按顺序。因此,无论您先放哪个 - 带有 weak 或 strong 的库 - 都会使用该符号,而所有后续相同的符号都将被忽略。
I can compile and run everything here, however "L2" implementation of Logger_Init doesn't get called.
这很奇怪,因为您的 post 中的 -l(L2_NAME) -l(L1_NAME)
应该会调用 l2 实现。一个 MCVE:
cat >Makefile <<EOF
all: l1.a l2.a main.o
gcc main.o l1.a l2.a
./a.out
gcc main.o l2.a l1.a
./a.out
l2.a: l2.o
ar rcs $@ $<
l1.a: l1.o
ar rcs $@ $<
EOF
cat >main.c <<EOF
int main() {
void Logger_Init();
Logger_Init();
}
EOF
cat >l1.c <<EOF
void __attribute__((weak)) Logger_Init(void) {
puts("I am weak");
}
EOF
cat >l2.c <<EOF
void Logger_Init(void)
{
puts("I am strong");
}
EOF
结果:
$ make
...
gcc main.o l1.a l2.a
./a.out
I am weak
gcc main.o l2.a l1.a
./a.out
I am strong
即。以先到者为先。我还使用 -L. -ll2 -ll1
对其进行了测试,并将库重命名为 libl*.a
- 结果相同。我怀疑你的检查方法有问题。
Make已经44岁了,是个留着长胡子的爷爷了。使用现代的东西,比如 cmake。
使用 weak
属性可能会导致非常糟糕的意大利面条代码,以后很难修复和重构。考虑只使用带有 get/set 访问器的函数指针。
Can you tell us more about why you think weak functions are bad? @Bktero
基于意见:
缺点:
- 编译器特定语法,非 portable 代码,非标准。
- 如果不可重入,则很难修补以允许传递用户指定的上下文。
- 您可以在代码中的任何地方覆盖函数。它基本上是你的意大利面代码的辣酱。
- IDE一头雾水,不知道跳转到哪里定义,因为有两个。
- 很难进行单元测试,因为:
- 一个executable可以提供一个函数重载,所以:
- 使用多个 executable 进行单元测试需要更多的编写
- 这使得使用 IDE“转到定义”功能变得非常糟糕,因为那样你会得到越来越多的相同功能的定义
- 使用带有 settable 函数指针的包装器进行单元测试是解决方案,它...它可以作为回调本身实现。
- 如果它是 library/subsystem 的回调:
- 基本上允许该库的一个实例
- 随着编程的发展,需要同一个库的多个实例
- 这需要 writing/merging 来自多个代码位置的单个入口点。
- 合并多个项目很难,因为:
- 想象一个带有弱回调的库
- 两个库正在使用该库并覆盖该弱回调
- 那么你不能同时使用这两个库,你只会得到一个函数的重复定义。
- 它需要对这些库进行修补或选择性编译。
- 它需要一个 单个 入口点和一个调用它的库 table。
- 意大利面条代码。
- 如 OP 所述 - 与顺序相关的静态库链接问题,需要使用编译器特定语法解决
--whole-archive
。因为它取决于顺序,所以它可能会令人惊讶,有时有效,有时无效,从而导致令人惊讶和意想不到的错误,因为您仅更改库和 oops 的顺序 - 您的应用程序无法正常工作。
与全局变量类似的问题。基本上与信号相同的问题。与信号相同的解决方案 - 使用函数指针。就像将 SA_SIGINFO
与 sigaction
一起使用允许使用自定义 void *context
指针传递自定义函数指针一样。
优点:
- 更快的代码
- 减少打字
Any experience to share?
好吧,我使用并研究了弱(或未定义)函数作为库的回调,它导致代码难以合并和重构。
STM32 HAL 库是用弱函数实现的,它们稍后可选择启用函数指针,现在它们的源代码中有 #if (USE_HAL_*_REGISTER_CALLBACKS == 1)
东西,参见前 stm32l0xx_hal_uart.h#L248