CMake and Visual Studio

CMake produces Visual Studio solutions seamlessly. This post will map CMake commands to the Visual Studio IDE with an example which makes learning much easier. It is primarily intended for a C++ developer using Visual Studio. Most references here is based on Visual Studio 2010 but will apply equally well to other versions. Continuing from the preface CMake for Visual Studio Developers.

Introduction
Visual Studio to CMake Mapping
Example
    Source Structure
    Execute CMake
    Visual Studio Solution Explorer View
    Build and Debug
    Install and Run
    Test
    CMakeLists.txt Details
CMake pre-defined projects
Debug and Release Configurations
Conclusion

Introduction

A short background on the CMake philosophy. Typically source should be considered as any files that are explicitly modified by the developer. Anything that is or can be consistently generated from the source files should be considered as output of the build process. A build will always generate a lot of temporary/intermediate files and to avoid polluting the actual source, it is recommended to have out of source builds.

Other than the typical intermediate files like .obj, Visual Studio produces many more transient files including .sln, .sbr, .suo, .vcxproj.user, .vcxproj.filters. These need not (and should not) be checked into the source repository as sometimes they are large and user specific.

A Visual Studio developer might consider the project file (.vcproj) as a “source” since it involves adding, removing source files and modifying dependencies etc. However, with CMake you can consider this to be an intermediate file too, as CMake will generate it and is recommended for it to be outside the source directory.

In a CMake build system, the build “rules” or “project settings” are defined in text files called CMakeLists.txt.

Visual Studio to CMake Mapping

Some common Visual Studio project operations and settings and its mapping to CMake is listed below as an overview.

Visual Studio CMake Command
Solution file (.sln) project
Project file (.vcproj) target name in the command add_executable or add_library
executable (.exe) add_executable
static library (.lib) add_library
dynamic library (.dll) add_library(SHARED)
Source Folders source_group
Project Folders set_property(TARGET PROPERTY FOLDER)
Properties->General->Output Directory set_target_properties(PROPERTIES RUNTIME_OUTPUT_DIRECTORY)
Properties->C/C++->Preprocessor->Preprocessor Definitions add_definitions
Properties->C/C++->General->Additional Include Directories include_directories
Properties->Linker->General->Additional Library Directories link_directories
Properties->Linker->Input->Additional Dependencies target_link_libraries

Example

The CMake tutorial from http://www.cmake.org/cmake/help/cmake_tutorial.html is a very simple example. Please refer to it if you are not familiar with the basics. Here it has been enhanced to show specific aspects commonly used on Windows.
 
The example code can be accessed via GitHub at https://github.com/cognitivewaves/CMake-VisualStudio-Example. For those not familiar with Git, GitHub has an option to download it as a zip file.

Source Structure

CMake-VisualStudio-Example
   |-- app
   |   |-- CMakeLists.txt
   |   |-- main.cxx
   |-- math
   |   |-- advanced
   |   |   |-- AdvancedFunctions.cxx
   |   |   |-- AdvancedFunctions.h
   |   |-- simple
   |   |   |-- SimpleFunctions.cxx
   |   |   |-- SimpleFunctions.h
   |   |-- CMakeLists.txt
   |   |-- MathExports.h
   |-- CMakeLists.txt
   |-- TutorialConfig.h.in

Execute CMake

As recommended earlier, for an out of source build, create a directory where CMake will produce the required Visual Studio Project files and a lot of CMake specific files.

D:\tmp\CMake-VisualStudio-Example> mkdir _build

Make the build directory the current working directory.

D:\tmp\CMake-VisualStudio-Example> cd _build

Run the CMake command and specify where to find the first(root) CMakeLists.txt. In this case ".." is used to indicate one directory up from the current working directory. The -G option specifies it to generate a Visual Studio 2010 Win64 project files.

D:\tmp\CMake-VisualStudio-Example\_build> cmake .. -G "Visual Studio 10 Win64"

