前言
最近在開發一個組件,但是這個東西是以dll的形式發布的界面庫,所以在開發的時候就需要上層調用。
如果你是很懂CMake的話,ui_xx.h的文件目錄在
${CMAKE_CURRENT_BINARY_DIR}
下
然后除了有關這個ui_xx.h,還有一些別的可以簡單聊聊的
一、父子工程組織,或者說依賴關系
在使用CMake進行開發的時候,一般可以有一個上下級的關系,或者一般情況下上下級工程會擺在同一個文件夾下,對于我這個項目來說,View_Equalizer是Demo_View_Equalizer的依賴
在CMake中,如果工程之間有依賴,一般代表了幾件事:
- 子工程一定是要先于父工程編譯的
- 父工程需要引用到子工程的所有頭文件
- 父工程需要鏈接到子工程
那我們一步步拆解地來看
1.要求子工程優先于父工程編譯
可以直接在父工程中添加
add_subdirectory(./View_Equalizer)
的方式來添加子工程,這樣的話View_Equalizer就會優先于當前工程進行編譯了
2. 要求父工程能引用到子工程的全部頭文件
這是因為,如果父工程如果不能引用到子工程的所有頭文件的話,很有可能會出現無法編譯的情況,即子工程引用了頭文件,但是父工程則無法直接引用到所有的頭文件,這樣父工程的編譯就會報錯。
為了解決這個問題,我們需要在子工程中添加target_include_directories,以在作為子工程的時候向上傳遞包含列表
示例如下:
target_include_directories(View_Equalizer PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/math
${CMAKE_CURRENT_SOURCE_DIR}/QCustomPlot
${CMAKE_CURRENT_SOURCE_DIR}/includes
${CMAKE_CURRENT_SOURCE_DIR}/Views
${CMAKE_CURRENT_SOURCE_DIR}/View_Items
${CMAKE_CURRENT_BINARY_DIR})
需要注意的是,這里target_include_directories傳遞的是路徑,而不是具體的文件,如果傳遞具體文件的話,上層仍然是找不到的,這里需要注意。
注:關于之前提到的找不到文件ui_xx.h的問題,這個其實就是沒有寫
target_include_directories(View_Equalizer PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
所有的ui_xx.h文件都會存放在${CMAKE_CURRENT_BINARY_DIR}下,所以將這個目錄傳遞給上層,就不會出現找不到 ui_xx.h的情況了。
3.父工程需要鏈接子工程
這個很好理解了,在父工程的CMakeLists.txt中添上這么一句話就行了
target_link_libraries(Demo_View_Equalizer PRIVATE View_Equalizer)
二、有關ui、qrc等qt特有的文件
首先,當你在使用CMake編寫Qt的時候,這三個屬性是必不可少的
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
如果你想要添加ui或者qrc文件,同樣的,需要將ui文件添加到add_library的名下,我這里是通過列表的形式插入所有需要的文件
set(HEADER_FILES ./includes/DataClass.h ./includes/View_Equalizer_global.h./includes/math_functions.h./includes/Center.h./Views/view_equalizer.h./View_Items/ViewItem_ControlPoint.h./View_Items/PointWidget.h
) set(SOURCE_FILES
./src/DataClass.cpp
./src/Center.cpp
./QCustomPlot/qcustomplot.cpp
./Views/view_equalizer.cpp
./View_Items/ViewItem_ControlPoint.cpp
./View_Items/PointWidget.cpp
)set(UI_FILES
./View_Items/PointWidget.ui
)add_library(View_Equalizer SHARED ${HEADER_FILES} ${SOURCE_FILES} ${UI_FILES} ${QRC_SOURCES})
當然了,既然是qt的庫,對于ui文件和qrc文件,則需要加入以下兩個命令:
qt5_add_resources(QRC_SOURCES ${RESOURCE_FILES})
qt5_wrap_ui(${UI_FILES})
子模塊完整的CMakeLists.txt放在下面:
cmake_minimum_required(VERSION 3.5)project(View_Equalizer LANGUAGES CXX)#(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(Qt5 COMPONENTS Widgets PrintSupport REQUIRED)include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes)
set(RESOURCE_FILES ./Resource/Resource.qrc
)
qt5_add_resources(QRC_SOURCES ${RESOURCE_FILES})set(HEADER_FILES ./includes/DataClass.h ./includes/View_Equalizer_global.h./includes/math_functions.h./includes/Center.h./Views/view_equalizer.h./View_Items/ViewItem_ControlPoint.h./View_Items/PointWidget.h
) set(SOURCE_FILES
./src/DataClass.cpp
./src/Center.cpp
./QCustomPlot/qcustomplot.cpp
./Views/view_equalizer.cpp
./View_Items/ViewItem_ControlPoint.cpp
./View_Items/PointWidget.cpp
)set(UI_FILES
./View_Items/PointWidget.ui
)
# 假設生成的頭文件被放置在當前構建目錄下的對應子目錄中 qt5_wrap_ui(${UI_FILES}) add_library(View_Equalizer SHARED ${HEADER_FILES} ${SOURCE_FILES} ${UI_FILES} ${QRC_SOURCES})target_include_directories(View_Equalizer PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/math
${CMAKE_CURRENT_SOURCE_DIR}/QCustomPlot
${CMAKE_CURRENT_SOURCE_DIR}/includes
${CMAKE_CURRENT_SOURCE_DIR}/Views
${CMAKE_CURRENT_SOURCE_DIR}/View_Items
${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(View_Equalizer PRIVATE Qt5::Widgets Qt5::PrintSupport)target_compile_definitions(View_Equalizer PRIVATE VIEW_EQUALIZER_LIBRARY)
三、關于編譯后,組織編譯后的內容
我這里是寫了一下編譯后的事件,可以參考一下
cmake_minimum_required(VERSION 3.5)project(Demo_View_Equalizer LANGUAGES CXX)
add_subdirectory(./View_Equalizer)
add_subdirectory(./QtHid)
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)# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check http://doc.qt.io/qt-5/deployment-android.html for more information.
# They need to be set before the find_package(Qt5 ...) call.#if(ANDROID)
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
# if (ANDROID_ABI STREQUAL "armeabi-v7a")
# set(ANDROID_EXTRA_LIBS
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
# endif()
#endif()find_package(Qt5 COMPONENTS Widgets REQUIRED)
if(ANDROID)add_library(Demo_View_Equalizer SHAREDmain.cppmainwindow.cppmainwindow.hmainwindow.ui)
else()add_executable(Demo_View_Equalizermain.cppmainwindow.cppmainwindow.hmainwindow.ui)
endif()target_link_libraries(Demo_View_Equalizer PRIVATE Qt5::Widgets)
target_link_libraries(Demo_View_Equalizer PRIVATE View_Equalizer)# 假設View_Equalizer模塊的可執行文件或庫在構建后將位于對應的Debug或Release目錄下
# 并且想在Demo_View_Equalizer模塊構建完成后將其復制到對應的Demo_View_Equalizer的Debug或Release目錄 # 獲取當前構建類型,默認為Debug,如果未設置CMAKE_BUILD_TYPE
if(NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug)
endif() # 根據構建類型設置A模塊的輸出目錄路徑
set(A_OUTPUT_DIR "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}") # 假設View_Equalizer模塊的輸出文件名(需要根據實際情況替換)
set(B_OUTPUT_NAME "View_Equalizer.dll") # 假設的輸出文件名 # 設置View_Equalizer模塊的輸出文件路徑
set(B_OUTPUT_FILE "${CMAKE_BINARY_DIR}/View_Equalizer/${CMAKE_BUILD_TYPE}/${B_OUTPUT_NAME}") # 目標文件在Demo_View_Equalizer模塊的輸出目錄下的路徑
set(B_OUTPUT_DESTINATION "${A_OUTPUT_DIR}/${B_OUTPUT_NAME}") message(STATUS "B_OUTPUT_FILE : ${B_OUTPUT_FILE}")
message(STATUS "B_OUTPUT_DESTINATION : ${B_OUTPUT_DESTINATION}")
message(STATUS "command : ${CMAKE_COMMAND} -E copy ${B_OUTPUT_FILE} ${B_OUTPUT_DESTINATION}")
# 添加一個自定義目標,以確保復制操作被執行
add_custom_target(AllBuild ALL DEPENDS ${B_OUTPUT_DESTINATION}
)
# 添加一個自定義命令來執行復制操作
add_custom_command( OUTPUT ${B_OUTPUT_DESTINATION} COMMAND ${CMAKE_COMMAND} -E copy ${B_OUTPUT_FILE} ${B_OUTPUT_DESTINATION} DEPENDS ${B_OUTPUT_FILE} COMMENT "Copying View_Equalizer output to Demo_View_Equalizer/${CMAKE_BUILD_TYPE} directory" VERBATIM
)
# 確保我們的自定義目標在Demo_View_Equalizer之后構建
add_dependencies(AllBuild Demo_View_Equalizer)