Which part of GCC is still involved when building with Clang++ and LLD? - c++

I built a very simple program using Clang++/LLD:
clang++ -fuse-ld=lld -o test test.cpp
I than ran readelf to confirm that LLD was indeed used as the linker, as mentioned on https://releases.llvm.org/11.0.0/tools/lld/docs/index.html:
$ readelf --string-dump .comment test
String dump of section '.comment':
[ 0] Linker: LLD 7.0.1
[ 12] clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final)
[ 49] GCC: (Debian 8.3.0-6) 8.3.0
Very good, the linker used was indeed LDD. But it makes me wonder why GCC is still mentioned there. Maybe because the standard libraries were (presumably) build with GCC? Just wondering.

Depending on how you built libc++, you may still be using libgcc and libsupc++ to provide some routines otherwise provided by libc++abi and libcxxrt (and even then, there may still be some parts of libgcc required to make everything work).
Depending on the platform, there may still be some startup files or libc bits linked in which may or may not contain a string reference to GCC.
On Mac or BSD, for example nothing GCC should be involved anymore.
The Clang driver also (used to) use(s) GCC to infer e.g. library and header search paths, but I think it only does that as a fallback on unknown platforms.

Related

Use compiled LLVM/clang without gcc

I have been trying to compile LLVM/clang from source, both by myself and using this script. I am compiling clang using gcc 11.2, which itself was also built from source, and hence resides in a non-default location on my system (/scratch/opt/gcc-ml-11.2). Note that it only works with a gcc that was compiled with multilib enabled.
The problem is that I can use the compiled clang and clang++ binaries only if I supply the gcc location as follows: --gcc-toolchain=/scratch/opt/gcc-ml-11.2.0. Without that flag, I run into linker errors:
clang test.c -o test
/usr/bin/ld: cannot find crtbeginS.o: No such file or directory
/usr/bin/ld: cannot find -lgcc
/usr/bin/ld: cannot find -lgcc_s
I do not understand why a clang compiled binary needs to link against some kind of gcc library and why clang does not supply the crtbeginS.O file.
I have also tried using the LLVM linker as well as the LLVM standard library for C++ test applications, i.e., "-fuse-ld=lld -stdlib=libc++. This did not help either.
While I could just export CXXFLAGS=--gcc-toolchain=/scratch/opt/gcc-ml-11.2.0, I am not sure whether this is the right approach. Shouldn't clang/LLVM be able to function without a gcc installation?
I have also tried using my clang installation with the --gcc-toolchain=/scratch/opt/gcc-ml-11.2.0 flag to compile clang again, but the new binary also requires the gcc-toolchain flag.
Should I just globally export the path to my gcc toolchain? Why is this necessary? Isn't clang a standalone compiler that - if supplied with the option to use its own standard library - does not require gcc?
Thank you very much for your help!
Best,
Maxbit

undefined reference to `log2f#GLIBC_2.27' undefined reference to `logf#GLIBC_2.27'

