簡體   English   中英

使用設置編譯依賴項

[英]CMake compile dependencies with settings

我想知道如何為我的項目編譯依賴項,同時為這些依賴項啟用特定設置,例如將依賴項編譯為靜態或動態庫或使用x64或x86設置或作為另一個示例,當項目定義變量以確定如何構建項目(與Wayland或X.Org支持一樣)。

我目前的設置如下:

文件夾結構

root_project
  |─── CMakeLists.txt
  |─── Project 1
  |      |─── .h and .cpp files
  |      └─── CMakeLists.txt
  |─── Dependency 1 (GLFW)
  |      |─── include directory
  |      |─── source directory
  |      |─── ...
  |      └─── CMakeLists.txt
  └─── Dependency 2 (GLEW)
         |─── build
         |      └─── cmake
         |            └─── CMakeLists.txt
         |─── source directory
         |─── include directory
         └─── ...

CMake文件

我的root cmake文件:

cmake_minimum_required (VERSION 3.8)
project ("EbsiStaller")
add_subdirectory ("EbsiStaller")

# Adds the CMakeLists.txt file located in the specified directory
# as a build dependency.
add_subdirectory ("glfw")
include_directories("glfw/include")

add_subdirectory ("glew/build/cmake")
include_directories("glew/include")

我的項目cmake文件:

cmake_minimum_required (VERSION 3.8)

add_executable (EbsiStaller 
    "....cpp" 
    "....h"
)

SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED  ON)

# Links the CMake build output against glfw.
target_link_libraries(EbsiStaller glfw ${GLFW_LIBRARIES} glew ${GLEW_LIBRARIES})

補充說明:

我在Windows下使用Visual Studio 2017進行此項目,而項目應該與平台無關。 因為我對CMake沒有太多經驗,所以我總是對我的CMake文件的任何建議更改開放。

在為依賴項定義特定於編譯器的設置時,我不想編輯它們的CMake文件來執行此操作。

在CMake中這樣做有很多困難,但我會盡我所能回答它。

通常,通過add_subdirectory添加的任何項目都將繼承當前作用域中當前定義的所有設置。 更改單個依賴項設置的最簡單方法(IMO)是將ExternalProject_Add與以下一起使用:

include(ExternalProject)

#
#   Add external project.
#
#   \param name             Name of external project
#   \param path             Path to source directory
#   \param external         Name of the external target
#
macro(add_external_project name path)
    # Create external project
    set(${name}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${path})
    set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${path})
    ExternalProject_Add(${name}
        SOURCE_DIR "${${name}_SOURCE_DIR}"
        BINARY_DIR "${${name}_BINARY_DIR}"
        CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}"
                   "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
                   "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
                   "-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}"
                   # These are only useful if you're cross-compiling.
                   # They, however, will not hurt regardless.
                   "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}"
                   "-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}"
                   "-DCMAKE_AR=${CMAKE_AR}"
                   "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
                   "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
                   "-DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}"
                   "-DCMAKE_COMPILER_PREFIX=${CMAKE_COMPILER_PREFIX}"
                   "-DCMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}"
       INSTALL_COMMAND ""
    )

endmacro(add_external_project)

