Undefined symbols when linking application to library

When building this project, I get linker errors:

17:28:00: Running steps for project root...
17:28:00: Starting: "/opt/homebrew/Cellar/cmake/3.23.1/bin/cmake" --build /Users/mitch/dev/cmake-test-qt_dev_debug_non_fw-Debug --target all
[1/5 1.9/sec] Building CXX object app/CMakeFiles/app.dir/main.cpp.o
[2/5 3.5/sec] Building CXX object libs/libfoo/CMakeFiles/libfoo.dir/AbstractApplication.cpp.o
[3/5 5.3/sec] Building CXX object app/CMakeFiles/app.dir/Application.cpp.o
[4/5 6.6/sec] Linking CXX static library libs/libfoo/libfoo.a
[5/5 7.8/sec] Linking CXX executable app/app
FAILED: app/app 
: && /usr/bin/clang++ -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names  app/CMakeFiles/app.dir/main.cpp.o app/CMakeFiles/app.dir/Application.cpp.o -o app/app  -Wl,-rpath,/Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib  libs/libfoo/libfoo.a  /Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib/libQt6Core_debug.6.5.0.dylib  /Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib/libQt6Core_debug.6.5.0.dylib  -framework DiskArbitration  -framework IOKit && :
Undefined symbols for architecture arm64:
  "vtable for Application", referenced from:
      Application::Application() in main.cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
  "vtable for AbstractApplication", referenced from:
      AbstractApplication::AbstractApplication() in main.cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
17:28:01: The process "/opt/homebrew/Cellar/cmake/3.23.1/bin/cmake" exited with code 1.
Error while building/deploying project root (kit: qt-dev-debug-non-fw)
When executing step "Build"
17:28:01: Elapsed time: 00:01.

The classes in libfoo are exported correctly from what I can see, and I’d prefer to not use generate_export_header as I’ll be supporting two build systems for this project.

The only thing that I can see that looks odd is that is that the linker uses a relative path to libfoo:

libs/libfoo/libfoo.a

From searching around I’ve read that CMake should already be aware of the library if it’s created by the same project. However, the answer on that same page says that the libraries need to be copied to the executable directory so that the application can find them, but if that were the case, I would think that I’d get a different error (about the linker being unable to find libfoo.a).

So what am I missing? What is the standard way to do this?

You need a virtual destructor which is not defined anywhere. Add ~Application() override = default; to your Application class. AbstractApplication likely needs the same thing.

Thanks for the reply.

That was a mistake when making a minimal example from the original project. I’ve updated the example to fix that (and added Qbs build files to demonstrate that it works with Qbs):

However, I’m still getting the error:

22:13:27: Running steps for project build-test...
22:13:27: Starting: "/opt/homebrew/Cellar/cmake/3.23.1/bin/cmake" --build /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-cmake --target all
[1/1 21.6/sec] Linking CXX executable app/app
FAILED: app/app 
: && /usr/bin/clang++ -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names  app/CMakeFiles/app.dir/main.cpp.o app/CMakeFiles/app.dir/Application.cpp.o -o app/app  -Wl,-rpath,/Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib  libs/libfoo/libfoo.a  /Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib/libQt6Core_debug.6.5.0.dylib  /Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib/libQt6Core_debug.6.5.0.dylib  -framework DiskArbitration  -framework IOKit && :
Undefined symbols for architecture arm64:
  "vtable for Application", referenced from:
      Application::Application() in Application.cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
  "vtable for AbstractApplication", referenced from:
      AbstractApplication::AbstractApplication() in libfoo.a(AbstractApplication.cpp.o)
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
22:13:27: The process "/opt/homebrew/Cellar/cmake/3.23.1/bin/cmake" exited with code 1.
Error while building/deploying project build-test (kit: qt-dev-debug-non-fw)
When executing step "Build"
22:13:27: Elapsed time: 00:00.

Where is this coming from? The sanitizers tend to want to instrument things that might be implicit in normal builds. Does qbs have the same problem if you enable sanitizers there?

[duplicate]

That comes from the Qt build I built the project with. It was configured with -DFEATURE_sanitize_address=ON. The Qbs project is built with the same Qt build. Here’s the output from building app with Qbs in case it’s useful:

00:27:22: Running steps for project build-test...
/usr/bin/clang++ -g -O0 -Wall -Wextra -fsanitize=address -target arm64-apple-macosx10.13-macho -pipe -fexceptions -fvisibility=default -fPIC -DQT_DEPRECATED_WARNINGS -DQT_GUI_LIB -DQT_CORE_LIB -I/Users/mitch/dev/build-test/libs/libfoo -I/Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/qt.headers -isystem/Users/mitch/dev/qt-dev-debug-non-fw/qtbase/include -isystem/Users/mitch/dev/qt-dev-debug-non-fw/qtbase/include/QtGui -isystem/Users/mitch/dev/qt-dev-debug-non-fw/qtbase/include/QtCore -isystem/Users/mitch/dev/qt-dev-debug-non-fw/qtbase/mkspecs/macx-clang -std=c++17 -stdlib=libc++ -o /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/3a52ce780950d4d9/main.cpp.o -c /Users/mitch/dev/build-test/app/main.cpp
/usr/bin/clang++ -Wl,-arch,arm64,-rpath,@loader_path/../../../Library/Frameworks -stdlib=libc++ -L/Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib -fsanitize=address -target arm64-apple-macosx10.13-macho -o /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/.tmp/app /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/3a52ce780950d4d9/Application.cpp.o /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/3a52ce780950d4d9/main.cpp.o /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/73489b871e127538/moc_Application.cpp.o -framework DiskArbitration -framework IOKit -framework OpenGL -framework AGL -framework AppKit -framework ImageIO -framework Metal -framework DiskArbitration -framework IOKit /Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib/libQt6Gui_debug.dylib /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/libfoo.d09145fd/libfoo.dylib /Users/mitch/dev/qt-dev-debug-non-fw/qtbase/lib/libQt6Core_debug.dylib -framework OpenGL -framework AGL -framework AppKit -framework ImageIO -framework Metal -framework DiskArbitration -framework IOKit
/usr/bin/dsymutil -o /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/app.app.dSYM /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/.tmp/app
/usr/bin/strip -S /Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/app.7d104347/.tmp/app
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -f app.app
00:27:23: Elapsed time: 00:01.

Qbs installs everything to install-root:

mitch@Mitchs-MacBook-Pro install-root % pwd 
/Users/mitch/dev/build-test-qt_dev_debug_non_fw-Debug-qbs/Debug_qt_dev_d_3883db5c1278cc67/install-root
mitch@Mitchs-MacBook-Pro install-root % tree
.
└── usr
    └── local
        ├── Library
        │   └── Frameworks
        │       └── libfoo.dylib
        └── app.app
            └── Contents
                ├── Info.plist
                ├── MacOS
                │   └── app
                └── PkgInfo

7 directories, 4 files

I was told that this is because

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

needs to be before add_library and add_executable.