https://anadoxin.org/blog

Bringing Visual Studio compiler into MSYS2 environment

Thu, 22 November 2018 :: #windows :: #visualstudio :: #msys2 :: #cpp

Using Windows is a painful experience for a command-line oriented person like me. Unfortunately, Windows doesn't offer any decent command-line oriented environment, because well, it has different goals, and that's understandable. The problem is when one is forced to use Windows when it's clear that those goals are incompatible with the person's goals.

One solution is to use MSYS2 environment. It's a msys/cygwin-like shell that effectively provides you with a bash shell, and this runs on Windows. Of course it's not as fast as a native Linux shell, but still it's better than nothing. And it uses pacman from ArchLinux!

(one trick: MSYS2 also allows you to run sshd, and you'll be able to ssh into your Windows boxes the same way you can ssh on your Linux machines)

Another solution would probably be WSL (Windows Subsystem for Linux), but honestly last time I've checked the state of this, a simple ls -la took 2 seconds everytime it was run, and apt-get update took probably half of an hour of constant disk swapping. I've lost patience, aborted WSL session and promised myself to look into this after a year. This year has not passed yet.

So, after installing MSYS2 you're going to need a development environment. It's easy to install MinGW's gcc with pacman, as well as clang so you can proof-test your C++ code with different compilers. But since we're on Windows, we can do better, and we can actually hack our way into integrating Visual Studio with MSYS2 shell, so we'll be able to use Visual Studio's development tools directly from MSYS2.

This has several advantages, but mostly it's convinient if you're forced to either:

  • Make the project compilable on different compilers, like GCC, Clang and Visual Studio,

  • You're interested in how different compilers generate assembly from your C++ source,

  • You have to work using Visual Studio, but you're not a Windows person,

  • I'm sure you can find more arguments for it ;).

The approach taken in this note is to install Visual Studio, open its command-line tools window that allow you to use command-line Visual Studio tools, snapshot its environment, and re-create this environment in your ~/.bashrc from MSYS2.

Install Visual Studio

So the first step is to install Visual Studio Community edition, because it's free. And it contains all the tools we need, skipping all the tools we don't need. I won't provide you with a direct link to Microsoft's site, because any link pointing to them dies faster than a hope for humanity after watching YouTube, that's why I'll just simply link to a DuckDuckGo search query, and you should be able to find the proper link on the first page (hopefully it will be the first link, but with DuckDuckGo you'll never know).

One fun fact during installation of Visual Studio is that you better install it on your C drive, because if you'll select some other drive, it will still mostly install itself on C drive. So I'm not sure it's worth splitting the installation to two drives. I'm always installing it to C.

After installing, Visual Studio will provide some convinient shortcuts in the glorious Start menu (which is apparently more important than the kernel itself). One of those shortcuts is called:

Visual Studio 2017/Command line for x64 Native Tools for Visual Studio 2017

Or something like this, as it also depends on the language version of your system.

Just run this shortcut, and you'll be greeted with a black console window that contains all the necessary setup in order to run command-line Visual Studio tools. Don't close this window yet; we'll need it later.

Install envdiff

I've prepared a small tool, envdiff, that will dump the environment variables of the current shell. It's very small and primitive, but this only means that there are not many things than can break (then again, it's Windows we're talking about).

You'll need Rust compiler in order to compile envdiff, but don't worry, installing Rust is really fast, it's nowhere near the bloated Visual Studio installer.

You can compile envdiff like this (you can do it under MSYS2 shell):

$ cd ~/dev
$ mkdir envdiff && cd envdiff
$ git clone https://gitlab.com/antekone/envdiff.git .
$ cargo build --release
Downloading ...
Downloading ...
  Compiling ...
  Compiling ...
...
$ ls -la target/release/envdiff.exe

First compilation will take a while, because it will need to download and compile all dependencies for JSON serialization, which the tool uses. The resulting binary file will be placed in the target/release/envdiff.exe file.

Snapshot the environment of a clean shell

Next step is to open a normal cmd.exe shell to open a black terminal with a clean shell. Then you can run envdiff.exe you've build in your previous step.

C:\> cd c:\msys64\home\antek\dev\envdiff
C:\msys64\home\antek\dev\envdiff> target\release\envdiff.exe
Stored snapshot.env

This output means that your current environment has been stored inside the snapshot.env file.

Diff clean environment with Visual Studio environment

Remember the Visual Studio command-line tools console box I've told you to not close earlier? You can bring it back now. Enter the same directory that you've used previously, the one with the snapshot.env file, and run envdiff.exe again, but remember to use the Visual Studio command-line tools console box this time.

**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.8.7
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community> cd c:\msys64\home\antek\dev\envdiff
C:\msys64\home\antek\dev\envdiff> target\release\envdiff.exe
...

This time it will display the environment in the bash syntax that you need to append to your ~/.bashrc file. You can do a helper bash script like this:

C:\msys64\home\antek\dev\envdiff> target\release\envdiff.exe > c:\msys64\home\antek\.visualstudio.sh

Then, under MSYS2, just edit your ~/.bashrc and put this line at the end of this file:

source ~/.visualstudio.sh

Relogin, check if it works

Run a new MSYS2 terminal and check if it works:

antek@MORDOR MSYS ~
$ cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.15.26730 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

antek@MORDOR MSYS ~
$ msbuild.exe
Microsoft (R) Build Engine version 15.8.169+g1ccb72aefa for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

MSBUILD : error MSB1003: Specify a project or solution file. The current working directory does not contain a project or solution file.

It should work and you should be able to produce Visual Studio-generated executables directly from your MSYS2 shell.

Gotchas

There's one name collision. MSYS2 already has an executable /bin/link.exe in current PATH variable, and Visual Studio uses its own link.exe to link object files to executable files. The /bin/link.exe file will have to be renamed to i.e. /bin/link2.exe to get Visual Studio tools to work properly. I'm not sure if anything uses /bin/link.exe though, after renaming it I haven't noticed any breakages.

Another issue is that CMake's Visual Studio 2017 (or 2019) generator won't work when you try to do it from ssh shell. Solution for this is to install sshd as a system service running in the context of SYSTEM user (so, with admin rights). Then finding VS installation will work, thus CMake will work without problems. Setting up sshd as a system service is unfortunately out of scope of this blog post, so I'll maybe create a new one instead in the future. In the meantime, you can check this script, it worked for me (with some modifications).

Hope this works for you!