簡體   English   中英

如何使用 CMake 為 Linux 鏈接和編譯 C++ 項目? (改編 CMakeLists.txt)

[英]How to link and compile a C++ project for Linux using CMake? (Adapting CMakeLists.txt)

上下文:我想為 Linux、Windows 和 MacOS 制作跨平台的 GameClient、GameServer 和自定義庫(客戶端和服務器都使用)。 服務器和客戶端都依賴於我更喜歡​​靜態鏈接的各種庫和標頭。 我聽說我可以通過將我當前由 VisualStudio 開發的 3 個項目包裝到 CMake 環境中來做到這一點,所以我首先為 Server 和 Shared lib 創建了 CMakeLists.txt,它們是最簡單的,並且具有較少的庫依賴項。

問題:我如何調整這些 CMakeLists.txt(目前在 Windows 上構建),以便我可以選擇是為 Windows 還是 Linux(最好是從 Windows)編譯?

共享庫 CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

project(MORPH_Server VERSION 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

set(SFML_STATIC_LIBRARIES TRUE) #Link to statically
set(SFML_DIR "C:/libraries/SFML/SFMLx64SourceAndCompile")
find_package(SFML 2.5.1 COMPONENTS system network REQUIRED)

add_library(MORPH_Shared_Functions)
target_sources(MORPH_Shared_Functions
               PRIVATE Transform.cpp
               PRIVATE World.cpp
               PRIVATE Player.cpp
               PRIVATE PropsData.cpp
               PRIVATE Prop.cpp
               PRIVATE udp_network_manager.cpp
               PRIVATE utility_functions.cpp
               )

target_link_libraries(MORPH_Shared_Functions 
                      sfml-system #Basically already found sfml modules and their dependencies (find-package)
                      sfml-network
                      )

target_include_directories(MORPH_Shared_Functions
                           PRIVATE C:/libraries/SFML/SFML-2.5.1/include
                           PRIVATE C:/libraries/GLM/glm
                           PRIVATE C:/libraries/CEREAL
                           )

服務器 CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

project(MORPH_Server VERSION 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

configure_file(CmakeConfig.h.in CmakeConfig.h)

set(SFML_STATIC_LIBRARIES TRUE) #Link to statically
set(SFML_DIR "C:/libraries/SFML/SFMLx64SourceAndCompile")
find_package(SFML 2.5.1 COMPONENTS system network REQUIRED)

add_executable(MORPH_Server)
target_sources(MORPH_Server
               PRIVATE Main.cpp 
               PRIVATE Game.cpp
               PRIVATE CommandManager.cpp
               PRIVATE ServerPlayer.cpp
               PRIVATE ServerProp.cpp
               PRIVATE ServerWorldState.cpp
               PRIVATE UDP_Server_CS.cpp
               )
add_library(MORPH_Shared_Functions STATIC IMPORTED)

set_target_properties(MORPH_Shared_Functions PROPERTIES IMPORTED_LOCATION C:/Users/dylan/Desktop/MORPH/MORPH_Shared_Functions/Build/Debug/MORPH_Shared_Functions.lib)

target_link_libraries(MORPH_Server
                      MORPH_Shared_Functions 
                      sfml-system
                      sfml-network
                      )

target_include_directories(MORPH_Server 
                           PRIVATE C:/Users/dylan/Desktop/MORPH/MORPH_Shared_Functions
                           PRIVATE C:/libraries/SFML/SFML-2.5.1/include
                           PRIVATE C:/libraries/GLM/glm
                           PRIVATE C:/libraries/CEREAL
                           )

您很幸運,因為您使用的三個庫都正確導出了它們的包。

在 linux 上,我假設庫安裝在~/workspace/libraries

訣竅是對所有依賴項使用find_package ,並且您必須刪除每個自定義Findxyz.cmake文件。

然后,您必須刪除目錄名稱的 ALL_CAPS。 這對於 CMake 正確找到包很重要。 在 Windows 上這可能無關緊要,因為文件系統不區分大小寫,但在 linux 上是。

因此,首先,為了讓您的 CMakeLists 完全不知道在哪里可以找到包,我們將創建一個名為linux-dependencies.cmake的新文件,其中包含以下內容:

list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}/workspace/libraries")
list(APPEND CMAKE_PREFIX_PATH "path/to/morph/build") # can be relative

windows-dependencies.cmake

list(APPEND CMAKE_PREFIX_PATH "C:/libraries/")
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOMEPATH}/Desktop/MORPH/build")

當然,如果你設置了庫安裝目錄相對於項目或者兩個平台都相對於home目錄,則可以只有一個dependencies.cmake文件。

