Cmake Visual Studio Code



This is a quick video to show how to quickly get a CMake project configured, built, executed, and debugged in VS Code. Visual Studio Code has become a very popular code editor. You may be using it for development tasks already, but perhaps not yet for embedded development work. Or perhaps you are using it for embedded development work as you prefer the editing environment over your existing embedded development tools, but you haven’t been able to. Visual Studio uses a configuration file called CMakeSettings.json. This file lets you define and store multiple build configurations, and conveniently switch between them in the IDE. A configuration is a Visual Studio construct that encapsulates settings that are specific to a given build type. The settings are used to configure the default command-line options that Visual Studio passes to cmake.exe. CMake tools includes a bundled vswhere.exe which it uses to ask about existing Visual Studio instances installed on the system. For each of x86, amd64, x86amd64, x86arm, x86arm64, amd64x86, amd64arm, and amd64arm64, CMake Tools will check // for installed Visual C environments. // A kit is generated for each existing MSVC toolchain. CMake Tools for Visual Studio Code — CMake Tools 1.4.0 documentation CMake Tools for Visual Studio Code ¶ CMake Tools is an extension designed to make working with CMake-based projects as easy as possible. If you are new, check the Getting Started docs.

-->

In Visual Studio 2019 and later, you can add configurations and customize their settings by using the CMake settings editor. The editor is intended to be a simpler alternative to manually editing the CMakeSettings.json file, but if you prefer to edit the file directly, you can click the Edit JSON link in the upper right of the editor.

To open the editor, click on the Configuration drop-down in the main toolbar and choose Manage Configurations.

Now you see the Settings Editor with the installed configurations on the left.

Visual Studio provides one x64-Debug configuration by default. You can add additional configurations by clicking the green plus sign. The settings that you see in the editor might vary depending on which configuration is selected.

The options that you choose in the editor are written to a file called CMakeSettings.json. This file provides command-line arguments and environment variables that are passed to CMake when you build the projects. Visual Studio never modifies CMakeLists.txt automatically; by using CMakeSettings.json you can customize the build through Visual Studio while leaving the CMake project files untouched so that others on your team can consume them with whatever tools they're using.

CMake General Settings

The following settings are available under the General heading:

Configuration name

Corresponds to the name setting. This name appears in the C++ configuration dropdown. You can use the ${name} macro to compose other property values such as paths.

Configuration type

Corresponds to the configurationType setting. Defines the build configuration type for the selected generator. Currently supported values are 'Debug', 'MinSizeRel', 'Release', and 'RelWithDebInfo'. It maps to CMAKE_BUILD_TYPE.

Toolset

Corresponds to the inheritedEnvironments setting. Defines the compiler environment that's used to build the selected configuration. Supported values depend on the type of configuration. To create a custom environment, choose the Edit JSON link in the upper right corner of the Settings editor, and edit the CMakeSettings.json file directly.

CMake toolchain file

Path to the CMake toolchain file. This path is passed to CMake as '-DCMAKE_TOOLCHAIN_FILE = <filepath>'. Toolchain files specify locations of compilers and toolchain utilities, and other target platform and compiler related information. By default, Visual Studio uses the vcpkg toolchain file if this setting is unspecified.

Build root

Corresponds to buildRoot. Maps to CMAKE_BINARY_DIR, and specifies where to create the CMake cache. The specified folder is created if it doesn't exist.

Command arguments

The following settings are available under the Command arguments heading:

CMake command arguments

Corresponds to cmakeCommandArgs. Specifies any additional command line options passed to CMake.exe.

Build command arguments

Corresponds to buildCommandArgs. Specifies additional switches to pass to the underlying build system. For example, passing -v when using the Ninja generator forces Ninja to output command lines.

CTest command arguments

Corresponds to ctestCommandArgs. Specifies additional command line options to pass to CTest when running tests.

General settings for remote builds

For configurations such as Linux that use remote builds, the following settings are also available:

rsync command arguments

Additional command line options passed to rsync, a fast and versatile file-copying tool.

CMake variables and cache

These settings enable you to set CMake variables and save them in CMakeSettings.json. They're passed to CMake at build time, and override whatever values are in the CMakeLists.txt file. You can use this section in the same way that you might use the CMakeGUI to view a list of all the CMake variables available to edit. Click the Save and generate cache button to view a list of all CMake variables available to edit, including advanced variables (per the CMakeGUI). You can filter the list by variable name.

Corresponds to variables. Contains a name-value pair of CMake variables passed as -Dname=value to CMake. If your CMake project build instructions specify the addition of any variables directly to the CMake cache file, we recommend you add them here instead.

Advanced settings

CMake generator

