Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

CMAKE undefined references when building a console application that uses custom libraries



  • I am trying to work out CMAKE with my Qt solution. I have a set of libraries that I utilize as a platform to build other applications. Then I have an applications link to those libraries to utilize there functionality. For some reason all of sudden I am getting undefinded references when adding members to class within one of the libraries. Below I show the structure of my libraries and application plus the cmake files plust the output from cmake. any help would be great!
    QT Version 5.12.8

    • Library Project

      • CMakeLists.txt
      • Lib 1
        • CMakeLists.txt
        • src
      • Lib 2
        • CMakeList.txt
        • src
      • Lib 3
        • CMakeList.txt
        • src
    • Application

      • CMakeLists.txt
      • src

    The Library Projects Highest Level CMakeLists.txt File

    cmake_minimum_required(VERSION 3.5.0)
    set(FRAMEWORK_BUILD_VERSION 0.1.0 CACHE STRING "Version of the Framework")
    set(COMMON_BUILD_VERSION 0.1.0 CACHE STRING "Version of the Common Library")
    set(INJECTORCLIENT_BUILD_VERSION 0.1.0 CACHE STRING "Version of the Common Library")
    set(SYSTEMSERVICE_BUILD_VERSION 0.1.0 CACHE STRING "Version of the Common Library")
    
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    project(RADIANT-SCP-Framework VERSION ${FRAMEWORK_BUILD_VERSION})
    add_subdirectory(Common)
    add_subdirectory(InjectorClient)
    add_subdirectory(SystemService)
    
    

    Lib1 CMakeList.txt

    project(RADIANT-SCP-Common VERSION ${COMMON_BUILD_VERSION})
    find_package(Qt5 COMPONENTS Core REQUIRED)
    
    add_library(RADIANT-SCP-Common SHARED src/helloworld.h
                                          src/helloworld.cpp
                                          src/common_global.h
                                          src/utils/logger.h
                                          src/utils/logger.cpp)
    
    target_link_libraries(RADIANT-SCP-Common PRIVATE Qt5::Core)
    
    target_include_directories(RADIANT-SCP-Common PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
    
    target_compile_definitions(RADIANT-SCP-Common PRIVATE COMMON_LIBRARY)
    
    INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src
                DESTINATION /usr/local/include/RADIANT/SCP/Common
                FILES_MATCHING PATTERN "*.h")
    INSTALL(TARGETS RADIANT-SCP-Common
                LIBRARY DESTINATION /usr/lib)
    
    

    Application

    CMakeList.txt

    cmake_minimum_required(VERSION 3.5)
    
    project(SRU-Injector-Client LANGUAGES CXX)
    
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
    
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    find_package(Qt5Core)
    
    add_executable(SRU-Injector-Client
      main.cpp
    )
    
    target_include_directories(SRU-Injector-Client PUBLIC "/usr/local/include/RADIANT")
    
    LINK_DIRECTORIES(/usr/lib)
    target_link_libraries(SRU-Injector-Client RADIANT-SCP-Common)
    target_link_libraries(SRU-Injector-Client RADIANT-SCP-InjectorClient)
    target_link_libraries(SRU-Injector-Client Qt5::Core)
    

    Now when I add the STATIC m_logfile member to the logger.h and the implementation to the logger.cpp file. I can build the libraries fine but when I go to build the application .I get an undefined ref.
    logger.h

    #ifndef LOGGER_H
    #define LOGGER_H
    #include <QLoggingCategory>
    #include <stdio.h>
    #include "../common_global.h"
    
    namespace RADIANT{
    namespace SCP{
    namespace Common{
    class COMMON_EXPORT logger
    {
    public:
          static void intializeLogger(const QString &filePath);
          static void processLogToFile(QtMsgType type, const QMessageLogContext &context, const QString &msg);
          static void openLogFile(const QString &filePath);
          static void closeLogFile();
          static FILE *m_logFile;
    
    };
    }}}
    #endif // LOGGER_H
    

    logger.cpp

    #include "logger.h"
    #include <QDateTime>
    
    namespace RADIANT{
    namespace SCP{
    namespace Common{
    void logger::intializeLogger(const QString &filePath)
    {
        openLogFile(filePath);
        qInstallMessageHandler(processLogToFile);
    }
    void logger::openLogFile(const QString &filePath)
    {
       if(m_logFile == NULL)
        {
            m_logFile = fopen(filePath.toLocal8Bit(),"w");
            if(m_logFile == NULL)
            {
                qDebug() << "Could not open log file %s",filePath;
            }
        }
        else
        {
            qDebug() << "%s file is use",filePath;
        }
    }
    void logger::closeLogFile()
    {
       fclose(m_logFile);
    }
    void logger::processLogToFile(QtMsgType type, const QMessageLogContext &context, const QString &msg)
    {
        const char *file = context.file ? context.file : "";
        const char *function = context.function ? context.function : "";
        // TODO: Change this to get time from the Date Time Manager
        QString timeStamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
        QString logMessage;
        std::string s;
        switch (type) {
        case QtDebugMsg:
            logMessage = QString("Debug: %1 (%2:%3, %4)\n").arg(msg).arg(file).arg(context.line).arg(function);
            break;
        case QtInfoMsg:
         logMessage = QString("Info: %1 (%2:%3, %4)\n").arg(msg).arg(file).arg(context.line).arg(function);
            break;
        case QtWarningMsg:
           logMessage = QString("Warning: %1 (%2:%3, %4)\n").arg(msg).arg(file).arg(context.line).arg(function);
            break;
        case QtCriticalMsg:
            logMessage = QString("Critical: %1 (%2:%3, %4)\n").arg(msg).arg(file).arg(context.line).arg(function);
            break;
        case QtFatalMsg:
           logMessage = QString("Fatal: %1 (%2:%3, %4)\n").arg(msg).arg(file).arg(context.line).arg(function);
            break;
        }
        logMessage = timeStamp + " " + logMessage;
        fprintf(stdout,"%s",logMessage.toLocal8Bit().constData());
        if(m_logFile != NULL) fprintf(m_logFile, "%s",logMessage.toLocal8Bit().constData());
    
    }
    }}}
    
    

    build output for libraries

    -- The C compiler identification is GNU 9.2.1
    -- The CXX compiler identification is GNU 9.2.1
    -- Check for working C compiler: /usr/bin/gcc
    -- Check for working C compiler: /usr/bin/gcc -- 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/g++
    -- Check for working CXX compiler: /usr/bin/g++ -- 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
    CMake Warning:
      Manually-specified variables were not used by the project:
    
        QT_QMAKE_EXECUTABLE
    
    
    -- Build files have been written to: /home/developer/src/RADIANT/SCP/radiant.scp.framework/builds/0.1.0/Qt5.12.8/gcc_64/Debug
    Scanning dependencies of target RADIANT-SCP-Common_autogen
    [  7%] Automatic MOC and UIC for target RADIANT-SCP-Common
    [  7%] Built target RADIANT-SCP-Common_autogen
    Scanning dependencies of target RADIANT-SCP-Common
    [ 15%] Building CXX object Common/CMakeFiles/RADIANT-SCP-Common.dir/RADIANT-SCP-Common_autogen/mocs_compilation.cpp.o
    [ 23%] Building CXX object Common/CMakeFiles/RADIANT-SCP-Common.dir/src/helloworld.cpp.o
    [ 30%] Building CXX object Common/CMakeFiles/RADIANT-SCP-Common.dir/src/utils/logger.cpp.o
    [ 38%] Linking CXX shared library libRADIANT-SCP-Common.so
    [ 38%] Built target RADIANT-SCP-Common
    Scanning dependencies of target RADIANT-SCP-InjectorClient_autogen
    [ 46%] Automatic MOC and UIC for target RADIANT-SCP-InjectorClient
    [ 46%] Built target RADIANT-SCP-InjectorClient_autogen
    Scanning dependencies of target RADIANT-SCP-InjectorClient
    [ 53%] Building CXX object InjectorClient/CMakeFiles/RADIANT-SCP-InjectorClient.dir/RADIANT-SCP-InjectorClient_autogen/mocs_compilation.cpp.o
    [ 61%] Building CXX object InjectorClient/CMakeFiles/RADIANT-SCP-InjectorClient.dir/src/helloworldinjectorclient.cpp.o
    [ 69%] Linking CXX shared library libRADIANT-SCP-InjectorClient.so
    [ 69%] Built target RADIANT-SCP-InjectorClient
    Scanning dependencies of target RADIANT-SCP-SystemService_autogen
    [ 76%] Automatic MOC and UIC for target RADIANT-SCP-SystemService
    [ 76%] Built target RADIANT-SCP-SystemService_autogen
    Scanning dependencies of target RADIANT-SCP-SystemService
    [ 84%] Building CXX object SystemService/CMakeFiles/RADIANT-SCP-SystemService.dir/RADIANT-SCP-SystemService_autogen/mocs_compilation.cpp.o
    [ 92%] Building CXX object SystemService/CMakeFiles/RADIANT-SCP-SystemService.dir/src/helloworldsystemservice.cpp.o
    [100%] Linking CXX shared library libRADIANT-SCP-SystemService.so
    [100%] Built target RADIANT-SCP-SystemService
    [  7%] Automatic MOC and UIC for target RADIANT-SCP-Common
    [  7%] Built target RADIANT-SCP-Common_autogen
    [ 38%] Built target RADIANT-SCP-Common
    [ 46%] Automatic MOC and UIC for target RADIANT-SCP-InjectorClient
    [ 53%] Automatic MOC and UIC for target RADIANT-SCP-SystemService
    [ 53%] Built target RADIANT-SCP-InjectorClient_autogen
    [ 53%] Built target RADIANT-SCP-SystemService_autogen
    [ 76%] Built target RADIANT-SCP-InjectorClient
    [100%] Built target RADIANT-SCP-SystemService
    [  7%] Automatic MOC and UIC for target RADIANT-SCP-Common
    [  7%] Built target RADIANT-SCP-Common_autogen
    [ 38%] Built target RADIANT-SCP-Common
    [ 46%] Automatic MOC and UIC for target RADIANT-SCP-InjectorClient
    [ 46%] Built target RADIANT-SCP-InjectorClient_autogen
    [ 69%] Built target RADIANT-SCP-InjectorClient
    [ 76%] Automatic MOC and UIC for target RADIANT-SCP-SystemService
    [ 76%] Built target RADIANT-SCP-SystemService_autogen
    [100%] Built target RADIANT-SCP-SystemService
    Install the project...
    -- Install configuration: "Debug"
    -- Installing: /usr/local/include/RADIANT/SCP/Common/src
    -- Installing: /usr/local/include/RADIANT/SCP/Common/src/common_global.h
    -- Installing: /usr/local/include/RADIANT/SCP/Common/src/utils
    -- Installing: /usr/local/include/RADIANT/SCP/Common/src/utils/logger.h
    -- Installing: /usr/local/include/RADIANT/SCP/Common/src/helloworld.h
    -- Installing: /usr/lib/libRADIANT-SCP-Common.so
    -- Set runtime path of "/usr/lib/libRADIANT-SCP-Common.so" to ""
    -- Installing: /usr/local/include/RADIANT/SCP/InjectorClient/src
    -- Installing: /usr/local/include/RADIANT/SCP/InjectorClient/src/helloworldinjectorclient.h
    -- Installing: /usr/local/include/RADIANT/SCP/InjectorClient/src/injectorclient_global.h
    -- Installing: /usr/lib/libRADIANT-SCP-InjectorClient.so
    -- Set runtime path of "/usr/lib/libRADIANT-SCP-InjectorClient.so" to ""
    -- Installing: /usr/local/include/RADIANT/SCP/SystemService/src
    -- Installing: /usr/local/include/RADIANT/SCP/SystemService/src/helloworldsystemservice.h
    -- Installing: /usr/local/include/RADIANT/SCP/SystemService/src/systemservice_global.h
    -- Installing: /usr/lib/libRADIANT-SCP-SystemService.so
    -- Set runtime path of "/usr/lib/libRADIANT-SCP-SystemService.so" to ""
    

    but when I build the application get the undefined error

    -- The CXX compiler identification is GNU 9.2.1
    -- Check for working CXX compiler: /usr/bin/g++
    -- Check for working CXX compiler: /usr/bin/g++ -- 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
    CMake Warning:
      Manually-specified variables were not used by the project:
    
        CMAKE_C_COMPILER
        FRAMEWORK_BUILD_VERSION
        QT_QMAKE_EXECUTABLE
        Qt5_DIR
    
    
    -- Build files have been written to: /home/developer/src/NextGenCT/SCP/sru-injector-client/builds/0.1.0/Qt5.12.8/gcc_64/Debug
    Scanning dependencies of target SRU-Injector-Client_autogen
    [ 25%] Automatic MOC and UIC for target SRU-Injector-Client
    [ 25%] Built target SRU-Injector-Client_autogen
    Scanning dependencies of target SRU-Injector-Client
    [ 50%] Building CXX object CMakeFiles/SRU-Injector-Client.dir/SRU-Injector-Client_autogen/mocs_compilation.cpp.o
    [ 75%] Building CXX object CMakeFiles/SRU-Injector-Client.dir/main.cpp.o
    [100%] Linking CXX executable SRU-Injector-Client
    /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/libRADIANT-SCP-Common.so: undefined reference to `RADIANT::SCP::Common::logger::m_logFile'
    collect2: error: ld returned 1 exit status
    make[2]: *** [CMakeFiles/SRU-Injector-Client.dir/build.make:100: SRU-Injector-Client] Error 1
    make[1]: *** [CMakeFiles/Makefile2:77: CMakeFiles/SRU-Injector-Client.dir/all] Error 2
    make: *** [Makefile:84: all] Error 2
    

    I have tried adding the cpp wrap to libraries CMakeLists.txt file to have it generate the moc files but I did not have any luck with this working

    qt_wrap_cpp(RADIANT-SCP-Common src.utils/logger.h
                                   src/utils/logger.cpp)
    

    any help would be much apperciated.



  • ok I figured out my problem based on your feedback @Christian-Ehrlicher. I am new c++ and qt and see what I did wrong. After declaring this in the top of the .cpp all was good.

    logger.cpp

    FILE *logger::m_logFile = NULL;
    
    

  • Lifetime Qt Champion

    @pjorourke05 said in CMAKE undefined references when building a console application that uses custom libraries:

    static FILE *m_logFile;

    C basics - where do you declare this variable?



  • I declare the variable in the header. as show above. but for quick reference see the snippet below

    #ifndef LOGGER_H
    #define LOGGER_H
    #include <QLoggingCategory>
    #include <stdio.h>
    #include "../common_global.h"
    
    namespace RADIANT{
    namespace SCP{
    namespace Common{
    {
    public:
           ...
          static FILE *m_logFile;
    


  • ok I figured out my problem based on your feedback @Christian-Ehrlicher. I am new c++ and qt and see what I did wrong. After declaring this in the top of the .cpp all was good.

    logger.cpp

    FILE *logger::m_logFile = NULL;
    
    

Log in to reply