繁体   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