Like most build systems, CMake is not clearly documented enough for me. I’m going to use libgit2 as an example of something real that is available to everyone. I’m doing this because there’s still not a single build system that’s good enough for general use, at least not when it comes to working on multi-platform projects.
You’ll almost always be using CMake to generate and use Visual Studio projects, although you have a choice of:
- Makefile: MinGW, MSYS, NMake
- Visual Studio projects (6-12)
Let’s start with Visual Studio projects, since that’s the common case.
Visual Studio generation
Grab the libgit2 source. Since I’m going to build for PyGit, I want a specific tag for compatibility. I definitely don’t want the development branch
> git clone firstname.lastname@example.org:libgit2/libgit2.git > cd libgit2 > git checkout -b local-v0.20.0 v0.20.0
You’re meant to run CMake from the output folder. This is weird, but whatever. So here’s the naive way to use CMake.
> mkdir build > cd build > cmake .. -- Building for: Visual Studio 12 -- The C compiler identification is MSVC 18.0.21005.1 -- Check for working C compiler using: Visual Studio 12 -- Check for working C compiler using: Visual Studio 12 -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done zlib was not found; using bundled 3rd-party sources. -- Found PythonInterp: C:/Python27/python.exe (found version "2.7.6") -- Configuring done -- Generating done -- Build files have been written to: C:/projects/git/github/libgit2/build
Of course, this will auto-pick a Visual Studio toolchain, and since it’s Windows, it won’t use the toolchain found in my path (that I very carefully put there), since it’s actually not common that the Visual Studio toolchain is in the path. CMake will default to the newest version it finds, and while that’s a reasonable thing to do, I need to be specific. So you need to tell CMake about the toolchain.
> mkdir build > cd build > cmake -G "Visual Studio 11" .. -- The C compiler identification is MSVC 17.0.61030.0 -- Check for working C compiler using: Visual Studio 11 -- Check for working C compiler using: Visual Studio 11 -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done zlib was not found; using bundled 3rd-party sources. -- Found PythonInterp: C:/Python27/python.exe (found version "2.7.6") -- Configuring done -- Generating done -- Build files have been written to: C:/projects/git/github/libgit2/build
It doesn’t look like it’s possible to hard-code a generator in the CMakeLists.txt file. A kickstarter CMakeCache.txt file can go into the target folder, but there’s a chicken-and-egg issue there.
In CMake, there is a distinction between “generator” and “toolchain”. E.g. you can use the “Visual Studio 12″ generator but have it create projects that use the “Visual Studio 11″ toolchain.
> cmake -G "Visual Studio 12" -T "Visual Studio 11" ..
Up until now, all we’ve done is create a Visual Studio project file. While that’s useful, we actually want some built libraries and binaries.
You can build from the command-line like so:
> cmake --build .
(assuming you were in the build directory). However, it’s of limited use, because (on Windows with Visual Studio) you can only do debug builds this way. There’s no way to tell CMake to do a release build with Visual Studio. If you do this
> cmake --build . --target Release
you’ll get an error; the target functionality only works for makefile generators. You’ll also find out that cmake is using devenv, when it should now be using msbuild to be a good Windows citizen. CMake is great for creating cross-platform projects, but less good as an actual build tool. So you’ll want to directly use MSBuild.
> msbuild libgit2.sln /t:Build /p:Configuration=Release;Platform=Win32
And now I have libraries and binaries in libgit2/build/Release. If you really want to use devenv (against Microsoft’s desires, but what the heck), then
> devenv libgit2.sln /build Release /project ALL_BUILD
There is nothing that mandated the output folder being named build, it’s merely a convention.
Once you’ve generated makefiles with a specific generator, you can’t change the generator. You need to wipe the build folder, or pick a new build folder. So for doing cross-platform builds on a single machine, you’ll want some consistent naming for multiple build folders.
CMake likes to generate projects for a single architecture.
> cmake -G "Visual Studio 12 Win32" .. > cmake -G "Visual Studio 12 Win64" ..
I don’t know how to generate a multi-architecture project. Or rather, the CMake philosophy is to use multiple build directories, with a single source tree, and it sounds like from the architecture of CMake that it just won’t be possible.
- CMake 2.8.12 Documentation
- CMake Tutorial
- CMake FAQ
- CMake Wiki
- CMake: Building with all your cores
- CMake 3.0-rc6 now ready for testing!
- CMAKE AND VISUAL STUDIO
- Building a solution file using msbuild
- Cmake and Visual Studio platforms
- CMake Cross Compiling
- CMake Multiarchitecture Compilation