8

I want to generate a Visual Studio Solution for a cross-platform Linux Project from a CMake Project.

The Visual Studio 2017 cross-platform workload works nicely, especially when it comes to debugging. I use it to target the WSL. Now I have an existing Linux CMake project that I want to develop on Windows and Visual Studio and build it on WSL. I just don't seem to see a way of generating an appropriate Solution for Visual Studio. Can anyone enlighten me?

Felix
  • 203
  • 3
  • 5
  • What is a WSL? If you need to generate a VS solution, which uses MSVC compiler to build windows binaries you can just use cmake-gui for that. I could right a proper answer, but I need more info. – dragn Mar 13 '17 at 19:55
  • WSL is the new Windows Subsystem for Linux, which allows you to run linux binaries on windows. You can also run ssh in there and then target it from VS on Windows via the cross-platform workload. Therefore my question. – Felix Mar 15 '17 at 11:47

1 Answers1

3

There were already some queries to support the "Linux" project type by CMake, but I don't think that there is something implemented yet (looking at the code it's not able to generate the required project settings).

In those cases you can only work with include_external_msproject() command calls.

This would include an existing .vcproj file into your CMake generated solution like:

include_external_msproject(
    MyProject 
    ${CMAKE_CURRENT_SOURCE_DIR}/MyProject/MyProject.vcproj
)

So let's make a template of an existing Linux .vcxproj file like this:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="@CMAKE_MATCH_1@.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|x86">
      <Configuration>Debug</Configuration>
      <Platform>x86</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x86">
      <Configuration>Release</Configuration>
      <Platform>x86</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>@_guid@</ProjectGuid>
    <Keyword>Linux</Keyword>
    <RootNamespace>@_target@</RootNamespace>
    <MinimumVisualStudioVersion>@CMAKE_MATCH_1@.0</MinimumVisualStudioVersion>
    <ApplicationType>Linux</ApplicationType>
    <ApplicationTypeRevision>1.0</ApplicationTypeRevision>
    <TargetLinuxPlatform>Generic</TargetLinuxPlatform>
    <LinuxProjectType>{D51BCBC9-82E9-4017-911E-C93873C4EA2B}</LinuxProjectType>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
    <UseDebugLibraries>true</UseDebugLibraries>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
    <UseDebugLibraries>false</UseDebugLibraries>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings" />
  <ImportGroup Label="Shared" />
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros" />
  <ItemGroup>
    <ClCompile Include="@_sources@" />
  </ItemGroup>
  <ItemGroup>
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets" />
</Project>

And create a new add_linux_executable() command using this:

cmake_minimum_required(VERSION 2.8)

project(ConfigureVCXProjForLinux)

function(add_linux_executable _target)
    if (CMAKE_GENERATOR MATCHES "Visual Studio ([0-9]*)")
        foreach(_source IN LISTS ARGN)
            get_filename_component(_source_abs "${_source}" ABSOLUTE)
            file(TO_NATIVE_PATH "${_source_abs}" _source_native)
            list(APPEND _sources "${_source_native}")
        endforeach()
        file(TO_NATIVE_PATH "${CMAKE_CURRENT_LIST_FILE}" _list_file_native)
        list(APPEND _sources "${_list_file_native}")

        string(
            UUID _guid 
            NAMESPACE "2e4779e9-c831-47b0-b138-3745b2ed6ba9" 
            NAME ${_target}
            TYPE SHA1
            UPPER
        )

        configure_file(
           "LinuxTemplate.vcxproj.in" 
            "${CMAKE_CURRENT_BINARY_DIR}/${_target}.vcxproj" 
            @ONLY
        )

        include_external_msproject(
            ${_target}
            "${CMAKE_CURRENT_BINARY_DIR}/${_target}.vcxproj"
            TYPE "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
            GUID "${_guid}"
        )
    endif()
endfunction()

file(WRITE "main.cpp" [=[
    #include <iostream>

    int main()
    {
        std::cout << "Hello Linux !" << std::endl;
    }
]=])
add_linux_executable(${PROJECT_NAME} "main.cpp")

Note the template replacements:

  • @CMAKE_MATCH_1@ for the Visual Studio version number
  • @_target@ for the project RootNamespace
  • @_sources@ for ever source file you have given ``add_linux_executable()` as an argument
  • @_guid@ a unique GUID for the project

This would still require one template per whatever compilation options you choose. But using templates makes this approach somewhat more flexible.

Florian
  • 39,996
  • 9
  • 133
  • 149
  • How would `include_external_msproject()` work conceptually? – Felix Mar 15 '17 at 11:54
  • @Felix I've added an example. But I have to admit that `include_external_msproject()` may not really help in your case, since you need existing VS project files to be included. – Florian Mar 15 '17 at 12:20
  • @Felix To be more concrete: my projects have a CMake generated Visual Studio solution which builds the Windows version of my project. And those solutions do include a single Linux "external" project which calls an external script for cross-compiling (utilizing CMake again) and is mainly used for (remote) debugging out of Visual Studio. But I've not yet used the Linux VS projects, I'm using an external commercial tool called [`VisualGDB`](https://visualgdb.com/). – Florian Mar 15 '17 at 12:35
  • This doesn't seem like an actual solution to the scenario described (which i also share). Does anyone have any updates on native support for visual studio performing remote linux compilation from a standard CMake project folder? – solvingJ Jun 10 '17 at 01:08
  • @Felix I've added a more detailed example. And for an "alternative" until this is officially supported by CMake see [here](https://stackoverflow.com/questions/44468507/how-to-add-linux-compilation-to-cmake-project-in-visual-studio). – Florian Jul 08 '17 at 21:13