I'am trying to a run a sample code from pardiso website but end up with this error.
I installed the lapack package from http://www.netlib.org/lapack/
gcc pardiso_sym.c -L /home/sree/ -lpardiso600-GNU800-X86-64 -llapack -lgfortran -fopenmp -lm -ldl
error:
/home/sree//libpardiso600-GNU800-X86-64.so: undefined reference to `log2f#GLIBC_2.27'
/home/sree//libpardiso600-GNU800-X86-64.so: undefined reference to `logf#GLIBC_2.27'
collect2: error: ld returned 1 exit status
I know this question is quite old but anyway:
First of all - the error you are getting is a linker error and is seems like it cannot resolve a reference to a function defined in glibc.
The version given here for glibc (the GNU C library) is 2.27.
I would now suspect that the version used by GCC when trying to compile pardiso_sym.c was lower than the specified version of glibc - thus the error.
You can find a nice thread about checking the version of glibc used by different gcc compilers here.
That said - different gcc compilers might use different versions of glibc for linking. You could now either specifically try and link a proper version of glibc (like described here) or - probably more feasible - try and update your glibc version.
The described pardiso packages were also compiled with gcc 8.0 but there is a pardiso version available compiled using the gcc 7.2. Both versions also link agains different glibc versions and it might already be feasible to use libpardiso600-GNU720-X86-64.so.
In addition I'd also use a gcc version that is higher equal than the one used to compile pardiso so you might want to upgrade gcc too.
Edit:
Originally Pardiso 6.0 (and, for that matter also 6.2) was deployed as either libpardiso600-GNU720-X86-64.so or libpardiso600-GNU800-X86-64.so both available under its Download-Link.
As promised, here comes the summary of what I learned:
The Pardiso library (like all shared libraries) remembers which glibc version was used when it was compiled. Occasionally glibc may be older on your system than what Pardiso expects, leading to the link errors described by OP. You can check the version of your glibc by running ldd --version.
I applied for a free time-limited academic license, that gave me a personal download link. As #Flusslauf pointed out, one has the choice of 2 versions for the Linux 64-bit platform. As of today (2021-03-03) the two versions available to me were: libpardiso600-GNU720-X86-64.so (note: GNU720 and not GNU729, but that's a minor difference) and libpardiso600-GNU800-X86-64.so. The latter didn't work for me for the reasons explained above. So I compiled one of the little example programs from the Pardiso website in the directory containing the former Pardiso library as follows:
cd /path/to/pardiso
gcc pardiso_sym.c -L/usr/lib64 -L. -lpardiso600-GNU720-X86-64 \
-llapack -lblas -fopenmp -lpthread -lm -ldl -o psym
export LD_LIBRARY_PATH=/path/to/pardiso:${LD_LIBRARY_PATH}
export OMP_NUM_THREADS=2
export PARDISOLICMESSAGE=1
./psym
The -L/usr/lib64 was necessary to find LAPACK and BLAS on the machine I used. The -L. tells GCC to look for the Pardiso library in the current directory (/path/to/pardiso where I compiled the test program). After compilation, add to LD_LIBRARY_PATH the Pardiso library location, ask for 2 OpenMP threads and silence the Pardiso license message.
Oh, one last thing: don't forget to copy your license file to your home directory! :-)

GCC not linking against libstdc++?

