CMake for static library using Qt Core
-
wrote on 5 Feb 2024, 05:44 last edited by
I have a project that uses CMake and builds just fine. I want to pull a single class out into a re-useable static library. The class does use QFile and QString. I thought I had my CMakeLists.txt setup correctly with the find_packages(Qt6 Components Core Required). But, when I try to build, the compile of the class source can't find QFile or other Qt symbols. Below is a minimum example I created to show the same issue. Any idea what I have wrong or missing?
CMakeLists.txt:
cmake_minimum_required(VERSION 3.16) project(qt_testlib LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 COMPONENTS Core REQUIRED) add_library(qt_testlib STATIC MyClass.cpp MyClass.h ) target_link_libraries(qt_testlib PRIVATE) target_compile_definitions(qt_testlib PRIVATE COMMON_LIBRARY)
Class header file:
#ifndef MYCLASS_H_INCLUDED #define MYCLASS_H_INCLUDED #include <string> namespace testlib { class MyClass { public: static std::string Load(const std::string& path); }; } // namespace testlib #endif // MYCLASS_H_INCLUDED
Class source file:
#include "MyClass.h" #include <QFile> #include <QString> #include <QTextStream> namespace testlib { std::string MyClass::Load(const std::string& path) { QString qpath(":/"); qpath += path.c_str(); QFile file(qpath); if (!file.open(QIODeviceBase::ReadOnly | QIODeviceBase::Text)) { return ""; } std::string returnVal; QTextStream textStream(&file); if (!textStream.atEnd()) { returnVal = textStream.readLine().toStdString(); } return returnVal; } } // namespace testlib
-
I have a project that uses CMake and builds just fine. I want to pull a single class out into a re-useable static library. The class does use QFile and QString. I thought I had my CMakeLists.txt setup correctly with the find_packages(Qt6 Components Core Required). But, when I try to build, the compile of the class source can't find QFile or other Qt symbols. Below is a minimum example I created to show the same issue. Any idea what I have wrong or missing?
CMakeLists.txt:
cmake_minimum_required(VERSION 3.16) project(qt_testlib LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 COMPONENTS Core REQUIRED) add_library(qt_testlib STATIC MyClass.cpp MyClass.h ) target_link_libraries(qt_testlib PRIVATE) target_compile_definitions(qt_testlib PRIVATE COMMON_LIBRARY)
Class header file:
#ifndef MYCLASS_H_INCLUDED #define MYCLASS_H_INCLUDED #include <string> namespace testlib { class MyClass { public: static std::string Load(const std::string& path); }; } // namespace testlib #endif // MYCLASS_H_INCLUDED
Class source file:
#include "MyClass.h" #include <QFile> #include <QString> #include <QTextStream> namespace testlib { std::string MyClass::Load(const std::string& path) { QString qpath(":/"); qpath += path.c_str(); QFile file(qpath); if (!file.open(QIODeviceBase::ReadOnly | QIODeviceBase::Text)) { return ""; } std::string returnVal; QTextStream textStream(&file); if (!textStream.atEnd()) { returnVal = textStream.readLine().toStdString(); } return returnVal; } } // namespace testlib
@CodeFan You're missing
target_link_libraries(qt_testlib PRIVATE Qt6::Core)
-
wrote on 5 Feb 2024, 18:45 last edited by
@jsulm Thank you for the quick reply. Adding Qt6::Core to the target_link_libraries statement does allow the build to succeed. But, isn't that telling CMake to statically link Qt6::Core into my static lbrary? Meaning, parts of Qt6::Core implementation will be included in my library as well? It seems odd to have to specify a link library in order for a #include to be found at compile time. With that change, the resulting qt_testlib.a is over 500k in size for one tiny class. The 'nm' tool shows lots of Qt function definitions included in the library and not just templated ones. I would have expected these non-templated ones to be undefined and only reside in the Qt library.
-
@jsulm Thank you for the quick reply. Adding Qt6::Core to the target_link_libraries statement does allow the build to succeed. But, isn't that telling CMake to statically link Qt6::Core into my static lbrary? Meaning, parts of Qt6::Core implementation will be included in my library as well? It seems odd to have to specify a link library in order for a #include to be found at compile time. With that change, the resulting qt_testlib.a is over 500k in size for one tiny class. The 'nm' tool shows lots of Qt function definitions included in the library and not just templated ones. I would have expected these non-templated ones to be undefined and only reside in the Qt library.
@CodeFan hi,
No it does not. The use of PRIVATE means that the library you are linking is only used internally and users of your code won't need to link to that library.
As for needing target_link_libraries, find_package just finds the dependencies, it does not tell the system what to do with them.
-
@CodeFan hi,
No it does not. The use of PRIVATE means that the library you are linking is only used internally and users of your code won't need to link to that library.
As for needing target_link_libraries, find_package just finds the dependencies, it does not tell the system what to do with them.
wrote on 6 Feb 2024, 00:15 last edited byThis post is deleted! -
@CodeFan hi,
No it does not. The use of PRIVATE means that the library you are linking is only used internally and users of your code won't need to link to that library.
As for needing target_link_libraries, find_package just finds the dependencies, it does not tell the system what to do with them.
wrote on 6 Feb 2024, 02:54 last edited by@SGaist I re-read the CMake docs. It certainly agrees with what you said. I guess the part that confuses me is why my compiled libqt_testlib.a has definitions for many Qt symbols.
nm -C --defined-only libqt_testlib.a gives output including these:
QArrayData::deref()
QByteArray::~QByteArray()
QByteArrayView::castHelper(char const*)
QFlag::QFlag(unsigned int)
QString::QString(char const*)
QString::~QString()
QString::operator+=(char const*)
QFlag::operator unsigned int() const
QString::toStdStringabi:cxx11 const
QString::toUtf8() const & -
@SGaist I re-read the CMake docs. It certainly agrees with what you said. I guess the part that confuses me is why my compiled libqt_testlib.a has definitions for many Qt symbols.
nm -C --defined-only libqt_testlib.a gives output including these:
QArrayData::deref()
QByteArray::~QByteArray()
QByteArrayView::castHelper(char const*)
QFlag::QFlag(unsigned int)
QString::QString(char const*)
QString::~QString()
QString::operator+=(char const*)
QFlag::operator unsigned int() const
QString::toStdStringabi:cxx11 const
QString::toUtf8() const &@CodeFan These are all inlined functions.
-
wrote on 6 Feb 2024, 07:59 last edited by
With static linking you can be sure that final linking of the executable will only include the parts of the library that are actually used. Don't bother to much with the size of your own library (though most likely you really have that many dependencies because of the features you are using from QtCore).
-
With static linking you can be sure that final linking of the executable will only include the parts of the library that are actually used. Don't bother to much with the size of your own library (though most likely you really have that many dependencies because of the features you are using from QtCore).
wrote on 6 Feb 2024, 18:51 last edited byThanks to all who contributed! I really appreciate it.
-
1/9