Corresponds to generator. Maps to the CMake -G switch, and specifies the CMake generator to use. This property can also be used as a macro, ${generator}, when composing other property values. Visual Studio currently supports the following CMake generators:

  • 'Ninja'
  • 'Unix Makefiles'
  • 'Visual Studio 16 2019'
  • 'Visual Studio 16 2019 Win64'
  • 'Visual Studio 16 2019 ARM'
  • 'Visual Studio 15 2017'
  • 'Visual Studio 15 2017 Win64'
  • 'Visual Studio 15 2017 ARM'
  • 'Visual Studio 14 2015'
  • 'Visual Studio 14 2015 Win64'
  • 'Visual Studio 14 2015 ARM'

Because Ninja is designed for fast build speeds instead of flexibility and function, it's set as the default. However, some CMake projects may be unable to correctly build using Ninja. If that occurs, you can instruct CMake to generate a Visual Studio project instead.

IntelliSense mode

The IntelliSense mode used by the IntelliSense engine. If no mode is selected then Visual Studio will inherit from the specified toolset.

Install directory

The directory in which CMake installs targets. Maps to CMAKE_INSTALL_PREFIX.

CMake executable

The full path to the CMake program executable, including the file name and extension. It allows you to use a custom version of CMake with Visual Studio. For remote builds, specify the CMake location on the remote machine.

For configurations such as Linux that use remote builds, the following settings are also available:

Remote CMakeLists.txt root

The directory on the remote machine that contains the root CMakeLists.txt file.

Remote install root

The directory on the remote machine in which CMake installs targets. Maps to CMAKE_INSTALL_PREFIX.

Remote copy sources

Specifies whether to copy source files to the remote machine, and lets you specify whether to use rsync or sftp.

Directly edit CMakeSettings.json

You can also directly edit CMakeSettings.json to create custom configurations. The Settings Editor has an Edit JSON button in the upper right that opens the file for editing.

Make Raining Images In Visual Studio Code

The following example shows a sample configuration, which you can use as a starting point:

JSON IntelliSense helps you edit the CMakeSettings.json file:

The JSON editor also informs you when you choose incompatible settings.

For more information about each of the properties in the file, see CMakeSettings.json schema reference.

Visual Studio 2017 provides several CMake configurations that define how CMake.exe is invoked to create the CMake cache for a given project. To add a new configuration, click the configuration drop-down in the toolbar and choose Manage Configurations:

You can choose from the list of predefined configurations:

The first time you select a configuration, Visual Studio creates a CMakeSettings.json file in your project's root folder. This file is used to re-create the CMake cache file, for example after a Clean operation.

To add an additional configuration, right click CMakeSettings.json and choose Add Configuration.

You can also edit the file using the CMake Settings Editor. Right-click on CMakeSettings.json in Solution Explorer and choose Edit CMake Settings. Or, select Manage Configurations from the configuration drop-down at the top of the editor window.

You can also directly edit CMakeSettings.json to create custom configurations. The following example shows a sample configuration, which you can use as a starting point:

JSON IntelliSense helps you edit the CMakeSettings.json file:

For more information about each of the properties in the file, see CMakeSettings.json schema reference.

See also

CMake Projects in Visual Studio
Configure a Linux CMake project
Connect to your remote Linux computer
Configure CMake debugging sessions
Deploy, run, and debug your Linux project
CMake predefined configuration reference

For quite some time now I’ve been working inside teams who wereusing Visual Studio to build complex C++ projects.

Because I’ve often been the “buildfarm guy” and because I don’t like GUIsthat much, I had to find ways to build Visual Studio projects from the commandline.

This is the story of everything I’ve tried.

Quick note before we begin: throughout this article, I will be using VisualStudio 2015 on Windows 10 to build the source code of CMake itself. If’s a niceproject for a case study, since it’s neither too big nor too small, and has nodependencies to worry about (and of course, it uses CMake to build itself :)

Using CMake to generate Visual Studio projects #

CMake works by parsing code in CMakeLists.txt files, and then generatingcode that will be used by an other program that would perform the builditself.

When you use CMake, you must specify a generator.On Windows, the default generator will be the most recent Visual Studio found,and after running CMake, you’ll get a .sln file you can open in VisualStudio to edit, build, and debug the project.

So my task was to find a way to build those .sln files from the command line.

Using devenv #

The most obvious way I found was to use a tool called devenv. In fact, that’sthe probably the answer you’ll find if you look up “Building Visual Studioprojects from the command line” on an internet search engine. You’ll also findplaces where they suggest you use MSBuild.exe.

But, bad luck, if you try to run devenv directly from cmd.exe, you’ll get thefamous error message:

The trick is to use one of the “Command Prompt” you’ll find in the start menu:

I started with the “Developer Command Prompt”:

Cmake visual studio code debug

Visual Studio Code Cmake Windows

