Why do clang++ and gcc/g++ produce differently linked executables - c++

When compiling and linking with g++ and clang++ there is an expectation that the resulting executable will be linked equal with respect to their linkage.
However in certain cases it appears that clang++ executables are linked to more libraries than g++ despite the same arguments passed in.
This can cause functional differences especially with respect to dynamically linked libraries that have automatic execution on load and unload.
Why does this happen?

It turns out gcc has a feature enabled by default in ubuntu --as-needed which causes gcc to effectively ignore any library for which none of it's symbols are referenced in the chain of linked items
This can be disabled in gcc with --no-as-needed flag. Or alternatively you can issue -Wl,--as-needed as the first option to clang++ to behave the way gcc does.

Related

Undefined reference when combining C++ and Fortran [duplicate]

I am trying to link a .o file generated using g++ and another .o file generated using gfortran.
g++ -c mycppcode.cpp
produces the file mycppcode.o and the command
gfortran -c myfortrancode.f
produces the file myfortrancode.o
When I link these two files to get an output file
g++ -O mycppcode.o myfortrancode.o
I get the following error
Undefined symbols for architecture x86_64:
"__gfortran_pow_c8_i4", referenced from:
Could some one help me with this? Should I use another compiler? Also, I would like to know what functions or subroutines call "__gfortran_pow_c8_i4", so that I can try to avoid these functions or subroutines in fortran in future.
The following assumes you are using the GNU compiler tools. Things may be slightly different if you are using other compilers.
You can use either compiler to link the two together, but you need to provide the appropriate libraries.
Typically, you can use either
gfortran fortobj.o cppobj.o -lstdc++
or
g++ fortobj.o cppobj.o -lgfortran
This assumes that you are using a setup where both compilers know about each other's libraries (like if you installed through a linux repository).
In the case of the OP the C compilers came from XCode and gfortran is from homebrew. In that case, gfortran knows about the g++ libraries (since they were used to compile the compiler), but g++ doesn't know about the gfortran libraries. This is why using gfortran to link worked as advertised above. However, to link with g++ you need to add the path to libgfortran.* when you call the linker using the -L flag, like
g++ fortobj.o cppobj.o -L/path/to/fortran/libs -lgfortran
If for some reason your gfortran compiler is unaware of your g++ libs, you would do
gfortran fortobj.o cppobj.o -L/path/to/c++/libs -lstdc++
Note that there shouldn't be any difference in the final executable. I'm no compiler expert, but my understanding is that using the compiler to link your objects together is a convenience for calling the linker (ld on UNIX-like OS's) with the appropriate libraries associated with the language you are using. Therefore, using one compiler or the other to link shouldn't matter, as long as the right libraries are included.

Why does the order of clang compiler flags affect the resulting binary size?

Alternate title: Why does my dylib include extra exported symbols when compiled by Xcode vs Makefile?
My company builds a c++ dynamic library (dylib) on the Mac using clang and we recently ported our hand crafted Makefile to the CMake build system and are now using the generated Xcode projects. After ensuring that all the compiler/linker flags and environment variables matched exactly between the two systems, we noticed that the dylib created by CMake/Xcode was slightly larger. Closer examination showed that it contained some additional exported symbols (from templated functions that were never referenced and therefore should never have been instantiated - the specific templates had their definitions and specializations in the source files as we use explicit instantiation frequently, although in this case they were not explicitly instantiated). Examining the disassembly of some of the object files showed slight instruction differences as well. The only thing that got the libraries to match in size and symbols exactly was to match the order of the compiler flags exactly. This appears to demonstrate some order dependent interaction between compiler flags which seems like a compiler bug or at least poorly documented behavior.
For this specific issue, these were the compiler invocations:
clang++ -fvisibility=hidden -fvisibility-ms-compat -c foo.cpp -o foo.o
clang++ -fvisibility-ms-compat -fvisibility=hidden -c foo.cpp -o foo.o
And this was the linker invocation:
clang++ -dynamiclib -o libfoo.dylib foo.o
Displaying the exported symbols with:
nm -g libfoo.dylib
showed the differences. I submitted this LLVM Bug.
Are there ever any valid situations where compiler flag ordering matters?
Microsoft's compilers and pretty much everyone else's have traditionally had very different models for symbol visibility in the object file. The former has for a long time used C and C++ language extensions to control symbol emission by the compiler, and by default not exporting symbols.
It seems likely that -fvisibility=hidden and -fvisibility-ms-compat are mutually exclusive, and that the compiler honours the last one see on its command-line.
In all fairness, there is little documentation for -fvisibility-ms-compat to be had - other than the commit adding it to clang.

Why does gcc want me to link to libgcc_ext.10.5.dylib?

I've built GCC 4.9.2 on Mac OS X from source statically (using --disable-shared), for C language only (not C++), with the static version of libgcc (libgcc.a). Of course, since I only built the static version of libgcc, there's no such thing as libgcc*.dylib. GCC has built and installed libgcc.a (as expected) and that's all fine. Now when I invoke this newly-built copy of GCC using the following command (using a simple hello, world! example):
gcc -v test.c -o test
it shows these compiler flags as default:
-no_compact_unwind -lSystem -lgcc_ext.10.5 -lgcc -lSystem
No, no no! I don't want you to try to link to a shared version of libgcc! Don't you remember I told you that at the configuration step? And if I use the -static-libgcc option, I get this:
-no_compact_unwind -lgcc_eh -lgcc -lSystem
libgcc_eh? HUH? When was that built during GCC compilation? Oh right, it wasn't, hence why it can't find libgcc_eh.a.
What's going on here? I specifically told GCC I didn't want shared libraries, so why is it trying to link to them by default? I can, of course, remedy all this by using -nodefaultlibs and specifying -lgcc and -lSystem manually, but why should I have to do that?
Furthermore, the GCC documentation has this to say:
-shared-libgcc
-static-libgcc
On systems that provide libgcc as a shared library, these options force the use of either the shared or static version, respectively. If no shared version of libgcc was built when the compiler was configured, these options have no effect.
So, based on this, I take it that if I did not specifically ask GCC to build a shared version of libgcc, it should not assume I would want to link to anything but a static version. But, for some reason, it does anyway. I haven't been able to find a configure option that would prevent this, nor an option that lets me specify which "default libs" get linked to by default. It seems GCC is forcing me to link to a shared version of libgcc that isn't there unless I suppress this using -nodefaultlibs. This seems backwards.
I figured out how to fix this. I had to edit /gcc/config/darwin.h in GCC's source and comment out where the macro REAL_LIBGCC_SPEC is defined. By leaving this macro undefined, it ensures GCC will only pass the -lgcc and -lSystem library flags during linking, which is what I wanted.
The GCC docs for the compilation driver explain what this and other macros do:
https://gcc.gnu.org/onlinedocs/gccint/Driver.html
— Macro: LIBGCC_SPEC
Another C string constant that tells the GCC driver program how and when to place a reference to libgcc.a into the linker command line. This constant is placed both before and after the value of LIB_SPEC.
If this macro is not defined, the GCC driver provides a default that passes the string -lgcc to the linker.
— Macro: REAL_LIBGCC_SPEC
By default, if ENABLE_SHARED_LIBGCC is defined, the LIBGCC_SPEC is not directly used by the driver program but is instead modified to refer to different versions of libgcc.a depending on the values of the command line flags -static, -shared, -static-libgcc, and -shared-libgcc. On targets where these modifications are inappropriate, define REAL_LIBGCC_SPEC instead. REAL_LIBGCC_SPEC tells the driver how to place a reference to libgcc on the link command line, but, unlike LIBGCC_SPEC, it is used unmodified.

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.

Force to link against unused shared library

Moved from gcc 4.5 to gcc 4.6, and now it does not link against libraries that are not used at compile time (i.e. if no symbols are imported from them).
However the purpose of those libraries is that they execute static constructors and thus make themselves available to the app at runtime (register their symbols).
Is there a way to force gcc to link with all libraries listed via -l?
It looks like you need either -Wl,--no-as-needed to totally disable it. Or, --no-as-needed -lfoo --as-needed to disable "as-needed" just for libfoo.
Source: https://lists.ubuntu.com/archives/ubuntu-devel/2010-November/031991.html