In Visual Studio 2017 15.4 you can now target Linux from your CMake projects. This enables you to work on your existing code base that uses CMake as your build solution without having to convert it to a VS project. If your code base is cross-platform you can target both Windows and Linux from within Visual Studio.
This post will give an overview of the CMake support for Linux in Visual Studio. You can go here to learn more about CMake in Visual Studio generally.
Update 10/24/2017: 15.4.1 is in the Release channel now and addresses the setup issue previously noted here. 15.5 is in the Preview channel and removes the limitation on CMake 3.9, there CMake >= 3.8 can be used.
Getting Started
To enable this capability, make sure that you choose the Linux C++ Workload in the Visual Studio installer. The CMake support for Linux is selected by default for this workload. The CMake support in Visual Studio requires the server mode support that was introduced in CMake 3.8. See these instructions for building CMake from source if your package manager provides an older version.
To get started, create a simple CMakeLists.txt file in the same folder as a cpp file as in the example below. (via File > Open > Folder… or devenv.exe <foldername>).
Hello.cpp
#include <iostream>; int main(int argc, char* argv[]) { std::cout << "Hello" << std::endl; }
CMakeLists.txt
project (hello-cmake) add_executable(hello-cmake hello.cpp)
As soon as you open this folder, Visual Studio will parse the CMakeLists.txt. By default, a Windows target of x86-Debug will be used. To target Linux, change the project settings to Linux-Debug or Linux-Release. When you do this, your source will be copied to your Linux machine where CMake will be run to generate the CMake cache for your project.
By default, the first remote system in the list under Tools > Options > Cross Platform > Connection Manager will be used. If you have not created any remote connections, you will be prompted to create one the first time you select a Linux target in your project settings.
To debug your code on the remote system, set a breakpoint, select the CMake target as the startup item in the toolbar menu next to the project setting, and click run (or press F5).
Configuring CMake Settings for Linux
To change the defaults that are used use the menu CMake > Change CMake Settings > CMakeLists.txt, or use the context menu by right clicking CMakeSettings.txt and choosing Change CMake Settings. This will create a new file in your folder called CMakeSettings.json. Initially this will be populated with the default configurations that are listed in the project settings menu item. Here is an example configuration for Linux-Debug based on the example above.
{ "name": "Linux-Debug", "generator": "Unix Makefiles", "remoteMachineName": "${defaultRemoteMachineName}", "configurationType": "Debug", "remoteCMakeListsRoot": "/var/tmp/src/${workspaceHash}/${name}", "cmakeExecutable": "/usr/local/bin/cmake", "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", "remoteBuildRoot": "/var/tmp/build/${workspaceHash}/build/${name}", "remoteCopySources": true, "remoteCopySourcesOutputVerbosity": "Normal", "remoteCopySourcesConcurrentCopies": "10", "cmakeCommandArgs": "", "buildCommandArgs": "", "ctestCommandArgs": "", "inheritEnvironments": [ "linux-x64" ] }
The name on line 2 can be of your choosing to identify your custom configuration. If you have more than one remote system defined, you can enter it in place of the default on line 4. IntelliSense is enabled for this field from your system to help you select the right system. The field remoteCMakeListsRoot on line 6 is where your project sources will be copied to on the remote system, by default under /var/tmp. The field remoteBuildRoot on line 9 is where the build output will be generated on your remote system, that output is also copied locally in the location specified by buildRoot on line 8.
Building a supported CMake release from source
The minimum version of CMake required on your Linux machine is 3.8, and it must also support server mode. To verify this run
cmake --version
To verify that server mode is enabled run
cmake -E capabilities
In the output look for “serverMode”:true. Note that even if compiling from source as described below you should check the capabilities when done. Your Linux system may have limitations that prevent server mode from being enabled. As one example we have run into issues with enabling server mode on Ubuntu 14.04 because of library and compiler limitations.
To get started building from source in the shell for your Linux system make sure your package manager is up to date, you have git and cmake available, then clone the CMake sources.
sudo apt-get update sudo apt-get install -y git cmake git clone https://github.com/Kitware/CMake.git cd CMake
Now, make sure you are on a supported release of CMake for Visual Studio. We are actively tracking CMake development, but we cannot guarantee we support the latest.
15.4.1 is in the Release channel and supports up to 3.9.0 which you can ensure you build by running.
git checkout tags/v3.9.0
15.5 is in the Preview channel and removes the limitation on CMake 3.9, there CMake >= 3.8 can be used. You should be able to use the current release there.
Now to build and install a supported version, run the following commands.
mkdir out cd out cmake ../ make sudo make install
The above will build and install the current release of CMake to /usr/local/bin. Verify the version is >= 3.8 and that server mode is enabled.
/usr/local/bin/cmake –version cmake -E capabilities
Current Limitations
These are some known limitations that we are actively working on.
The Linux console window that enables input and output with a remote Linux application is not enabled for CMake yet. This is a limitation that this window currently only works for gdbserver mode, but our CMake support for Linux only works with gdb mode. This will be addressed in a future release.
What’s next
Download the Visual Studio 2017 Preview, install the Linux C++ Workload, and try our CMake support for Linux with your code. Let us know how it is or isn’t working for you. Your feedback matters.
The best way to reach us is via our GitHub hosted issue list, directly via mail at vcpplinux-support@microsoft.com or find me on Twitter @robotdad.
Hi, this is going to be awesome, thank you! :-)
My project requires at least CMake 3.9.20170812-g71ee6 (a nightly), so naturally I get an error:
CMake Error at CMakeLists.txt:4 (cmake_minimum_required):
1> CMake 3.9.20170812-g71ee6 or higher is required. You are running version 3.9.0-MSVC_2
Is there a way to make this work?
Thanks!
(This is on the Windows host of course, not on the target Linux machine.)
Are you targeting Windows with CMake or Linux?
I am in Windows with VS2017.4 and just did “File > Open > Folder”, this is when the error occurs. So it seems it naturally tries to run CMake for the Windows target first? (for which my project needs a CMake nightly build). So is there a way to make File > Open > Folder work with a CMake nightly on Windows?
Small nitpick:
#include <iostream>
The cout code also has “<“‘s inside ;-) Not that it’s important.
Btw, why would you build CMake from source? Particularly for this use case. You can just download the Linux x64 binary from cmake.org https://cmake.org/download/
I did just that, but it doesn’t work. I’m trying to build inside WSL. OpenSSH server running on port 2222, connection is made. CMakeSettings.json has
“remoteMachineName”: “localhost”,
“cmakeExecutable”: “/opt/Kitware/CMake/latest/bin/cmake”,
on the “remote” machine I issue
mnagy@MATTY-Z50-75:~$ which cmake
/opt/Kitware/CMake/latest/bin/cmake
mnagy@MATTY-Z50-75:~$ cmake –version
cmake version 3.9.1
/opt/Kitware/CMake/latest is simply a symlink to /opt/Kitware/CMake/3.9.1 which I installed from the online binary installer.sh
Once I try to build, it says
1> CMake version ‘3.9.1’ is not supported. Please use 3.8 or newer. See https://aka.ms/linuxcmakeconfig for more info
This was not expected.
Other than the early glitches: AWESOME STUFF! Can’ wait for it to work!
>> ‘3.9.1’ is not supported. Please use 3.8 or newer.
That sounds like a really weird error.
And when you build CMake 3.9.1 from source, it works?
We don’t currently support 3.9.x, but we’re planning to support it, we support anywhere from 3.8 and 3.9. Is it possible for you to use 3.9 or do you have a dependency on 3.9.1?
Just chiming in here: 3.9.x (nightlies) added *a lot* of fixes for VS 2017.3 particularly with respect to C++17 so it would be really important to have it! (or have at least 3.10.0 as soon as it comes out in Oct/Nov but it will be a long wait :( )
The reason we’re not using above 3.9.0 right now, is because the server mode protocol introduced a breaking change in 3.9.1, which we need to absorb and account for.
I don’t have any strong feelings towards 3.9.1, or at least I have not encountered any of the problems that .1 addresses. I simply went and obtained the best and latest.
I am having some troubles though, but first I’m trying to solve them on my own, and once I make sure mistakes aren’t on my end, or simply a few bolts and springs are missing to make the experience awesome, I’ll return.
This is a dream come true.
Any ideas when 15.4 will be released? Is the 6 week release rhythm valid?
Ha, you guys like double escaped your Hello.cpp example text.
Also, give us some CUDA + CMake + VS 2017 support. Nvidia couldn’t write proper VS integration to save their lives.
This is great next step!
One clarification – do we need to be able to run CMake on Windows in order to use this? Or can we use this to build our project on Linux and Visual Studio will pull over the folder / project structure from the remote box?
Similarly, are we still restricted in intellisense pulling from our local box? Or will intellisense read from the remote CMakelist ? Actually..looks like this is still a TODO (github issue: #43 )
>> do we need to be able to run CMake on Windows in order to use this?
Hey that’s a good point! The first thing it does for me is run CMake locally (which currently fails, see my post above).
But the question is, if it’s all about building on a remote Linux and it’s executing CMake there anyway, why does it also need to execute it locally in VS. I’m sure there’s probably a reason for it. (I don’t think #43 is related)
For CMake for Linux, we don’t use anything local. Everything happens remotely. CMake is invoked remotely to generate the cache, then parse it. Build is invoked remotely as well. So is debugging. Regarding IntelliSense, you are correct. We currently designing an experience to fix that problem.
CMake executes locally first though and if it doesn’t succeed, there seems to be no way of adding the Linux targets.
The reason for that is because Windows is the default configuration. So that runs first. If you switch the configuration to Linux, it will target Linux. Do you know see two Linux configurations in the dropdown?
No, there are just the 4 windows targets (or 2, I don’t remember and can’t currently check, but definitely just Windows targets and I found no way of adding/switching to Linux targets).
Pete, it’s possible that you already have a CMakeSettings.json?
Will there be a way to skip copy steps (both for source and output) for WSL use scenario?
This is great!
Finally a simple way to use the same physical project folder, source files and build specifications to develop cross platform applications for Windows and Linux.
I still hope for a direct integration of WSL, but this should also reduce the impact of the indirection through ssh, because the inner modify-compile-test cycle can largely run on Windows and then I only occasionally switch over to Linux to verify everything still works there.
Can’t wait until this hits the release.
I’m getting timeout:
1> 19:30:22: Copying files to remote machine …
1> Timed out executing command ‘/usr/local/bin/cmake –version’, waited for 19.5326ms.
at liblinux.Shell.NonHostedCommand.OnRunAsynchronously()
etc.
nevermind. turns out my connection was configured wrong.
The project is configured successfully but the CMAKE menu still shows “Cancel Cache Generation”.
The last line of the output is:
1> Target info extraction done.
I think `cmake + docker` is good choice.
Hi,
Since the CMAKE project does not have sln or vcxproj, I can`t find where to add include path on windows side just for intellisense.
How do I specify which source files/directories visual studio will copy on the remote linux machine. In my case the top level CMakeLists.txt file is in the project folder and all other CMakeLists.txt as well cpp/h files are in a sub-folder.
Is there a way I can also specify the location on my remote linux machine where the source files are copied, build files are generated and targets are installed?
Hi,
I just tried the example above. It builds successfully but I cannot run and debug it. When I try to run it remotely, I get the error message:
“Unable to start debugging. There was an error starting the pipe program ‘${debugInfo.shellexecPath}'”
Any ideas what might be wrong? Running it directly on the remote machine from the build directory works.
Thanks
I am having the same issue. Any update on why this is happening?
Does this feature work with an external (non-cmake) build system? As in, can we get VS to do the file replicating from an Open Folder project and then use tasks to connect the remote builds?
Not yet. We’ll have some news on this for the next preview of 15.5.
Does this feature support just Makefiles generator or Ninja too?
To get OpenSSL support in CMake, make sure `libssl-dev` is installed, before building CMake.
To find it: `dpkg –list | grep libssl-dev`
If no result: `sudo apt-get install libssl-dev`
You need this if you want to CMake to be able to get sources using `https://` addresses, from Github etc.
When doing this with an internal project, the parsing and such seem to work fine, although the “Startup” combobox never gets populated. What are the CMake conditions necessary in order to have targets (add_executable(target …)) to appear in the Startup combobox ?