Windows Subsystems
On Windows, you can run different subsystems that enhance the operating system with UNIX capabilities.
Conan supports MSYS2
, CYGWIN
, WSL
and in general any subsystem that is able to run a bash
shell.
Many libraries use these subsystems in order to use the Unix tools like the Autoconf
suite
that generates Makefiles
.
The difference between MSYS2 and CYGWIN is that MSYS2 is oriented to the development of native Windows packages, while CYGWIN tries to provide a complete POSIX-like system to run any Unix application on it.
For that reason, we recommend the use of MSYS2 as a subsystem to be used with Conan.
Operation Modes
The MSYS2
and CYGWIN
can be used with different operation modes:
You can use them together with MinGW to build Windows-native software.
You can use them together with any other compiler to build Windows-native software, even with Visual Studio.
You can use them with MinGW to build specific software for the subsystem, with a dependency to a runtime DLL (
msys-2.0.dll
andcygwin1.dll
)
If you are building specific software for the subsystem, you have to specify a value for the setting os.subsystem
,
if you are only using the subsystem for taking benefit of the UNIX tools but generating native Windows software, you
shouldn’t specify it.
Running commands inside the subsystem
self.win_bash
This is an experimental feature introduced in Conan 1.39. It supersedes the run(..., win_bash=True)
argument but
if the run(..., win_bash=True)
is used, it will have priority so the compatibility with the previous behavior is
guaranteed.
The self.win_bash
is an attribute of the conanfile, when set to True
and only when running in Windows (you don’t need
to check if you are in Windows), it will run the self.run()
commands inside a bash shell.
Note
The bash.exe
that will run is not auto-detected or read from the CONAN_BASH_PATH
anymore, neither the subsystem to be used.
These are the config variables used:
tools.microsoft.bash:subsystem
: Values can bemsys2
,cygwin
,msys
andwsl
.tools.microsoft.bash:path
: Path to thebash.exe
tools.microsoft.bash:active
: Define if Conan is already running inside the specific subsystem.
The new Autotools, AutotoolsToolchain, AutotoolsDeps and PkgConfigDeps will work automatically
when self.win_bash
is set.
self.win_bash_run
This is identical to the above self.win_bash
, but applies to execution of commands in the “run” scope,
so self.run(cmd, scope="run")
will run such <cmd>
inside a bash shell if win_bash_run==True
.
self.run()
In a Conan recipe, you can use the self.run
method specifying the parameter win_bash=True
that will call automatically to the tool tools.run_in_windows_bash.
It will use the bash in the path or the bash specified for the environment variable CONAN_BASH_PATH to run the specified command.
Conan will automatically escape the command to match the detected subsystem.
If you also specify the msys_mingw
parameter to False, and the subsystem is MSYS2
it will
run in Windows-native mode, the compiler won’t link against the msys-2.0.dll
.
AutoToolsBuildEnvironment
Note
From Conan 1.39 the new Autotools build helper will use the self.win_bash
conanfile attribute (see above) to adjust automatically all the paths to the subsystem.
In the constructor of the build helper, you have the win_bash
parameter. Set it to True
to
run the configure
and make
commands inside a bash.
Controlling the build environment
Building software in a Windows subsystem for a different compiler than MinGW can sometimes be painful. The reason is how the subsystem finds your compiler/tools in your system.
For example, the icu library requires Visual Studio to be built in Windows, but also a subsystem
able to build the Makefile. A very common problem and example of the pain is the link.exe
program.
In the Visual Studio suite, link.exe
is the linker, but in the MSYS2
environment the link.exe
is a tool to manage symbolic links.
Conan is able to prioritize the tools when you use tool_requires
, and put the tools in the PATH in
the right order.
There are some packages you can use as tool_requires
:
From ConanCenter:
mingw-w64/8.1: MinGW compiler installer as a Conan package.
msys2/20190524@: MSYS2 subsystem as a Conan package (Conan Center Index).
cygwin_installer/2.9.0@bincrafters/stable: Cygwin subsystem as a Conan package.
For example, create a profile and name it msys2_mingw with the following contents:
[tool_requires]
mingw_installer/1.0@conan/stable
msys2/20190524
[settings]
os_build=Windows
os=Windows
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=4.9
compiler.exception=seh
compiler.libcxx=libstdc++11
compiler.threads=posix
build_type=Release
Then you can have a conanfile.py that can use self.run()
with win_bash=True
to run any
command in a bash terminal or use the AutoToolsBuildEnvironment
to invoke configure/make
in the subsystem
:
from conans import ConanFile
import os
class MyToolchainXXXConan(ConanFile):
name = "mylib"
version = "0.1"
...
def build(self):
self.run("some_command", win_bash=True)
env_build = AutoToolsBuildEnvironment(self, win_bash=True)
env_build.configure()
env_build.make()
...
Apply the profile in your recipe to create a package using the MSYS2 and MINGW:
$ conan create . user/testing --profile msys2_mingw
As we included in the profile the MinGW
and then the MSYS2
build_require, when we run a command, the PATH
will contain first the MinGW tools and finally the MSYS2.
What could we do with the Visual Studio issue with link.exe
? You can pass an additional parameter to run_in_windows_bash
with a dictionary of environment variables to have more priority than the others:
def build(self):
# ...
vs_path = tools.vcvars_dict(self)["PATH"] # Extract the path from the vcvars_dict tool
tools.run_in_windows_bash(self, command, env={"PATH": vs_path})
So you will get first the link.exe
from the Visual Studio.
Also, Conan has a tool tools.remove_from_path
that you can use in a recipe to temporarily remove a
tool from the path if you know that it can interfere with your build script:
class MyToolchainXXXConan(ConanFile):
name = "mylib"
version = "0.1"
...
def build(self):
with tools.remove_from_path("link"):
# Call something
self.run("some_command", win_bash=True)
...