Note that other Visual Studio (e.g. VS 2012, VS 2013, VS 2015) generators can be specified. Use cmake --help to see the full list.

Visual Studio 11 2012 = Generates Visual Studio 11 (VS 2012) project files
Visual Studio 12 2013 = Generates Visual Studio 12 (VS 2013) project files
Visual Studio 14 2015 = Generates Visual Studio 14 (VS 2015) project files

The Visual Studio solution file will be created in the _build directory.

Visual Studio Solution Explorer View

Open the solution file in Visual Studio.
cmake_vs_solution

Build and Debug

Build the solution in Visual Studio. By default, the output binary files (app.exe, math.dll) from the build are created under their own sub-directories in the _build directory. But you can set the RUNTIME_OUTPUT_DIRECTORY property to specify an output directory in Visual Studio. This will ensure that the executable can be launched from the debugger and will find all the dependent libraries.

⚠ Note that project ALL_BUILD is the default “Startup Project”. This is never the case for debugging. So right click on the executable project (app in this case) and select as “Startup Project” from the context menu.
CMake 3.6.3 has added a property VS_STARTUP_PROJECT to specify a startup project.

⚠ Since this example takes a command line argument, to run/debug it from Visual Studio, the properties on the executable project (app in this case), must be set.
Set Properties->Debugging->Command Arguments to 200

Install and Run

Install is a concept which comes from Linux (make install) and not very common in a Windows development environment. Basically, the build process will generate many artifacts but only a subset may be necessary for deployment. This is where install comes into play. The INSTALL project copies the binaries to the specified installation directory. So build INSTALL.vcproj explicitly, as it does not get built as part of the solution.

The executable can now be run in a command window from the installation directory.

D:\tmp\CMake-VisualStudio-Example\_install> app.exe 200
The sum of 200 and 200 is 400
The square root of 200 is 14.1421

Test

Invoking CTest from the build directory will run the tests. Alternatively, the tests can be run within the Visual Studio environment by right click “Build” on the RUN_TESTS project and the test run report will be displayed in the output window.

D:\tmp\CMake-VisualStudio-Example\_build>ctest
Test project D:/tmp/CMake-VisualStudio-Example/_build
    Start 1: AppTest1
1/3 Test #1: AppTest1 .........................   Passed    0.00 sec
    Start 2: AppTest2
2/3 Test #2: AppTest2 .........................   Passed    0.00 sec
    Start 3: AppTest3
3/3 Test #3: AppTest3 .........................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 3

Total Test time (real) =   0.03 sec

CMakeLists.txt Details

The comments in each line provides more details about each CMake command.

File: CMake-VisualStudio-Example/CMakelist.txt

cmake_minimum_required (VERSION 2.6)

# Maps to Visual Studio solution file (Tutorial.sln)
# The solution will have all targets (exe, lib, dll) 
# as Visual Studio projects (.vcproj)
project (Tutorial)

# Turn on the ability to create folders to organize projects (.vcproj)
# It creates "CMakePredefinedTargets" folder by default and adds CMake
# defined projects like INSTALL.vcproj and ZERO_CHECK.vcproj
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

# Set compiler flags and options. 
# Here it is setting the Visual Studio warning level to 4
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")

# Command to output information to the console
# Useful for displaying errors, warnings, and debugging
message ("cxx Flags:" ${CMAKE_CXX_FLAGS})

# Sub-directories where more CMakeLists.txt exist
add_subdirectory(app)
add_subdirectory (math)

# Turn on CMake testing capabilities
enable_testing()

# Add test cases
add_test(AppTest1 ${PROJECT_BINARY_DIR}/bin/app 100)
add_test(AppTest2 ${PROJECT_BINARY_DIR}/bin/app 200)
add_test(AppTest3 ${PROJECT_BINARY_DIR}/bin/app 300)

File: CMake-VisualStudio-Example/math/CMakeLists.txt

