起因

最近因为CS537操作系统课程的原因,经常需要开发Unix下的小应用程序,比如实现个Shell啊什么的。 我目前的桌面台式机是同时装了Windows(10), Linux(两个发行版), macOS(黑苹果)三个操作系统的,并且都是实体安装, 这就导致Windows下办公完了想去Linux下写写程序就需要重启。而在去年的时候微软宣布他们的Visual Studio支持开发Linux的应用程序了,所以觉得我也折腾一把之后或许会方便一些。

原料

这个特性貌似是Visual Studio 2017 15.4才加进来的特性,所以各位没装的或者旧版本的可能需要升级才可以使用这个功能。

尝试新建Linux Console项目

输入项目名称,文件夹路径,选Linux Console Application,点完成
之后就可以按照正常的Visual Studio项目配置过程来配置Linux项目了。

微软远程编译、调试的原理就是在本地生成CMakeCache以及Unix Makefile,然后将源码和构建脚本直接复制到Linux机器上远程调用编译器编译。 这个过程是单向的,本地源码永远是最新,远程工作目录每次编译的时候更新一次,然后Visual Studio根据本地的CMakeCache来了解这个项目。
于是就可以在全宇宙最好用的IDE Visual Studio 下写这个菜的抠脚的操作系统课作业了。


以为这样就完了?Windows才不会让你这么轻易的解决问题…

微软家的编译器和所有IDE配套工具链都有个共同的问题,分不清C和C++,根本原因就是自家的cl.exe同时支持C/C++编译并且不作分开处理。 然后在项目配置里有两个选项直接致命,第一个是-frtti,另一个是-fno-strict-aliasing两个在GCC上都是C++-only的选项。 而我们的教授要求我们用-Wall -Werror编译程序,所以这两个warning直接报错:(

然后尝试自定义命令行参数,或者覆盖之前的参数,然后查文档发现Visual Studio自然是不支持覆盖编译参数的,至少在Linux项目里不行。

不过意外地发现Visual Studio 2017引进了CMake支持,并且在2017 15.4的时候支持了Linux的CMake项目,那当然是CMake直接上了

尝试打开Linux CMake项目

CMakeLists:

cmake_minimum_required(VERSION 2.8.9)
project (wish)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
add_executable(wish wish.c)

然后配置CMakeSettings然Visual Studio生成对应Cache以及自动连上我宿舍常开的Linux机器远程编译、调试:

{
  // 请参阅 https://go.microsoft.com//fwlink//?linkid=834763 了解有关此文件的详细信息。
  "configurations": [
    {
      "name": "Manjaro-Debug",
      "generator": "Unix Makefiles",
      "remoteMachineName": "${defaultRemoteMachineName}",
      "configurationType": "Debug",
      "remoteCMakeListsRoot": "/tmp/src/${workspaceHash}/${name}",
      "cmakeExecutable": "/usr/bin/cmake",
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
      "remoteBuildRoot": "/tmp/build/${workspaceHash}/build/${name}",
      "remoteCopySources": true,
      "remoteCopySourcesOutputVerbosity": "Normal",
      "remoteCopySourcesConcurrentCopies": "10",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "linux-x64" ]
    },
    {
      "name": "Manjaro-Release",
      "generator": "Unix Makefiles",
      "remoteMachineName": "${defaultRemoteMachineName}",
      "configurationType": "Release",
      "remoteCMakeListsRoot": "/tmp/src/${workspaceHash}/${name}",
      "cmakeExecutable": "/usr/bin/cmake",
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
      "remoteBuildRoot": "/tmp/build/${workspaceHash}/build/${name}",
      "remoteCopySources": true,
      "remoteCopySourcesOutputVerbosity": "Normal",
      "remoteCopySourcesConcurrentCopies": "10",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "linux-x64" ]
    }
  ]
}

大概就是如下图所示的配置:

这时候就可以完美编译了,-Wall -Werror也在乐呵呵地向我招手,远程GDB调试也是完美的,表扬一下VS的调试器可能是全宇宙最好用的。


以为这样就完了?Windows才不会让你这么轻易的解决问题…

Intellisense在Linux CMake项目下的补全

是炸的,补不全的。

巨硬家的Intellisense依靠理解C/C++的文件依赖关系并且遍历源文件中的函数/变量标记来帮你智能补全。
正常写Windows代码的时候这个补全是相当智能的,我在Vim下尝试过多个全功能的补全插件,但是都没有VS家的用得得心应手。
但是写Linux程序的时候需要Linux/Unix标准的头文件,没有是没有办法补全的。
所以理所当然尝试从隔壁Manjaro复制了一份/usr/include到项目目录,并且配置CppProperties如下:

{
  "configurations": [
    {
      "inheritEnvironments": [
        "x64-Debug",
        "linux-x64"
      ],
      "name": "Manjaro-Debug",
      "includePath": [
        "D:\\Code\\Wish",
        "D:\\Code\\Wish\\mjro-include",
        "D:\\Code\\Wish\\mjro-include\\x86_64-linux-gnu"
      ],
      "defines": [
        "WIN32",
        "_DEBUG",
        "UNICODE",
        "_UNICODE"
      ],
      "intelliSenseMode": "linux-gcc-x64"
    }
  ]
}

这样Intellisense就可以找到本地的Linux头文件并且提供补全和语法检查了。


以为这样就完了?Windows才不会让你这么轻易的解决问题…

Intellisense 根本找不到那些头文件!!!

可以看到所有Linux头文件的include以及用到那些头文件的语句都是标红的。

这么惊天一个大Bug值得开一个Issue,结果早就有人吃过这坨shi了,
Github:Microsoft/VSLinux, Issue #195#215, 现在仍然没有解决。。。


这样就完了?嗯…这样就完了

作业还是要写的,最后一部分由WSL下开Vim完成,至少我配置的补全和检查都是在工作的。

Tmux和ssh都在工作,只是需要手动操作了。

微软如果想吸引Linux开发者来用他们的VS写出程序的话,可能还需要好好优化一下VS在这方面的兼容性和易用性。欢迎使用Vim,全宇宙最好的编辑器。