Convert from Xcode to CMake - c++

I have a C++ project that I initially developed using Xcode on my Mac and I would like to set up the very same project using CMake. The project makes use of some external libraries, including eigen and boost. Xcode has a rather long list of Build Settings, including paths to external libraries, specification of the compiler version, additional linker flags, compiler optimization level, etc... and I am wondering where all of this information goes in the CMakeLists.txt file. I've searched extensively for help on this but have found precious little. I am new to CMake and have never written make files before. If there were a utility that could convert my Xcode project into a CMake project, that would be ideal. But I would be very glad to know of a tutorial on this, or to have some specific guidance. Any help on this would be greatly appreciated.

Conversion Strategy
I am pretty sure that the easiest and fastest way to move to CMake is a mixture of looking at comparable projects that link the same dependencies, and maybe copying a few relative file paths to your source files from XCode.
A well-written CMakeLists.txt that uses Eigen and Boost can be very small (and platform-independent).
One reason for this is CMake has a very different way to use dependencies.
For well-known libraries such as Boost, CMake includes scripts to include headers and link libraries.
Minimal CMakeLists.txt
A minimal example may look like this:
find_package(Eigen3 REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)
add_executable(
app
src/main.cpp
)
target_include_directories(
app
${Eigen3_INCLUDE_DIRS}
${Boost_INCLUDE_DIR}
)
target_link_libraries(
app
${Boost_LIBRARIES}
)
Example Projects
For Eigen, there is no such pre-installed script that can be called by find_package.
Here are two real-world example projects that link Eigen and Boost: https://github.com/ompl/ompl/blob/master/CMakeLists.txt
https://github.com/roboticslibrary/rl
Here is an example for a find script for Eigen.
As a piece of advice, some CMake projects are out there are convoluted and use old syntax, newer project files tend to use small letters in commands.

If it happens that directly target linking libraries doesn't work, you'll have to write your own Find*.cmake files by yourself.
Here's a spec of what you should cover to make it (this is just one approach):
Imagine you have a library XYZ:
Your file
FindXYZ.cmake should have as a result a set of variables to use:
XYZ_LIBRARIES
XYZ_INCLUDE_DIR
For example:
set(XYZ_LIBRARIES ${SOME_PATH_TO_LIBRARY1} ${SOME_PATH_TO_LIBRARY2})
find_path(XYZ_INCLUDE_DIR NAMES xyz/xyz.h HINTS ${PLACE_WHERE_INCLUDE_SHOULD_BE}
PATH_SUFFIXES include
)
From your main cmake maybe you 'use' it:
find_package(XYZ REQUIRED)
# Now we use both _INCLUDE_DIR and _LIBRARIES
include_directories(SYSTEM "${XYZ_INCLUDE_DIR}")
# TARGET_NAME is the current target, the 'client' of XYZ
# append XYZ to our list of libraries to link
target_link_libraries(${TARGET_NAME} ${XYZ_LIBRARIES})
I'm surely missing details but that's the general idea. Here are some cmake scripts that I know work in a big project:
Example with OpenSSL
Find:
https://github.com/highfidelity/hifi/blob/Android/cmake/modules/FindOpenSSL.cmake
Client (in this case is a library that indeed needs OpenSSL):
https://github.com/highfidelity/hifi/blob/Android/domain-server/CMakeLists.txt

Related

Setting up 3rd party libraries environment for CMake on Windows 10

