How to recompile with -fPIC - c++

I was trying to reinstall my ffmpeg, following this guide, on my ARM Ubuntu machine. Unfortunately, when I compile a program which uses this lib I get the following failure:
/usr/bin/ld: /usr/local/lib/libavcodec.a(amrnbdec.o): relocation R_ARM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libavcodec.a: could not read symbols: Bad value
collect2: ld returned 1 exit status
Now I would like to recompile it with -fPIC like the compiler is suggesting but I have no idea how. Any help is appreciated.

Briefly, the error means that you can't use a static library to be linked w/ a dynamic one.
The correct way is to have a libavcodec compiled into a .so instead of .a, so the other .so library you are trying to build will link well.
The shortest way to do so is to add --enable-shared at ./configure options. Or even you may try to disable shared (or static) libraries at all... you choose what is suitable for you!

Have a look at this page.
you can try globally adding the flag using: export CXXFLAGS="$CXXFLAGS -fPIC"

I had this problem when building FFMPEG static libraries (e.g. libavcodec.a) for Android x86_64 target platform (using Android NDK clang). When statically linking with my library the problem occured although all FFMPEG C -> object files (*.o) were compiled with -fPIC compile option:
x86_64/libavcodec.a(h264_qpel_10bit.o):
requires dynamic R_X86_64_PC32 reloc against 'ff_pw_1023'
which may overflow at runtime; recompile with -fPIC
The problem occured only for libavcodec.a and libswscale.a.
Source of this problem is that FFMPEG has assembler optimizations for x86* platforms e.g. the reported problem cause is in libavcodec/h264_qpel_10bit.asm -> h264_qpel_10bit.o.
When producing X86-64 bit static library (e.g. libavcodec.a) it looks like assembler files (e.g. libavcodec/h264_qpel_10bit.asm) uses some x86 (32bit) assembler commands which are incompatible when statically linking with x86-64 bit target library since they don't support required relocation type.
Possible solutions:
compile all ffmpeg files with no assembler optimizations (for ffmpeg this is configure option: --disable-asm)
produce dynamic libraries (e.g. libavcodec.so) and link them in your final library dynamically
I chose 1) and it solved the problem.
Reference: https://tecnocode.co.uk/2014/10/01/dynamic-relocs-runtime-overflows-and-fpic/

After the configure step you probably have a makefile. Inside this makefile look for CFLAGS (or similar). puf -fPIC at the end and run make again. In other words -fPIC is a compiler option that has to be passed to the compiler somewhere.

If you're building a shared library but need to link with static libavcodec add linker flags:
-Wl,-Bsymbolic
In case of cmake:
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-Bsymbolic")

I hit this same issue trying to install Dashcast on Centos 7. The fix was adding -fPIC at the end of each of the CFLAGS in the x264 Makefile. Then I had to run make distclean for both x264 and ffmpeg and rebuild.

In addirion to the good answers here, specifically Robert Lujo's.
I want to say in my case I've been deliberately trying to statically compile a version of ffmpeg. All the required dependencies and what else heretofore required, I've done static compilation.
When I ran ./configure for the ffmpeg process I didnt notice --enable-shared was on the commandline. Removing it and running ./configure is only then I was able to compile correctly (All 56 mbs of an ffmpeg binary). Check that out as well if your intention is static compilation

I'm building ffmpeg 5.1.2 on CentOS7 with gcc4.8.5.
As mentioned in ${ffmpegRoot}/doc/platform.texi:
1)configure with option
"--enable-pic"
2)add the following option to your project LDFLAGS
"-Wl,-Bsymbolic"

Before compiling make sure that "rules.mk" file is included properly in Makefile or include it explicitly by:
"source rules.mk"

Related

LLVM crosscompile can't create dynamic relocation R_ARM_ABS32

