static linking, duplicate symbol error and inlineing

If you define a function in a header file (i.e. have it’s implementation in the header) and statically link your program, you need to declare it inline if the header is used in multiple files. This is different from issues you get when a header file is included multiple times in a compilation unit.

Consider the following program made of four files

// a.hpp
#pragma once

double foo(double x) { return 2 * x;}
// b.cpp
#include "a.hpp"
// c.cpp
#include "a.hpp"
// main.cpp
#include "a.hpp"

int main(int argc, char* argv[]) { return 0; }

Compiling this with

c++ b.cpp c.cpp main.cpp

Yields

duplicate symbol __Z3food in:
    /var/folders/l7/wx3r7wbx6q3_1rv_mvv069h00000gn/T/b-9d06d3.o
    /var/folders/l7/wx3r7wbx6q3_1rv_mvv069h00000gn/T/c-d62c76.o
duplicate symbol __Z3food in:
    /var/folders/l7/wx3r7wbx6q3_1rv_mvv069h00000gn/T/b-9d06d3.o
    /var/folders/l7/wx3r7wbx6q3_1rv_mvv069h00000gn/T/main-129c77.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

This is because the linker, when it goes to statically join the units b, c and main, finds three definitions (implementation) of the function foo.

The solution is to declare foo as inline

#pragma once

inline double foo(double x) { return 2 * x;}

which helps the compile resolve this.

Incidentally, when you implement class/struct member functions in a header, they are implicitly “inline” so this problem does not have.

Now, if you dynamically link the units instead:

c++ -dynamiclib -o libb.dylib b.cpp
c++ -dynamiclib -o libc.dylib c.cpp
c++ main.cpp -L. -lb -lc

The linker does fine even without declaring the function as inline. In our case the duplicate symbol (function) in the libraries was actually the same. For an informative discussion of what happens when duplicate symbols that are intended to be defined differently appear in different shared libraries, see here.

(These commands are for creating dynamic libraries on macOS, for linux take a look here)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.