I am using GCC for ARM (Red Suite 4 NXP). I am compiling static library files (.a) that are used for a final application. I need to configure the project so any developer can produce the exact same static library output. (This is mainly so a new developer can verify they have their setup correct.) I have two copies of my project (two checkouts from SVN). When I build with each, I notice some absolute path information in the static library .a output files. This means that SVN detects as a change. I'm using the ar -D (deterministic) option already. Are there any other options to remove path information? I tried gcc -s but this didn't work (it appears this is only for final executable, not libraries)
I don't know where/why the absolute paths are in the .a, but I can provide more information if someone can point me in the right direction.
I've looked at the strip utility man pages (haven't tried it yet), would this remove this path information?
Also, I am using Red Suite to manage the project, so I'm trying to do things the Red Suite way (and to let it do its thing). However, if there is a gcc or ar option I need to adjust, I do know how to do that. I just don't know what option to change.
Here is the build console output. This causes the absolute path of my project to be included into the resulting .a. That is what I am trying to fix.
**** Build of configuration Release for project lib_touch ****
make -j all
Building file: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/Touch.c
Building file: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchCalibration.c
Building file: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchPoint.c
Building file: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchEventQueue.c
Invoking: MCU C Compiler
Invoking: MCU C Compiler
arm-none-eabi-gcc -D__REDLIB__ -DNDEBUG -D__CODE_RED -D__USE_CMSIS=CMSISv2p00_LPC177x_8x -I"C:\Users\my_user_name\Documents\My Project Verification build\src\build\RedSuite4NXP\CMSISv2p00_LPC177x_8x\inc" -I../../../../board -I../../../../board/lpc1788 -I../../../../communication -I../../../../events -I../../../../geometry -I../../../../graphics -I../../../../hmilogic/include -I../../../../sound -I../../../../util -O3 -Wall -Werror -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -std=gnu99 -mcpu=cortex-m3 -mthumb -MMD -MP -MF"touch/Touch.d" -MT"touch/Touch.d" -o"touch/Touch.o" "C:/Users/my_user_name/Documents/My Project Verification build/src/touch/Touch.c"
arm-none-eabi-gcc -D__REDLIB__ -DNDEBUG -D__CODE_RED -D__USE_CMSIS=CMSISv2p00_LPC177x_8x -I"C:\Users\my_user_name\Documents\My Project Verification build\src\build\RedSuite4NXP\CMSISv2p00_LPC177x_8x\inc" -I../../../../board -I../../../../board/lpc1788 -I../../../../communication -I../../../../events -I../../../../geometry -I../../../../graphics -I../../../../hmilogic/include -I../../../../sound -I../../../../util -O3 -Wall -Werror -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -std=gnu99 -mcpu=cortex-m3 -mthumb -MMD -MP -MF"touch/TouchCalibration.d" -MT"touch/TouchCalibration.d" -o"touch/TouchCalibration.o" "C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchCalibration.c"
Invoking: MCU C Compiler
Invoking: MCU C Compiler
arm-none-eabi-gcc -D__REDLIB__ -DNDEBUG -D__CODE_RED -D__USE_CMSIS=CMSISv2p00_LPC177x_8x -I"C:\Users\my_user_name\Documents\My Project Verification build\src\build\RedSuite4NXP\CMSISv2p00_LPC177x_8x\inc" -I../../../../board -I../../../../board/lpc1788 -I../../../../communication -I../../../../events -I../../../../geometry -I../../../../graphics -I../../../../hmilogic/include -I../../../../sound -I../../../../util -O3 -Wall -Werror -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -std=gnu99 -mcpu=cortex-m3 -mthumb -MMD -MP -MF"touch/TouchEventQueue.d" -MT"touch/TouchEventQueue.d" -o"touch/TouchEventQueue.o" "C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchEventQueue.c"
Finished building: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/Touch.c
arm-none-eabi-gcc -D__REDLIB__ -DNDEBUG -D__CODE_RED -D__USE_CMSIS=CMSISv2p00_LPC177x_8x -I"C:\Users\my_user_name\Documents\My Project Verification build\src\build\RedSuite4NXP\CMSISv2p00_LPC177x_8x\inc" -I../../../../board -I../../../../board/lpc1788 -I../../../../communication -I../../../../events -I../../../../geometry -I../../../../graphics -I../../../../hmilogic/include -I../../../../sound -I../../../../util -O3 -Wall -Werror -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -std=gnu99 -mcpu=cortex-m3 -mthumb -MMD -MP -MF"touch/TouchPoint.d" -MT"touch/TouchPoint.d" -o"touch/TouchPoint.o" "C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchPoint.c"
Finished building: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchEventQueue.c
Finished building: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchCalibration.c
Finished building: C:/Users/my_user_name/Documents/My Project Verification build/src/touch/TouchPoint.c
Building target: lib_touch.a
Invoking: MCU Archiver
arm-none-eabi-ar -rD "lib_touch.a" ./touch/Touch.o ./touch/TouchCalibration.o ./touch/TouchEventQueue.o ./touch/TouchPoint.o
c:\code_red\RedSuiteNXP_4.3.0_1033\redsuite\tools\bin\arm-none-eabi-ar.exe: creating lib_touch.a
Finished building target: lib_touch.a
make --no-print-directory post-build
Performing post-build steps
arm-none-eabi-size "lib_touch.a" ; cp "lib_touch.a" "../../../../lib/lib_touch.a"; # arm-none-eabi-objdump -h -S "lib_touch.a" >"lib_touch.lss"
text data bss dec hex filename
1864 0 156 2020 7e4 Touch.o (ex lib_touch.a)
576 0 0 576 240 TouchCalibration.o (ex lib_touch.a)
320 0 0 320 140 TouchEventQueue.o (ex lib_touch.a)
96 0 0 96 60 TouchPoint.o (ex lib_touch.a)
UPDATE: MORE INFORMATION
I have done some more digging, and it appears the full file path is in front of a string constant. The path data within the .a file shows
C:/Users/my_user_name/Documents/My Project Verification build/src/touch/Touch.c.TouchIdleTimer
I have a string literal "TouchIdleTimer" within the file Touch.c. Is this the cause? How would I remove the path portion, or is it possible? TIA
Update
Via this answer to GCC: static linking only some libraries
Note: If you use full path of a .so file, it will again be linked in dynamically.
Enhanced Static Library Support in Code Red IDE v4: Creating static library projects
Searching around I'm seeing suggestions for -fPIC or -fpic. It was recommended in this comment thread in response to a question similar to yours.
3.2 Shared libraries and static libraries provides a nice breakdown of compiling shared and static libraries.
You stated static not shared libraries but just in case: How to Write Shared Libraries
Related
Im using poky version of yocto, and adding zbar library in my yocto build. I found a readymade recipe at http://cgit.openembedded.org/meta-openembedded/tree/meta-oe/recipes-support/zbar/zbar_0.10.bb and modified it a bit to get working with poky. I got it working fine with imagemagick, and the compiled zbarimg works on the target board.
The modified recipe is available here: http://paste.ubuntu.com/25725000/
When I proceed configuring python support (--with-python) to the build, some dependency issues crept up, which Im unable to resolve.
It appears as if the compiler doesn't find the appropriate headers, since the include paths don't contain appropriate folder.
The full compiler command is:
arm-poky-linux-gnueabi-libtool: compile: arm-poky-linux-gnueabi-gcc -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a7 --sysroot=/home/jlumme/imx_build/build-x11-pico-imx6ul/tmp/sysroots/pico-imx6ul-emmc -DHAVE_CONFIG_H -I. -I/home/jlumme/imx_build/build-x11-pico-imx6ul/tmp/work/cortexa7hf-vfp-neon-poky-linux-gnueabi/zbar/0.10-r0/zbar-0.10 -I./include -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -I/usr/include/python2.7 -I/usr/include/python2.7 -I/home/jlumme/imx_build/build-x11-pico-imx6ul/tmp/work/cortexa7hf-vfp-neon-poky-linux-gnueabi/zbar/0.10-r0/zbar-0.10/include -Wall -Wno-parentheses -O2 -pipe -g -feliminate-unused-debug-types -c /home/jlumme/imx_build/build-x11-pico-imx6ul/tmp/work/cortexa7hf-vfp-neon-poky-linux-gnueabi/zbar/0.10-r0/zbar-0.10/python/symbol.c -fPIC -DPIC -o python/.libs/python_zbar_la-symbol.o
You can see that sysroot variable is set, and it appears like the right location, and there is /usr/include/python2.7 there, though its pointing right at the host system include path.
There is a warning from compiler: cc1: warning: include location "/usr/include/python2.7" is unsafe for cross-compilation [-Wpoison-system-directories] which I don't know why it happens, but it seems like the python2.7 folder is appropriately looked at, just not under the sysroot (my host system doesn't have /usr/lib/python2.7)
If I go to the sysroot include (/home/jlumme/imx_build/build-x11-pico-imx6ul/tmp/sysroots/pico-imx6ul-emmc/usr/include/) folder, I can see that it has a subfolder python2.7. If under this usr/include folder I add a symlink Python.h -> python2.7/Python.h, the compiler will complain about the next header file which is not found.
So to me it seems, all I should do is add the appropriate 'sysroot' + usr/include/python2.7 as include search folder it would compile happily - but Im not sure how..
The full compilation log is available here: http://paste.ubuntu.com/25725014/
This is a bug in the zbar configure script.
Try inheriting pythonnative so the configure script can run a compatible Python to know where to look.
I'm using Gradle and CMake to compile an Android NDK project from the command line. Previously, I was using Ant and ndk-build but I'm trying to migrate the project completely to Gradle and CMake.
In my build.gradle I have the following lines to invoke CMake:
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
Now how can I force CMake to print all compiler calls to the console before it makes them? Specifically, I want to see just how CMake runs the compiler and linker.
I've already tried the following, all to no avail:
1) In my CMakeLists.txt I have put the following line:
set(CMAKE_VERBOSE_MAKEFILE on)
Didn't have any effect.
2) I have started the build like this:
./gradlew build --info
Gradle printed some stuff, but no compiler calls.
3) And like this:
./gradlew build --debug
Gradle printed lots of stuff, but no compiler calls.
So none of those three attempts did what I wanted which makes me wonder how can I see how CMake runs clang on my individual source files?
Disclaimer: the following description applies to the version of Android Gradle Plugin (AGP) that was the latest at the time I updated this Answer (aug '21). If you are curious, have a look at the history of edits.
As #artyomd has noticed, for AGP 4.2.0 and higher, you can set android.native.buildOutput gradle property to verbose to force cmake logging.
In Android Studio, gradle creates directory .cxx under the module root, for each module that has NDK integration, via CMake or ndk-build.
For CMake, the gradle plugin is quite verbose. For each build variant it creates separate subdirectory, e.g. .cxx/cmake/debug/x86 or .cxx/cmake/release/armeabi-v7a, etc.
Each directory contains some useful files: cmake_build_command.txt describes the actual parameters passed to CMake; android_gradle_build.json shows what parameters the gradle plugin derived for your binaries; from build.ninja you can deduce the how these parameters were applied for each compilation or linkage step.
For ndk-build, the android_gradle_build.json file is also quite useful. ndkBuild_build_command.txt lists all parameters passed to ndk-build command, and ndkBuild_build_output.txt is the unabridged output of that command. You can easily add V=1 to the arguments, e.g.
externalNativeBuild {
ndkBuild {
cppFlags "-std=c++11"
arguments "APP_STL=c++_static", "APP_OPTIM=release", "NDK_DEBUG=0", "V=1"
abiFilters "armeabi-v7a"
}
}
For CMake, the relevant argument is "-DCMAKE_VERBOSE_MAKEFILE=ON" (see explanation
and alternatives):
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DCMAKE_VERBOSE_MAKEFILE=ON"
abiFilters "armeabi-v7a"
}
}
But, as #user7860670 has observed, the recent versions of AGP ignore this flag.
Without CMAKE_VERBOSE_MAKEFILE, the Gradle Console displays:
:app:externalNativeBuildDebug
Build native-lib armeabi-v7a
[1/2] Building CXX object CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o
[2/2] Linking CXX shared library ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so
With "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON", I used to get tons of output:
:app:externalNativeBuildDebug
Build native-lib armeabi-v7a
[1/2] /Users/alex/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ --target=armv5te-none-linux-androideabi --gcc-toolchain=/Users/alex/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=/Users/alex/Library/Android/sdk/ndk-bundle/platforms/android-14/arch-arm -Dnative_lib_EXPORTS -isystem /Users/alex/Library/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include -isystem /Users/alex/Library/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/include -isystem /Users/alex/Library/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/backward -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv5te -mtune=xscale -msoft-float -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv5te -mtune=xscale -msoft-float -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fno-limit-debug-info -O0 -fno-limit-debug-info -fPIC -MD -MT CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o -MF CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o.d -o CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o -c /Users/alex/test/egl/app/src/main/cpp/native-lib.cpp
[2/2] : && /Users/alex/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ --target=armv5te-none-linux-androideabi --gcc-toolchain=/Users/alex/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=/Users/alex/Library/Android/sdk/ndk-bundle/platforms/android-14/arch-arm -fPIC -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv5te -mtune=xscale -msoft-float -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv5te -mtune=xscale -msoft-float -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fno-limit-debug-info -O0 -fno-limit-debug-info -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o -llog -lEGL -lGLESv2 -lm "/Users/alex/Library/Android/sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a" "-latomic" && :
Not anymore. As far as I know, this information is filtered by Gradle Plugin and is completely lost. I can recover it only manually: run the command
/Users/alex/Library/Android/sdk/cmake/3.10.2.4988404/bin/cmake --build app/.cxx/cmake/debug/armeabi-v7a
You can use the Terminal window (Alt-F12) of Android Studio. This will invoke ninja with -v flag when -DCMAKE_VERBOSE_MAKEFILE=ON was used to sync C++ with Gradle.
Note that the expected file .cxx/cmake/debug/armeabi-v7a/cmake_build_output.txt does not contain interesting information (unless you have problems with CMake configuration per se).
P.S. with this 3.6.0 Gradle Plugin, if you have a compilation error, then the whole command line for compiler is shown in Build Output window, no matter whether you set CMAKE_VERBOSE_MAKEFILE or not. Actually, twice: once, in black on white (I don't use the dark theme), second time, in brown on white, after
FAILURE: Build failed with an exception.
* What went wrong:
As an ugly workaround I've replaced ninja with my own executable that passes all the commands to the real ninja executable appending "-v"
Try to update your gradle version.
I am working on a small project of mine on Digilent Atlys and after all of the standard generating the netlist and bitstream, and exporting to SDK, I happen to get a weird error which states that the xil_cache.h is not present anywhere (even though it is there).
I need to mention that if I don't add an interrupt controller and a timer it works, but I really do need them.
Has anyone encountered this error before?
Error Message:
08:24:21 **** Build of configuration Debug for project hiworld ****
make all
'Building file: ../src/helloworld.c'
'Invoking: MicroBlaze gcc compiler'
mb-gcc -Wall -O0 -g3 -c -fmessage-length=0 -I../../hiworld_bsp/microblaze_0/include -mlittle-endian -mxl-barrel-shift -mxl-pattern-compare -mcpu=v8.50.c -mno-xl-soft-mul -Wl,--no-relax -ffunction-sections -fdata-sections -MMD -MP -MF"src/helloworld.d" -MT"src/helloworld.d" -o "src/helloworld.o" "../src/helloworld.c"
'Finished building: ../src/helloworld.c'
' '
'Building file: ../src/platform.c'
'Invoking: MicroBlaze gcc compiler'
mb-gcc -Wall -O0 -g3 -c -fmessage-length=0 -I../../hiworld_bsp/microblaze_0/include -mlittle-endian -mxl-barrel-shift -mxl-pattern-compare -mcpu=v8.50.c -mno-xl-soft-mul -Wl,--no-relax -ffunction-sections -fdata-sections -MMD -MP -MF"src/platform.d" -MT"src/platform.d" -o "src/platform.o" "../src/platform.c"
../src/platform.c:43:23: fatal error: xil_cache.h: No such file or directory
compilation terminated.
make: *** [src/platform.o] Error 1
08:24:21 Build Finished (took 734ms)
Try after setting below environmental variables:
XILINX = C:\Xilinx\14.5\ISE_DS
XILINX_EDK = C:\Xilinx\14.5\ISE_DS\EDK\bin\nt64
this is suggested in the Xilinx forum and seems to solve the problem.
A user writes:
"Magic :-)
I created a batch file to launch it, as from what I know the path variables persit within that batch file
I set it to
set path=""
XILINX = C:\Xilinx\14.5\ISE_DS
XILINX_EDK = C:\Xilinx\14.5\ISE_DS\EDK\bin\nt64
C:\Xilinx\14.5\ISE_DS\EDK\bin\nt64\xsdk.exe
Interesting the shortcut to the SDK first contains a link to settings64.bat which I assumed set all these variables correctly, but it looks like it doesnt get them right!
I have to admit its been a trek just getting this far as the documentation is a bit blurry."
Here you can find the page.
Im developing an android app thats loading two shared libraries. One is external, its called libpcan.so . Usually its build to libpcan.so.0.6, this somehow cant be used by my android, i so changed the gcc flags compiling it from:
arm-linux-androideabi-gcc src/libpcan.c -fPIC -shared -O2 -Wall -Wl,-soname,-libpcan.so.0 -lc -I. -I../driver -DNO_RT -o -libpcan.so.0.6
ln -sf libpcan.so.0.6 libpcan.so
to
arm-linux-androideabi-gcc src/libpcan.c -fPIC -shared -O2 -Wall -lc -I. -I../driver -DNO_RT -o -libpcan.so
This .so has the same size as the so.0.6 so i assume it worked fine.
My own c-code is getting compiled with
arm-linux-androideabi -shared src/receivetest.c src/common.c -I. -I../lib -I../driver -L../lib -L/lib -L/usr/lib -L/usr/local/lib -o libreceivetest.so
I load both of these files, so the libpcan.so and the libreceivetest.so to my app
static {
System.loadLibrary("pcan");
System.loadLibrary("receivetest");
}
When I'm trying to launch that app i get the error message:
07-14 11:12:43.812: E/AndroidRuntime(753): java.lang.ExceptionInInitializerError
07-14 11:12:43.812: E/AndroidRuntime(753): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1306]: 36 cannot locate 'CAN_Open'...
My receivetest is using that function, but since it declared in the libpcan.so and im also loading that library, i don't know where that error could come from.
I'd just guess its an error in my clags, since I'm new to building .so files via using gcc in the shell i don't really understand all the flags im using.
It's quite long since i solved this. But I haven't ever marked this question as solved.
Thanks to jww for reminding me.
As I've said in the comment to my question, the link to the function CAN_Open was missing due to a missing parameter at compiling the .so-file. The function CAN_Open is a part of the libpcan.so and by skipping the link to that file the CAN_Open function just never made it into the receivetest.so .
Under gcc (g++), I have compiled a static .a (call it some_static_lib.a) library. I want to link (is that the right phrase?) this .a file into another dynamic library (call it libsomeDyn.so) that I'm building. Though the .so compiles, I don't see content of .a under .so using nm command:
/usr/bin/g++ -fPIC -g -O2 -Wall -Werror -pipe -march=pentium3
-mtune=prescott -MD -D_FILE_OFFSET_BITS=64 -DLINUX -D_GNU_SOURCE -D_THREAD_SAFE -I../../../../../../../../ -I../../../../../../../..//libraries -Wl,-rpath,/usr/lib -o libsomeDyn.so some.o another.o some_static_lib.a -shared -Wl -x
-Wl,-soname,libsomeDyn.so
I do not see functions under some_static_lib.a under libsomeDyn.so. What am I doing wrong?
Static libraries have special rules when it comes to linking. An object from the static library will only be added to the binary if the object provides an unresolved symbol.
On Linux, you can change that behavior with the --whole-archive linker option:
g++ -Wl,--whole-archive some_static_lib.a -Wl,--no-whole-archive
For every one that comes across that problem like me (and has not understand the answer properly): here is a short howto generate a dynamic library (libmylib.so) from a static one (mylib.a):
1.) create a mylib.c file that only imports the mylib.h file
2.) compile this mylib.c to mylib.o with
gcc -c -fPIC mylib.c -o mylib.o
3.) generate a dynamic library with the following command:
gcc --whole-archive -shared -Wl,-soname,libmylib.so -o libmylib.so mylib.o mylib.a
That worked at least for me, turning a static library (compiled with -fPIC) to
a dynamic library. I'm not sure wether this will work for other libraries too.