CMake基礎 第13節 構建子項目


介紹

此示例說明如何設置包含子項目的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_DIRsublibrary2_SOURCE_DIRsubbinary_SOURCE_DIR
name_BINARY_DIR 名為“name”的項目的二進制目錄。在本例中,創建的二進制目錄為sublibrary1_BINARY_DIRsublibrary2_BINARY_DIRsubbinary_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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM