2

I'm trying to build a shared library in C++ in Ubuntu (which I will load at runtime using dlopen), but I noticed that the shared library builds just fine even if there's some missing dependencies. If I were to build an executable I would get an undefined reference linker error, which is what I would like to see here.

There might be a little too much detail in this example, but I wasn't entirely sure how to pare it down and also make it representative.

Base.h

class Base{
 public:
 virtual void foo()=0;
};

extern "C" {
Base* CreateBase();
}
extern "C" {
void DestroyBase(Base* b);
}

Derived.h

#include "Base.h"

class Derived : public Base {
 public:
 void foo();
};

extern "C" {
Base* CreateBase() {
   return new Derived;
}
}
extern "C" {
void DestroyBase(Base* b) {
   delete b;
}
}

Derived.cc

#include "Derived.h"
#include "OtherClass.h"

#include <iostream>

void Derived::foo(){
  std::cout << "Derived::foo()" << std::endl;
  std::cout << "Calling OtherClass::bar()" << std::endl;
  OtherClass other;
  other.bar();
}

OtherClass.h

class OtherClass{
  public:
  void bar();
};

My command line to build the shared library is

g++ -shared -fPIC -o libtest_dll.so Derived.cc

The problem is that I have no definition of OtherClass::bar() which is called by Derived::foo(), but libtest_dll.so builds without error or warning. It's my understanding that in Visual Studio in Windows if I were to build a DLL out of this code, it would fail to link. How can I get that behavior using g++ in Ubuntu/Linux?

Running g++ 8.3.0-6 on Ubuntu 19.04

LedHead
  • 237
  • 1
  • 3
  • 13
  • Of course it’s fine. Run any tool for the shared object inspection and you will find that the symbol will be marked as run time dependency. `ldd libtest_dll.so` should show the dependency. – 0andriy Dec 18 '19 at 22:11
  • @0andriy The idea is that `OtherClass::bar()` _should_ be in this source code, but I've made a mistake by accidentally leaving it out. Instead of finding that out at runtime, I'd like to find it out at compile time. – LedHead Dec 18 '19 at 23:13

1 Answers1

3

When I'm building and want to avoid this situation, I compile the library with the options: -Wl,--no-allow-shlib-undefined -Wl,-z,defs

The first option causes the link of the shared library to fail in the situation that a symbol is not defined in the code, when used in combination with the second option, which causes the linker to report the missing symbols.

This works well to prevent missing symbols at run-time by detecting them at link time. I do, however, need to link the .so with all the libraries it uses, as otherwise it will fail to build.

sample (src.c):

#include <math.h>

extern
double share_the_stuff(double val)
{
    return acos(val * val);
}

Build with missing symbol:

gcc -shared -o src.so src.c -Wl,--no-allow-shlib-undefined -Wl,-z,defs
/usr/bin/ld: /tmp/ccFmD5uY.o: in function `share_the_stuff':
src.c:(.text+0x17): undefined reference to `acos'
collect2: error: ld returned 1 exit status

link in libm.so:

gcc -shared -o src.so src.c -Wl,--no-allow-shlib-undefined -Wl,-z,defs -lm

It behaves the same with missing internal symbols.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • Great! `-Wl,-z,defs` fixes the problem, although I don't think `-Wl,--no-allow-shlib-undefined` affects anything for either your example or my example. Also, it looks like `-Wl,--no-undefined` is the same as `-Wl,z,defs`. Knowing the proper keywords to search for pointed me to [this question](https://stackoverflow.com/questions/2356168/force-gcc-to-notify-about-undefined-references-in-shared-libraries) of which mine is probably a duplicate. – LedHead Dec 19 '19 at 04:40
  • `--no-allow-shlib-undefined` is for checking the shared library one is linking against, but not the shared library one is creating. Also, it is already the default currently (though I am not sure about 2019). – Yongwei Wu Apr 03 '23 at 01:11