關于我想要實作的一些背景知識:我已經有一個在 CMake 中開發的專案(它是 CMake 專案的集合:基本上是一個帶有一些幫助程式庫的狀態機)。現在,我想在 Qt 中開發一個這個狀態機可以控制的 GUI(并讓它做一些事情)。但是,對于我的生活,我無法弄清楚如何正確地將具有 Qt 類和函式的庫匯出到另一個 CMake 包的可執行檔案。我在 Windows 上,使用 Mingw-w64 編譯器和 make 程式。
我正在試驗 2 個簡單的 CMake 專案,一個具有簡單的 Qt 表單(我只是從該存盤庫中復制并修改了該存盤庫以及 README 中給出的相應 youtube 視頻),另一個具有可執行檔案。我試圖將第一個專案與第二個專案鏈接起來,但是,每當我構建自動生成的 makefile 時,它??最終都會失敗,說符號是未定義的(例如對 run_stuff::run_stuff()' 的未定義參考)。如果檔案很臟,我深表歉意,我一直在嘗試各種方法無濟于事。
我嘗試過的事情:
我非常仔細地遵循了這里的答案。
我已嘗試將 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS 設定為 ON,正如許多站點(例如這個站點)所建議的那樣,用于運行 DLL
我嘗試將庫設為靜態(因此不再需要 DLL)
我嘗試將 target_include_dirs 從私有設定為公共,并注釋掉該行。(不知道那是什么,但沒關系)
但是,無論我做什么,最后總是以鏈接錯誤結束,并且我在第二個專案中的可執行檔案無法訪問 Qt 專案中的任何功能。關于我接下來應該嘗試什么的任何建議?如果您能指出我在 CMakeLists.txt 檔案中犯的錯誤,那將非常有幫助(再次為凌亂的代碼和 CMakeLists 道歉)
我的專案 CMake 檔案如下所示:
cmake_minimum_required(VERSION 3.14)
# if (WIN32)
# set(CMAKE_SHARED_LIBRARY_PREFIX "")
# endif ()
set(CMAKE_MAKE_PROGRAM $ENV{MAKE})
set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "" FORCE)
set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_subdirectory(QT6CMake)
add_subdirectory(Exec)
庫 CMake 檔案:
cmake_minimum_required(VERSION 3.14)
if (WIN32)
project(MY_PROJECT LANGUAGES CXX)
elseif(UNIX)
project(MY_PROJECT)
endif()
set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "" FORCE)
#======================= INCLUSION OF Qt =======================#
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_PREFIX_PATH $ENV{QTDIR})
find_package(Qt6Core REQUIRED)
find_package(Qt6Widgets REQUIRED)
#=================== INCLUSION OF Project Files ====================#
set(FORMS_DIR "${CMAKE_SOURCE_DIR}/forms")
set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include")
set(SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
include_directories(${FORMS_DIR})
include_directories(${INCLUDE_DIR})
include_directories(${SOURCE_DIR})
file(GLOB_RECURSE SOURCES
"${FORMS_DIR}/*.ui"
"${FORMS_DIR}/*.qrc"
"${INCLUDE_DIR}/*.h"
"${SOURCE_DIR}/*.cpp"
)
#=================== SETUP EXECTUABLE ====================#
# Enable debug logging on RELWITHDEBINFO configuration
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:RELWITHDEBINFO>:QT_MESSAGELOGCONTEXT>
)
# Add the forms directory to the AUTOUIC search paths
set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${FORMS_DIR})
# Add the executable
if (WIN32)
add_executable(MY_PROJECT WIN32 ${SOURCES})
elseif(UNIX)
add_executable(MY_PROJECT ${SOURCES})
endif()
# Add the target includes for MY_PROJECT
target_include_directories(MY_PROJECT PRIVATE ${FORMS_DIR})
target_include_directories(MY_PROJECT PRIVATE ${INCLUDE_DIR})
target_include_directories(MY_PROJECT PRIVATE ${SOURCE_DIR})
#===================== LINKING LIBRARIES =======================#
target_link_libraries(MY_PROJECT Qt6::Widgets)
執行 CMake 檔案:
cmake_minimum_required(VERSION 3.14)
project(somexec)
add_definitions(${MY_PROJECT_DEFINITIONS})
include_directories(${MY_PROJECT_INCLUDE_DIRS})
if (WIN32)
add_executable(${PROJECT_NAME} WIN32 main.cpp)
elseif(UNIX)
add_executable(${PROJECT_NAME} main.cpp)
endif()
target_link_libraries(${PROJECT_NAME} MY_PROJECT)
這是代碼庫。
EDIT: Finally the code seems to be working, courtesy of Guillaume Racicot's multiple edits and fixes. I am going to leave this repository public in case anyone wants to see the codebase. Also, right now, I don't understand all the CMake commands that he has used, will try to understand those as well
uj5u.com熱心網友回復:
本教程中的 CMake 代碼使用了非常老式和過時的 CMake 實踐。它在創建簡單專案時有效,但在創建庫時不起作用。要在專案之間共享檔案,您需要匯出 CMake 目標。您可以通過首先創建此檔案來做到這一點:
cmake/yourlibrary-config.cmake
include(CMakeFindDependencyMacro)
# write it like you find_package of your cmake scripts
find_dependency(Qt6 COMPONENTS Core Widgets REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/yourlibrary-targets.cmake")
然后,將其添加到您的主專案 cmake 檔案中。您應該有一個如下所示的 CMake 檔案:
cmake_minimum_required(VERSION 3.21)
project(yourlibrary CXX)
# First, create your library. List all the files one by one. Don't use globs
add_library(yourlibrary src/mainwindow.cpp)
# Then add an alias of your library to enable target syntax
add_library(yourlibrary::yourlibrary ALIAS yourlibrary)
# Automatically generate Qt ui and moc
set_target_properties(yourlibrary PROPERTIES
AUTOUIC ON
AUTOMOC ON
AUTOUIC_SEARCH_PATHS forms
)
# Then, include gnuinstalldir to get the platform's standard directories:
include(GNUInstallDirs)
# Then, carefully add your include directories. All of your `target_include_directories` must look like this
target_include_directories(yourlibrary PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # include directory in your build tree
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> # include directory when installed
)
# Then, include Qt and link qt
find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
target_link_libraries(yourlibrary PUBLIC Qt6::Core Qt6::Widgets)
# Now, create the install script. We install all header files under `include/yourlibrary` to install them in `<prefix>/include/yourlibrary`:
install(
DIRECTORY include/yourlibrary
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h"
)
# We add `yourlibrary` target into the export set.
# The export set will contain all targets to be imported by the other project.
# It also installs the library to the install script so they are installed:
install(TARGETS yourlibrary EXPORT yourlibrary-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
# Now, we install the export set. This will generate a CMake file exporting all the target for other projects to use:
install(EXPORT yourlibrary-targets
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yourlibrary"
NAMESPACE yourlibrary::
)
# Now, we also export the current buildtree. Other project will be able to import the project directly from a build dir:
configure_file(cmake/yourlibrary-config.cmake yourlibrary-config.cmake COPYONLY)
export(
EXPORT yourlibrary-targets
NAMESPACE yourlibrary::
FILE "${PROJECT_BINARY_DIR}/yourlibrary-targets.cmake"
)
# The file we created earlier:
install(
FILES cmake/yourlibrary-config.cmake
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yourlibrary"
)
我省略了生成的頭檔案的安裝,因為它們通常被認為是專案私有的。
對于庫,有一個如下所示的源代碼樹:
yourlibrary
├── cmake
│ └── yourlibrary-config.cmake
├── forms
│ └── mainwindow.ui
├── include
│ └── yourlibrary
│ └── mainwindow.h
├── src
│ └── mainwindow.cpp
└── CMakeLists.txt
要使用該庫,您有兩個選擇。
- 您可以使用將其嵌入到您的專案中
add_subdirectory(yourlibrary) - 您可以單獨構建它并使用
find_package(yourlibrary REQUIRED)
你不能兩者都做。
I usually prefer using find_package, but it require a package manager to avoid manually building all dependencies.
If you use add_subdirectory
Then remove find_package(yourlibrary REQUIRED) from your project. Simply add the directory and have your main project file look like this:
cmake_minimum_required(VERSION 3.21)
project(exec LANGUAGES CXX)
# Embed the project
add_subdirectory(yourlibrary)
add_executable(myexec main.cpp)
target_link_libraries(myexec PUBLIC yourlibrary::yourlibrary)
I assume a project tree like this:
SampleProject
├── yourlibrary
│ └── ...
├── CMakeLists.txt
└── main.cpp
If you build yourlibrary separately
First, build the library and (optionally) install it in a known location.
Now, you can build your library that uses Qt. You will need a CMakeLists.txt that looks like this:
cmake_minimum_required(VERSION 3.21)
project(myexec LANGUAGES CXX)
# also finds Qt and all
find_package(yourlibrary REQUIRED)
add_executable(myexec main.cpp)
target_link_libraries(myexec PUBLIC yourlibrary::yourlibrary)
If you install the yourlibrary library, it will simply work. If you want to use it from its build tree, simply run the CMake command with -DCMAKE_PREFIX_PATH=/path/to/yourlibrary/build. It should point to the build directory of the library, or the installation prefix if you installed it in a custom location.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/443309.html
