Garmaine Staff asked 1 year ago

I have the following files:

ClassA.h:

#ifndef CLASS_A_H
#define CLASS_A_H

class A
{
public:
    A();
    double foo();
private:
    double value;
};

#endif

ClassA.cpp

#include "ClassA.h"

A::A()
{
    this->value = 1.0;
}

double A::foo()
{
    return this->value;
}

ClassB.h

#ifndef CLASS_B_H
#define CLASS_B_H

#include "ClassA.h"

class B
{
public:
    B();
    double bar();

private:
    A a;
};

#endif

Class B.cpp

#include "ClassB.h"

B::B(){}

double B::bar()
{
    return this->a.foo();
}

main.cpp

#include "ClassB.h"
#include <iostream>

int main()
{
    B b;
    std::cout << b.bar() << std::endl;
    return 0;
}

If I compile everything together into an executable and run (g++ *.cpp && ./a.out), I get the expected output.

However, if I compile the two classes into separate libraries and try to link them into a single executable, I get linking errors:

$ g++ -fPIC -c CLassA.cpp
$ g++ -fPIC -c CLassB.cpp
$ g++ -shared ClassA.o -o libClasssA.so
$ g++ -shared ClassB.o -o libClasssB.so
$ g++ main.cpp -L./ -lClassA -lClassB

$ .//libClassB.so: undefined reference to `A::A()'
$.//libClassB.so: undefined reference to `A::foo()'
$ collect2: error: ld returned 1 exit status

One way to fix the link error is to simply swap the order of -lClassA and -lClassB in the executable compilation.

However, I also found that if I take the B constructor out of the .cpp file and place it in the header, the link error disappears.

So here are my two questions:

  1. Why does the link order matter here? This StackOverflow post claims link order doesn't matter for dynamic libs.
  2. Why does moving the implementation of the empty B constructor into the .cpp file cause link errors?