Context: I want to make a GameClient, GameServer, and custom library (which both Client and Server use) cross platform for Linux, Windows & MacOS. Server and Client both depend on various libraries I prefer linking statically, and headers. I heard I could do this by wrapping my 3 currently VisualStudio developed projects into a CMake environment, so I started by making CMakeLists.txt's for Server and Shared lib, which are the simplest and have fewer library dependencies.
Question: How can I adapt these CMakeLists.txt's (currently building on and for Windows), so I can choose if I want to compile for Windows or Linux (preferably from Windows)?
Shared Lib 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
)
Server 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
)
You are lucky as both the three libraries you use export their packages correctly.
On linux, I will assume that the libraries are installed in ~/workspace/libraries
.
The trick will be to use find_package
for all your dependencies, and you must drop every custom Findxyz.cmake
files.
Then, you will have to drop the ALL_CAPS for the directory name. This is important for CMake to find the packages correctly. On windows it may not matter as the filesystem is not case sensitive, but on linux it is.
So first, to make your CMakeLists completely agnostic on where to find the packages, we will create a new file called linux-dependencies.cmake
with this content:
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}/workspace/libraries")
list(APPEND CMAKE_PREFIX_PATH "path/to/morph/build") # can be relative
And windows-dependencies.cmake
:
list(APPEND CMAKE_PREFIX_PATH "C:/libraries/")
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOMEPATH}/Desktop/MORPH/build")
Of course, if you set the library installation directory relative to the project or on both platform relative to the home directory, you can have only one dependencies.cmake
file.
Then, on your next cmake invocation, simply tell cmake to include that file:
cmake .. -DCMAKE_PROJECT_INCLUDE=linux-dependencies.cmake
Note that CMAKE_PROJECT_INCLUDE
is only available since CMake 3.15. If you don't want to upgrade CMake or simply to provide a default, you can always include the file manually.
You CMakeLists file should look like this:
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
)
Another thing that can help: set the same CMAKE_PREFIX_PATH
as CMAKE_INSTALL_PREFIX
or CMAKE_INSTALL_PREFIX/libname
when installing libraries.
If you want to compile the linux executable on windows, I would advise to simply use WSL or to run the compiler inside Docker. VSCode actually has a nice extension to use a docker as a build environment, and as far as I know, can also use WSL as a build and run environment.
my 2 cents,
According to the find_package()
search procedure documentation:
In all cases the
<name>
is treated as case-insensitive and corresponds to any of the names specified (<PackageName>
or names given byNAMES
).
ref: https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure
note: personally I prefer to use PackageNameConfig.cmake
than package-name-config.cmake
...
Why not simply add the CMAKE_PREFIX_PATH
on the configure command line than passing by your dependencies.cmake
files ?
For static linking, I would use a FetchContent()
approach to control the "static-ness" since most of Linux distro will tend to build libraries as shared then put them in directories following the FHS .
You can also use flag to allow user to use system-wide libraries if they want (thus distro maintainers are happy as well as you can create a standalone artifact easily).
warning: Most libraries are not intended to be used inside a super build so you may need to patch them (ie 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()
You may also provide a default 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)
So you don't have to play with CMAKE_PREFIX_PATH
or dependencies.cmake
etc. and users can still provide their own FindThirdParty.cmake
and prepend the CMAKE_PREFIX_PATH
if they want to change...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.