I am trying to cross-compile for the Raspberry Pi with LLVM using LLD as the linker with the gnu stdlib implementation. I get a load of the following warnings, which refer to relocations inside read-only sections, all contained within the standard library implementation (seems to happen for c and cpp).
ld.lld: error: can't create dynamic relocation R_ARM_ABS32 against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in /home/ted/cross.llvm.raspbian/sysroot/usr/lib/gcc/arm-linux-gnueabihf/6.3.0/../../../arm-linux-gnueabihf/libm.a(s_atan.o)
>>> referenced by s_atan.o:(atanMp.constprop.0) in archive /home/ted/cross.llvm.raspbian/sysroot/usr/lib/gcc/arm-linux-gnueabihf/6.3.0/../../../arm-linux-gnueabihf/libm.a
While the diagnostic tells me to use -z,notext this is apparently bad. Is there another way to fix the issue, or am I using incorrect flags for the cross-compilation?
Side note: for the cross-compilation I use
clang++ --target=arm-linux-gnueabihf --sysroot=./sysroot -fuse-ld=lld --verbose test.cpp -o test
./sysroot contains /usr and /lib from the Raspberry.
The problem is that by default clang compiler tries to link dynamic libraries. And your dynamic library is (most probably) a symlink to absolute path.
To me it is like that:
$ ls -l /Volumes/AlphaRacing/emlid-rootfs/lib/arm-linux-gnueabihf/libm*
# ...
/Volumes/AlphaRacing/emlid-rootfs/lib/arm-linux-gnueabihf/libm.so -> /lib/arm-linux-gnueabihf/libm.so.6
As long as you cross-compile, you the real path of symlink source is different.
So you have two options:
Compile with -static flag.
Fix those symlinks to use relative paths. But beware, there are plenty of them.
Thanks to this post, it helped me to figure out this problem.

"Recompile with -fPIC" error persists even after adding -fPIC compile flag