I'm receiving C++ build errors on Ubuntu 16.04 (g++ 5.4) that I don't understand:
The linker errors are (taken a few of them and run them through c++filt)
undefined reference to symbol 'std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const##GLIBCXX_3.4'
undefined reference to symbol 'std::condition_variable::notify_one()##GLIBCXX_3.4.11'
The command lanks I'm using are: gcc -std=c++11 -m64 -fPIC -std=c++11 ... (the ... has all the libs, etc.)
I assume I'm trying to link against /usr/lib/x86_64-linux-gnu/libstdc++.so.6. When I run strings against it, I see GLIBCXX_3.4 and GLIBCXX_3.4.11 (but I really don't know what this is indicating.)
nm shows me that the symbols (at least the condition_variable one is defined)
$ nm -DA /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | c++filt | grep condition_variable::notify_one
/usr/lib/x86_64-linux-gnu/libstdc++.so.6:00000000000b3930 T std::condition_variable::notify_one()
I've run readelf on all the libraries I'm attempting to link, and they all appear to be built for the same ABI (GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609)
Update
I noticed that the first error is resolved by explicitly linking against libstd++.so (i.e. I added stdc++ to my target_link_libraries in CMake). I was under the impression that I should never have to do this?
tl;dr: Invoke g++ rather than gcc to avoid this problem
(based on #SergeyA's comment)
GCC behaves differently depending on whether you run it as the gcc or the g++ binary. Specifically, it apparently won't automatically link against its bundled C++ standard library, libstdc++. I'm guessing it will link against its C standard library - which doesn't help you much.
So just use the appropriate binary for your language; specifying --std=c++whatever isn't enough.

Debug symbol bug with MacPorts installed GCC 4.9?

I have recently installed GCC 4.9.2 (port name gcc49) through MacPorts. I am quite happy with its new features such as colorized diagnostics and C++1y/C++14 support improvements, etc.
However, since I started to compile code using GCC 4.9.2, I realized that it is not generating debug symbol directory *.dSYM and gdb says "no debugging symbols found" when I try to debug a program I compiled with -g flag.
Is this a MacPorts specific bug or is there a problem with GCC 4.9?
Thanks
It is not a MacPorts specific issue. MacPorts doesn't really do much to customize the gcc ports.
If you want to create a dSYM bundle and strip your executable, you should just do something like:
gcc-mp-4.9 -g3 -c example.c
gcc-mp-4.9 example.o -o example
dsymutil --out example.dSYM example
strip -S -x example
As a side note, if you want C++11/C++14 support, I suggest you use the clang-3.5 port as that will allow you to use libc++ from the system instead of libstdc++ from MacPorts (and allow you to use system and MacPorts C++ libraries rather than just the STL). Also, lldb is really the preferred debugger for OS X these days.

GCC dies trying to compile 64bit code on OSX 10.6

I have a brand-new off-the-cd OSX 10.6 installation.
I'd now like to compile the following trivial C program as a 64bit binary:
#include <stdio.h>
int main()
{
printf("hello world");
return 0;
}
I invoke gcc as follows:
gcc -m64 hello.c
However, this fails with the following error:
Undefined symbols:
"___gxx_personality_v0", referenced from:
_main in ccUAOnse.o
CIE in ccUAOnse.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
What's going on here? Why is gcc dying?
Compiling without the -m64 flag works fine.
Two things:
I don't think you actually used gcc -m64 hello.c. The error you got is usually the result of doing something like gcc -m64 hello.cc- using the C compiler to compile C++ code.
shell% gcc -m64 hello.c
shell% ./a.out
hello world [added missing newline]
shell% cp hello.c hello.cc
shell% gcc -m64 hello.cc
Undefined symbols:
"___gxx_personality_v0", referenced from:
_main in ccYaNq32.o
CIE in ccYaNq32.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
You can "get this to work" with the following:
shell% gcc -m64 hello.cc -lstdc++
shell% ./a.out
hello world
Second, -m64 is not the preferred way of specifying that you'd like to generate 64-bit code on Mac OS X. The preferred way is to use -arch ARCH, where ARCH is one of ppc, ppc64, i386, or x86_64. There may be more (or less) architectures available depending on how your tools are set up (i.e., iPhone ARM, ppc64 deprecated, etc). Also, on 10.6, gcc defaults to -arch x86_64, or generating 64-bit code by default.
Using this style, it's possible to have the compiler create "fat binaries" automatically- you can use -arch multiple times. For example, to create a "Universal Binary":
shell% gcc -arch x86_64 -arch i386 -arch ppc hello.c
shell% file a.out
a.out: Mach-O universal binary with 3 architectures
a.out (for architecture x86_64): Mach-O 64-bit executable x86_64
a.out (for architecture i386): Mach-O executable i386
a.out (for architecture ppc7400): Mach-O executable ppc
EDIT: The following was added to answer the OPs question "I did make a mistake and call my file .cc instead of .c. I'm still confused about why this should matter?"
Well... that's a sort of complicated answer. I'll give a brief explanation, but I'll ask that you have a little faith that "there's actually a good reason."
It's fair to say that "compiling a program" is a fairly complicated process. For both historical and practical reasons, when you execute gcc -m64 hello.cc, it's actually broken up in to several discrete steps behind the scenes. These steps, each of which usually feeds the result of each step to the next step, are approximately:
Run the C Pre-Processor, cpp, on the source code that is being compiled. This step is responsible for performing all the #include statements, various #define macro expansions, and other "pre-processing" stuff.
Run the C compiler proper on the C Pre-Processed results. The output of this step is a .s file, or the result of the C code compiled to assembly language.
Run the as assembler on the .s source. This assembles the assembly language in to a .o object file.
Run the ld linker on the .o file(s) to link the various compiled object files and various static and dynamically linked libraries in to a useable executable.
Note: This is a "typical" flow for most compilers. An individual implementation of a compiler doesn't have to follow the above steps. Some compilers combine multiple steps in to one for performance reasons. Modern versions of gcc, for example, don't use a separate cpp pass. The tcc compiler, on the other hand, performs all the above steps in one pass, using no additional external tools or intermediate steps.
In the above, traditional compiler tool chain flow, the cc (or, in our case, gcc) command is called a "compiler driver". It's a "logical front end" to all of the above tools and steps and knows how to intelligently apply all the steps and tools (like the assembler and linker) in order to create a final executable. In order to do this, though, it usually needs to know "the kind of" file it is dealing with. You can't really feed an assembled .o file to the C compiler, for example. Therefore, there are a couple of "standard" .* designations used to specify the "kind" of file (see man gcc for more info):
.c, .h C source code and C header files.
.m Objective-C source code.
.cc, .cp, .cpp, .cxx, .c++ C++ Source code.
.hh C++ header file.
.mm, .M Objective-C++ source code.
.s Assembly language source code.
.o Assembled object code.
.a ar archive or static library.
.dylib Dynamic shared library.
It's also possible to over-ride this "automatically determined file type" using various compiler flags (see man gcc for how to do this), but it's generally MUCH easier to just stick with the standard conventions so that everything "just works" automatically.
And, in a round about way, if you had used the C++ "compiler driver", or g++, in your original example, you wouldn't have encountered this problem:
shell% g++ -m64 hello.cc
shell% ./a.out
hello world
The reason for this is gcc essentially says "Use C rules when driving the tool chain" and g++ says "Use C++ rules when driving the tool chain". g++ knows that to create a working executable, it needs to pass -lstdc++ to the linker stage, whereas gcc obviously doesn't think this is necessary even though it knew to use the C++ compiler at the "Compile the source code" stage because of the .cc file ending.
Some of the other C/C++ compilers available to you on Mac OS X 10.6 by default: gcc-4.0, gcc-4.2, g++-4.0, g++-4.2, llvm-gcc, llvm-g++, llvm-gcc-4.0, llvm-g++-4.0, llvm-gcc-4.2, llvm-g++-4.2, clang. These tools (usually) swap out the first two steps in the tool chain flow and use the same lower-level tools like the assembler and linker. The llvm- compilers use the gcc front end to parse the C code and turn it in to an intermediate representation, and then use the llvm tools to transform that intermediate representation in to code. Since the llvm tools use a "low-level virtual machine" as its near-final output, it allows for a richer set of optimization strategies, the most notable being that it can perform optimizations across different, already compiled .o files. This is typically called link time optimization. clang is a completely new C compiler that also targets the llvm tools as its output, allowing for the same kinds of optimizations.
So, there you go. The not so short explanation of why gcc -m64 hello.cc failed for you. :)
EDIT: One more thing...
It's a common "compiler driver technique" to have commands like gcc and g++ sym-link to the same "all-in-one" compiler driver executable. Then, at run time, the compiler driver checks the path and file name that was used to create the process and dynamically switch rules based on whether that file name ends with gcc or g++ (or equivalent). This allows the developer of the compiler to re-use the bulk of the front end code and then just change the handful of differences required between the two.
I don't know why this happens (works fine for me), but
Try compile with g++, or link to libstdc++. ___gxx_personality_v0 is a symbol used by GNU C++ to set up the SjLj callback for the destructors, so for some reason C++ code creeps into your C code. or
Remove the -m64 flag. Binaries generated by GCC 4.2 on 10.6 defaults to 64-bit as far as I know. You can check by file the output and ensure it reads "Mach-O 64-bit executable x86_64". or
Reinstall the latest Xcode from http://developer.apple.com/technology/xcode.html.
OK:
adding -m64 doesn't do anything, a normal gcc with no options is a 64-bit compile
if you are really just off-the-cd then you should update and install a new xcode
your program works fine for me with or without -m64 on 10.6.2
We had a similar issue when working with CocoaPods when creating and using a pod that contained Objective-C++ code so I thought it's also worth mentioning:
You should edit the .podspec of the pod that contains the c++ code, and add a line like:
s.xcconfig = {
'OTHER_LDFLAGS' => '$(inherited) -lstdc++',
}