From c218ea2227dc973880b1cb5527ca90289cd737a1 Mon Sep 17 00:00:00 2001 From: Luis Martinez de Bartolome Izquierdo Date: Fri, 9 Jul 2021 13:32:24 +0200 Subject: [PATCH] VCVars generator (#9230) * Missing more tests * Added tests * Removed comment * None is activated by default * Hide write_conanvcvars * Fixed call to vcvars --- conan/tools/cmake/toolchain.py | 4 +- conan/tools/meson/toolchain.py | 4 +- conan/tools/microsoft/__init__.py | 2 +- conan/tools/microsoft/toolchain.py | 53 +---------------- conan/tools/microsoft/visual.py | 58 +++++++++++++++++++ conans/client/generators/__init__.py | 6 +- .../toolchains/gnu/autotools/test_win_bash.py | 5 +- .../toolchains/microsoft/__init__.py | 0 .../toolchains/microsoft/vcvars_test.py | 53 +++++++++++++++++ 9 files changed, 125 insertions(+), 60 deletions(-) create mode 100644 conans/test/integration/toolchains/microsoft/__init__.py create mode 100644 conans/test/integration/toolchains/microsoft/vcvars_test.py diff --git a/conan/tools/cmake/toolchain.py b/conan/tools/cmake/toolchain.py index db4aba8cfaf..2ff9ba810b6 100644 --- a/conan/tools/cmake/toolchain.py +++ b/conan/tools/cmake/toolchain.py @@ -11,7 +11,7 @@ from conan.tools._check_build_profile import check_using_build_profile from conan.tools._compilers import architecture_flag, use_win_mingw from conan.tools.cmake.utils import is_multi_configuration, get_file_name -from conan.tools.microsoft.toolchain import write_conanvcvars +from conan.tools.microsoft import VCVars from conan.tools.microsoft.visual import vs_ide_version from conans.errors import ConanException from conans.util.files import load, save @@ -729,7 +729,7 @@ def generate(self): save(self.filename, self.content) # Generators like Ninja or NMake requires an active vcvars if self.generator is not None and "Visual" not in self.generator: - write_conanvcvars(self._conanfile) + VCVars(self._conanfile).generate() self._writebuild(toolchain_file) def _writebuild(self, toolchain_file): diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py index 7ea919c932c..5ac8cc6b18e 100644 --- a/conan/tools/meson/toolchain.py +++ b/conan/tools/meson/toolchain.py @@ -4,7 +4,7 @@ from conan.tools._check_build_profile import check_using_build_profile from conan.tools.env import VirtualBuildEnv -from conan.tools.microsoft.toolchain import write_conanvcvars +from conan.tools.microsoft import VCVars from conans.client.build.cppstd_flags import cppstd_from_settings from conans.client.tools.oss import cross_building, get_cross_building_settings from conans.util.files import save @@ -313,4 +313,4 @@ def generate(self): self._write_cross_file() else: self._write_native_file() - write_conanvcvars(self._conanfile) + VCVars(self._conanfile).generate() diff --git a/conan/tools/microsoft/__init__.py b/conan/tools/microsoft/__init__.py index 776d856299f..c3f84315d2e 100644 --- a/conan/tools/microsoft/__init__.py +++ b/conan/tools/microsoft/__init__.py @@ -1,5 +1,5 @@ from conan.tools.microsoft.toolchain import MSBuildToolchain from conan.tools.microsoft.msbuild import MSBuild from conan.tools.microsoft.msbuilddeps import MSBuildDeps -from conan.tools.microsoft.visual import msvc_runtime_flag +from conan.tools.microsoft.visual import msvc_runtime_flag, VCVars from conan.tools.microsoft.subsystems import unix_path diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index 07abb4ff081..68a1d1c9caf 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -3,59 +3,10 @@ from xml.dom import minidom from conan.tools._check_build_profile import check_using_build_profile -from conan.tools.env.environment import register_environment_script -from conan.tools.microsoft.visual import vcvars_command, vcvars_arch -from conans.client.tools import intel_compilervars_command +from conan.tools.microsoft.visual import VCVars from conans.errors import ConanException from conans.util.files import save, load -CONAN_VCVARS_FILE = "conanvcvars.bat" - - -def write_conanvcvars(conanfile, auto_activate=True): - # FIXME: Write a VCVars generator for the final user - """ - write a conanvcvars.bat file with the good args from settings - """ - os_ = conanfile.settings.get_safe("os") - if os_ != "Windows": - return - - compiler = conanfile.settings.get_safe("compiler") - cvars = None - if compiler == "intel": - cvars = intel_compilervars_command(conanfile) - elif compiler == "Visual Studio" or compiler == "msvc": - vs_version = vs_ide_version(conanfile) - vcvarsarch = vcvars_arch(conanfile) - vcvars_ver = None - if compiler == "Visual Studio": - toolset = conanfile.settings.get_safe("compiler.toolset") - if toolset is not None: - vcvars_ver = {"v140": "14.0", - "v141": "14.1", - "v142": "14.2"}.get(toolset) - else: - # Code similar to CMakeToolchain toolset one - compiler_version = str(conanfile.settings.compiler.version) - version_components = compiler_version.split(".") - assert len(version_components) >= 2 # there is a 19.XX - minor = version_components[1] - # The equivalent of compiler 19.26 is toolset 14.26 - vcvars_ver = "14.{}".format(minor) - cvars = vcvars_command(vs_version, architecture=vcvarsarch, platform_type=None, - winsdk_version=None, vcvars_ver=vcvars_ver) - if cvars: - content = textwrap.dedent("""\ - @echo off - {} - """.format(cvars)) - path = os.path.join(conanfile.generators_folder, CONAN_VCVARS_FILE) - save(path, content) - - if auto_activate: - register_environment_script(conanfile, path) - def vs_ide_version(conanfile): compiler = conanfile.settings.get_safe("compiler") @@ -105,7 +56,7 @@ def generate(self): config_filename = "conantoolchain{}.props".format(name) self._write_config_toolchain(config_filename) self._write_main_toolchain(config_filename, condition) - write_conanvcvars(self._conanfile) + VCVars(self._conanfile).generate() @staticmethod def _msvs_toolset(settings): diff --git a/conan/tools/microsoft/visual.py b/conan/tools/microsoft/visual.py index 15267fc6d3c..4db11a37352 100644 --- a/conan/tools/microsoft/visual.py +++ b/conan/tools/microsoft/visual.py @@ -1,7 +1,65 @@ import os +import textwrap +from conan.tools.env.environment import register_environment_script +from conans.client.tools import intel_compilervars_command from conans.client.tools.win import vs_installation_path from conans.errors import ConanException +from conans.util.files import save + +CONAN_VCVARS_FILE = "conanvcvars.bat" + + +class VCVars: + def __init__(self, conanfile): + self._conanfile = conanfile + + def generate(self, auto_activate=True): + _write_conanvcvars(self._conanfile, auto_activate=auto_activate) + + +def _write_conanvcvars(conanfile, auto_activate=True): + """ + write a conanvcvars.bat file with the good args from settings + """ + os_ = conanfile.settings.get_safe("os") + if os_ != "Windows": + return + + compiler = conanfile.settings.get_safe("compiler") + cvars = None + if compiler == "intel": + cvars = intel_compilervars_command(conanfile) + elif compiler == "Visual Studio" or compiler == "msvc": + vs_version = vs_ide_version(conanfile) + vcvarsarch = vcvars_arch(conanfile) + vcvars_ver = None + if compiler == "Visual Studio": + toolset = conanfile.settings.get_safe("compiler.toolset") + if toolset is not None: + vcvars_ver = {"v140": "14.0", + "v141": "14.1", + "v142": "14.2"}.get(toolset) + else: + # Code similar to CMakeToolchain toolset one + compiler_version = str(conanfile.settings.compiler.version) + version_components = compiler_version.split(".") + assert len(version_components) >= 2 # there is a 19.XX + minor = version_components[1] + # The equivalent of compiler 19.26 is toolset 14.26 + vcvars_ver = "14.{}".format(minor) + cvars = vcvars_command(vs_version, architecture=vcvarsarch, platform_type=None, + winsdk_version=None, vcvars_ver=vcvars_ver) + if cvars: + content = textwrap.dedent("""\ + @echo off + {} + """.format(cvars)) + path = os.path.join(conanfile.generators_folder, CONAN_VCVARS_FILE) + save(path, content) + + if auto_activate: + register_environment_script(conanfile, path) def vs_ide_version(conanfile): diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py index b31305c9e2c..7cf22fdd0ca 100644 --- a/conans/client/generators/__init__.py +++ b/conans/client/generators/__init__.py @@ -71,7 +71,8 @@ def __init__(self): self._new_generators = ["CMakeToolchain", "CMakeDeps", "MSBuildToolchain", "MesonToolchain", "MSBuildDeps", "QbsToolchain", "msbuild", "VirtualRunEnv", "VirtualBuildEnv", "AutotoolsDeps", - "AutotoolsToolchain", "BazelDeps", "BazelToolchain", "PkgConfigDeps"] + "AutotoolsToolchain", "BazelDeps", "BazelToolchain", "PkgConfigDeps", + "VCVars"] def add(self, name, generator_class, custom=False): if name not in self._generators or custom: @@ -115,6 +116,9 @@ def _new_generator(self, generator_name, output): elif generator_name in ("MSBuildDeps", "msbuild"): from conan.tools.microsoft import MSBuildDeps return MSBuildDeps + elif generator_name == "VCVars": + from conan.tools.microsoft import VCVars + return VCVars elif generator_name == "QbsToolchain" or generator_name == "QbsProfile": from conan.tools.qbs.qbsprofile import QbsProfile return QbsProfile diff --git a/conans/test/functional/toolchains/gnu/autotools/test_win_bash.py b/conans/test/functional/toolchains/gnu/autotools/test_win_bash.py index 1cd62d2860c..2c5844d5b4b 100644 --- a/conans/test/functional/toolchains/gnu/autotools/test_win_bash.py +++ b/conans/test/functional/toolchains/gnu/autotools/test_win_bash.py @@ -30,7 +30,7 @@ def test_autotools_bash_complete(): conanfile = textwrap.dedent(""" from conans import ConanFile from conan.tools.gnu import Autotools - from conan.tools.microsoft.toolchain import write_conanvcvars + from conan.tools.microsoft import VCVars from conan.tools.env import Environment class TestConan(ConanFile): @@ -41,8 +41,7 @@ class TestConan(ConanFile): def generate(self): # Add vcvars launcher - # FIXME: Write a generator class for the vcvars - write_conanvcvars(self) + VCVars(self).generate() # Force autotools to use "cl" compiler # FIXME: Should this be added to AutotoolsToolchain when visual? diff --git a/conans/test/integration/toolchains/microsoft/__init__.py b/conans/test/integration/toolchains/microsoft/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/conans/test/integration/toolchains/microsoft/vcvars_test.py b/conans/test/integration/toolchains/microsoft/vcvars_test.py new file mode 100644 index 00000000000..7ea099d8541 --- /dev/null +++ b/conans/test/integration/toolchains/microsoft/vcvars_test.py @@ -0,0 +1,53 @@ +import platform +import textwrap +import os + +import pytest + +from conans.test.utils.tools import TestClient + + +@pytest.mark.skipif(platform.system() not in ["Windows"], reason="Requires Windows") +@pytest.mark.parametrize("auto_activate", [False, True, None]) +def test_vcvars_generator(auto_activate): + client = TestClient(path_with_spaces=False) + + conanfile = textwrap.dedent(""" + from conans import ConanFile + from conan.tools.microsoft import VCVars + + class TestConan(ConanFile): + settings = "os", "compiler", "arch", "build_type" + + def generate(self): + VCVars(self).generate({}) + """.format("True" if auto_activate else "False" if auto_activate is False else "")) + + client.save({"conanfile.py": conanfile}) + client.run('install . -s os=Windows -s compiler="msvc" -s compiler.version=19.1 ' + '-s compiler.cppstd=14 -s compiler.runtime=static') + + assert os.path.exists(os.path.join(client.current_folder, "conanvcvars.bat")) + + if auto_activate is True or auto_activate is None: + bat_contents = client.load("conanenv.bat") + assert "conanvcvars.bat" in bat_contents + else: + assert not os.path.exists(os.path.join(client.current_folder, "conanenv.bat")) + + +@pytest.mark.skipif(platform.system() not in ["Windows"], reason="Requires Windows") +def test_vcvars_generator_string(): + client = TestClient(path_with_spaces=False) + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class TestConan(ConanFile): + generators = "VCVars" + settings = "os", "compiler", "arch", "build_type" + """) + client.save({"conanfile.py": conanfile}) + client.run('install . -s os=Windows -s compiler="msvc" -s compiler.version=19.1 ' + '-s compiler.cppstd=14 -s compiler.runtime=static') + + assert os.path.exists(os.path.join(client.current_folder, "conanvcvars.bat"))