Skip to content

paleozogt/MSVCDocker

Repository files navigation

Build Status

Microsoft Visual C via Wine in Docker

CI with MSVC is unnecessarily difficult. Can't we just use Docker?

It turns out we can-- by running MSVC in Wine. Lots of folks have tried to do this over the years [1], but the setup is involved and fiddly. But scripting complicated setups is what Docker was made for!

The big blocker to getting MSVC in Wine is that even though the software itself works under Wine, the installers don't. We dodge that problem by using Vagrant to drive the MSVC installer in a real Windows OS within VirtualBox, export a snapshot of the installation, and then Docker copies the snapshot into Wine.

Requirements

Building an Image

To create an msvc:15 Docker image:

make clean
make msvc15

MSVC 9, 10, 11, 12, 14, 15, and 16 are supported.

Note: The snapshot step can take quite some time, as the MSVC installers are notoriously gigantic and slow.

Usage

Let's simplify our Docker command:

function vcwine() { docker run -v$HOME:/host/$HOME -w/host/$PWD -u $(id -u):$(id -g) -eMSVCARCH=$MSVCARCH --rm -t -i msvc:15 "$@"; }

The Docker images are setup to run (nearly) everything through Wine. So for example, we can do DOS things like dir:

✗ vcwine cmd /c dir
Volume in drive Z has no label.
Volume Serial Number is 0000-0000

Directory of Z:\host\Users\paleozogt\Development\test\MSVCDocker

 8/31/2018   9:08 PM  <DIR>         .
 8/31/2018   9:21 PM  <DIR>         ..
 8/31/2018   8:55 PM  <DIR>         build
 8/31/2018   9:07 PM         3,421  Dockerfile
 8/31/2018   9:07 PM  <DIR>         dockertools
 8/31/2018   9:07 PM           464  Makefile
 8/31/2018   9:08 PM            45  README.md
 8/31/2018   9:07 PM  <DIR>         test
 8/31/2018   9:07 PM         2,654  Vagrantfile
 8/31/2018   9:07 PM  <DIR>         vagranttools
       4 files                    6,584 bytes
       6 directories     97,359,118,336 bytes free

MSVC's cl

Compiling a Hello World:

✗ vcwine cl test/helloworld.cpp 
Microsoft (R) C/C++ Optimizing Compiler Version 19.15.26726 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

helloworld.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.15.26726\include\xlocale(319): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
Microsoft (R) Incremental Linker Version 14.15.26726.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:helloworld.exe 
helloworld.obj 


✗ vcwine helloworld.exe
hello world from win x86_64 msvc v1915

Even though its 2018, maybe we want to build for 32-bit:

✗ MSVCARCH=32 vcwine cl test/helloworld.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

helloworld.cpp
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\xlocale(337) : warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
Microsoft (R) Incremental Linker Version 12.00.31101.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:helloworld.exe
helloworld.obj


✗ vcwine helloworld.exe
hello world from win x86 msvc v1915

LLVM's clang-cl

Clang can cross-compile MSVC-compatible binaries with clang-cl. A linux version is included (ie, it doesn't use Wine), but it still needs the MSVC installation for headers/libs, and Wine is still useful for running the resulting binary.

Compiling a Hello World:

✗ vcwine clang-cl test/helloworld.cpp 


✗ vcwine helloworld.exe
hello world from win x86_64 clang v7

Even though its 2018, maybe we want to build for 32-bit:

✗ MSVCARCH=32 vcwine clang-cl test/helloworld.cpp


✗ vcwine helloworld.exe
hello world from win x86 clang v7

Examples

For more examples, including the use of CMake and high-level language bindings, see the examples subfolder.

Known Issues

  • MSBuild doesn't work, so we can't do things like

    vcwine cmake ../../test -G "Visual Studio 15 2017 Win64"
    vcwine msbuild
    

    If you're using CMake, use the "NMake Makefiles", "NMake Makefiles JOM", or "Ninja" generators.

  • When using LLVM's clang-cl, paths that begin with /U (such as /Users/) will cause strange errors:

    clang-7: warning: '/Users/paleozogt/Development/test/MSVCDocker/build/test/CMakeFiles/CMakeTmp/testCCompiler.c' treated as the '/U' option [-Wslash-u-filename]
    clang-7: note: Use '--' to treat subsequent arguments as filenames
    clang-7: error: no input files
    

    It appears that /Users/... is getting mistaken for a cl flag /U.

References