ajclinto
ajclinto

Reputation: 145

How to get gcc to report an error for an undefined, unused, external symbol

I'm looking for a way to produce a linker error when a function is declared but not defined in an exported class. Here is a simple example that illustrates the problem:

test.h:

#define DLLEXPORT __attribute__((__visibility__("default")))

class DLLEXPORT CLASS_A {
public:
     CLASS_A();
    ~CLASS_A();
    void withdefinition();
    void nodefinition();
};

test.cpp:

#include "test.h"

CLASS_A::CLASS_A() {}
CLASS_A::~CLASS_A() {}
void CLASS_A::withdefinition() {}

Makefile:

CFLAGS = -Wall -Wextra -fvisibility=hidden -fvisibility-inlines-hidden -fPIC
LDFLAGS = -Wl,--no-undefined

top: test.so

test.o: test.cpp test.h Makefile
    g++ $(CFLAGS) -c $< -o $@
    nm -C test.o

test.so: test.o
    g++ -shared $(CFLAGS) $(LDFLAGS) $< -o $@
    nm -C test.so

The output that I see from "nm test.o" is the following:

nm -C test.o
0000000000000014 T withdefinition()
0000000000000000 T CLASS_A::CLASS_A()
0000000000000000 T CLASS_A::CLASS_A()
000000000000000a T CLASS_A::~CLASS_A()
000000000000000a T CLASS_A::~CLASS_A()

The function "withdefinition()" generates an external definition, while the function "nodefinition()" generates no symbol at all. In theory, if the compilation of test.cpp could generate an undefined symbol for "nodefinition" the subsequent link command would complain about the undefined symbol. Unfortunately, this only happens if "nodefinition()" is explicitly called in the code. This is an error that can commonly occur during refactoring and it would be helpful if it could be detected as early as possible - is there an easy way to do this automatically with the gcc toolchain?

Upvotes: 3

Views: 392

Answers (2)

Mats Petersson
Mats Petersson

Reputation: 129344

Since the compiler doesn't actually KNOW which functions you are defining where, it's impossible for the compiler/linker to perform this task.

Note that the knowledge that there may be a function called nodefinition is lost during the compilation phase, so this information is only retained if you actually USE the function somewhere.

You could possibly write some (or find someone else's already written) code-analysis tool using the clang analysing framework, if you have a strict "x.h" and "x.cpp" relationship, so no functionality declared in "x.h" is ever defined in another file than "x.cpp" (or files included by "x.cpp"). But if the implementation is allowed elsewhere, then it's only possible to detect when the function is actually needed by the linker.

Of course, code-review should also catch this sort of problem in most cases.

Upvotes: 0

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

A (non-virtual) function declared but not defined produces no trace in the compiled code. This is by design. You cannot change it because such change will break absolutely everything.

Imagine every function, every class, every piece of data, every little nothing you have in the standard include files that you don't use, don't care about and don't even know it exists leaving a symbol in your compiled code.

Upvotes: 1

Related Questions