#
#   Add external target to external project.
#
#   \param name             Name of external project
#   \param includedir       Path to include directory
#   \param libdir           Path to library directory
#   \param build_type       Build type {STATIC, SHARED}
#   \param external         Name of the external target
#
macro(add_external_target name includedir libdir build_type external)
    # Configurations
    set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${libdir})

    # Create external library
    add_library(${name} ${build_type} IMPORTED)
    set(${name}_LIBRARY "${${name}_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${CMAKE_${build_type}_LIBRARY_PREFIX}${name}${CMAKE_${build_type}_LIBRARY_SUFFIX}")

    # Find paths and set dependencies
    add_dependencies(${name} ${external})
    set(${name}_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${includedir}")

    # Set interface properties
    set_target_properties(${name} PROPERTIES IMPORTED_LOCATION ${${name}_LIBRARY})
    set_target_properties(${name} PROPERTIES INCLUDE_DIRECTORIES ${${name}_INCLUDE_DIR})
endmacro(add_external_target)

宏解釋

這些宏基本上配置了一個具有非常相似的CMake變量定義的CMake新實例。

第一個宏, ExternalProject_Add ,通知那些自定義CMake參數,源目錄和輸出二進制目錄需要構建一次的外部項目。 特別是,像"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"這樣的選項告訴CMake使用與當前構建類型相同的構建類型(Debug,Release等),而"-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}"指示CMake使用構建共享庫時的相同偏好(默認情況下,如果BUILD_SHARED_LIBS設置為OFF ,則項目應構建靜態依賴項)。

第二個宏然后創建導入的目標CMake可以鏈接與類似於本機CMake庫的屬性。

使用這些宏

要默認使用這些宏,您可以執行以下操作:

add_external_project(googletest_external googletest)
add_external_target(gtest googletest/googletest/include googletest/googlemock/gtest STATIC googletest_external)
add_external_target(gtest_main googletest/googletest/include googletest/googlemock/gtest STATIC googletest_external)

在這個例子中,我配置外部項目googletest ,然后創建目標gtestgtest_main ,它們應該是靜態庫(由於Googletest如何強制靜態鏈接),它可以像任何普通的CMake庫一樣鏈接。

劫持這些宏以進行自定義構建

現在您已經粗略地了解了這些宏的功能,修改它們以允許每個依賴項的自定義配置非常容易。 比如說,無論我的實際項目設置如何,我都想要一個靜態版本的glew。 讓我們假設我想要將GLEW_OSMESA設置為ON

#
#   Add external project.
#
macro(add_release_osmesa_glew)
    # Create external project
    set(${name}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/glew)
    set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/glew)
    ExternalProject_Add(glew_external
        SOURCE_DIR "${${name}_SOURCE_DIR}"
        BINARY_DIR "${${name}_BINARY_DIR}"
        CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}"
                   "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
                   "-DCMAKE_BUILD_TYPE=Release"
                   "-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}"
                   # These are only useful if you're cross-compiling.
                   # They, however, will not hurt regardless.
                   "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}"
                   "-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}"
                   "-DCMAKE_AR=${CMAKE_AR}"
                   "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
                   "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
                   "-DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}"
                   "-DCMAKE_COMPILER_PREFIX=${CMAKE_COMPILER_PREFIX}"
                   "-DCMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}"
                   "-DGLEW_OSMESA=ON"
       INSTALL_COMMAND ""
    )

然后,要使用使用這些配置選項構建的glew,我可以執行以下操作:

add_release_osmesa_glew()
add_external_target(
    glew
    glew/include 
    glew 
    SHARED 
    glew_external
)

add_external_target(
    glew_s 
    glew/include 
    glew 
    STATIC 
    glew_external
)

最后,我可以使用以下選項鏈接它:

target_link_libraries(my_target
    glew_s
    ...
)

優點

  • 不需要更改項目的CMakeLists。
  • 支持依賴項目支持的所有可能配置。
  • 僅構建一次依賴庫,並可根據需要使用繼承的設置或自定義設置。
  • 應該是目標獨立的(意味着它應該與Visual C ++項目,Makefile等一起工作)開箱即用。

缺點

  • 大量的樣板
  • 配置取決於依賴項目中的CMakeLists

正確的方法是直接對目標進行操作。 例如(猜測目標名稱,原諒我):

add_subdirectory ("glfw")
set_target_properties(glfw PROPERTIES
    COMPILE_FLAGS "-m32 -O2" # Adjust as needed
)
target_link_libraries(glew INTERFACE
    ${GLFW_LIBRARIES}
)

add_subdirectory ("glew/build/cmake")
target_include_directories(glew PUBLIC
    "glfw/include"
)
target_link_libraries(glew INTERFACE
    ${GLEW_LIBRARIES}
)

這使您可以按目標而不是全局調整內容(這是現代CMake使用的基礎)。 你可以使用這些函數和他們的朋友調整你喜歡的關於目標的任何東西,包括調整編譯器標志甚至添加新文件。

您正在使用的方法有效,但是您正在影響之后聲明的每個目標,包括稍后添加的子目錄。

您的主項目的CMakeLists.txt可能如下所示:

 add_executable (EbsiStaller 
    "....cpp" 
    "....h"
)
target_compile_features(EbsiStaller PUBLIC
    cxx_std_17 # might actually be a cmake 3.9 thing, but you get the idea
)

# Links the CMake build output against glfw.
target_link_libraries(EbsiStaller
    glfw
    glew
)

這里有太多的內容,但這一切都歸結為你的CMake的現代化。 在線文檔太棒了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM