-1

I am having trouble when I create a library that links to an external library (linear algebra, MUMPS). If I simply write a program composed of a Main.cpp , and a module SOLVER.h and SOLVER.cpp, and I link the library MUMPS everything runs fine. But, if I first create the SOLVER library, and then compile the same Main.cpp an try to link against the SOLVER and MUMPS library, I get an error. Below, the example: Main.cpp file

#include "SOLVER.h"
int main(void) {       
    Eigen::VectorXd  A; Eigen::VectorXd b;
    A.resize(2);  b.resize(2);
    b << 1,2 ;   A << 3.0 , 4.0 ; 
    SOLVER Solver;
    Solver.SolveLinSyst(A, b);    
    return 0;
}

Here the sought library header

#include <Eigen/Dense>
#include "dmumps_c.h" 
#include <vector> 

class SOLVER
{   
public:         
    std::vector<int> ROW_ , COL_ ; 
    DMUMPS_STRUC_C mumps_par;     // mumps structure  
    void SolveLinSyst(Eigen::VectorXd &a, Eigen::VectorXd &inout);   
protected:         
    void AllocateInitializeVectors(); 
    void NewtonStep();                       
};

Inside the SOLVER.cpp I have an instantiation of a MUMPS structure dmumps_c(&mumps_par).

When I compile directly the Main and SOLVER module, all works fine. However, when I first compile SOLVER as a library, and then, separately, I try to compile the Main linking it against the generated libSolver.a library I get an error message. This is the makefile that I used to create the library, or to compile directly the Main and the SOLVER.cpp .

CFLAGS=-c  -std=c++14  -Wfatal-errors   -lm -O0 -g -Wall -Wunused-parameter -fwhole-file   -pedantic  -Wextra

LIBS = -ldmumps -lmumps_common -lmpiseq -lopenblas -lgfortran -lquadmath -lpthread
all:    Main_

library:    SOLVER.o
    ar  r  libSolver.a SOLVER.o
    ranlib libSolver.a

Main_: SOLVER.o Main.o
    g++ -static $(INCLUDES) SOLVER.o Main.o -o Main.exe $(LIBS_PATH) $(LIBS)  -Wl,-rpath=$(LIBS_PATH)  


Main_.o: Main_.cpp
    g++ $(CFLAGS)  $(INCLUDES) Main_.cpp 

SOLVER.o: SOLVER.cpp
    g++ $(CFLAGS)  $(INCLUDES) $(LIBS_PATH) $(LIBS) SOLVER.cpp 

If I create the library separately, I copy the Main_.cpp into Main_testlib.cpp in a subfolder, I add the include path of SOLVER.h, the path of the above generated libSolver.a library

INCLUDES2 = $(INCLUDES) -I../
LIBS2 =  $(LIBS) -lSolver
LIBS_PATH2 = $(LIBS_PATH) -L../

all:    Main_testlib

Main_testlib: Main_testlib.o
    g++  Main_testlib.o -o  Main_testlib.exe $(LIBS_PATH2) $(LIBS2)  -Wl,-rpath=$(LIBS_PATH2)

Main_testlib.o:  Main_testlib.cpp
    g++ $(CFLAGS) $(INCLUDES) Main_testlib.cpp

I ge the error at linking stage:

>     ..//libSolver.a(SOLVER.o): In function `SOLVER::SolveLinSyst(Eigen::Matrix<double, -1, 1, 0, -1, 1>&,
> Eigen::Matrix<double, -1, 1, 0, -1, 1>&)':
>     C:\test/SOLVER.cpp:18: undefined reference to `dmumps_c'
>     ..//libSolver.a(SOLVER.o): In function `SOLVER::AllocateInitializeVectors()':
>     C:\test/SOLVER.cpp:34: undefined reference to `dmumps_c'
>     collect2.exe: error: ld returned 1 exit status
Rauno C.
  • 61
  • 1
  • 7

1 Answers1

1

I believe you need to specify all the dependencies of your libraries when linking your binary. This is because a library is not usually created by a linker but rather by a library took which does not aim to resolve all dependencies. For example, it does not copy all the code from the dependencies into the resulting library.

The rationale is that this needs to be done anyway when the linker builds the final binary, which would have a wider perspective (e.g on the target platform, static or dynamic usage of libraries, etc) so early failing the library creation due to a missing external symbol make little sense.

Uri Cohen
  • 3,488
  • 1
  • 29
  • 46
  • A static library is basically an archive of object files. It would be similar to linking with the objects straight away, in which case you need to specify all the dependences. When linking against dynamic libraries this is not necessary, as the `.dynamic` section of the library contains which libraries it depends on (`NEEDED` entries). – Jorge Bellon Feb 27 '18 at 09:10