I'm having problems with the "proper" way of installation third-party libraries for use with CMake projects (C++). For most of the time I haven't been bothering myself with this stuff and just hardcoding library paths in my CMakeLists.txt, but I really want to start using this properly.
I ultimately want to have something where I can just type, for example, find_package(SDL2 REQUIRED) in a project and the library is there, found, and works perfectly.
What I have right now is I have a folder C:\CMakeLibs where I --install all 3rd party libraries, so for example there is C:\CMakeLibs\SDL2 and in it, there are folders like cmake, include, lib, etc. Then I include the folder C:\CMakeLibs\SDL2 in CMAKE_PREFIX_PATH in system environment variables, so that CMake can find the SDL2Config.cmake file and there's no need for any FindSDL2.cmake. This way I can just type following code and it straight works, and is also probably the most portable for open-source projects.
find_package(SDL2 REQUIRED)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE SDL2::SDL2main SDL2::SDL2-static)
My only concern here is that I have to manually add any new libraries to CMAKE_PREFIX_PATH. I'd like just have only C:\CMakeLibs as my CMAKE_PREFIX_PATH and everything working fine. I could technically --install the libraries directly to C:\CMakeLibs but I fear of any possible incompatibilities when having all the different files in one shared folders, it doesn't feel like the best solutions.
I know this question might be one of those "without the best answers/based on opinion". I've been looking for solutions on internet for long time already, ever since I started using CMake, so I decided to just write this post here. I hope I described my problem clearly, English isn't my native language.

Using Cmake, how do I prevent library sources from being included in my IDE?

Using a bunch of different libraries in my project (from GitHub sources, not precompiled), I add them to my target like this in my root CMakeLists.txt file:
add_subdirectory(lib/glew-1.13.0/build/cmake)
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/lib/glew-1.13.0/include/)
...
target_link_libraries(MyApp glew ${GLEW_LIBRARIES} ... )
However, you can see from the screenshot below that Xcode includes all of the sources for those libraries in my project, which makes an insanely long list that I have to scroll through to find my code.
I have tried the EXCLUDE_FROM_ALL flag in the add_subdirectory command, which removes the library sources from my Xcode project, but then I cannot compile my project because Xcode doesn't compile the library at all.
Additionally, Xcode gives me tons of warnings from the libraries that I don't really care about. Using the SYSTEM flag with the include_directories command doesn't fix it.
What's the best way to solve this? Should I be compiling my libraries as a completely separate part of my build process rather than compiling them with my executable?
I'm not sure how it will work, but try this:
turn on the USE_FOLDERS in your root CMakeLists.txt
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
And then after you've added all the projects, set the FOLDER target property on all of the third party libraries:
set_property(TARGET target1 target2 ...
PROPERTY FOLDER "ThirdPartyLibs")
Being unfamiliar with C++, I thought that all of my libraries should be compiled along with my project every time. I ended up solving this by writing a shell script that precompiles all of my libraries once as static libraries, and now I don't have to worry about their sources in my IDE, plus I get faster compile times.

How do I write system-independent code when there are paths involved?

Say I am creating a project that uses a certain library and I have to provide the path for that library while linking. In the command line or makefile I might have:
g++ ... -L/path/to/mylibrary
I'm also going to send this project to someone else who wants to use it. The path on their system might not necessarily be the same as mine. They could be using a different file path all together.
How do I make sure that the path to the library works for both my computer and the recipient of my project?
This is the role of a build system or build configuration tool. There are many of those around. The main one is probably CMake as it has a very extensive feature set, cross-platform, and widely adopted. There are others like Boost.Jam, autoconf, and others.
The way that these tools will be used is that they have automated scripts for looking into the file-system and finding the headers or libraries that you need, i.e., the dependencies required to compile your code. They can also be used to do all sorts of other fancy things, like checking what features the OS supports and reconfiguring the build as a consequence of that. But the point is, you don't hard-code any file-paths into the build configuration, everything is either relative to your source folder or it is found automatically by the build script.
Here is an example CMake file for a project that uses Boost:
cmake_minimum_required (VERSION 2.8)
project (ExampleWithBoost)
find_package(Boost 1.46 COMPONENTS thread program_options filesystem REQUIRED)
# Add the boost directory to the include paths:
include_directories(SYSTEM ${Boost_INCLUDE_DIR})
# Add the boost library directory to the link paths:
link_directories(${Boost_LIBRARY_DIRS})
# Add an executable target (for compilation):
add_executable(example_with_boost example_with_boost.cpp)
# Add boost libraries to the linking on the target:
target_link_libraries(example_with_boost ${Boost_LIBRARIES})
The find_package cmake function is simply a special script (specialized for Boost, and installed with CMake) that finds the latest version of boost (with some minimal version) installed on the system, and it does so based on the file-name patterns that the library uses. You can also write your own equivalents of find_package, or even your own package finders, using the functions that CMake provides for searching the file system for certain file-name patterns (e.g., regular expressions).
As you see, the build configuration file above only refer directly to your source files, like "example_with_boost.cpp", and it's only relative to the source folder. If you do things right, the configuration scripts will work on virtually any system and any OS that CMake supports (and that the libraries you depend on support). This is how most major cross-platform projects work, and when you understand how to work with these systems, it's very powerful and very easy to use (in general, far easier to use and trouble-free than build configurations that you do by point-and-click within IDE menus like in Visual Studio).
You can use premake that generates cross platform makefiles: Visual Studio, Gcc and others
http://industriousone.com/what-premake
CMake is another alternative
http://www.cmake.org/
I'm not sure if there's a single universal way of doing this, but people often provide different config files and let the main Makefile detect which one to include: linux.make, darwin.make, cygwin.make etc.
there are also various tools like CMake that allow to automate this, but all in all it's just scripting that hides the system-dependency from the developer.

