【问题标题】:How do you build depended-upon libs before the main project with CMake in Qt?在 Qt 中使用 CMake 的主项目之前如何构建依赖库?
【发布时间】:2021-06-05 09:02:58
【问题描述】:

我查看了类似的问题,但没有找到适合这种基本情况的问题。我对 CMake 比较陌生。我有一个基于 CMake 的 Qt 5 项目。这是一个简单的测试应用程序;在其构建期间,我想构建并静态链接开源 Paho MQTT C lib 和 C++ 包装器。这是两个独立的项目,有自己的 CMakeLists.txt 文件。

根据 Qt 的默认设置,它会构建到源代码树之外的目录中。

我已经在我的项目的父目录下复制了这些开源库的源代码树,并编辑了顶级 CMakeLists.txt 文件以添加_子目录。

我还添加了 target_link_libraries。我可以自己获取 C lib 以构建并链接到父项目,但是如果我添加 C++ 包装器,C++ 包装器的处理会抱怨它找不到 C lib...这是真的,因为它没有还没有建成。简单地使用 Qt 的“构建所有项目”菜单项解决了对 C 库的类似投诉,但是当添加 C++ 包装器库时,这不起作用。包装器的 CMakeLists.txt 文件问题如下:

paho.mqtt.cpp/src/CMakeLists.txt:150 处的 CMake 错误(消息): 找不到 Paho MQTT C 库

果然它不存在,因为在这个预处理完成时它还没有被构建。

更新:这是我的顶级 CMakeLists.txt 文件,根据 Corristo 的建议进行了修改,它成功地让 CMake 解析整个层次结构。该项目现在构建。不过,我很困惑这里的最后两行会导致一个空字符串。对链接目录的类似尝试也是如此。

find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)

set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mainwindow.h
        mainwindow.ui
    task.h
    task.cpp
    task.ui
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(MQTTTest
        ${PROJECT_SOURCES}
    )
else()
    if(ANDROID)
        add_library(MQTTTest SHARED
            ${PROJECT_SOURCES}
        )
    else()
        add_executable(MQTTTest
            ${PROJECT_SOURCES}
        )
    endif()
endif()

add_subdirectory(paho.mqtt.c)
set(PAHO_MQTT_C_LIB paho-mqtt3a)
set(PAHO_MQTT_C_PATH "${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.c")
add_subdirectory(paho.mqtt.cpp)

target_link_libraries(MQTTTest PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_directories(MQTTTest PUBLIC
                        "${CMAKE_CURRENT_LIST_DIR}/build/paho.mqtt.c/src"
                        "${CMAKE_CURRENT_LIST_DIR}/build/paho.mqtt.cpp/src")

target_link_libraries(MQTTTest PUBLIC paho-mqtt3a)
target_link_libraries(MQTTTest PUBLIC paho-mqttpp3)

target_include_directories(MQTTTest PUBLIC
                        "${PROJECT_BINARY_DIR}"
                        "${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.c/src"
                        "${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.cpp/src")

get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
message("Top-level include dirs = ${inc_dirs}")

【问题讨论】:

    标签: qt cmake cmakelists-options


    【解决方案1】:

    这有点小技巧,但如果结果变量已设置,您可以使用 CMake find_* 命令不执行搜索这一事实。

    paho.mqtt.cpp/src/CMakeLists.txt 文件中我们发现find_library 的输出变量被称为PAHO_MQTT_C_LIB 并且包含目录预计在PAHO_MQTT_C_INC_DIR 中,它在original CMakeLists.txt from version 1.0.0 中(这似乎是版本你正在使用) 本身是从 PAHO_MQTT_C_PATH 计算出来的。

    在两个 add_subdirectory 调用之间设置这两个变量应该可以使这个工作:

    add_subdirectory(paho.mqtt.c)
    set(PAHO_MQTT_C_LIB paho-mqtt3a)
    set(PAHO_MQTT_C_PATH "${CMAKE_CURRENT_LIST_DIR}/paho.mqtt.c")
    add_subdirectory(paho.mqtt.cpp)
    

    这利用了 target_link_libraries 既可以使用库文件(这是原始 paho.mqtt.cpp 项目所期望的)和现有 CMake 目标(这是我们替换它的目标)调用的事实。链接到 CMake 目标还会自动引入构建顺序依赖关系,因此这同时确保了 c 库在 cpp 库之前构建。

    但是,由于这依赖于 paho.mqtt.cpp 项目中使用的变量名称以及 paho.mqtt.c 项目中库目标的目标名称,因此在您将其中一个库更新为较新的版本。

    【讨论】:

    • 太好了,谢谢!它似乎让我大部分时间都在那里。现在我遇到了编译失败的问题,找不到头文件。在顶级 CMakeLists.txt 中,我提供了包含目录。但是在此之后使用 get_property 检索 INCLUDE_DIRECTORIES 属性并将它们打印出来表明它是空的。我将编辑我的问题,以便发布此信息。再次感谢,帮助很大。
    • 顺便说一句,如果这是一种“hacky”方式,我想知道非hacky解决方案是什么。
    • @Oscar:目前还没有任何非 hacky 解决方案,但在 CMake 问题跟踪器上讨论了提供一种集成 FetchContent 的方法(即从源代码构建) with find_package /find_library` 目前只搜索二进制文件,也在这里使用。
    • @Oscar 这也不足为奇:您只在您的target_link_library 调用中链接PUBLICly,因此所有接口都包含您链接的目标的目录以填充INTERFACE_INCLUDE_DIRECTORIES 属性。如果您要链接 PRIVATEly 反对例如。 paho-mqttpp3 你应该会看到 C++ mqtt 库的包含目录出现在 INCLUDE_DIRECTORIES 中。
    • @Oscar:你可以使用get_target_property,或者get_property(... TARGET MQTTTest ...)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多