I ran into a rather bizarre issue while building a dynamic library. Here are details with a small example:
A simple file called static.h whose contents are:
#pragma once
#include <string>
std::string static_speak();
static.cpp looks like this:
#include "static.h"
std::string static_speak() {
return "I am static";
}
one can build a static library with these two files (using cmake) as:
add_library(static
static.cpp
)
Now, consider another file called shared.cpp whose contents are:
#include "static.h"
std::string dynamic_speak() {
return static_speak() + " I am dynamic";
}
One can try to build a dynamic library (again using cmake) as:
add_library(shared SHARED
shared.cpp
)
target_link_libraries(shared PRIVATE
static
)
When one tries to build the above, one will run into the following error:
[4/4] Linking CXX shared library libshared.so
FAILED: libshared.so
: && /opt/vatic/bin/clang++ -fPIC -g -shared -Wl,-soname,libshared.so -o libshared.so CMakeFiles/shared.dir/shared.cpp.o libstatic.a && :
/usr/bin/ld: libstatic.a(static.cpp.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
clang-10: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
This makes sense. We didn't compile static with POSITION_INDEPENDENT_CODE. That is easily fixable via:
add_library(static
static.cpp
)
set_target_properties(static
PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
Everything works perfectly now when one compiles shared library.
Now here is the problem. Let's say I didn't enable POSITION_INDEPENDENT_CODE but instead disabled exceptions (!) in my code as:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
Now when I try to compile shared, everything still works!!
How are exceptions and fPIC related to each other?
Here is a repo to reproduce the issue:
https://github.com/skgbanga/shared
How are exceptions and fPIC related to each other?
They aren't (mostly).
What happens is that compiling with -fno-exceptions changes the relocations (certain exception-related data is no longer referenced), and because of that, there is no relocation which causes the error at link time.
You can confirm this by building with and without -fno-exceptions, and comparing output from objdump -dr CMakeFiles/static.dir/static.cpp.o.
P.S. I could not reproduce your problem using g++ (Debian 9.3.0-8), because it defaults to building with -fPIE, and both links succeed.
And if I add -fno-pie, then both links fail the same way.
Related
I have a c++ CMAKE (VERSION 3.10.2 -std=c++17 ) project that i am able to compile and link with bought gcc and clang. Bought of them produce the target binaries which work as expected. Recently i decided to to try and add another target i.e. webassembly. The project is compiling as expect, however when the EMscripten build is being executed i.e. in the linking phase i get the following error:
Elapsed time: 1 s. (time), 0.002241 s. (clock)
[100%] Linking CXX executable wasmExec.js
cd /Projects/time/time.cpp/build/src/wasm && /usr/bin/cmake -E cmake_link_script CMakeFiles/wasmExec.dir/link.txt --verbose=1
/Projects/emscripten/emsdk/emscripten/1.38.12/em++ -s WASM=1 -s NO_EXIT_RUNTIME=1 -s VERBOSE=1 --pre-js /Projects/time/time.cpp/src/wasm/preModule.js -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0 #CMakeFiles/wasmExec.dir/objects1.rsp -o wasmExec.js #CMakeFiles/wasmExec.dir/linklibs.rsp
error: Linking globals named '_ZTVN9timeproto3time8defaults20TimeDefaultParametersE': symbol multiply defined!
WARNING:root:Note: Input file "#/tmp/tmpUeJ6zc.response" did not exist.
ERROR:root:Failed to run llvm optimizations:
When i do
c++filt _ZTVN9timeproto3time8defaults20TimeDefaultParametersE
i get
vtable for timeproto::time::defaults::TimeDefaultParameters
from another answer by Stackoverflow i.e.
Possible reasons for symbol multiply defined other than 'extern'
i do understand that i have defined this class more then once, however my problem is that i can not locate that place where i have made the mistake with the second definition. In the previous answer the person had the hint i.e. the cpp file where that he has made that mistake but in my case emscipten is not so generous.
This class is used all over the code base in many many files and after long manual searching i was not able to find anything that can point me at least to the localtion of the second definition. Thus i was hoping that someone can help me with the following questions
1) how can this be troubleshoot further in order to find where exactly the second defintion of the class is occuring, maybe a flag by gcc or clang ?
2) why this error is beeing displayed only when I am trying to compile/build the webassmbly target. The regular Linux64 build target is successefull and the test are also working correctly.
3) I am running cmake with following "add_definitions" i.e.
if(UNIX)
add_definitions(" -pedantic -pedantic-errors -W ")
add_definitions(" -Wall -Wextra -Werror -Wshadow -Wnon-virtual-dtor ")
add_definitions(" -v ")
# add_definitions(" -Worl-style-cast -Wcast-align ")
# add_definitions(" -Wunused -Woverloaded-virtual ")
add_definitions(" -g ")
endif(UNIX)
if the TimeDefaultParameters has been defined more then once should't clang not complain also for linux build with the above "add_definitions" ?
here is the code below TimeDefaultParameters.cpp This is a very simple file that does not contain any object instead it has 43 "static const uint32_t" variables.
#include "TimeDefaultParameters.h"
namespace timeproto::time::defaults
{
TimeDefaultParameters::TimeDefaultParameters() {
}
TimeDefaultParameters::~TimeDefaultParameters() {
}
const uint32_t TimeDefaultParameters::SIGNED_SHORT_MAX_VALUE = 32767;
.... (another 42 static const uint32_t)
}
and the header file TimeDefaultParameters.h:
#ifndef _TIME_DEFAULT_PARAMETERS_
#define _TIME_DEFAULT_PARAMETERS_
#include <stdint.h>
namespace timeproto::time::defaults
{
class TimeDefaultParameters final
{
public:
explicit TimeDefaultParameters();
virtual ~TimeDefaultParameters();
static const uint32_t SIGNED_SHORT_MAX_VALUE;
.....
.... (another 42 static const uint32_t)
};
}
#endif //#ifndef _TIME_DEFAULT_PARAMETERS_
in cmake i have the set my target properties like:
set_target_properties(wasmExec PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_EXIT_RUNTIME=1 -s VERBOSE=1 --pre-js /Projects/time/time.cpp/src/wasm/preModule.js -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0" )
this is how i am calling cmake to make the build from withing the build directory
emconfigure cmake -DCMAKE_BUILD_TYPE=Emscripten -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=/Projects/emscripten/emsdk/emscripten/1.38.12/cmake/Modules/Platform/Emscripten.cmake ../
make -j8
any ideas are greatly appreciated.
ADDITION: 05 January 2020
I was able to find a workaround for this problem but i still it leaves some questions of the nature of the error.
The class in question was part of the archive that was created and loaded dynamically i.e. i had used in the CMAKE part for this library "set(LIB_TYPE SHARED)".
here is full example how cmake generated that archive i.e. the CMakeLists.txt.
set( TIME_DEFAULTS_SRC
...
TimeDefaultParameters.h TimeDefaultParameters.cpp
...
)
set(LIB_TYPE STATIC)
#set(LIB_TYPE SHARED)
add_library(time_defaults ${LIB_TYPE} ${TIME_DEFAULTS_SRC} )
target_include_directories(time_defaults PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/")
I have changed from dynamic to static and i was able to create the wasm no errors were shown. During the compilation i also saw somewhere in between of the compilation process some warrning i.e. :
WARNING:root:When Emscripten compiles to a typical native suffix for shared libraries (.so, .dylib, .dll) then it emits an LLVM bitcode file. You should then compile that to an emscripten SIDE_MODULE (using that flag) with suffix .wasm (for wasm) or .js (for asm.js). (You may also want to adapt your build system to emit the more standard suffix for a file with LLVM bitcode, '.bc', which would avoid this warning.)
this warrning is now gone. But it is very easy to oversee thing like that especially if the compilation process is taking long time. However my understanding is that the very first error message tells us , "look you have made duplicate definition of some symbol in your code go find the place and make sure that the class is define only once". That was exactly what i was doing i.e. searching the code base for that duplicate definition. Thus now the question is: Why emscripten have a problem does with dynamic linking i.e. i know that it is officially supported i.e.
https://webassembly.org/docs/dynamic-linking/
and is that the source of the error at all or is something else?
Why this error disappears when i change to static. I can reproduce this by simply changing library type!
I think i already found the answer here
https://github.com/emscripten-core/emscripten/wiki/Linking
So the solution in my case was to find the occurrences in the CMAKE file where the library was added dynamically and change that to static linking i.e.
#set(LIB_TYPE SHARED)
set(LIB_TYPE STATIC)
I am currently building a shared library (lib1.so) out of a cmake environment.
lib1.so depends on an external static lib libLASlib.a (which I am able to recompile if necessary).
Everything works wonder on windows so far, but it's another story when switching to linux:
/usr/bin/ld: lib/LASlib/libLASlib.a(lasreader.cpp.o): relocation R_X86_64_PC32 against symbol `_ZN9LASreader35read_point_filtered_and_transformedEv' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
So I tried recompiling the libLASlib with -fPIC -> same error
Due to my environment I could not verify the fpic was effectivelly added to the gcc command line.
Here is what I tried to confirm there was no issue with the fPIC:
readelf --dynamic libLASlib.a | grep lasreader.cpp.o -A2
File: libLASlib.a(lasreader.cpp.o)
There is no dynamic section in this file.
For the record not a single cpp.o was found with a dynamic section
I have tried just to see what it would give if i changed liblas from a static to a shared library -> no error
Any thoughs?
Many thanks!
You need to compile lasreader.cpp with -fPIC. Something like this:
g++ -c -fPIC -o lasreader.cpp.o lasreader.cpp
The fPIC was indeed not applied
Conan doesn't seem to forward the fPIC option
I edited the CMAKELIST and added
set_property(TARGET LASlib PROPERTY POSITION_INDEPENDENT_CODE ON)
And it eventualy passed
I am using the command:
g++ --std=c++11 -fPIC -Iincludes parser.cpp lib/main-parser.o lib/lib.a
To compile a C++ program on Debian 9. But I am getting the below error message:
/usr/bin/ld: lib/lib.a(csdocument.o): relocation R_X86_64_32 against '.rodata' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
I have already seen the thread:
Compilation fails with "relocation R_X86_64_32 against `.rodata.str1.8' can not be used when making a shared object"
However, I have tried adding the -fPIC argument however it strangely gives the same error message, along with "recompile with -fPIC"
Any ideas would be appreciated. I have tried compiling this on my University's RedHat systems and it works fine there. I'm thinking it could be a missing dependency, but I've been unable to find any answers.
Thanks in advance
As it seems gcc is trying to produce a position-independent executable ("shared object" is the hint), tell it not to:
g++ --std=c++11 -no-pie -Iincludes parser.cpp lib/main-parser.o lib/lib.a
It seems that g++ produces position-independent executables by default on your system. Other systems would require -pie to do so. Using -no-pie should create a "regular" (position dependent) executable.
(The error is a result of trying to link an object file that was compiled as non-position-independent into an executable that is supposed to be position-independent).
/usr/bin/ld: lib/lib.a(csdocument.o): relocation R_X86_64_32 against '.rodata' \
can not be used when making a shared object; recompile with -fPIC
This linker error is telling you that the object file csdocument.o in the
static library lib/lib.a is not Position Independent Code and hence
cannot be linked with your PIE program. So you need to recompile the source
files of lib/lib.a with -fPIC, then rebuild the static library, then link
it with your PIE program. If you don't have control of the libary sources
then request a PIC build from its supplier.
(Others have questioned why you should need to build a PIE target at all
since it's not a shared library. In Debian 9, GCC produces PIE executables
by default,
whether programs or shared libraries. The same goes for Ubuntu as of 17.04. )
Adding this worked for me.
g++ --std=c++11 -no-pie
I also added the -fPIC to compile flag.
I am trying to use the libsodium library in a C++ project and I'm having difficulty with linking the static Libsodium Library into a Shared Object that I've created. This project is being compiled using G++ and is set to use C++11 Standards.
After reading various forum posts about linking a Static Library into a Shared Object, I've tried using the Whole Archive which seems to get me further but still will not link in correctly.
The following is the Command being used to link:
/usr/bin/g++ -shared -fPIC -o ./Debug/libwowcrypt.so #"libwowcrypt.txt" -L. -L../SharedLibraries/Sodium/lib -Wl,--whole-archive -lsodium -Wl,--no-whole-archive
The following error messages are returned from ld:
/usr/bin/ld: ../SharedLibraries/Sodium/lib/libsodium.a(libsodium_la-hmac_hmacsha256.o): relocation R_X86_64_PC32 against symbol `crypto_auth_hmacsha256_init' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
Can anyone advise on the correct linker flags that are needed to incorporate this static library into my shared object?
I ran into the same problem. Assuming you are on Ubuntu < 15.04 (mine is 14.04 LTS), you need to disable PIE
./configure --disable-pie
and then the usual: make / make install etc.
Now you should be able to link the static libsodium.a to your .so. I got this from a recent discussion on github issue i raised here
I want to link my C++ executable to both a static (libStatic.a) and a shared (libShared.so) library, using a makefile.
The makefile so far has the following content:
myExe: main.cpp libStatic.a libShared.so
g++ main.cpp libStatic.a libShared.so
I'm fairly sure that the static linking is correct, as I have seen similar things elsewhere. What I am unsure of is the shared linking part. Is this correct? Or is linking to a static library done differently?
If I run make, then it seems to be ok, and creates the executable. However, when I execute this, I reveive the error:
/usr/bin/ld: cannot find -lShared
However, my executable and libShared.so are in the same directory.
You need to set LD_LIBARY_PATH to this directory where the shared object is sitting before you run your program.
You can read up on 'rpath' in man ld for other possibilities.