Linking difference between clang and gcc - c++11

I am running fedora 23 and just compiled and installed casadi 2.4.1 (however, I do not think that this is casadi specific).
I am trying to compile and run a simple test program:
#include <iostream>
#include <casadi/casadi.hpp>
using namespace casadi;
int main () {
const SX m(42);
const SX n(23);
const SX x = m + n ;
std::cout << x << std::endl;
}
It works fine with gcc:
$ g++ test.cpp -std=c++11 -I$HOME/local/include -L$HOME/local/lib -lcasadi && ./a.out
SX(65)
But using clang, I get a linker error:
$ clang++ test.cpp -std=c++11 -I$HOME/local/include -L$HOME/local/lib -lcasadi && ./a.out
/tmp/test-cde41f.o: In function `casadi::GenericMatrix<casadi::Matrix<casadi::SXElement> >::dimString() const':
test.cpp:(.text._ZNK6casadi13GenericMatrixINS_6MatrixINS_9SXElementEEEE9dimStringEv[_ZNK6casadi13GenericMatrixINS_6MatrixINS_9SXElementEEEE9dimStringEv]+0x2b): undefined reference to `casadi::Sparsity::dimString() const'
/tmp/test-cde41f.o: In function `void casadi::Sparsity::set<casadi::SXElement>(casadi::SXElement*, casadi::SXElement const*, casadi::Sparsity const&) const':
test.cpp:(.text._ZNK6casadi8Sparsity3setINS_9SXElementEEEvPT_PKS3_RKS0_[_ZNK6casadi8Sparsity3setINS_9SXElementEEEvPT_PKS3_RKS0_]+0x6f0): undefined reference to `casadi::Sparsity::dimString() const'
test.cpp:(.text._ZNK6casadi8Sparsity3setINS_9SXElementEEEvPT_PKS3_RKS0_[_ZNK6casadi8Sparsity3setINS_9SXElementEEEvPT_PKS3_RKS0_]+0x743): undefined reference to `casadi::Sparsity::dimString() const'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I am pretty confident that the symbol is defined in the library. However, I fail to understand what clang is missing here. Is there some special c++11 ABI flag that I need to pass to the linker or something like that?

I would suspect version skew. Unless you do something special, clang uses some gcc stdc++ library, for which it searches. That was the case the last time I used clang for much. They may use their own std c++ library now. But if casadi was compiled with one version of gcc and you used clang which uses the std c++ library for another version of gcc, you can see linker errors like this.
You may learn something if you run clang -V to get version information. Also, gcc -v to get gcc version information, and verify that the version of gcc clang wants is the same as the version with which you are compiling.

Related

Is it possible to link LAPACK, LAPACKE, and BLAS libraries with GCC instead of GFORTRAN?

I have an application that is written in C. I would like to use the LAPACK library to do some linear algebra calculations. I am using LAPACKE, which is the C interface to LAPACK. The C code compiled fine with GCC, but I am having trouble linking the libraries with GCC. It only works with GFORTRAN. I downloaded the lapack-3.11.0.tar.gz file from the LAPACK website. I unpacked the file then I built it. I did not make any changes to the make.inc.example file, which was already configured for a linux machine running GNU compilers. Here is how I built it once in the ~/lapack-3.11.0 directory:
cp make.inc.example make.inc
make
LAPACK built successfully and all of the tests passed. Then, I built LAPACKE. To do this, I simply ran make in the ~/lapack-3.11.0/LAPACKE directory. Similarly, it built successfully and all of the tests passed. Notice that in my case, LAPACK is installed in my home directory and not in a system directory.
To test that I could actually use LAPACKE, I wrote a sample C program that solves a system of equations using LAPACKE_dgesv().
lapack_test.c:
#include <stdio.h>
#include <lapacke.h>
int main()
{
int n = 3;
int nrhs = 1;
int lda = n;
int ipiv[n];
double a[9] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0};
double b[3] = {3.0, 3.0, 4.0};
int info;
info = LAPACKE_dgesv(LAPACK_ROW_MAJOR, n, nrhs, a, lda, ipiv, b, nrhs);
if (info == 0)
{
printf("Solution: %f %f %f\n", b[0], b[1], b[2]);
}
else
{
printf("dgsev failed with error code %d\n", info);
}
return 0;
}
Assuming that lapack_test.c is in my home directory, here is how I compiled it and linked the libraries:
gcc -I./lapack-3.11.0/LAPACKE/include -c -o lapack_test.o lapack_test.c
gfortran -o lapack_test lapack_test.o ./lapack-3.11.0/liblapacke.a ./lapack-3.11.0/liblapack.a ./lapack-3.11.0/librefblas.a
This gave my no errors. However, GFORTRAN is very inconvenient for my case. In my application I have many C libraries that probably will not link using GFORTRAN. Or at least, I do not think that that they will.
If I use GCC, I get linkage errors. For example, if I simply replace GFORTRAN with GCC in the last step I get a bunch of errors:
/usr/bin/ld: ./lapack-3.11.0/liblapack.a(iparmq.o): in function `iparmq_':
iparmq.f:(.text+0x25e): undefined reference to `logf'
/usr/bin/ld: iparmq.f:(.text+0x26b): undefined reference to `lroundf'
/usr/bin/ld: ./lapack-3.11.0/liblapack.a(xerbla.o): in function `xerbla_':
xerbla.f:(.text+0x55): undefined reference to `_gfortran_st_write'
/usr/bin/ld: xerbla.f:(.text+0x60): undefined reference to `_gfortran_string_len_trim'
/usr/bin/ld: xerbla.f:(.text+0x77): undefined reference to `_gfortran_transfer_character_write'
/usr/bin/ld: xerbla.f:(.text+0x87): undefined reference to `_gfortran_transfer_integer_write'
/usr/bin/ld: xerbla.f:(.text+0x8f): undefined reference to `_gfortran_st_write_done'
/usr/bin/ld: xerbla.f:(.text+0x9a): undefined reference to `_gfortran_stop_string'
collect2: error: ld returned 1 exit status
Seems to be linking the static library liblapacke.a with no errors. liblapack.a seems to be where the errors are. It is a FORTRAN library, so it makes sense why it would not link correctly using GCC.
Is there a workaround here? Is it worth using LAPACKE? Or, should I try some other way to interface between FORTRAN and C?
There is no difference in linking else than some libraries being added automatically. gfortran and gcc do the same when linking. Only gfortran links some libraries like libgfortran or libm automatically while with gcc you have to use -lgfortran or -lm. Otherwise they do the exact same thing.
You can even use the gcc command to compile Fortran code and the gfortran command to compile C code. Or C++ code. It really does not matter. Just link all the necessary library when linking, depending whether you link with gcc, gfortran, g++ or ld.
In the end the linking is always done by ld, just with some particular flags added by the compiler command.
Finally, to be precise, distinguish GCC, the GNU compiler collection, and gcc, the command that calls the C frontend or the GCC's C compiler. The gfortran command calls the Fortran frontend. They share the same backend and middlend. When you call, e.g. gcc test.f90, the command recognizes that it is a Fortran source file and will invoke the Fortran frontend for you.

Undocumented ABI changes of std::function between GCC-4 and GCC-5/6/7/8/9, how to make a .so working with devtoolset-4/6/7/8/9?

with _GLIBCXX_USE_CXX11_ABI=0
std::function of GCC-4 is different of GCC-5 and follwing versions.
The following code show you the fact:
==> lib.cc <==
#include <functional>
std::function<int(const void*p)> holder;
int run_holder(const void *p)
{
return holder(p);
}
==> main.cc <==
#include <stdio.h>
#include <functional>
extern int run_holder(const void*p);
extern std::function<int(const void*p)> holder;
int foo(const void* p)
{
printf("p=%p\n", p);
return 0;
}
int main()
{
holder = foo;
foo((void*)0x12345678);
holder((void*)0x12345678);
run_holder((void*)0x12345678);
}
==> make.sh <==
#!/bin/bash
GCC4=/usr/bin/g++
GCCN="scl enable devtoolset-5 -- g++"
$GCC4 -std=c++11 -c -g lib.cc -shared -o libfoo.so &&
$GCCN -std=c++11 -L. -lfoo -g main.cc -o a.out &&
LD_LIBRARY_PATH=. ./a.out
expected result, something like:
p=0x12345678
p=0x12345678
p=0x12345678
actual result:
p=0x12345678
./make.sh: line 6: 973 Segmentation fault LD_LIBRARY_PATH=. ./a.out
The reason is the implementation of std::function changes without document.
gcc4: /usr/include/c++/4.8.2/functional:2430
typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...);
gcc5: /opt/rh/devtoolset-4/root/usr/include/c++/5.3.1/functional:2226
gcc8: /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/std_function.h:609
using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...);
So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8. There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.
So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8.
Correct. Neither Red Hat nor the GCC project has ever claimed that's possible, quite the opposite. C++11 support in GCC 4.x was incomplete and unstable, and subject to ABI changes and API changes. What you're trying to do was never supported.
I've explained this in more detail at https://stackoverflow.com/a/49119902/981959
The Developer Toolset documentation covers it too (emphasis mine):
"A compiler in C++11 or C++14 mode is only guaranteed to be compatible with another compiler in C++11 or C++14 mode if they are from the same release series (for example from Red Hat Developer Toolset 6.x).
...
"Using the C++14 language version is supported in Red Hat Developer Toolset when all C++ objects compiled with the respective flag have been built using Red Hat Developer Toolset 6 or later. Objects compiled by the system GCC in its default mode of C++98 are also compatible, but objects compiled with the system GCC in C++11 or C++14 mode are not compatible."
There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.
We do not provide macros to control things that are unsupported and cannot work.
If you want to use C++11 with a mix of GCC versions you need to use a release that has stable, non-experimental support for C++11. So not GCC 4.x.

unresolved std::__cxx11::basic_string::~basic_string and std::allocator<char>::~allocator() symbols

I am trying to compile QtWebApp with Qt5.5.1 onto the latest RPI4-Raspbian Buster and I am encountering inexplicable GLIBCXX unresolved symbols
What Works : QtWebApp cross compiled from windows to armhf using qt5.5.1 binaries natively compiled on Raspbian Buster works fine with the following components
Toolchain : raspberry-gcc8.3.0.exe installed on Windows 10.
Qt Binary Libs : Native compiled on RPI4 Raspbian Buster OS and
copied over to Windows 10.
Command line :
c:/SysGCC/raspberry/bin/arm-linux-gnueabihf-g++.exe -std=c++11 -fPIC -I.
{ALL QT INCLUDE DIRS}
-IC:/SysGCC/raspberry/arm-linux-gnueabihf/sysroot/opt/vc/include
-g -rdynamic -funwind-tables -Woverflow
{ALL QTWEB SOURCE FILES}
-LC:/SysGCC/pi4/pi4qt551/lib
-lQt5Core -lQt5Gui -lQt5Widgets
-lQt5Multimedia -lQt5MultimediaWidgets
-lQt5Network -lm -lpthread -o qtweb
This produces an arm executable that worksfine on RPI-4.
What fails
When compiling natively (which is what I want as the development env) on RPI4 the compilation strangely fails with the following error :
/usr/bin/ld: /tmp/ccnnsRCD.o: undefined reference to symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev##GLIBCXX_3.4.21'
What I have tried (didnt work)
1) Following suggestions from Converting std::__cxx11::string to std::string and passing -D_GLIBCXX_USE_CXX11_ABI=0 it fails with the following error :
/usr/bin/ld: /tmp/ccZfI5co.o: undefined reference to symbol '_ZNSaIcED1Ev##GLIBCXX_3.4'
where those symbol demangles to std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() and std::allocator<char>::~allocator() respectively.
2) I also ran all the combinations WITH/WITHOUT -std=c++11 and D_GLIBCXX_USE_CXX11_ABI=0 and these are the errors
WITH -std=c++11, WITHOUT -D_GLIBCXX_USE_CXX11_ABI=0
/usr/bin/ld: /tmp/ccnnsRCD.o: undefined reference to symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev##GLIBCXX_3.4.21'
WITH -std=c++11, WITH -D_GLIBCXX_USE_CXX11_ABI=0
/usr/bin/ld: /tmp/ccZfI5co.o: undefined reference to symbol '_ZNSaIcED1Ev##GLIBCXX_3.4'
WITHOUT -std=c++11, WITH -D_GLIBCXX_USE_CXX11_ABI=0
/usr/bin/ld: /tmp/cctFncwz.o: undefined reference to symbol '_ZNSaIcED1Ev##GLIBCXX_3.4'
WITHOUT -std=c++11, WITHOUT -D_GLIBCXX_USE_CXX11_ABI=0
/usr/bin/ld: /tmp/cchkJYdO.o: undefined reference to symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev##GLIBCXX_3.4.21'
3) I also copied the sysroot from the raspberry-gcc8.3.0.exe install on Win10 over to RPi-4 and passed that to gcc as its --sysroot location - which also fails with the ~basic_string() unresolver error. (I dont know how to verify if the --sysroot had any effect though I checked that gcc -v output doesnt have --with_libs in it as suggested in a GCC ignores --sysroot post)
INFO: The command line is exactly the same on the RPI4-Buster other than using gcc and not passing -IC:/SysGCC/raspberry/arm-linux-gnueabihf/sysroot/opt/vc/include
Question :
How is it that (assuming no glaring compile option mismatch ;) cross compiling with a gcc 8.3 toolchain from windows to arm-linux works but the same code base when compiled natively on raspbian buster with gcc 8.3 fails with what looks like GLIBCXX version mismatch in the Raspbian Buster OS binaries ?
I am stuck on this for 2 days now. Please suggest any other steps I can try here.
Are you executing the compiler as gcc instead of g++? That would cause this problem. Invoke g++.
Otherwise, Try adding -lstdc++ to your link flags.
Explanation:
The symbols are, obviously, from the C++ standard library. Under some circumstances - at the very least, when you invoke GCC using the gcc binary rather than g++ - GCC compiles C++ code, but doesn't automatically link against the GNU C++ standard library. If for some reason this isn't resolved by invoking g++, you could try adding the -lstdc++ flag, which means "link against the library libstdc++.so or libstdc++.a which you should find in the library search path".

Undefined reference when linking with Boost using g++-4.9 on a g++-5-ish distribution

I've written the following groundbreaking application:
#include <boost/program_options.hpp>
int main(int argc, char** argv)
{
boost::program_options::options_description generic_options("foo");
return 0;
}
I am trying to build this on Debian Stretch, on which the default compiler is GCC 5.3.1-5, and the installed version of Boost is 1.58.0.
However, for reasons which I will not go into here (which would be apparent had this not been a MCVE), I need to compile and link the binary using g++-4.9, not g++-5.3. Compiling works fine, but when I try to link, this is what happens:
/usr/bin/g++-4.9 -Wall -std=c++11 CMakeFiles/tester3.dir/src/altmain2.cpp.o -o bin/tester3 -rdynamic -lboost_log -lboost_system -lboost_program_options
CMakeFiles/tester3.dir/src/altmain2.cpp.o: In function `main':
altmain2.cpp:(.text+0x61): undefined reference to `boost::program_options::options_description::options_description(std::string const&, unsigned int, unsigned int)'
Is this due to some ABI incompatibility between gcc 4 and 5?
If so, is there any way to get around it other than building my own version of Boost?
If not, what could cause this?
Is this due to some ABI incompatibility between gcc 4 and 5?
Looks like it is. By default GCC 5 uses a new ABI for several important standard library classes, including std::basic_string template (and thus also std::string). Unfortunately it would be impossible to make std::string fully conform to C++11 and later without breaking the ABI.
libstdc++ implements dual ABI, so that binaries compiled with older versions of GCC will link (and work correctly) with the new library. See this post by Jason Merrill (the maintainer of GCC's C++ front end) for details.
If so, is there any way to get around it other than building my own
version of Boost?
Probably not. Boost depends on the new implementation of std::string and does not provide backward compatibility (unlike libstdc++). This problem is mentioned in Debian bugtracker.

OpenMP not available on mac with gcc 4.9

The OpenMP website says: "GCC 4.9 supports OpenMP 4.0 for C/C++".
I'm using gcc 4.9.1 from brew, yet I see this error when I try to compile liblinear: omp.h file not found.
Specifically:
Compiling liblinear version 1.93
Source code page:
http://www.csie.ntu.edu.tw/~cjlin/liblinear/
external/liblinear-1.93_multicore/matlab/train.cpp:7:10: fatal error: 'omp.h' file not found
#include <omp.h>
^
1 error generated.
mex: compile of ' "external/liblinear-1.93_multicore/matlab/train.cpp"' failed.
Here's the matlab code used to compile liblinear, which contains a file that contains #include <omp.h>:
% Compile liblinear
if ~exist('liblinear_train')
fprintf('Compiling liblinear version 1.93\n');
fprintf('Source code page:\n');
fprintf(' http://www.csie.ntu.edu.tw/~cjlin/liblinear/\n');
mex -outdir bin ...
COMPFLAGS="$COMPFLAGS -fopenmp" -largeArrayDims ...
external/liblinear-1.93_multicore/matlab/train.cpp ...
external/liblinear-1.93_multicore/matlab/linear_model_matlab.cpp ...
external/liblinear-1.93_multicore/linear.cpp ...
external/liblinear-1.93_multicore/tron.cpp ...
"external/liblinear-1.93_multicore/blas/*.c" ...
-output liblinear_train;
end`
UPDATE
I changed the gcc version in mexopts.sh (side note: I copied it from /Applications/MATLAB_R2013a_Student.app/bin/mexopts.sh to ~/.matlab/R2013a). Specifically, I changed CC=xcrun -sdk macosx10.9 clang to CC='gcc-4.9'.
I think Matlab does indeed use this compiler, because when I run this code:
if ~exist('anigauss')
fprintf('Compiling the anisotropic gauss filtering of:\n');
fprintf(' J. Geusebroek, A. Smeulders, and J. van de Weijer\n');
fprintf(' Fast anisotropic gauss filtering\n');
fprintf(' IEEE Transactions on Image Processing, 2003\n');
fprintf('Source code/Project page:\n');
fprintf(' http://staff.science.uva.nl/~mark/downloads.html#anigauss\n\n');
mex -Dchar16_t=uint16_T -outdir bin ...
selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss_mex.c ...
selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss.c ...
-output anigauss
end
Matlab prints:
dyld: Library not loaded: /usr/local/opt/mpfr2/lib/libmpfr.1.dylib
Referenced from: /usr/local/Cellar/gcc49/4.9.1/libexec/gcc/x86_64-apple-darwin14.0.0/4.9.1/cc1
Reason: Incompatible library version: cc1 requires version 4.0.0 or later, but libmpfr.1.dylib provides version 3.0.0
gcc-4.9: internal compiler error: Trace/BPT trap: 5 (program cc1)
/Applications/MATLAB_R2013a_Student.app/bin/mex: line 1343: 77128 Abort trap: 6 gcc-4.9 -c -I/Applications/MATLAB_R2013a_Student.app/extern/include -I/Applications/MATLAB_R2013a_Student.app/simulink/include -DMATLAB_MEX_FILE -fno-common -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -mmacosx-version-min=10.9 -fexceptions -Dchar16_t=uint16_T -DMX_COMPAT_32 -O2 -DNDEBUG "selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss_mex.c" -o bin/anigauss_mex.o
mex: compile of ' "selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss_mex.c"' failed.
Yet when I try to compile liblinear, I get the very same error message as usual.
COMPFLAGS="$COMPFLAGS /openmp" -largeArrayDims ...
^^^^^^^
This was probably written for Microsoft Visual C/C++ or for Intel C/C++ Compiler on Windows. Unix systems, including OS X, traditionally use - to denote command line flags.
To enable OpenMP support in GCC you should change /openmp to -fopenmp in the compiler flags COMPFLAGS.
It appears that in addition to passing the wrong OpenMP flag, mex is using the wrong compiler. Compare the error outputs from GCC and Clang:
GCC
foo.c:1:25: fatal error: nonexistent.h: No such file or directory
#include <nonexistent.h>
^
compilation terminated.
Clang
foo.c:1:10: fatal error: 'nonexistent.h' file not found
#include <nonexistent.h>
^
1 error generated.
Clang, or at least the version that Apple ships with Xcode, does not support OpenMP. Consult the MATLAB documentation of the mex command on how to select a different compiler. Basically, you have to execute:
mex -setup
If MATLAB detects several usable compilers, it should present you with the ability to pick one of them. Unfortunately, according to this table, MATLAB might not support GCC on OS X (at least it is not listed in the table).

Resources