Linking a static library to a shared library in cmake

I have been working on a fun project (a game engine) for awhile now and figured i could make it more portable and easy to compile across platforms if I use cmake. Right now i have it set up like so, with a main executable and then a bunch of shared libraries that the executable is linked to. I've found all the material needed to produce the libraries and the executable, and linking those to the executable, but what of linking a dependency like a static library or another shared library to one of the libraries i produce? Here is a visual
Sentiment (name of project)
-Root (all the interfaces and components of the engine. main.cpp is here
-Sentiment_OGL4Renderer (the files for the Renderer library)
-Sentiment_SFMLGui (the files for the Gui library)
-Sentiment_TestGame (the code for a game)
now i want all of these, the executable and the shared libraries built and put into the bin folder in the top level directory. What i found suggested online for a setup like this was to make cmakelists.txt files in each folder, and then one in the root, for each project. What i have thus far is this.
#Sentiment
cmake_minimum_required(VERSION 2.6)
project(Sentiment)
set(RENDERER Sentiment_OGL4Renderer)
set(GUI Sentiment_SFMLGui)
set(GAME Test_Game)
add_definitions(-DBUILD_DLL)
list( APPEND CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
set(EXECUTABLE_OUTPUT_PATH "${Sentiment_SOURCE_DIR}/bin")
set(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}")
link_directories("${LIBRARY_OUTPUT_PATH}")
add_subdirectory("${RENDERER}")
add_subdirectory("${GUI}")
add_subdirectory("${GAME}")
add_subdirectory(Root)
in root
project(Sentiment_exe)
link_directories("${Sentiment_SOURCE_DIR}/bin")
AUX_SOURCE_DIRECTORY(. new_source_list)
add_executable("${CMAKE_PROJECT_NAME}" ${new_source_list})
target_link_libraries("${CMAKE_PROJECT_NAME}" "${LIBRARY_OUTPUT_PATH}/${RENDERER}" "${LIBRARY_OUPUT_PATH}/${GUI}" "${LIBRARY_OUTPUT_PATH}/${GAME}" "${ADDITIONAL_DEPENDENCIES}")
in Sentiment_OGL4Renderer
project(Sentiment_OGL4-3Renderer)
include_directories(${Sentiment_SOURCE_DIR})
add_definitions(-DGLEW_STATIC)
add_library(Sentiment_OGL4-3Renderer SHARED Sentiment_OGL4Renderer.cpp GL/glew.cpp)
in Sentiment_SFMLGui
project(Sentiment_SFMLGui)
include_directories(${Sentiment_SOURCE_DIR})
add_library(Sentiment_SFMLGui SHARED Sentiment_SFMLGui.cpp)
in Sentiment_TestGame
project(Sentiment_Game)
include_directories(${Sentiment_SOURCE_DIR})
add_library(Sentiment_Game SHARED Game.cpp)
As you can tell there are a lot of third party libraries, and i tried various methods of linking, like with target_link_libraries, and i cannot for the life of me figure how to link an external library to the ones i've made. First off, the renderer uses GLEW but it needs no external dependency so ignore that. Then it needs OpenGL32.lib and Gdi32.lib from the windows sdk (only for windows). As for SFML, i've got the DLL's in the bin folder which need to be linked, (can easily get the .so's when working in linux and can distribute with the final product if I ever choose to do so). I need these all linked as dependencies to the libraries i create, but nothing seems to work. The project is all c++ and I am currently using mingw32 to compile it. I'm brand new to cmake so please be gentle if it is really simple.
To link external libraries, best practice is to use or create FindModule for given external library.
CMake comes with numerous modules that aid in finding various well-known libraries and packages.
The list of standard modules is in the official documentation
In case there is no standard module for your external library, you should write your own.
The OpenGL library has standard module FindOpenGL:
find_package (OpenGL)
if (OPENGL_FOUND)
include_directories(${OPENGL_INCLUDE_DIR})
target_link_libraries (Sentiment_OGL4-3Renderer ${OPENGL_gl_LIBRARY})
endif (OPENGL_FOUND)

Creating CMakeLists file from existing Makefile

I want to use cmake to generate my build files for a C++ project. I have an existing Makefile.
I am having problems generating this Makefile using the standard cmake syntax.
How do I include standard C++ libraries like -lstdc++ -lpthread -lboost_thread-mt in the TARGET_LINK_LIBRARIES section of cmake? Or should these files be included in the ADD_DEPENDENCIES section.
(OR)
Is there a simple tool which generates a CMakeList.txt file from a Makefile
Unfortunately, there is no straightforward 1:1 conversion from Makefiles to CMakeLists. Since CMake is supposed to run on all platforms, it can not rely on platform specific assumptions like GNU make does, which complicates things in certain places.
In particular, CMake offers a very powerful and rather complex mechanism for using libraries: You call find_package with the name of your library, which will invoke a library search script from your cmake module path. This script (which is also written in CMake) will attempt to detect the location of the library's header and lib files and store them in a couple of CMake variables that can then be passed to the according CMake commands like include_directories and target_link_libraries.
There are two problems with this approach: First, you need a search script. Fortunately, CMake ships with search scripts for Pthreads, Boost and a couple of others, but if you are using a more exotic library, you might have to write the search script yourself, which is kind of an arcane experience at first...
The second major problem is that there is no standard way for a search script to return its results. While there are naming conventions for the used variables, those often don't apply. In practice that means you will have to check out a search script's source to know how to use it. Fortunately, the scripts that come with CMake are mostly very well documented.
The builtin scripts are located somewhere like <cmake-install-prefix>/share/cmake-2.8/Modules. For your question, look at the FindBoost.cmake and FindThreads.cmake files (CMake should automatically link with the standard library). Anycorn already gave some sample code for using the Boost script, everything else you need to know is in the CMake documentation or directly in the search script files.
Like this:
target_link_libraries(your-target-name pthread boost_thread-mt etc)
You should not use add_dependencies when you want to link libraries. Linking implies a dependency, but the dependency alone will not be sufficient when you need to link.
With Boost you really need to use package finder
set(Boost_ADDITIONAL_VERSIONS "1.46" "1.46.0" "1.46.1")
set(Boost_USE_MULTITHREADED ON) # for -mt
find_package(Boost COMPONENTS thread)
if(Boost_FOUND)
MESSAGE(STATUS "Found Boost: ${Boost_LIBRARY_DIRS}")
MESSAGE(STATUS "Found Boost libraries: ${Boost_LIBRARIES}")
set(LIBRARIES "${LIBRARIES};${Boost_LIBRARIES}")
else()
MESSAGE(FATAL_ERROR "Boost Thread NOT FOUND")
endif()
target_link_libraries(executable ${LIBRARIES})