Visual Studio opened. Hum, that’s not what I wanted. Turns out, if you makeany mistake in the command line prompt, Visual Studio will open.

The correct way is to add the /build switch:

The output is quite nice:

Using MSBuild #

You can also try using MSBuild.exe, but the output is a bit uglier.(But you get more info, such as the time it took to compile a project, the fullcommand line used, and the number of warnings/errors):

Using CMake to build #

OK, so now I knew how to build Visual Studio projects from command line.

We had a pretty big C++ code base, that we wanted to build on Linux, macOS and Windows.

We were using Jenkins to do continuous integration, so we had to writebuild scripts that would run on the nodes as soon as any developer would make amerge request to make sure the proposed changes will build on all platforms.

On Linux and macOS, the default generator is “Unix Makefiles”, so the code wasstraightforward:

On Windows, we used Batch files:

You may wonder where the weird @call '%VS140COMNTOOLS%VsDevCmd.bat' line comes from.

First, if you go to C:ProgramDataMicrosoftWindowsStart MenuProgramsVisual Studio 2015Visual Studio Tools, you can right-click on the “Developer CommandPrompt” shortcut and open the “Properties” window. There you’ll find that thetarget is:cmd.exe /k 'C:Program Files (x86)Microsoft Visual Studio 14.0Common7ToolsVsDevCmd.bat'

Second, if you are lucky, someone1 will tell you that with any version of VisualStudio, an environment variable called VS<version>COMNTOOLS is set, where<version> is the 2 or 3 digits version number of your Visual Studio install.

Here is a table if you don’t know what I mean: T?i matlab 2018a full crack.

Thus, you can avoid hard-coding the Visual Studio installation path, and use theVS140COMNTOOLS Naruto all episodes in hindi dubbed watch. variable instead. (You still need to hard-code Visual Studioversion, though).

So what the command does is concatenate the value of the VS140COMNTOOLSenvironment variable with the basename of the prompt file (VsDevCmd.bat), and run@call on it.

Using Python #

But, as time went by, we wanted to rewrite all the build scripts in Python,so that we could factorize some of the code.(For instance, running git pull to update the sources before building)

On Linux and macOS it was easy:

But on Windows, things were a bit trickier. How were we going to implementthe @call pathtobat_file in Python?

setuptools to the rescue! #

I discovered that setuptools – the module used by Python to run the setup.pyfiles – was able to build things with Visual Studio, without having to use theVisual Studio command prompts.

So I looked at the implementation, and found a solution:

The idea is to run a batch script (that’s why we are using shell=True) that will:

Visual
  • Call the .bat file we need
  • Run the built-in set command and parse its output
  • Returns the whole environment in a Python dict.

Indeed, there are several ways to use set on cmd.exe:

  • To set an environment variable: set FOO=BAR
  • To unset an environment variable: set FOO=
  • To see all the environment variable whose name start with prefix: set <prefix>
  • To dump all the environment variables: set

We parse the output of set to find the three variables we need (they areall lists of semi-colon separated paths)

  • PATH: to find the required executables (the devenv command)
  • LIB: where the compiler will look for .lib files
  • INCLUDE: where the compiler will look for headers files.

By the way, if you are wondering why the function is called source_bat, it’sbecause on Unix, to execute a bash script and have your environment updated, youneed to use the source built-in, or, on some other shells, the . command,(but I digress).

Building the .sln file #

There was an other problem, though. On Linux and macOS, the command to build isalways make. Gta vice city pc game installation overview.

But on Windows, I had to carefully craft the devenv command, and this meantspecifying the path to the .sln file.

At first, I only had a few bad solutions:

  • Hard-code the name of the .sln file
  • Parse the top CMakeLists to find the project() call2
  • List the contents of the build directory, and hope they’ll will be only onefile with the .sln extension.

Luckily, by running cmake --help I discovered there was --build switch Icould use to abstract the command line to run for the project to be built.

So the code looked like:

This meant I could run cmake --build anywhere, without having to deal withthose nasty .bat files.

Using multiple CPUs at once #

By default, Visual Studio projects get built using all the CPU resources, butit’s not the case for the make command.

So the code had to be patched again to have make use all available CPUS:

(The -- argument is here to separate arguments parsed by cmake binary fromthe one sent to the underlying build command. It’s a common practice for command-line tools)

Performance issues #

So we had our Jenkins nodes running Python scripts to build the same source codeon Linux, macOS, and Windows, and everything was fine, except that the buildswould take much longer on Windows.

At first I thought, “Well,it’s a known fact that running executables andaccessing the file system will always be slower on Windows, andthere’s nothing we can do about it”.

But members of my team kept complaining about the long build times, and I wasnot feeling good about it: as someone said once, “When doing continuousintegration, computers should be waiting for humans, and not the other wayaround”.

So, I looked for solutions to improve performance.

