Reputation: 95
let me start by saying that this is my first time really meddling with GCC, so I apologize if this question is not very constructive or has been answered before.
I have two static libraries:
"L1.h"
void __attribute__((weak)) Logger_Init(void) { // Invalid... }
"L2.h"
void Logger_Init(void);
"L2.c"
void Logger_Init(void)
{
// Do stuff...
}
My goal is for certain executables to include "L2" into the compilation process and override "L1"'s implementation of Logger_Init
.
I read here that you cannot link two static libraries, but I do the check of whether to even call Logger_Init
at runtime, so I need the declaration of the function during compilation.
In the executable project, there is an option to add library paths and names, in which I added both of these libraries. My first question is, does the order matter here? I played with these two commands below and it made no difference (they're trimmed up quite a bit, but I assume that this is the relevant part).
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)
My main question here though, is how to tell the linker(?) that there is a strong definition of the function in another static library, or something along those lines?
I've also read that using the __attribute__((weak))
is not very helpful for static libraries, but I'm not really understanding why, it seems like it does exactly what I am trying to achieve.
I can compile and run everything here, however "L2" implementation of Logger_Init
doesn't get called.
I am working in an embedded environment, so using dynamic/shared libraries is out of the question.
EDIT:
Per request, Bodo, here is the entire list of command. I am not writing these commands, they're all auto-generated by Vitis. This is where I'm running my code. I turned verbose on and let it rip. Over half of this stuff is gibberish to me, I am sorry for the bloat. Towards the very bottom is the useful stuff.
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\Vitis\2020.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\Vitis\2020.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\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/
-isysroot C:\Xilinx\Vitis\2020.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\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/../../../../../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\Vitis\2020.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\Vitis\2020.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\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/include
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/include-fixed
C:\Xilinx\Vitis\2020.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\Vitis\2020.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\Vitis\2020.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'
' '
Upvotes: 0
Views: 2376
Reputation: 140880
My first question is, does the order matter here?
Yes, literally from 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?
Typically in modern embedded:
-Wl,--whole-archive -l(L1_NAME) -l(L2_NAME) -Wl,--no-whole-archive
Another alternative is to unpack both libraries and pass object files to gcc.
but I'm not really understanding why
Linker searches up until the first symbol in libraries, in order. So whichever you put first - the library with weak or with strong - that symbol will be used and all following same symbols will just be ignored.
I can compile and run everything here, however "L2" implementation of Logger_Init doesn't get called.
That's odd, because -l(L2_NAME) -l(L1_NAME)
that is in your post should result in l2 implementation called. An 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
results in:
$ 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
ie. whichever is first, is first. I tested it also with -L. -ll2 -ll1
and renamed libraries to libl*.a
- same result. I suspect your method of checking was flawed.
Make has 44 years, it's a grandpa with a long beard. Use something modern, like cmake.
Using weak
attribute may lead to very bad spaghetti code that is very, very hard to fix and refactor later. Consider just using a function pointer with get/set accessors.
Can you tell us more about why you think weak functions are bad? @Bktero
Opinion based:
Disadvantages:
--whole-archive
. Because it depends on order, it can be surprising, sometimes work and sometimes not, resulting in surprising and unexpected bugs, because you only change the order of libraries and oops - your application does not work.Similar problems to global variables. Basically same problems as with signals. Same solution as to signals - using function pointers. Just like using SA_SIGINFO
with sigaction
allows to pass a custom function pointer with custom void *context
pointer.
Advantages:
Any experience to share?
Well, I used and researched weak (or undefined) functions as callback from libraries and it resulted in code that is hard to merge and hard to refactor.
STM32 HAL libraries were implemented with weak functions, they optionally enabled function pointers later, now there is a #if (USE_HAL_*_REGISTER_CALLBACKS == 1)
stuff in their sources, see ex stm32l0xx_hal_uart.h#L248
Upvotes: 2