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.

Out of source builds
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

Out of source builds

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 like .sbr, .suo, .vcxproj.filters, .db etc. 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 (.vcxproj) and the solution file (.sln) as a “source” since it involves adding/removing source files, modifying library dependencies, setting build 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.

To clean or reset your build environment, you would simply delete the out of source build directory.

Visual Studio to CMake Mapping

In a CMake build system, the build “rules” or “project settings” are defined in text files called CMakeLists.txt.
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 tutorial from CMake 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) 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 CMake FAQ: How can I specify my own configurations (for generators that allow it)? for changing the default.

Conclusion

CMake is a better build system than Visual Studio projects and solutions. It is compact and much more easier to maintain even for Windows only projects. See CMake for Visual Studio Developers for some reasons.

Microsoft now claims direct CMake support in Visual Studio, but a cursory look at it seems more like an obfuscation of the CMake philosophy to make you dependent on Microsoft.

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


39 thoughts on “CMake and Visual Studio

  1. yuan xu

    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!

    Reply
  2. Pingback: Using CMake | Some Things Are Obvious

  3. Tovah Whitesell

    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!

    Reply
    1. cognitivewaves Post author

      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.

      Reply
  4. Kyle

    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.

    Reply
    1. cognitivewaves Post author

      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
      
      Reply
    2. Kostas

      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

      Reply
      1. cognitivewaves Post author

        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.

  5. Danny

    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.

    Reply
    1. cognitivewaves Post author

      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.

      Reply
  6. engineer24

    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?

    Reply
  7. cognitivewaves Post author

    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?

    Reply
  8. Pingback: windows 8.1下编译alembic 1.5.8 Visual Studio 2012各种错误备忘录 | 一半君的回忆

  9. Hung Dau Do

    “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 ? )

    Reply
  10. Saif

    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.

    Reply
  11. cognitivewaves Post author

    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.

    Reply
  12. Pingback: Visual Studio to CMake Mapping | Vic's World

    1. Cognitive Waves Post author

      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.

      Reply
  13. Sandeep S

    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

    Reply
  14. Mark

    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)

    Reply
    1. Cognitive Waves Post author

      That’s a good observation. It is now fixed (specify the CMake target name rather than the output executable name).
      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).

      Reply
  15. ambrmi09

    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?

    Reply
    1. Cognitive Waves Post author

      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.

      Reply
  16. graham

    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.

    Reply
  17. graham

    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.

    Reply
  18. Pingback: Apache Thrift on Windows | Cognitive Waves

  19. Pingback: Linking additional dependencies and library directories to static library project with CMake [duplicate] – Windows Questions

  20. akisud

    Hi,
    I need to edit the librarian settings in vs 2010 using cmake (especially the additional dependencies and additional library directories). Is there any way to do it???

    Reply
    1. Cognitive Waves Post author

      target_link_libraries for additional dependencies and link_directories for additional library directories should work for a static library. Make sure that the STATIC in add_library(<name> STATIC) is specified.

      Reply
  21. David

    Hi,
    First of all, thank you for taking the time to write this very useful tutorial.
    Unfortunately, after following the steps outlined in your tutorial, I’ve found a problem. Everything seems to work fine when I build the solution using CMake from the command line. However, when I open the solution file (Tutorial.sln) using Visual Studio 2019, the “Output” panel shows the following error messages:

    D:\Documentos\Cpp\CMakeExample\CMake-VisualStudio-Example\_build\ALL_BUILD.vcxproj : error : The application for the project is not installed.
    D:\Documentos\Cpp\CMakeExample\CMake-VisualStudio-Example\_build\INSTALL.vcxproj : error : The application for the project is not installed.
    D:\Documentos\Cpp\CMakeExample\CMake-VisualStudio-Example\_build\RUN_TESTS.vcxproj : error : The application for the project is not installed.
    D:\Documentos\Cpp\CMakeExample\CMake-VisualStudio-Example\_build\ZERO_CHECK.vcxproj : error : The application for the project is not installed.
    D:\Documentos\Cpp\CMakeExample\CMake-VisualStudio-Example\_build\app\app.vcxproj : error : The application for the project is not installed.
    D:\Documentos\Cpp\CMakeExample\CMake-VisualStudio-Example\_build\math\math.vcxproj : error : The application for the project is not installed.

    Also, the “Solution Explorer” inside Visual Studio shows that Solution “Tutorial” has “0 of 6 projects”.
    I would really appreciate it if you could give me some guidance on how to solve this issue.
    Thank you.

    Reply
    1. Cognitive Waves Post author

      I am not able to reproduce the issue you are seeing.

      “Everything seems to work fine when I build the solution using CMake from the command line.”
      I’m assuming you mean generate the project/solution and not actually build the solution.

      Note that the CMake command to generate the VS solution has changed slightly for VS2019.
      cmake .. -G "Visual Studio 16 2019" -A x64

      Reply

Leave a reply to Cognitive Waves Cancel reply