# Collect sources into the variable MATH_SOURCES without
# having to explicitly list each header and source file.
#
# CMake documentation states "We do not recommend using GLOB to collect a
# list of source files from your source tree. If no CMakeLists.txt file
# changes when a source is added or removed then the generated build system
# cannot know when to ask CMake to regenerate".
file (GLOB MATH_SOURCES
      "*.h")

# Collect sources into the variable SIMPLE_FUNCTION_SOURCES
file (GLOB SIMPLE_FUNCTION_SOURCES
      "simple/*.h"
      "simple/*.cxx")

# The recommended way to collect sources in variable 
# ADVANCED_FUNCTION_SOURCES by explicitly specifying the source files
set  (ADVANCED_FUNCTION_SOURCES
      "advanced/AdvancedFunctions.h"
      "advanced/AdvancedFunctions.cxx")

# Create named folders for the sources within the .vcproj
# Empty name lists them directly under the .vcproj
source_group("" FILES ${MATH_SOURCES})
source_group("simple" FILES ${SIMPLE_FUNCTION_SOURCES})
source_group("advanced" FILES ${ADVANCED_FUNCTION_SOURCES})

# Properties->C/C++->General->Additional Include Directories
include_directories (.)

# Set Properties->General->Configuration Type to Dynamic Library(.dll)
# Creates math.dll with the listed sources collected in the variables
# Also adds sources to the Solution Explorer
add_library(math SHARED ${MATH_SOURCES} 
                        ${SIMPLE_FUNCTION_SOURCES} 
                        ${ADVANCED_FUNCTION_SOURCES})

# Creates folder "libraries" and adds target project (math.vcproj)
set_property(TARGET math PROPERTY FOLDER "libraries")

# Properties->General->Output Directory
set_target_properties(math PROPERTIES
                      RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)

# Adds logic to INSTALL.vcproj to copy math.dll to the destination directory
install (TARGETS math
         RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/_install
         LIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/_install)

File: CMake-VisualStudio-Example/app/CMakeLists.txt

# Properties->C/C++->General->Additional Include Directories
include_directories ("${PROJECT_SOURCE_DIR}/Math")

# Set Properties->General->Configuration Type to Application(.exe)
# Creates app.exe with the listed sources (main.cxx)
# Adds sources to the Solution Explorer
add_executable (app main.cxx)

# Properties->Linker->Input->Additional Dependencies
target_link_libraries (app math)

# Creates a folder "executables" and adds target 
# project (app.vcproj) under it
set_property(TARGET app PROPERTY FOLDER "executables")

# Properties->General->Output Directory
set_target_properties(app PROPERTIES
                      RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)

# Adds logic to INSTALL.vcproj to copy app.exe to destination directory
install (TARGETS app
         RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/_install)

CMake pre-defined projects

To add some CMake functionality to the Visual Studio environment, it creates a few project files which can be ignored for the most part. In any case, a brief description is given below.

INSTALL CMake install specification. It is simulating the Linux make install so it has to be manually built after the full build.
RUN_TESTS CMake test specification. This project will enable running tests in Visual Studio and the test run report will be shown in the output window
ZERO_CHECK Used to make sure that the project files are up-to-date with respect to the CMakeLists.txt files
ALL_BUILD Builds all projects with its dependency order

Debug and Release Configurations

Visual Studio supports multiple configurations in a single project file and creates a per-configuration directory. CMake generates four configurations by default: Debug, Release, MinSizeRel and RelWithDebInfo.

See the link for changing the default.
CMake Wiki: How can I specify my own configurations (for generators that allow it) ?

Conclusion

CMake is a better build system than Visual Studio projects and solutions. It is compact and much more easier to maintain even for a Windows only projects. Microsoft now claims direct CMake support in Visual Studio 2017 (though I have not experimented with it).

Hope the the document is useful. Feel free to comment if you need any clarifications or further information.