然后,在您下一次 cmake 調用時,只需告訴 cmake 包含該文件:

cmake .. -DCMAKE_PROJECT_INCLUDE=linux-dependencies.cmake

請注意, CMAKE_PROJECT_INCLUDE僅自 CMake 3.15 起可用。 如果您不想升級 CMake 或只是提供默認值,您始終可以手動包含該文件。

您的 CMakeLists 文件應如下所示:

cmake_minimum_required(VERSION 3.15)

project(MORPH_Server VERSION 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

configure_file(CmakeConfig.h.in CmakeConfig.h)

find_package(SFML 2.5.1 COMPONENTS system network REQUIRED)
find_package(glm 0.9.9 REQUIRED)
find_package(cereal REQUIRED) # cereal don't export version info as far as I know

# You will have to export your target or write a MORPH-config.cmake file
find_package(MORPH REQUIRED)

add_executable(MORPH_Server)
target_sources(MORPH_Server
               PRIVATE Main.cpp 
               PRIVATE Game.cpp
               PRIVATE CommandManager.cpp
               PRIVATE ServerPlayer.cpp
               PRIVATE ServerProp.cpp
               PRIVATE ServerWorldState.cpp
               PRIVATE UDP_Server_CS.cpp
               )

# this take care of both linking and include dirs
target_link_libraries(MORPH_Server
                      MORPH_Shared_Functions 
                      sfml-system
                      sfml-network
                      glm
                      cereal
                      )

另一件事可以提供幫助:在安裝庫時設置與CMAKE_INSTALL_PREFIXCMAKE_INSTALL_PREFIX/libname相同的CMAKE_PREFIX_PATH


如果你想在 Windows 上編譯 linux 可執行文件,我建議簡單地使用 WSL 或在 Docker 中運行編譯器。 VSCode 實際上有一個很好的擴展,可以使用 docker 作為構建環境,而且據我所知,還可以使用 WSL 作為構建和運行環境。

我的 2 美分,

1

根據find_package()搜索過程文檔:

在所有情況下, <name>都被視為不區分大小寫,並對應於指定的任何名稱( <PackageName>NAMES給出的NAMES )。

參考: https : //cmake.org/cmake/help/latest/command/find_package.html#search-procedure

注意:我個人更喜歡使用PackageNameConfig.cmake不是package-name-config.cmake ...

2

為什么CMAKE_PREFIX_PATH地在配置命令行上添加CMAKE_PREFIX_PATH而不是通過您的dependencies.cmake文件?

3

對於靜態鏈接,我將使用FetchContent()方法來控制“靜態性”,因為大多數 Linux 發行版傾向於將庫構建為共享庫,然后將它們放在FHS之后的目錄中。

3.1

您還可以使用標志來允許用戶根據需要使用系統范圍的庫(因此發行版維護人員很高興,並且您可以輕松創建獨立的工件)。
警告:大多數庫不打算在超級構建中使用,因此您可能需要修補它們(即PATCH_COMMAND git apply ...

# enable CMP0077 so superbuild can set it.
option(BUILD_THIRDPARTY "Build the third party" ON)
...
# to allow recursive superbuild (add_subdirectory(morph_server) etc...) 
# first check if third party target is not already present
# see: https://gitlab.kitware.com/cmake/cmake/-/issues/17735
if(NOT TARGET ThirdParty::ThirdParty)
  if(BUILD_THIRDPARTY)
   FetchContent_Declare(...)
   set(BUILD_SHARED_LIBS OFF)
   set(BUILD_EXAMPLES OFF) ...
   FetchContent_MakeAvailable(third_party)
   set(BUILD_SHARED_LIBS ${BUILD_SHARED_BCKP})
  else()
    find_package(ThirdParty REQUIRED)
  endif()
endif()

4

您還可以提供默認的FindThirdParty.cmake

if(UNIX)
  list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}/workspace/libraries")
  list(APPEND CMAKE_PREFIX_PATH "path/to/morph/build") # can be relative
else()
  list(APPEND CMAKE_PREFIX_PATH "C:/libraries/")
  list(APPEND CMAKE_PREFIX_PATH "$ENV{HOMEPATH}/Desktop/MORPH/build")
endif()

find_package(ThirdParty CONFIG REQUIRED)

因此,您不必使用CMAKE_PREFIX_PATHdependencies.cmake等,並且用戶仍然可以提供他們自己的FindThirdParty.cmake並在CMAKE_PREFIX_PATH如果他們想更改...

暫無
暫無

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

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