3.11.4.2. Simple error

Examples on GitHub

Here is an example of trivial “undefined reference” error with diagnostic and, of course, fix instructions.

Library boo:

# boo/CMakeLists.txt

add_library(boo Boo.hpp Boo.cpp)
// boo/Boo.hpp

#ifndef BOO_HPP_
#define BOO_HPP_

class Boo {
 public:
  int boo(int, int);
};

#endif // BOO_HPP_
// boo/Boo.cpp

#include "boo/Boo.hpp"

int Boo::boo(int, int) {
  return 0x42;
}

Library foo use library boo but since we are trying to trigger an error the target_link_libraries directive is intentionally missing:

# foo/CMakeLists.txt

add_library(foo Foo.cpp Foo.hpp)
// foo/Foo.hpp

#ifndef FOO_HPP_
#define FOO_HPP_

class Foo {
 public:
  int foo(int, char);
};

#endif // FOO_HPP_
// foo/Foo.cpp

#include "foo/Foo.hpp"
#include "boo/Boo.hpp"

int Foo::foo(int, char) {
  Boo boo;
  return boo.boo(14, 15);
}

Final baz executable:

# Top-level CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(baz)

include_directories(${CMAKE_CURRENT_LIST_DIR}) # for '#include <boo/Boo.hpp>'

add_subdirectory(boo)
add_subdirectory(foo)

add_executable(baz main.cpp)
target_link_libraries(baz foo)
#include "foo/Foo.hpp"

int main() {
  Foo foo;
  return foo.foo(144, 'x');
}

Generate project:

[library-examples]> rm -rf _builds
[library-examples]> cmake -Hlink-error -B_builds
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../library-examples/_builds

First let’s build library boo:

[library-examples]> cmake --build _builds --target boo
-- Configuring done
-- Generating done
-- Build files have been written to: /.../library-examples/_builds
Scanning dependencies of target boo
[ 50%] Building CXX object boo/CMakeFiles/boo.dir/Boo.cpp.o
[100%] Linking CXX static library libboo.a
[100%] Built target boo

An attempt to build executable baz will fail with link error:

> cmake --build _builds --target baz
Scanning dependencies of target foo
[ 25%] Building CXX object foo/CMakeFiles/foo.dir/Foo.cpp.o
[ 50%] Linking CXX static library libfoo.a
[ 50%] Built target foo
Scanning dependencies of target baz
[ 75%] Building CXX object CMakeFiles/baz.dir/main.cpp.o
[100%] Linking CXX executable baz
foo/libfoo.a(Foo.cpp.o): In function `Foo::foo(int, char)':
Foo.cpp:(.text+0x35): undefined reference to `Boo::boo(int, int)'
collect2: error: ld returned 1 exit status
CMakeFiles/baz.dir/build.make:95: recipe for target 'baz' failed
make[3]: *** [baz] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/baz.dir/all' failed
make[2]: *** [CMakeFiles/baz.dir/all] Error 2
CMakeFiles/Makefile2:79: recipe for target 'CMakeFiles/baz.dir/rule' failed
make[1]: *** [CMakeFiles/baz.dir/rule] Error 2
Makefile:118: recipe for target 'baz' failed
make: *** [baz] Error 2

Use nm tool to verify that symbol is indeed undefined:

> nm --undefined-only --demangle _builds/foo/libfoo.a

Foo.cpp.o:
                 U __stack_chk_fail
                 U Boo::boo(int, int)

Library boo has it:

> nm --defined-only --demangle _builds/boo/libboo.a

Boo.cpp.o:
0000000000000000 T Boo::boo(int, int)

So library foo depends on library boo, every time we are linking foo we have to link boo too. This can be expressed by target_link_libraries command. Fix:

--- /home/docs/checkouts/readthedocs.org/user_builds/cgold/checkouts/latest/docs/examples/library-examples/link-error/foo/CMakeLists.txt
+++ /home/docs/checkouts/readthedocs.org/user_builds/cgold/checkouts/latest/docs/examples/library-examples/link-error-fix/foo/CMakeLists.txt
@@ -1,3 +1,4 @@
 # foo/CMakeLists.txt
 
 add_library(foo Foo.cpp Foo.hpp)
+target_link_libraries(foo PUBLIC boo)

Should work now:

[library-examples]> rm -rf _builds
[library-examples]> cmake -Hlink-error-fix -B_builds
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../library-examples/_builds

[library-examples]> cmake --build _builds
Scanning dependencies of target boo
[ 16%] Building CXX object boo/CMakeFiles/boo.dir/Boo.cpp.o
[ 33%] Linking CXX static library libboo.a
[ 33%] Built target boo
Scanning dependencies of target foo
[ 50%] Building CXX object foo/CMakeFiles/foo.dir/Foo.cpp.o
[ 66%] Linking CXX static library libfoo.a
[ 66%] Built target foo
Scanning dependencies of target baz
[ 83%] Building CXX object CMakeFiles/baz.dir/main.cpp.o
[100%] Linking CXX executable baz
[100%] Built target baz