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

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.

Related

gcc 5.40 doesn't include standard include files?

gcc 5.4.0
cygwin 2.8.0
Win10
I've been been knocking my head around this problem.When I compile a simple program, see below, I get an error in one of the gcc include files. I checked the cygwin mailing list and no one has reported an error in the gcc download so I think it's a misunderstanding on my part but I can't figure what I did wrong. Prior to this point all the gcc include fileswere included automatically. Oh, and the compile is correct for other libraries.
The code is:
gcc -std=c++11 test.cpp or gcc test.cpp
include iostream
using namespace std;
int main(int argc, char** argv) { }
and the error message is:
/tmp/ccfBvaqg.o:test.cpp:(.text+0x44): undefined reference to std::ios_base::Init::Init()'
/tmp/ccfBvaqg.o:test.cpp:(.text+0x44): relocation truncated to fit: R_X86_64_PC32 against undefined symbolstd::ios_base::Init::Init()'
/tmp/ccfBvaqg.o:test.cpp:(.rdata$.refptr._ZNSt8ios_base4InitD1Ev[.refptr._ZNSt8ios_base4InitD1Ev]+0x0): undefined reference to `std::ios_base::Init::~Init()'
gcc is the C compiler driver. The compiler automatically detects the language based on the file name; that is why the compilation succeeded. However, the linker is not affected by the names of the source files. By default, the C compiler driver does not link with the C++ standard library.
Since you used the standard library (<iostream> is a bit atypical header file in such a way that merely including it causes a standard library function to be called at the start of the program), but did not link it, the linker fails. The solution is to link with the C++ standard library. The simplest way to do that is to use the C++ compiler driver (g++) which links the standard library by default.

Failed to compile using mpich and gcc

I have compiled mpich 3.2 with gcc 4.8.3 on centos. Everything seems to be fine. Then I wrote a simple test program,
#include "mpi.h"
int main(int argc,char **argv)
{}
and use the mpic++ to compile. Then errors return,
/home/setups/mpich-3.2/build/lib/libmpi.so: undefined reference to _intel_fast_memcpy'
/home/setups/mpich-3.2/build/lib/libmpi.so: undefined reference to__intel_sse2_strncmp'
/home/setups/mpich-3.2/build/lib/libmpi.so: undefined reference to _intel_fast_memset'
/home/setups/mpich-3.2/build/lib/libmpi.so: undefined reference to__intel_sse2_strlen'
What exactly goes wrong? I'm so confused that the error seems to be related with intel compilers, but I use gcc to compile mpich by the command,
./configure --prefix=/home/setups/mpich-3.2/build/ CC=gcc CXX=gcc F77=gfortran FC=gfortran
I have added /home/setups/mpich-3.2/build/bin to PATH and /home/setups/mpich-3.2/build/lib to LD_LIBRARY_PATH
mpicc -v shows:
mpicc for MPICH version 3.2
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/home/setups/gcc-4.8.3/build/libexec/gcc/x86_64-unknown-linux-gnu/4.8.3/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ./configure --prefix=/home/setups/gcc-4.8.3/build --with-gmp=/home/setups/gmp-6.1.2/build --with-mpfr=/home/setups/mpfr-3.1.5/build --with-mpc=/home/setups/mpc-1.0.3/build --disable-multilib
Thread model: posix
gcc version 4.8.3 (GCC)
You might find your solution at the open-mpi.org site and their faq for building MPI. For example, item 17.
A common mistake when building Open MPI with the Intel compiler suite
is to accidentally specify the Intel C compiler as the C++ compiler.
Specifically, recent versions of the Intel compiler renamed the C++
compiler "icpc" (it used to be "icc", the same as the C compiler).
Users accustomed to the old name tend to specify "icc" as the C++
compiler, which will then cause a failure late in the Open MPI build
process because a C++ code will be compiled with the C compiler. Bad
Things then happen. The solution is to be sure to specify that the C++
compiler is "icpc", not "icc". For example:
https://www.open-mpi.org/faq/?category=building
/home/setups/mpich-3.2/build/lib/libmpi.so: undefined reference to _intel_fast_memcpy'
This strongly suggests an Intel compiler was used to build mpich.
That can happen is gcc/g++/gfortran is not in your PATH or if your environment points to the Intel compiler (e.g. CC=icc or CXX=icpc or FC=ifort).

Link against shared library with SONAME

How can I force the gcc linker to link against a given version (soname) of a shared library on the system?
I need this to enforce that the version of openssl that is #include'ed matches the version that is linked, on any system, even if multiple versions of openssl are installed. To find the ABI version, my configure script first compiles and runs a program that extracts the SONAME from the headers:
#include <openssl/opensslv.h>
#include <stdio.h>
int main () {
printf(SHLIB_VERSION_NUMBER);
return 0;
}
The SHLIB_VERSION_NUMBER contains the so version string, e.g. 0.9.8 or 1.0.2k or 1.1.0. But how do I tell gcc to link against this version of libssl or libcrypto rather than just any -lssl?
I tried "in situ" linking, so that instead of linking with gcc main.c -lcrypto we use:
gcc main.c libcrypto.so.1.1.0
However it seems the linker libcrypto.so.1.1.0 cannot be found:
gcc: error: libcrypto.so.1.1.0: No such file or directory
I guess the system only searches in the standard locations when using the -l flag. Is there a better way to make my software link against libcrypto.so.1.1.0?
To select the correct version of the openssl shared libraries use:
gcc main.c -l:libssl.so.1.0.0 -l:libcrypto.so.1.0.0
The key to answering this question is "how do I control ld so that is links the correct version of a shared library?".
The correct way to pass a linker flag (a command line parameter to ld) using the gnu compilers (gcc, g++, gdc, etc...) is to use the normal ld parameter prefixed with "-l". For example -lssl or -L/usr/local/lib.
Edit: As per How to specify the library version to use at link time? you can read the manual for ld with:man ld.

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.

Linking difference between clang and gcc

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.

Resources