I have downloaded some C++ which I want to compile from source. After running cmake ../src and then make from the command line, whilst in the build directory, I get the following error:
/usr/bin/ld: /usr/local/lib/libBulletCollision.a(btDbvtBroadphase.o):
relocation R_X86_64_32S against `_ZTV16btDbvtBroadphase' can not be used when making a shared object;
recompile with -fPIC
I believe that this is something to do with trying to create a shared library, but not providing the necessary memory to do so (although I don't fully understand this...). Anyway, following the advice I've seen around, I tried the following instead:
make CXXFLAGS='-fPIC'
However, this gives me exactly the same error as before. Any ideas as to why this did not solve the problem?
I believe Mark is correct when he says the error is about libBulletCollision.a. You are building a .so built with -fPIC but linking against a .a that did not use -fPIC. You will either need to change and build a static library or rebuild and install a new dependent libBulletCollision.a using -fPIC.
By the way, you should add the -fPIC flag to your build in a more permanent way in the cmake configure step rather in this transient way overriding CXXFLAGS when running make.
Also using make VERBOSE=1 with cmake generated makefile builds is quite helpful when debugging builds.

Linking OpenSSL into a dynamic library

I'm trying to static link OpenSSL into my program.
It works fine when linking into the executable. I need to use OpenSSL in a shared library (so, or dll) that I dynamically load later on when the process executes.
Trying to statically link OpenSSL into the shared library causes errors due to OpenSSL not being compiled with -fPIC. Is it possible to do this without recompiling openssl?
Also, is there a better way to do this?
I'm trying to static link OpenSSL into my program.
In this case, its as simple as:
gcc prog.c /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a -o prog.exe -ldl
It works fine when linking into the executable.
Devil's advocate... Does it work fine with Position Independent Code (PIE)? PIE on a program is the equivalent to PIC on a shared object (some hand waiving).
gcc -fPIE prog.c /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a -o prog.exe -ldl
According to the GCC folks, you can compile with fPIC, and then build a shared object with -fPIC or a relocatable executable with -fPIE. That is, its OK to use -fPIC for both.
Trying to statically link OpenSSL into the shared library causes errors due to OpenSSL not being compiled with -fPIC.
That's easy enough to fix. You simply specify shared in configure:
./config shared no-ssl2 no-ssl3 no-comp --openssldir=/usr/local/ssl
make
sudo make install
I think you can also (notice the lack of shared):
export CFLAGS="-fPIC"
./config no-ssl2 no-ssl3 no-comp --openssldir=/usr/local/ssl
make
sudo make install
not being compiled with -fPIC. Is it possible to do this without recompiling openssl?
NO, you have to compile with PIC to ensure GCC generates relocatable code.
Also, is there a better way to do this?
Usually you just configure with shared. That triggers -fPIC, which gets you relocatable code.
There's other things you can do, but they are more intrusive. For example, you can modify Configure line (like linux-x86_64), and add -fPIC in the second field. The fields are separated by colons, and the second field is $cflags used by the OpenSSL build system.
You can see an example of modifying Configure at Build OpenSSL with RPATH?

Static linking to libcrypto++, with g++

I am trying to compile a program on my system with Debian Wheezy and g++4.7. I want it to be able to run on another system with Debian Squeeze (and no recent g++). I can't compile the program on the Squeeze, because I use certain C++11 features the old g++ does not support, as well as a new Boost version and libcrypto++9.
As far as I understand the usual way to get around this problem is to static link the libraries not supported at the other system, in my case libstdc, boost and crypto++.
My (linking) compiler call right now is
g++-4.7 .obj/btcmirco.o -Wl,-Bstatic -lboost_program_options -lboost_system -lcrypto++ -Wl,-Bdynamic -lcurl -static-libgcc -std=c++11 -o MyProgram
However I seem to have missed something, because it throws a lot of undefined reference errors. It works fine if I dynamic link to crypto++ (and only static link libstdc and boost).
Can anyone tell me whats wrong, or if there is a fundamental error in my approach?
The linker errors I get are (shorted):
`.text._ZN8CryptoPP22BufferedTransformationD2Ev' referenced in section `.text._ZN8CryptoPP22BufferedTransformationD1Ev[_ZN8CryptoPP22BufferedTransformationD1Ev]' of /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libcrypto++.a(cryptlib.o): defined in discarded section `.text._ZN8CryptoPP22BufferedTransformationD2Ev[_ZN8CryptoPP22BufferedTransformationD5Ev]' of /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libcrypto++.a(cryptlib.o)
`.text._ZN8CryptoPP25MessageAuthenticationCodeD2Ev' referenced in section `.text._ZN8CryptoPP25MessageAuthenticationCodeD1Ev[_ZN8CryptoPP25MessageAuthenticationCodeD1Ev]' of /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libcrypto++.a(cryptlib.o): defined in discarded section `.text._ZN8CryptoPP25MessageAuthenticationCodeD2Ev[_ZN8CryptoPP25MessageAuthenticationCodeD5Ev]' of /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libcrypto++.a(cryptlib.o)
I experienced the same problem and this has to do with the fact that you are trying to mix code generated by g++-4.7 (your program) with code generated by a previous version of g++ (cryptopp library).
The reason behind this is that when you execute compile the library executing make command, it uses the default version of g++ set up for your system, usually the one that comes with the OS.
In order to solve the issue what you should do is compile cryptopp library with g++-4.7.
For that, compile the library by executing make CXX=g++-4.7. The resulting static library shouldn't give you the error when being linked with your code.

Clang linker does not look into LD_LIBRARY_PATH

I am trying to build and link a C++, cmake-based project with clang (3.0). This project links to several libraries that are installed in a custom directory /my/dir/. This directory is included in the LD_LIBRARY_PATH and LIBRARY_PATH environment variables. Project builds and links fine with g++.
The link command generated and executed by cmake looks like the following:
/usr/bin/clang++ -O3 stuff.cpp.o -o stuff -rdynamic -lmylib
ld then complains with the following message:
/usr/bin/ld: cannot find -lmylib
The link command above runs fine whenever I manually add -L/my/dir/. Is there a way to link without specifying the -L flag?
The $LD_LIBRARY_PATH environment variable (and its various alternatives on other UNIX-based platforms) is used at runtime, not link time, to find libraries.
Using -L is the correct approach and cannot be avoided.
Note: A better approach under Linux (you don't specify your platform so I'm guessing) is to correctly configure a file in /etc/ld.so.conf.d/ and avoid using $LD_LIBRARY_PATH altogether.