在 Qt 中如何使用 CMake 在主项目之前构建依赖库?
How do you build depended-upon libs before the main project with CMake in Qt?
我看过类似的问题,但没有找到针对这种基本情况的问题。我对 CMake 比较陌生。我有一个基于 CMake 的 Qt 5 项目。这是一个简单的测试应用程序;在其构建期间,我想构建并静态 link 开源 Paho MQTT C 库和它的 C++ 包装器。这是两个独立的项目,有自己的 CMakeLists.txt 文件。
根据 Qt 的默认设置,它构建到源代码树之外的目录中。
我已经将这些开源库的源代码树复制到我的项目的父目录下,并将顶级 CMakeLists.txt 文件编辑为 add_subdirectory 它们。
我也加了target_link_libraries。我可以自己获取 C 库来构建和 link 到父项目中,但是如果我添加 C++ 包装器,C++ 包装器的处理会抱怨它找不到 C 库...这是是的,因为它还没有建成。通过简单地使用 Qt 的“构建所有项目”菜单项解决了对 C 库的类似投诉,但是当添加了 C++ 包装器库时,这不起作用。包装器的 CMakeLists.txt 文件发出这个:
CMake Error at paho.mqtt.cpp/src/CMakeLists.txt:150 (message):
Could not find Paho MQTT C library
果然它不存在,因为在完成此预处理时它尚未构建。
更新:这是我的顶级 CMakeLists.txt 文件,根据 Corristo 的建议进行了修改,它成功地让 CMake 解析了整个层次结构。该项目现在构建。不过,令我困惑的是这里的最后两行导致了一个空字符串。 link 目录的类似尝试也是如此。
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}")
这有点 hack,但您可以利用 CMake find_*
命令在结果变量已设置的情况下不执行搜索这一事实。
从 paho.mqtt.cpp/src/CMakeLists.txt
文件中我们发现 find_library
的输出变量被称为 PAHO_MQTT_C_LIB
并且 include 目录应该在 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
项目中库目标的目标名称,这可能会在您更新时中断这些库之一到更新版本。
我看过类似的问题,但没有找到针对这种基本情况的问题。我对 CMake 比较陌生。我有一个基于 CMake 的 Qt 5 项目。这是一个简单的测试应用程序;在其构建期间,我想构建并静态 link 开源 Paho MQTT C 库和它的 C++ 包装器。这是两个独立的项目,有自己的 CMakeLists.txt 文件。
根据 Qt 的默认设置,它构建到源代码树之外的目录中。
我已经将这些开源库的源代码树复制到我的项目的父目录下,并将顶级 CMakeLists.txt 文件编辑为 add_subdirectory 它们。
我也加了target_link_libraries。我可以自己获取 C 库来构建和 link 到父项目中,但是如果我添加 C++ 包装器,C++ 包装器的处理会抱怨它找不到 C 库...这是是的,因为它还没有建成。通过简单地使用 Qt 的“构建所有项目”菜单项解决了对 C 库的类似投诉,但是当添加了 C++ 包装器库时,这不起作用。包装器的 CMakeLists.txt 文件发出这个:
CMake Error at paho.mqtt.cpp/src/CMakeLists.txt:150 (message): Could not find Paho MQTT C library
果然它不存在,因为在完成此预处理时它尚未构建。
更新:这是我的顶级 CMakeLists.txt 文件,根据 Corristo 的建议进行了修改,它成功地让 CMake 解析了整个层次结构。该项目现在构建。不过,令我困惑的是这里的最后两行导致了一个空字符串。 link 目录的类似尝试也是如此。
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}")
这有点 hack,但您可以利用 CMake find_*
命令在结果变量已设置的情况下不执行搜索这一事实。
从 paho.mqtt.cpp/src/CMakeLists.txt
文件中我们发现 find_library
的输出变量被称为 PAHO_MQTT_C_LIB
并且 include 目录应该在 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
项目中库目标的目标名称,这可能会在您更新时中断这些库之一到更新版本。