Advertisements

34 comments

  1. Thanks a lot.
    As a beginner of cmake learning, I found the learning material is rare. Could you recommend me what material and procedure is helpful to learn cmake?
    Thank you in advance!

  2. I’ve been struggling with the cmake basics with VS10 for over a day now. Your tutorial finally got me out of the ditch I was stuck in. Thank you so much! Your one line *Note that project ALL_BUILD is the default “Startup Project”. This is never the case for debugging. So right click on the executable project (app in this case) and select as “Startup Project” finally put it all together. I never thought to check the startup project. ARGH!!!!
    Keep up the great info please!

    1. Glad it helped. I had spent days to figure out the “Startup Project”, so that is why I added the note. Based on your feedback, I have made that information a little more visible (rather than a minor side note). Further, CMake 3.6.3 has added a property VS_STARTUP_PROJECT to specify a startup project.

  3. In Windows is there an equivalent command to the ‘make install DESTDIR=’ function that cmake provides on linux? I’m wondering about how to package and deploy my dll and exe files that are built in in the solution using cmake.

    1. If you have INSTALL command in your CMake file, it will generate INSTALL.vcxproj in the build folder which will have install instructions. For valid reasons, INSTALL.vcxproj is excluded when building the solution by Visual Studio.
      To emulate Linux make install you could create a Windows batch file to first build the solution and then build the INSTALL project.

      devenv /Build Debug INSTALL.vcxproj
      devenv.exe Tutorial.sln /Build Debug /Project INSTALL
      
    2. Hi there,

      yes there is an equivalent cmake command for this:

      cmake -DCMAKE_INSTALL_PREFIX={install_path}

      Also as a sidenote, if you want to build and install in one command regardless of the cmake generator, use the following:

      cmake --build . --target install --config Release

      This must be run in the build directory. Also the option –config Release only makes sense for IDE style generators (Visual Studio, XCode etc), but it doesn’t hurt even when using make style generators. To get make generators to do the same (release build) use -DCMAKE_BUILD_TYPE=Release

      1. Good suggestion.
        Please do keep in mind the following.

        “If a full path (with a leading slash or drive letter) is given it is used directly. If a relative path is given it is interpreted relative to the value of CMAKE_INSTALL_PREFIX”

        Note that the example in the post uses absolute path for the install destination.

  4. 2 corrections:

    1. Your example for
    cmake ..\.. -DCMAKE_BUILD_TYPE=Release -G “Visual Studio 10 Win64”
    is very misleading. The VS generators ignore DCMAKE_BUILD_TYPE, as it builds a solution that includes both debug and release configurations. Thus, the command-line string you give, should never be used.

    2. File GLOBbing should not be used, it’s bad practice. Please don’t give this bad example.

    1. Thanks for the feedback.

      1. You are right, -DCMAKE_BUILD_TYPE is valid only for single configuration systems and has been corrected.
      CMake wiki: How can I build multiple modes without switching ?

      2. I have noted the caveat with GLOBbing as per the CMake documentation.

      “We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate”

      However, it is still useful as long as you know the limitation and often allows you to jump start in using/migrating the CMake system.

  5. Thanks for the tutorial. I went through it and got “The program can’t start because math.dll is missing from your computer. Try reinstalling the program to fix this problem.”

    My cmake_test directory contains:
    1. app directory
    2. build directory
    3. math directory
    4. CMakeLists.txt
    5. README.md
    6. TutorialConfig.h.i.n

    Any ideas on how to resolve this problem?

  6. Hi,

    Excuse me if the topic is not appropriate for this group (I do not find any
    other forum for this question yet). We have an old PC which was installed a
    MSVC project. This project was generated from a Cmake file suite. The project
    can be built well on this computer. Now, I have a new PC and want to run this
    project too. First of all, I install Cmake to this new PC. Then, I copy all
    the MSVC project from the old PC to this new PC. there are three Cmake folder in the MSVC
    project:

    INSTALL
    RUN_TESTS
    ZERO_CHECK

    MSVC building has these errors:

    1>—— Build started: Project: ZERO_CHECK, Configuration: Debug Win32 —-
    2>—— Skipped Build: Project: RUN_TESTS, Configuration: Debug Win32 —-
    2>Project not selected to build for this solution configuration
    1>C:\Program Files(x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms
    \Win32\Microsoft.Cpp.Win32.Targets(518,5):
    error MSB8008: Specified platform toolset (v110) is not installed or invalid.
    Please make sure that a supported PlatformToolset value is selected.
    3>—— Build started: Project: wws-lxc, Configuration: Debug Win32 —
    4>—— Build started: Project: wws-lxd2, Configuration: Debug Win32 —
    5>—— Build started: Project: wws-lxdd, Configuration: Debug Win32 —-

    I have read a few Cmake tutorials, but it does not help yet. Because I am in
    a hurry to make it work. Could you help me on these questions?

    1. Whether it is possible to copy a Cmake generated MSVC 10.0 project from a
    computer to another computer?
    2. If some manual modifications are needed, what should I do to make it work?

    Thanks in advance,

    1. This is probably not the best forum for this question but will try to help.

      Generally, it’s not a good idea to copy the vcproj files. You should instead regenerate the project using CMake. Do you have the original CMake files (CMakeLists.txt) in the source? If so, you should be able to regenerate the project files for the new machine.

      If at all you want to reuse a vcproj files there may be a number of things that needs to be changed. First, do you have the same compiler installed on the new machine as the old one?

  7. “To run/debug it from Visual Studio, the Properties->Debugging->Command default must be changed to the executable in the _install directory.”
    Could you please clarify this ?
    do you mean the executable (in this case is app), right click on app-> property->Debugging->Command ..change to folder INSTALL ? (which file in the folder INSTALL ? )

  8. Thanks for such a very well structured explanation, I have been using cmake on linux and Mac over few years but there are few things in your tutorial I was unfamiliar. Moreover just switching to windows for cross platform development I was looking for a quick sneak in VS and CMAKE and you have done a great job. Keep up with good work.

  9. Hi,

    I’m configurating Cmake 3.4.3 with Visual Studio C++ 2010 Express, but Cmake has an error:

    CMake Error at cmake/Modules/Geant4MacroLibraryTargets.cmake:69 (target_compile_features):
    The compiler feature “cxx_alias_templates” is not known to CXX compiler

    “MSVC”

    version 16.0.30319.1.
    Call Stack (most recent call first):
    cmake/Modules/Geant4MacroLibraryTargets.cmake:300 (GEANT4_LIBRARY_TARGET)
    source/analysis/CMakeLists.txt:30 (GEANT4_GLOBAL_LIBRARY_TARGET)

    CMake Error at cmake/Modules/Geant4MacroLibraryTargets.cmake:94 (target_compile_features):
    The compiler feature “cxx_alias_templates” is not known to CXX compiler

    “MSVC”

    Configuring download of missing dataset G4NDL (4.5)
    Configuring download of missing dataset G4EMLOW (6.48)
    Configuring download of missing dataset PhotonEvaporation (3.2)
    Configuring download of missing dataset RadioactiveDecay (4.3)
    Configuring download of missing dataset G4NEUTRONXS (1.4)
    Configuring download of missing dataset G4PII (1.3)
    Configuring download of missing dataset RealSurface (1.0)
    Configuring download of missing dataset G4SAIDDATA (1.1)
    Configuring download of missing dataset G4ABLA (3.0)
    Configuring download of missing dataset G4ENSDFSTATE (1.2)
    CMake Warning at C:/Program Files/CMake/share/cmake-3.4/Modules/InstallRequiredSystemLibraries.cmake:440 (message):
    system runtime library file does not exist:
    ‘MSVC10_REDIST_DIR-NOTFOUND/x86/Microsoft.VC100.CRT/msvcp100.dll’
    Call Stack (most recent call first):
    cmake/Modules/Geant4CPackBase.cmake:9 (include)
    CMakeLists.txt:147 (include)

    The following Geant4 features are enabled:
    GEANT4_BUILD_CXXSTD: Compiling against C++ Standard ’11’

    Configuring incomplete, errors occurred!
    See also “E:/GEANT4/geant4_10_02_build/CMakeFiles/CMakeOutput.log”.
    See also “E:/GEANT4/geant4_10_02_build/CMakeFiles/CMakeError.log”.

    Any ideas on how to resolve this problem?
    Thanks so much!

    1. You may already be aware that VS Express is a “basic” version of the full professional environment. My guess is that some expected compiler features are not supported in VS Express. Having said that, this question is more appropriate in a forum like StackOverflow where you may get a more definitive answer.

    1. Visual Studio can have a user settings file vcxproj.user which can define these properties.

      In the CMakeLists.txt, copy this predefined vcxproj.user to the build directory using CONFIGURE_FILE command.

  10. Cmake with Visual Studio seems to work fine . But does Cmake work the same with CodeBlocks on Windows system? If yes can I know what is the Cmake generator for Codeblocks on windows

  11. Hi;

    Thanks for the tutorial.
    I trid it under linux with cmake version 3.5.1.
    Solely thing I found was:

    # Add test cases
    if(NOT UNIX)
    add_test(AppTest1 ${PROJECT_BINARY_DIR}/bin/app.exe 100)
    add_test(AppTest2 ${PROJECT_BINARY_DIR}/bin/app.exe 200)
    add_test(AppTest3 ${PROJECT_BINARY_DIR}/bin/app.exe 300)
    else(NOT UNIX)
    # Linux:
    add_test(AppTest1 ${PROJECT_BINARY_DIR}/app/app 100)
    add_test(AppTest2 ${PROJECT_BINARY_DIR}/app/app 200)
    add_test(AppTest3 ${PROJECT_BINARY_DIR}/app/app 300)
    endif(NOT UNIX)

    1. That’s a good observation. It is now fixed (specify the CMake target name rather than the output executable).
      CMake automatically takes care of many differences between Windows and Linux, this being one such example.

      But do keep in mind that every now and then, differences (some quite subtle) have to be managed between Windows and Linux.
      For such conditional statements, you could use if (NOT UNIX) or if (WIN32).

  12. Hi, thanks for a great Tutorial!

    I’ve found the following little tweak useful:

    Instead of `Set Properties->Debugging->Command to ..\bin\app.exe`

    I leave this as VS (2015 in my case) has set it, i.e. $(TargetPath)

    And instead setting I’m setting `Set Properties->Debugging->Environment` to `PATH=%PATH%;..\math\$(Configuration)`

    This will not require building `INSTALL` (i.e. it’s slightly faster to deploy the solution for debugging which is my most common operation), but most importantly IMO: `Clean Solution`will not remove the files under \bin.

    What do you think? Any serious drawbacks besides having to multiplying the method for each library if more than one exist?

    Or it it’s a bad tweak, how to fix so that `Clean Solution` also removes the files under \bin?

    1. Thanks for your feedback.
      There is a more Visual Studio centric approach to this, by using the RUNTIME_OUTPUT_DIRECTORY property. I have updated the post in the “Build and Debug” and “Install and Run” sections. Hope it resolves your issues.

  13. Using cmake v3,7,2 I got a warning in math/CMakeLists.txt at line 8/col19 due to the “,” separating the 2 files.Removing the “,” the warning goes away.

  14. Regrading my previous comment I see edits to the github .txt files that have not been updated in this article. However, when I run the app from Windows Explorer …\\Tutorial\build\bin it runs but if I run it from VS then it complains that math.dll is missing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s