Using NMake #

If you look at the size of the files generated by CMake when using VisualStudio, you realize it will not be easy to have good performance.

For instance, to build CMake you have a .sln file with 842 lines, whichreferences 115 .vcxproj files.

Looking at the contents of the files, it’s no wonder parsing them takesquite some time.

Also, if you look at CPU usage during build, you can see you are far from usingall the CPU power:

So I tried to find a CMake generator that would generate simpler code.

During my research, I found out that Microsoft had their own implementation ofthe Make program called NMake, so I decided to use the NMake Makefilegenerator.

This time I’ll be using cl.exe, link.exe and their friends directly.

I tried using the MSBuild command prompt, but I got:

Here, CMake cannot find cl.exe because it’s not in the %PATH%.And indeed, if you try to run cl.exe from the MSBuild Command Prompt, you’ll getthe same “cl.exe is not recognized …” error.

So I tried using the ‘Developer Command Prompt' I already used before back whenI was runnig devenv by hand:

Huzzah, the compiler is found!

You may notice that the path to cl.exe is just VCbincl.exe. (There areother folders in VCbin, but here we are using the default, 32 bits version)

Also, I was pleased to find out that only 30 or so Makefiles files were generated.

So the next step was:

I was quite happy to see the I got the same nice output (with thepercentage of progress) as on Linux and macOS.

But then I discovered that only one CPU was used during compilation.

And running nmake /? gave nothing being able to run multiple jobs in parallel.

Frack!

Vs Code C++ Cmake

Using JOM #

Looking at cmake --help output again I discovered there was yet another generatorcalled “NMake Makefiles JOM”

Jom is a tool made by Qt folks. It’s are-implementation of the nmake command, but with support for multiple jobs.The command line switch to build with multiple CPU is also called -j, which isnice because it meant the build script code would get simpler.

That gave quite some good results, but the build was still slower than on Linuxand macOS.

Run Cmake In Visual Studio Code

In order to investigate, I decided to keep the Windows resource monitor openedduring a build with JOM:

You can see there’s a drop in CPU usage during build. From what I understand,it happens during linking.

Using Ninja #

Finally, circa 2010, Ninja came out.

As soon as I read the description of the project: “a small build system with afocus on speed”, and the fact there was an experimental support for it inCMake, I was dying to try it out.

And it fact, it gave great results! For the first time in years, I finally hadthe same build times on Windows than on Linux, and the CPU usage was a nicesteady line around 100% for all cores:

I also got the terse output that gave Ninja its name. 3

A story of cross-compiling #

After several years of using the CMake + Ninja combination, I gotan error message during one of our CI builds:

Googling the error lead to:https://support.microsoft.com/en-us/help/2891057/linker-fatal-error-lnk1102-out-of-memory

So I tried to follow the advice in the “Resolution” section and took a closer look atthe list of command line prompts in the start menu:

Below the two prompts on top I already tried, there was a few entries, all ofthem shortcuts to the same .bat file, but with different arguments:

Aha! So, all I have to do was to call the vcvarsall.bat file with the correct arguments, which wasconfirmed when I took a look at the contents of the .bat file:

So the Python code was patched again:

And CMake output was:

Notice the amd64_x86 subfolder.

Code signing breakage #

Everything was OK for a while, until we decided we wanted to sign the executables before shipping them.

It seemed the most obvious way was to use signtool.exe, so I proceeded toinstall the Windows Driver Kit,as instructed on the Windows Dev Center4

But then all our builds started failing with:

I looked for a solution but all I got was people telling me to set INCLUDE and LIB by hand.

Well, I already had Python code computing the environment variables, so the fix was:

Note how we have x64 instead of amd64 here :)

Conclusion #

Well, that’s all I’ve got for today.

Building Visual Studio projects with CMake and Ninja works quite well if youhave build scripts in Python, providing you are willing to run .bat scripts,and carefully apply changes to the environment variables.

Soon I’ll try and see how things go with Visual Studio 2017, maybe things willget easier, who knows?

Until then, may the Build be with you!

Update: I’ve decided to cross-post this article ondev.to.Let’s see how it goes!

  1. David, if you read this, thank you so much! ↩︎

  2. More info in the CMake documentation↩︎

  3. It’s just one line of output that disappears quickly after the build is done, do you get it? ↩︎

  4. Turned out I somehow missed this page telling me signtool.exe was already installed when I set up Visual Studio on the node … ↩︎

Thanks for reading this far :)

I'd love to hear what you have to say, so please feel free to leave a comment below, or read the contact page for more ways to get in touch with me.

Note that to get notified when new articles are published, you can either:

  • Subscribe to the RSS feed or the newsletter
  • Or follow me on Mastodon, dev.to, or twitter.

Cheers!





Comments are closed.