介紹
此示例說明如何設置包含子項目的CMake項目。頂層CMakeLists.txt調用子目錄中的CMakeLists.txt以創建以下內容:
- sublibrary1 - 靜態庫
- sublibrary2 - 頭文件庫
- subbinary - 可執行文件
此示例中包含的文件包括:
$ tree
.
├── CMakeLists.txt
├── subbinary
│ ├── CMakeLists.txt
│ └── main.cpp
├── sublibrary1
│ ├── CMakeLists.txt
│ ├── include
│ │ └── sublib1
│ │ └── sublib1.h
│ └── src
│ └── sublib1.cpp
└── sublibrary2
├── CMakeLists.txt
└── include
└── sublib2
└── sublib2.h
-
[CMakeLists.txt] - 頂級CMakeLists.txt
cmake_minimum_required (VERSION 3.5) project(subprojects) # Add sub directories add_subdirectory(sublibrary1) add_subdirectory(sublibrary2) add_subdirectory(subbinary)
-
[subbinary/CMakeLists.txt] - 生成可執行文件
project(subbinary) # Create the executable add_executable(${PROJECT_NAME} main.cpp) # Link the static library from subproject1 using it's alias sub::lib1 # Link the header only library from subproject2 using it's alias sub::lib2 # This will cause the include directories for that target to be added to this project target_link_libraries(${PROJECT_NAME} sub::lib1 sub::lib2 )
-
[subbinary/main.cpp] - 可執行文件的源代碼
#include "sublib1/sublib1.h" #include "sublib2/sublib2.h" int main(int argc, char *argv[]) { sublib1 hi; hi.print(); sublib2 howdy; howdy.print(); return 0; }
-
[sublibrary1/CMakeLists.txt] - 創建靜態庫
# Set the project name project (sublibrary1) # Add a library with the above sources add_library(${PROJECT_NAME} src/sublib1.cpp) add_library(sub::lib1 ALIAS ${PROJECT_NAME}) target_include_directories( ${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include )
-
[sublibrary1/include/sublib1/sublib1.h]
#ifndef __SUBLIB_1_H__ #define __SUBLIB_1_H__ class sublib1 { public: void print(); }; #endif
-
[sublibrary1/src/sublib1.cpp]
#include <iostream> #include "sublib1/sublib1.h" void sublib1::print() { std::cout << "Hello sub-library 1!" << std::endl; }
-
[sublibrary2/CMakeLists.txt] - 設置僅含頭文件的庫
# Set the project name project (sublibrary2) add_library(${PROJECT_NAME} INTERFACE) add_library(sub::lib2 ALIAS ${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${PROJECT_SOURCE_DIR}/include )
-
[sublibrary2/include/sublib2/sublib2.h]
#ifndef __SUBLIB_2_H__ #define __SUBLIB_2_H__ #include <iostream> class sublib2 { public: void print() { std::cout << "Hello header only sub-library 2!" << std::endl; } }; #endif
Tip | 在本例中,我將頭文件移動到每個項目include目錄下的一個子文件夾中,同時將目標include保留為根include文件夾。這是防止文件名沖突的好主意,因為你必須包含如下所示的文件:#include“subib1/subib1.h” 。這也意味着,如果你為其他用戶安裝庫,默認安裝位置將是/usr/local/include/subib1/subib1.h 。 |
---|
概念
添加子目錄
CMakeLists.txt文件可以包含和調用含CMakeLists.txt的子目錄
add_subdirectory(sublibrary1)
add_subdirectory(sublibrary2)
add_subdirectory(subbinary)
引用子項目目錄
當使用project()命令創建項目時,CMake將自動創建許多變量,這些變量可用於引用有關項目的詳細信息。然后,其他子項目或主項目可以使用這些變量。例如,引用你可以使用的不同項目的源目錄。
${sublibrary1_SOURCE_DIR}
${sublibrary2_SOURCE_DIR}
CMake創建的變量包括:
Variable | Info |
---|---|
PROJECT_NAME | 由當前project() 設置的項目名稱 |
CMAKE_PROJECT_NAME | 由project()命令設置的第一個項目的名稱,即頂級項目 |
PROJECT_SOURCE_DIR | 當前項目的源目錄 |
PROJECT_BINARY_DIR | 當前項目的生成目錄 |
name_SOURCE_DIR | 名為“name”的項目的源目錄。在本例中,創建的源目錄將是sublibrary1_SOURCE_DIR 、sublibrary2_SOURCE_DIR 和subbinary_SOURCE_DIR |
name_BINARY_DIR | 名為“name”的項目的二進制目錄。在本例中,創建的二進制目錄為sublibrary1_BINARY_DIR 、sublibrary2_BINARY_DIR 和subbinary_BINARY_DIR 。 |
頭文件庫
如果你有一個被創建為只包含頭文件的庫,cmake支持接口目標,以允許在沒有任何構建輸出的情況下創建目標。有關更多詳細信息,請單擊此處。
add_library(${PROJECT_NAME} INTERFACE)
在創建目標時,你還可以使用INTERFACE作用域包含該目標的目錄。INTERFACE作用域用於制定目標要求,這些要求在鏈接此目標的任何庫中使用,但不用於目標本身的編譯。如下示例,鏈接至此目標的任何目標都將包含一個include目錄,但此目標本身並不進行編譯(即不產生任何實體內容):
target_include_directories(${PROJECT_NAME}
INTERFACE
${PROJECT_SOURCE_DIR}/include
)
從子項目中引用庫
如果某個子項目創建庫,則其他項目可以通過在target_link_library()
命令中調用該項目的名稱來引用該庫。這意味着你不必引用新庫的完整路徑,它將作為依賴項被添加。
target_link_libraries(subbinary
PUBLIC
sublibrary1
)
或者,你可以創建一個別名目標,使你可以在只讀上下文中引用該目標。
要創建別名目標運行,請執行以下操作:
add_library(sublibrary2)
add_library(sub::lib2 ALIAS sublibrary2)
要引用別名,只需如下所示:
target_link_libraries(subbinary
sub::lib2
)
包含來自子項目的頭文件目錄
當從子項目添加庫時,從cmake v3
開始,不需要使用它們在二進制文件的include目錄中添加項目include目錄。
這由創建庫時target_include_directory()
命令中的作用域控制。在本例中,因為子二進制可執行文件鏈接了subibrary1和subibrary2庫,所以它將自動包括${subibrary1_source_DIR}/include
和${subibrary2_source_DIR}/include
文件夾,因為它們是隨庫的PUBLIC和INTERFACE范圍導出的。
構建示例
$ mkdir build
$ cd build/
$ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/02-sub-projects/A-basic/build
$ make
Scanning dependencies of target sublibrary1
[ 50%] Building CXX object sublibrary1/CMakeFiles/sublibrary1.dir/src/sublib1.cpp.o
Linking CXX static library libsublibrary1.a
[ 50%] Built target sublibrary1
Scanning dependencies of target subbinary
[100%] Building CXX object subbinary/CMakeFiles/subbinary.dir/main.cpp.o
Linking CXX executable subbinary
[100%] Built target subbinary