I need to create a custom shared library that internally uses ffmpeg functions. The idea is to create one fat shared library, say, myffmpeg.so.
I first build ffmpeg code (3.3.1 as of this post). During configuration, I specify -fPIC via --extra-cflags and --extra-cxxflags. I also specify -enable-pic during the configuration. After running configure and make, various archive files such as libswscale.a, libavformat.a, etc. are successfully created.
Next, I try to build my shared library:
gcc -fPIC -Ixxx mywrapper.cpp
gcc -shared -o myffmpeg.so mywrapper.o -Lxxx -lswscale -lavformat...
However, this results in an error:
Relocation R_X86_64_PC32 against symbol ff_M24A can not be
used when making a shared object;
Looks like I am missing some compiler/linker setting. Can someone please point me in the right direction? Regards.
Here is how I solved the problem. You need to add "-Wl,-Bsymbolic" to ldflags during configuration. Also, when you create the shared library, you need to pass the same parameter to the linker. Regards.
If you need shared libraries, build ffmpeg with --enable-shared, which will generate shared objects libswscale.so, libavformat.so, etc. The .a files are static libraries built by default configuration.
Related
I'm compiling a static library, let's call it static.a which is later linked by a shared library shared.so and by a final executable binary file (shared.so uses just a few functions from static.a maybe later this can be further splited). If I try to compile it suing gcc 7.4 I get this linker error:
/usr/bin/ld: ../../static.a(file.cpp.o): relocation R_X86_64_TPOFF32 against symbol `_ZGVZN6spdlog7details2os9thread_idEvE3tid' can not be used when making a shared object; recompile with -fPIC
I decided to try also gcc 9.1 and this error doesn't apear anymore.
should I always use -fpic when building a static library that will be used in a shared library? I know fpic adds some overhead.
how come a newer version of gcc can relocate the symbols of the static.a inside the shared library? Is this safe?
Thank you.
All code in shared library should be compiled with -fPIC so your static library should too. -fPIC does indeed introduce an overhead but to a large extent it can be mitigated with options like -fno-semantic-interposition and/or -fvisibility=hidden.
The error that you see is coming from the linker so it seems that the newer GCC does not use the problematic relocation. You can inspect the generated assembly to find out the difference in generated code.
I just got this error when compiling some plugins for my new toy (on gcc/g++ on Linux):
relocation R_X86_64_32 can not be used when making a shared object; recompile with -fPIC
I basically understand why PIC is needed but, within the CMake system, the solution seems to be this:
IF (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
SET_TARGET_PROPERTIES (${PLUGIN_BASE_LIB} PROPERTIES COMPILE_FLAGS "-fPIC")
ENDIF (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
I don't understand why this solution is conditional.
The follow-up seems to suggest that -fPIC should be used basically everywhere except 32-bit Linux, which suggests that the above is not portable.
Should I always use -fPIC? Will there be any adverse effects?
${PLUGIN_BASE_LIB} needs to be statically linked to both the main executable, and statically the various shared libraries which are the plugins.
Ideally you want to build two versions of code: one for the main executable and one for the library. The first will need to be compiled with -fPIE (which is default in modern distros) and the second with -fPIC. As you point out this does not depend on target architecture.
You can compile only one version with -fPIC but then main executable will be suboptimal because -fPIC forces compiler to obey symbol interposition rules which significantly limits it's ability to optimize code e.g. inline and clone functions.
When building binutils, the bfd component is failing to link because it is linking against the system version of libiberty instead of the built version under binutuils/libiberty/lib64/libiberty.a.
I can't see a configure argument to allow me to override this. What's the best way to instruct configure to construct an LD_LIBRARY_PATH that prefers libraries from other components of its build over system versions? Obviously, it needs system libraries that are prerequisites, so I can't exclude this path entirely.
This is the error, due to the system version having not been compiled correctly. The version under binutils/libiberty/lib64 is compiled with -fPIC, so I need to tell configure to use that.
/lib64/libiberty.a(cplus-dem.o): relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
It doesn't seem as trivial to specify .:/usr/lib64:/lib64 since . is binutils/bfd.
I had a look at the generated automakefile and LDFLAGS was only specifying the system libraries:
LDFLAGS := -L/usr/lib64 -L/usr/lib
So I specified this as an argument to configure. Slightly hacky, but can't see a better way out:
LDFLAGS="-L./ -L../ -L../libiberty/pic -L/usr/lib64 -L/usr/lib" ./confgiure --enable-shared
Without modifying and recompiling the gnu gcc and stdc++ library builds, I need to be able to reproduce dynamic loading versions of those libraries with a different embedded soname.
I thought I would be clever and use the available static versions and repackage them with something like this:
ld -E -shared -static "-lstdc++" -lgcc -lgcc_eh -o librepackaged_standard.so
librepacked_standard.so is created, without warnings or errors, but ldd reports its not a dynamic library and readelf reports only these basic symbols:
Symbol table '.symtab' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000201000 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
2: 0000000000201000 0 NOTYPE GLOBAL DEFAULT ABS _edata
3: 0000000000201000 0 NOTYPE GLOBAL DEFAULT ABS _end
I am unsure why ld isn't bringing in all of the symbols defined statically. I also don't know if there are any other special parameters I need to give it for this to work.
Another option is if there is a know cross platform way to simply change the soname embedded in the original elf libraries. I'm currently only concerned with elf formatted binaries. I am not interested in writting my own tool to change the .soname in existing binaries.
UPDATE:
The reason no symbols were getting compiled is because ld handles static binaries differently than .o files. By default it does not import any symbols from the .a file unless they are required by a another library on the link line. I fixed that by provided the --whole-archive option.
However that gives me another error, relocation R_X86_64_32S against_ZSt12_S_first_one' can not be used when making a shared object; recompile with -fPICand could not read symbols: Bad value` They are both from libstdc++.a in the bitset.o archive. So I can't just recompile the .a's into a dynamic library because the GNU GCC compile, by default, does not compile the object files used for the static libraries with the PIC option.
That leaves me with finding an elf tool or recompiling GNU GCC with modifications to its build.
As stated by one of the answers, licensing issues could be a concern with any of these approaches. My best answer is that we need to change to our requirements and find a different solution that doesn't involve changing or repackaging the GCC standard libraries in any fashion.
The reason no symbols were getting compiled into the shared library is because ld handles static binaries differently than .o files. By default it does not import any symbols from the .a file unless they are required by a another library on the link line. The answer to that particular issue is to use the --whole-archive option and linking the .a files directly mostly works.
However, for this to work the .o files included in the static archive need to have been compiled using the -fPIC option at compile time. However the object files used for the static libraries are not compiled with that option in the static libraries available.
So, the solution to changing the SONAME is to use an ELF binary utility or rebuilding GNU GCC modified to use different SONAMEs.
Since there are licensing concerns in this situation any of the solutions are not practical for the project because it is not open source and we do not want the requirement to redistribute a modified source version of GNU GCC for all our platforms.
The -static probably undid the -shared.
Classically, you'd extract the object files from the static libraries and then package those object files into the shared library - relying on the universal use of PIC (position-independent code) so that the objects in the static libraries can safely be converted into a shared library. You might be able to do without that extract step, but I doubt it.
You might want to think about whether you're meeting the licencing terms and conditions.
I have a shared library (*.so) created using Real View Compiler Tools (RVCT 3.2) on windows target. Then I try to link this *.so file with my application using gcc on linux system.
What is the gcc option to link this shared library with my application linux?
My question is, is the -shared option, which is used as
gcc -shared myfile.so
..., used to create the SO file or to link the SO file? I believe it creates something like:
gcc -lmyfile.so
Is this enough? Or is there any other switch to tell the linker that it's a dynamic library (shared object)?
What worked for me was:
gcc -L. -l:myfile.so
gcc -lmyfile should be enough (provided that your library is named libmyfile.so). The linker searches for shared objects when possible and AFAIK prefers them.