From 0a6f82819078713695e46479e2c64ecdd882f561 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 10 Dec 2020 23:29:35 +0100 Subject: [PATCH 01/32] working in msvc new settings --- conan/tools/cmake/cmake.py | 52 +++++++++++++- conans/client/build/cmake_flags.py | 2 - conans/client/conf/__init__.py | 10 +++ .../test/integration/toolchains/test_cmake.py | 69 +++++++++++++++++++ 4 files changed, 129 insertions(+), 4 deletions(-) diff --git a/conan/tools/cmake/cmake.py b/conan/tools/cmake/cmake.py index ebb9e477964..4aa36955e41 100644 --- a/conan/tools/cmake/cmake.py +++ b/conan/tools/cmake/cmake.py @@ -3,14 +3,62 @@ from conans.client import tools from conans.client.build import join_arguments -from conans.client.build.cmake_flags import is_multi_configuration, get_generator +from conans.client.build.cmake_flags import is_multi_configuration from conan.tools.cmake.base import CMakeToolchainBase from conans.client.tools.files import chdir -from conans.client.tools.oss import cpu_count, args_to_string +from conans.client.tools.oss import cpu_count, args_to_string, get_cross_building_settings from conans.errors import ConanException from conans.model.version import Version from conans.util.conan_v2_mode import conan_v2_behavior from conans.util.files import mkdir +from conans.util.log import logger + + +def get_generator(conanfile): + # Returns the name of the generator to be used by CMake + # TODO: Provide a way to configure the generator from config + if "CONAN_CMAKE_GENERATOR" in os.environ: + return os.environ["CONAN_CMAKE_GENERATOR"] + + compiler = conanfile.settings.get_safe("compiler") + if compiler == "msvc": + toolset = conanfile.settings.get_safe("compiler.toolset") + _visuals = {'140': '14 2015', + '141': '15 2017', + '142': '16 2019'}[toolset] + base = "Visual Studio %s" % _visuals + return base + + compiler_base = conanfile.settings.get_safe("compiler.base") + arch = conanfile.settings.get_safe("arch") + compiler_version = conanfile.settings.get_safe("compiler.version") + compiler_base_version = conanfile.settings.get_safe("compiler.base.version") + os_build, _, _, _ = get_cross_building_settings(conanfile) + + if not compiler or not compiler_version or not arch: + if os_build == "Windows": + logger.warning("CMake generator could not be deduced from settings") + return None + return "Unix Makefiles" + + if compiler == "Visual Studio" or compiler_base == "Visual Studio": + version = compiler_base_version or compiler_version + _visuals = {'8': '8 2005', + '9': '9 2008', + '10': '10 2010', + '11': '11 2012', + '12': '12 2013', + '14': '14 2015', + '15': '15 2017', + '16': '16 2019'}.get(version, "UnknownVersion %s" % version) + base = "Visual Studio %s" % _visuals + return base + + # The generator depends on the build machine, not the target + if os_build == "Windows" and compiler != "qcc": + return "MinGW Makefiles" # it is valid only under Windows + + return "Unix Makefiles" def _validate_recipe(conanfile): diff --git a/conans/client/build/cmake_flags.py b/conans/client/build/cmake_flags.py index 6e99c7d2325..9ee264da0d4 100644 --- a/conans/client/build/cmake_flags.py +++ b/conans/client/build/cmake_flags.py @@ -37,8 +37,6 @@ def get_toolset(settings, generator): def get_generator(conanfile): # Returns the name of the generator to be used by CMake - if "CONAN_CMAKE_GENERATOR" in os.environ: - return os.environ["CONAN_CMAKE_GENERATOR"] compiler = conanfile.settings.get_safe("compiler") compiler_base = conanfile.settings.get_safe("compiler.base") diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py index eaf399c2cf8..c760303de1f 100644 --- a/conans/client/conf/__init__.py +++ b/conans/client/conf/__init__.py @@ -71,6 +71,16 @@ threads: [None, posix, win32] # Windows MinGW exception: [None, dwarf2, sjlj, seh] # Windows MinGW cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] + msvc: + runtime: [static, dynamic] + toolset: + 140: + 141: + version: [None, "1910", "1911", "1912", "1913", "1914", "1915", "1916"] + 142: + version: [None, "1920", "1921", "1922", "1923", "1924", "1925", "1926", + "1927", "1928"] + cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] version: ["8", "9", "10", "11", "12", "14", "15", "16"] diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 2a580624800..736b77835fe 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -238,6 +238,75 @@ def _verify_out(marker=">>"): self._incremental_build(build_type=opposite_build_type) self._run_app(opposite_build_type, bin_folder=True, msg="AppImproved") + @parameterized.expand([("Debug", "static", "141", "14", "x86", True), + ("Release", "dynamic", "141", "17", "x86_64", False)]) + def test_toolchain_win_msvc(self, build_type, runtime, toolset, cppstd, arch, shared): + settings = {"compiler": "msvc", + "compiler.toolset": toolset, + "compiler.runtime": runtime, + "compiler.cppstd": cppstd, + "arch": arch, + "build_type": build_type, + } + options = {"shared": shared} + install_out = self._run_build(settings, options) + self.assertIn("WARN: Toolchain: Ignoring fPIC option defined for Windows", install_out) + + # FIXME: Hardcoded VS version and partial toolset check + self.assertIn('CMake command: cmake -G "Visual Studio 15 2017" ' + '-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', self.client.out) + self.assertIn("Microsoft Visual Studio/2017", self.client.out) + + runtime = "MT" if runtime == "static" else "MD" + generator_platform = "x64" if arch == "x86_64" else "Win32" + arch = "x64" if arch == "x86_64" else "X86" + shared_str = "ON" if shared else "OFF" + vals = {"CMAKE_GENERATOR_PLATFORM": generator_platform, + "CMAKE_BUILD_TYPE": "", + "CMAKE_CXX_FLAGS": "/MP1 /DWIN32 /D_WINDOWS /W3 /GR /EHsc", + "CMAKE_CXX_FLAGS_DEBUG": "/%sd /Zi /Ob0 /Od /RTC1" % runtime, + "CMAKE_CXX_FLAGS_RELEASE": "/%s /O2 /Ob2 /DNDEBUG" % runtime, + "CMAKE_C_FLAGS": "/MP1 /DWIN32 /D_WINDOWS /W3", + "CMAKE_C_FLAGS_DEBUG": "/%sd /Zi /Ob0 /Od /RTC1" % runtime, + "CMAKE_C_FLAGS_RELEASE": "/%s /O2 /Ob2 /DNDEBUG" % runtime, + "CMAKE_SHARED_LINKER_FLAGS": "/machine:%s" % arch, + "CMAKE_EXE_LINKER_FLAGS": "/machine:%s" % arch, + "CMAKE_CXX_STANDARD": cppstd, + "CMAKE_CXX_EXTENSIONS": "OFF", + "BUILD_SHARED_LIBS": shared_str} + + def _verify_out(marker=">>"): + if shared: + self.assertIn("app_lib.dll", self.client.out) + else: + self.assertNotIn("app_lib.dll", self.client.out) + + out = str(self.client.out).splitlines() + for k, v in vals.items(): + self.assertIn("%s %s: %s" % (marker, k, v), out) + + _verify_out() + + toolchain = self.client.load("build/conan_toolchain.cmake") + include = self.client.load("build/conan_project_include.cmake") + opposite_build_type = "Release" if build_type == "Debug" else "Debug" + settings["build_type"] = opposite_build_type + self._run_build(settings, options) + # The generated toolchain files must be identical because it is a multi-config + self.assertEqual(toolchain, self.client.load("build/conan_toolchain.cmake")) + self.assertEqual(include, self.client.load("build/conan_project_include.cmake")) + + self._run_app("Release", bin_folder=True) + self._run_app("Debug", bin_folder=True) + + self._modify_code() + time.sleep(1) + self._incremental_build(build_type=build_type) + _verify_out(marker="++>>") + self._run_app(build_type, bin_folder=True, msg="AppImproved") + self._incremental_build(build_type=opposite_build_type) + self._run_app(opposite_build_type, bin_folder=True, msg="AppImproved") + @parameterized.expand([("Debug", "libstdc++", "4.9", "98", "x86_64", True), ("Release", "libstdc++", "4.9", "11", "x86_64", False)]) def test_toolchain_mingw_win(self, build_type, libcxx, version, cppstd, arch, shared): From 72f6bee298d8c492746890b4a8c344b837be53db Mon Sep 17 00:00:00 2001 From: memsharded Date: Sat, 12 Dec 2020 22:52:53 +0100 Subject: [PATCH 02/32] preliminary support for msvc compiler --- conan/tools/cmake/generic.py | 9 ++- conan/tools/cmake/utils.py | 10 ++- conans/client/conf/__init__.py | 8 +- .../test/integration/toolchains/test_cmake.py | 81 ++----------------- 4 files changed, 27 insertions(+), 81 deletions(-) diff --git a/conan/tools/cmake/generic.py b/conan/tools/cmake/generic.py index b1ebcf1c516..6fef03abccc 100644 --- a/conan/tools/cmake/generic.py +++ b/conan/tools/cmake/generic.py @@ -40,7 +40,7 @@ def get_generator_platform(settings, generator): if settings.get_safe("os") == "WindowsCE": return settings.get_safe("os.platform") - if (compiler == "Visual Studio" or compiler_base == "Visual Studio") and \ + if (compiler in ("Visual Studio", "msvc") or compiler_base == "Visual Studio") and \ generator and "Visual" in generator: return {"x86": "Win32", "x86_64": "x64", @@ -221,8 +221,11 @@ def _get_architecture(self): def _deduce_vs_static_runtime(self): settings = self._conanfile.settings - if (settings.get_safe("compiler") == "Visual Studio" and - "MT" in settings.get_safe("compiler.runtime")): + compiler = settings.get_safe("compiler") + runtime = settings.get_safe("compiler.runtime") + if compiler == "Visual Studio" and "MT" in runtime: + return True + if compiler == "msvc" and runtime == "static": return True return False diff --git a/conan/tools/cmake/utils.py b/conan/tools/cmake/utils.py index f8e94138900..95790221ac5 100644 --- a/conan/tools/cmake/utils.py +++ b/conan/tools/cmake/utils.py @@ -47,9 +47,17 @@ def get_generator(conanfile): return os.environ["CONAN_CMAKE_GENERATOR"] compiler = conanfile.settings.get_safe("compiler") + compiler_version = conanfile.settings.get_safe("compiler.version") + if compiler == "msvc": + _visuals = {'140': '14 2015', + '141': '15 2017', + '142': '16 2019'}[compiler_version] + base = "Visual Studio %s" % _visuals + return base + compiler_base = conanfile.settings.get_safe("compiler.base") arch = conanfile.settings.get_safe("arch") - compiler_version = conanfile.settings.get_safe("compiler.version") + compiler_base_version = conanfile.settings.get_safe("compiler.base.version") if hasattr(conanfile, 'settings_build'): os_build = conanfile.settings_build.get_safe('os') diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py index c760303de1f..efc3fb67e6e 100644 --- a/conans/client/conf/__init__.py +++ b/conans/client/conf/__init__.py @@ -73,13 +73,13 @@ cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] msvc: runtime: [static, dynamic] - toolset: + version: 140: 141: - version: [None, "1910", "1911", "1912", "1913", "1914", "1915", "1916"] + mscver: [None, "1910", "1911", "1912", "1913", "1914", "1915", "1916"] 142: - version: [None, "1920", "1921", "1922", "1923", "1924", "1925", "1926", - "1927", "1928"] + mscver: [None, "1920", "1921", "1922", "1923", "1924", "1925", "1926", + "1927", "1928"] cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 736b77835fe..8557a7a75da 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -165,10 +165,14 @@ def _run_app(self, build_type, bin_folder=False, msg="App", dyld_path=None): @unittest.skipUnless(platform.system() == "Windows", "Only for windows") class WinTest(Base): - @parameterized.expand([("Debug", "MTd", "15", "14", "x86", "v140", True), - ("Release", "MD", "15", "17", "x86_64", "", False)]) - def test_toolchain_win(self, build_type, runtime, version, cppstd, arch, toolset, shared): - settings = {"compiler": "Visual Studio", + @parameterized.expand([("Visual Studio", "Debug", "MTd", "15", "14", "x86", "v140", True), + ("Visual Studio", "Release", "MD", "15", "17", "x86_64", "", False), + ("msvc", "Debug", "static", "141", "14", "x86", None, True), + ("msvc", "Release", "dynamic", "141", "17", "x86_64", None, False)] + ) + def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arch, toolset, + shared): + settings = {"compiler": compiler, "compiler.version": version, "compiler.toolset": toolset, "compiler.runtime": runtime, @@ -238,75 +242,6 @@ def _verify_out(marker=">>"): self._incremental_build(build_type=opposite_build_type) self._run_app(opposite_build_type, bin_folder=True, msg="AppImproved") - @parameterized.expand([("Debug", "static", "141", "14", "x86", True), - ("Release", "dynamic", "141", "17", "x86_64", False)]) - def test_toolchain_win_msvc(self, build_type, runtime, toolset, cppstd, arch, shared): - settings = {"compiler": "msvc", - "compiler.toolset": toolset, - "compiler.runtime": runtime, - "compiler.cppstd": cppstd, - "arch": arch, - "build_type": build_type, - } - options = {"shared": shared} - install_out = self._run_build(settings, options) - self.assertIn("WARN: Toolchain: Ignoring fPIC option defined for Windows", install_out) - - # FIXME: Hardcoded VS version and partial toolset check - self.assertIn('CMake command: cmake -G "Visual Studio 15 2017" ' - '-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', self.client.out) - self.assertIn("Microsoft Visual Studio/2017", self.client.out) - - runtime = "MT" if runtime == "static" else "MD" - generator_platform = "x64" if arch == "x86_64" else "Win32" - arch = "x64" if arch == "x86_64" else "X86" - shared_str = "ON" if shared else "OFF" - vals = {"CMAKE_GENERATOR_PLATFORM": generator_platform, - "CMAKE_BUILD_TYPE": "", - "CMAKE_CXX_FLAGS": "/MP1 /DWIN32 /D_WINDOWS /W3 /GR /EHsc", - "CMAKE_CXX_FLAGS_DEBUG": "/%sd /Zi /Ob0 /Od /RTC1" % runtime, - "CMAKE_CXX_FLAGS_RELEASE": "/%s /O2 /Ob2 /DNDEBUG" % runtime, - "CMAKE_C_FLAGS": "/MP1 /DWIN32 /D_WINDOWS /W3", - "CMAKE_C_FLAGS_DEBUG": "/%sd /Zi /Ob0 /Od /RTC1" % runtime, - "CMAKE_C_FLAGS_RELEASE": "/%s /O2 /Ob2 /DNDEBUG" % runtime, - "CMAKE_SHARED_LINKER_FLAGS": "/machine:%s" % arch, - "CMAKE_EXE_LINKER_FLAGS": "/machine:%s" % arch, - "CMAKE_CXX_STANDARD": cppstd, - "CMAKE_CXX_EXTENSIONS": "OFF", - "BUILD_SHARED_LIBS": shared_str} - - def _verify_out(marker=">>"): - if shared: - self.assertIn("app_lib.dll", self.client.out) - else: - self.assertNotIn("app_lib.dll", self.client.out) - - out = str(self.client.out).splitlines() - for k, v in vals.items(): - self.assertIn("%s %s: %s" % (marker, k, v), out) - - _verify_out() - - toolchain = self.client.load("build/conan_toolchain.cmake") - include = self.client.load("build/conan_project_include.cmake") - opposite_build_type = "Release" if build_type == "Debug" else "Debug" - settings["build_type"] = opposite_build_type - self._run_build(settings, options) - # The generated toolchain files must be identical because it is a multi-config - self.assertEqual(toolchain, self.client.load("build/conan_toolchain.cmake")) - self.assertEqual(include, self.client.load("build/conan_project_include.cmake")) - - self._run_app("Release", bin_folder=True) - self._run_app("Debug", bin_folder=True) - - self._modify_code() - time.sleep(1) - self._incremental_build(build_type=build_type) - _verify_out(marker="++>>") - self._run_app(build_type, bin_folder=True, msg="AppImproved") - self._incremental_build(build_type=opposite_build_type) - self._run_app(opposite_build_type, bin_folder=True, msg="AppImproved") - @parameterized.expand([("Debug", "libstdc++", "4.9", "98", "x86_64", True), ("Release", "libstdc++", "4.9", "11", "x86_64", False)]) def test_toolchain_mingw_win(self, build_type, libcxx, version, cppstd, arch, shared): From 369143b47b43a8e9d865b35881c6ad761dcd2c52 Mon Sep 17 00:00:00 2001 From: memsharded Date: Sun, 13 Dec 2020 00:45:42 +0100 Subject: [PATCH 03/32] fix migration --- conans/client/migrations_settings.py | 110 +++++++++++++++++- .../test/integration/toolchains/test_cmake.py | 30 ++--- 2 files changed, 124 insertions(+), 16 deletions(-) diff --git a/conans/client/migrations_settings.py b/conans/client/migrations_settings.py index 4f16d879064..e4540bda693 100644 --- a/conans/client/migrations_settings.py +++ b/conans/client/migrations_settings.py @@ -1819,4 +1819,112 @@ settings_1_32_0 = settings_1_31_4 -settings_1_33_0 = settings_1_32_0 +settings_1_33_0 = """ +# Only for cross building, 'os_build/arch_build' is the system that runs Conan +os_build: [Windows, WindowsStore, Linux, Macos, FreeBSD, SunOS, AIX] +arch_build: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, sh4le] + +# Only for building cross compilation tools, 'os_target/arch_target' is the system for +# which the tools generate code +os_target: [Windows, Linux, Macos, Android, iOS, watchOS, tvOS, FreeBSD, SunOS, AIX, Arduino, Neutrino] +arch_target: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, asm.js, wasm, sh4le] + +# Rest of the settings are "host" settings: +# - For native building/cross building: Where the library/program will run. +# - For building cross compilation tools: Where the cross compiler will run. +os: + Windows: + subsystem: [None, cygwin, msys, msys2, wsl] + WindowsStore: + version: ["8.1", "10.0"] + WindowsCE: + platform: ANY + version: ["5.0", "6.0", "7.0", "8.0"] + Linux: + Macos: + version: [None, "10.6", "10.7", "10.8", "10.9", "10.10", "10.11", "10.12", "10.13", "10.14", "10.15", "11.0"] + Android: + api_level: ANY + iOS: + version: ["7.0", "7.1", "8.0", "8.1", "8.2", "8.3", "9.0", "9.1", "9.2", "9.3", "10.0", "10.1", "10.2", "10.3", "11.0", "11.1", "11.2", "11.3", "11.4", "12.0", "12.1", "12.2", "12.3", "12.4", "13.0", "13.1", "13.2", "13.3", "13.4", "13.5", "13.6"] + watchOS: + version: ["4.0", "4.1", "4.2", "4.3", "5.0", "5.1", "5.2", "5.3", "6.0", "6.1"] + tvOS: + version: ["11.0", "11.1", "11.2", "11.3", "11.4", "12.0", "12.1", "12.2", "12.3", "12.4", "13.0"] + FreeBSD: + SunOS: + AIX: + Arduino: + board: ANY + Emscripten: + Neutrino: + version: ["6.4", "6.5", "6.6", "7.0", "7.1"] +arch: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv4, armv4i, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, asm.js, wasm, sh4le] +compiler: + sun-cc: + version: ["5.10", "5.11", "5.12", "5.13", "5.14", "5.15"] + threads: [None, posix] + libcxx: [libCstd, libstdcxx, libstlport, libstdc++] + gcc: &gcc + version: ["4.1", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", + "5", "5.1", "5.2", "5.3", "5.4", "5.5", + "6", "6.1", "6.2", "6.3", "6.4", "6.5", + "7", "7.1", "7.2", "7.3", "7.4", "7.5", + "8", "8.1", "8.2", "8.3", "8.4", + "9", "9.1", "9.2", "9.3", + "10", "10.1"] + libcxx: [libstdc++, libstdc++11] + threads: [None, posix, win32] # Windows MinGW + exception: [None, dwarf2, sjlj, seh] # Windows MinGW + cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] + msvc: + runtime: [static, dynamic] + version: + 140: + 141: + mscver: [None, "1910", "1911", "1912", "1913", "1914", "1915", "1916"] + 142: + mscver: [None, "1920", "1921", "1922", "1923", "1924", "1925", "1926", + "1927", "1928"] + cppstd: [None, 14, 17, 20] + Visual Studio: &visual_studio + runtime: [MD, MT, MTd, MDd] + version: ["8", "9", "10", "11", "12", "14", "15", "16"] + toolset: [None, v90, v100, v110, v110_xp, v120, v120_xp, + v140, v140_xp, v140_clang_c2, LLVM-vs2012, LLVM-vs2012_xp, + LLVM-vs2013, LLVM-vs2013_xp, LLVM-vs2014, LLVM-vs2014_xp, + LLVM-vs2017, LLVM-vs2017_xp, v141, v141_xp, v141_clang_c2, v142, + llvm, ClangCL] + cppstd: [None, 14, 17, 20] + clang: + version: ["3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", + "5.0", "6.0", "7.0", "7.1", + "8", "9", "10", "11"] + libcxx: [None, libstdc++, libstdc++11, libc++, c++_shared, c++_static] + cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] + runtime: [None, MD, MT, MTd, MDd] + apple-clang: &apple_clang + version: ["5.0", "5.1", "6.0", "6.1", "7.0", "7.3", "8.0", "8.1", "9.0", "9.1", "10.0", "11.0", "12.0"] + libcxx: [libstdc++, libc++] + cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] + intel: + version: ["11", "12", "13", "14", "15", "16", "17", "18", "19", "19.1"] + base: + gcc: + <<: *gcc + threads: [None] + exception: [None] + Visual Studio: + <<: *visual_studio + apple-clang: + <<: *apple_clang + qcc: + version: ["4.4", "5.4", "8.3"] + libcxx: [cxx, gpp, cpp, cpp-ne, accp, acpp-ne, ecpp, ecpp-ne] + cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17] + +build_type: [None, Debug, Release, RelWithDebInfo, MinSizeRel] + + +cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] # Deprecated, use compiler.cppstd +""" diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 8557a7a75da..d134a59098f 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -192,7 +192,7 @@ def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arc else: self.assertIn("Microsoft Visual Studio/2017", self.client.out) - runtime = "MT" if "MT" in runtime else "MD" + runtime = "MT" if "MT" in runtime or runtime == "static" else "MD" generator_platform = "x64" if arch == "x86_64" else "Win32" arch = "x64" if arch == "x86_64" else "X86" shared_str = "ON" if shared else "OFF" @@ -260,26 +260,26 @@ def test_toolchain_mingw_win(self, build_type, libcxx, version, cppstd, arch, sh '-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', self.client.out) def _verify_out(marker=">>"): - vars = {"CMAKE_GENERATOR_PLATFORM": "", - "CMAKE_BUILD_TYPE": build_type, - "CMAKE_CXX_FLAGS": "-m64", - "CMAKE_CXX_FLAGS_DEBUG": "-g", - "CMAKE_CXX_FLAGS_RELEASE": "-O3 -DNDEBUG", - "CMAKE_C_FLAGS": "-m64", - "CMAKE_C_FLAGS_DEBUG": "-g", - "CMAKE_C_FLAGS_RELEASE": "-O3 -DNDEBUG", - "CMAKE_SHARED_LINKER_FLAGS": "-m64", - "CMAKE_EXE_LINKER_FLAGS": "-m64", - "CMAKE_CXX_STANDARD": cppstd, - "CMAKE_CXX_EXTENSIONS": "OFF", - "BUILD_SHARED_LIBS": "ON" if shared else "OFF"} + cmake_vars = {"CMAKE_GENERATOR_PLATFORM": "", + "CMAKE_BUILD_TYPE": build_type, + "CMAKE_CXX_FLAGS": "-m64", + "CMAKE_CXX_FLAGS_DEBUG": "-g", + "CMAKE_CXX_FLAGS_RELEASE": "-O3 -DNDEBUG", + "CMAKE_C_FLAGS": "-m64", + "CMAKE_C_FLAGS_DEBUG": "-g", + "CMAKE_C_FLAGS_RELEASE": "-O3 -DNDEBUG", + "CMAKE_SHARED_LINKER_FLAGS": "-m64", + "CMAKE_EXE_LINKER_FLAGS": "-m64", + "CMAKE_CXX_STANDARD": cppstd, + "CMAKE_CXX_EXTENSIONS": "OFF", + "BUILD_SHARED_LIBS": "ON" if shared else "OFF"} if shared: self.assertIn("app_lib.dll", self.client.out) else: self.assertNotIn("app_lib.dll", self.client.out) out = str(self.client.out).splitlines() - for k, v in vars.items(): + for k, v in cmake_vars.items(): self.assertIn("%s %s: %s" % (marker, k, v), out) _verify_out() From 49dad8558824534f088dd67b210b06a087141741 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 14 Dec 2020 01:33:22 +0100 Subject: [PATCH 04/32] adding msvc for msbuild toolchain --- conan/tools/microsoft/msbuild.py | 5 +++++ conan/tools/microsoft/toolchain.py | 18 ++++++++++++++---- conans/client/tools/win.py | 5 ++++- .../integration/toolchains/test_msbuild.py | 13 +++++++++---- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/conan/tools/microsoft/msbuild.py b/conan/tools/microsoft/msbuild.py index e4aca1e47a5..21e06ef2f15 100644 --- a/conan/tools/microsoft/msbuild.py +++ b/conan/tools/microsoft/msbuild.py @@ -8,6 +8,11 @@ def __init__(self, conanfile): self.compiler = conanfile.settings.get_safe("compiler") self.version = conanfile.settings.get_safe("compiler.base.version") or \ conanfile.settings.get_safe("compiler.version") + if self.compiler == "msvc": + _visuals = {'140': '14', # TODO: This is common to CMake, refactor + '141': '15', + '142': '16'} + self.version = _visuals[self.version] self.vcvars_arch = vcvars_arch(conanfile) self.build_type = conanfile.settings.get_safe("build_type") msvc_arch = {'x86': 'x86', diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index bdb5dacc2a9..0ee246e1467 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -53,13 +53,23 @@ def _write_config_toolchain(self, config_filename): def format_macro(k, value): return '%s="%s"' % (k, value) if value is not None else k + compiler = self._conanfile.settings.get_safe("compiler") runtime = self._conanfile.settings.get_safe("compiler.runtime") cppstd = self._conanfile.settings.get_safe("compiler.cppstd") toolset = msvs_toolset(self._conanfile.settings) - runtime_library = {"MT": "MultiThreaded", - "MTd": "MultiThreadedDebug", - "MD": "MultiThreadedDLL", - "MDd": "MultiThreadedDebugDLL"}.get(runtime, "") + if compiler == "msvc": + build_type = self._conanfile.settings.get_safe("build_type") + if build_type == "Debug": + runtime_library = {"static": "MultiThreaded", + "dyanmic": "MultiThreadedDLL"}.get(runtime, "") + else: + runtime_library = {"static": "MultiThreadedDebug", + "dyanmic": "MultiThreadedDebugDLL"}.get(runtime, "") + else: + runtime_library = {"MT": "MultiThreaded", + "MTd": "MultiThreadedDebug", + "MD": "MultiThreadedDLL", + "MDd": "MultiThreadedDebugDLL"}.get(runtime, "") content = textwrap.dedent("""\ diff --git a/conans/client/tools/win.py b/conans/client/tools/win.py index ce9b056332b..146010b42cb 100644 --- a/conans/client/tools/win.py +++ b/conans/client/tools/win.py @@ -138,11 +138,14 @@ def msvs_toolset(conanfile): settings = conanfile toolset = settings.get_safe("compiler.toolset") if not toolset: + compiler = settings.get_safe("compiler") compiler_version = settings.get_safe("compiler.version") - if settings.get_safe("compiler") == "intel": + if compiler == "intel": compiler_version = compiler_version if "." in compiler_version else \ "%s.0" % compiler_version toolset = "Intel C++ Compiler " + compiler_version + elif compiler == "msvc": + toolset = "v{}".format(compiler_version) else: toolset = MSVS_DEFAULT_TOOLSETS.get(compiler_version) return toolset diff --git a/conans/test/integration/toolchains/test_msbuild.py b/conans/test/integration/toolchains/test_msbuild.py index b7df26f1101..5186492488f 100644 --- a/conans/test/integration/toolchains/test_msbuild.py +++ b/conans/test/integration/toolchains/test_msbuild.py @@ -5,6 +5,7 @@ import unittest import pytest +from parameterized import parameterized from conan.tools.microsoft.visual import vcvars_command from conans.client.tools import vs_installation_path @@ -266,12 +267,15 @@ def _run_app(self, client, arch, build_type, msg="main"): self.assertIn("DEFINITIONS_CONFIG: %s" % build_type, client.out) @pytest.mark.tool_cmake - def test_toolchain_win(self): + @parameterized.expand([("Visual Studio", "15", "MT"), + ("msvc", "141", "static")] + ) + def test_toolchain_win(self, compiler, version, runtime): client = TestClient(path_with_spaces=False) - settings = {"compiler": "Visual Studio", - "compiler.version": "15", + settings = {"compiler": compiler, + "compiler.version": version, "compiler.cppstd": "17", - "compiler.runtime": "MT", + "compiler.runtime": runtime, "build_type": "Release", "arch": "x86"} @@ -280,6 +284,7 @@ def test_toolchain_win(self): client.run("new hello/0.1 -s") client.run("create . hello/0.1@ %s" % (settings, )) + print(client.out) # Prepare the actual consumer package client.save({"conanfile.py": self.conanfile, From fb110ba3efa127a09fc58e7d221bb6de1d9be9d1 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 15 Dec 2020 13:49:49 +0100 Subject: [PATCH 05/32] changing to version 19.1, 19.11, etc --- conan/tools/cmake/utils.py | 7 ++++--- conans/client/conf/__init__.py | 10 +++------- conans/client/migrations_settings.py | 10 +++------- conans/test/integration/toolchains/test_cmake.py | 4 ++-- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/conan/tools/cmake/utils.py b/conan/tools/cmake/utils.py index 95790221ac5..c525e659fa9 100644 --- a/conan/tools/cmake/utils.py +++ b/conan/tools/cmake/utils.py @@ -49,9 +49,10 @@ def get_generator(conanfile): compiler = conanfile.settings.get_safe("compiler") compiler_version = conanfile.settings.get_safe("compiler.version") if compiler == "msvc": - _visuals = {'140': '14 2015', - '141': '15 2017', - '142': '16 2019'}[compiler_version] + version = compiler_version[:4] # Remove the latest version number 19.1X if existing + _visuals = {'19.0': '14 2015', + '19.1': '15 2017', + '19.2': '16 2019'}[version] base = "Visual Studio %s" % _visuals return base diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py index efc3fb67e6e..6bbb2da8b7c 100644 --- a/conans/client/conf/__init__.py +++ b/conans/client/conf/__init__.py @@ -72,14 +72,10 @@ exception: [None, dwarf2, sjlj, seh] # Windows MinGW cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] msvc: + version: ["19.0", + "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16", + "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"] runtime: [static, dynamic] - version: - 140: - 141: - mscver: [None, "1910", "1911", "1912", "1913", "1914", "1915", "1916"] - 142: - mscver: [None, "1920", "1921", "1922", "1923", "1924", "1925", "1926", - "1927", "1928"] cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] diff --git a/conans/client/migrations_settings.py b/conans/client/migrations_settings.py index e4540bda693..0481a37d21f 100644 --- a/conans/client/migrations_settings.py +++ b/conans/client/migrations_settings.py @@ -1878,14 +1878,10 @@ exception: [None, dwarf2, sjlj, seh] # Windows MinGW cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] msvc: + version: ["19.0", + "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16", + "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"] runtime: [static, dynamic] - version: - 140: - 141: - mscver: [None, "1910", "1911", "1912", "1913", "1914", "1915", "1916"] - 142: - mscver: [None, "1920", "1921", "1922", "1923", "1924", "1925", "1926", - "1927", "1928"] cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index d134a59098f..4f5bc25f661 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -167,8 +167,8 @@ def _run_app(self, build_type, bin_folder=False, msg="App", dyld_path=None): class WinTest(Base): @parameterized.expand([("Visual Studio", "Debug", "MTd", "15", "14", "x86", "v140", True), ("Visual Studio", "Release", "MD", "15", "17", "x86_64", "", False), - ("msvc", "Debug", "static", "141", "14", "x86", None, True), - ("msvc", "Release", "dynamic", "141", "17", "x86_64", None, False)] + ("msvc", "Debug", "static", "19.1", "14", "x86", None, True), + ("msvc", "Release", "dynamic", "19.11", "17", "x86_64", None, False)] ) def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arch, toolset, shared): From cfc28fe6e43ee01517e820f0624828929be9a3b4 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 02:27:00 +0100 Subject: [PATCH 06/32] working on static/dynamic runtime --- conan/tools/cmake/base.py | 18 +---- conan/tools/cmake/generic.py | 72 ++++++++++--------- conans/client/conf/__init__.py | 1 + conans/client/settings_preprocessor.py | 7 +- .../test/integration/toolchains/test_cmake.py | 5 +- 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/conan/tools/cmake/base.py b/conan/tools/cmake/base.py index a9b1b6f6361..b025e580c3b 100644 --- a/conan/tools/cmake/base.py +++ b/conan/tools/cmake/base.py @@ -85,22 +85,8 @@ class CMakeToolchainBase(object): message("Using Conan toolchain through ${CMAKE_TOOLCHAIN_FILE}.") {% if conan_project_include_cmake %} - if(CMAKE_VERSION VERSION_LESS "3.15") - message(WARNING - " CMake version less than 3.15 doesn't support CMAKE_PROJECT_INCLUDE variable\\n" - " used by Conan toolchain to work. In order to get the same behavior you will\\n" - " need to manually include the generated file after your 'project()' call in the\\n" - " main CMakeLists.txt file:\\n" - " \\n" - " project(YourProject C CXX)\\n" - " include(\\"\\${CMAKE_BINARY_DIR}/conan_project_include.cmake\\")\\n" - " \\n" - " This file contains some definitions and extra adjustments that depend on\\n" - " the build_type and it cannot be done in the toolchain.") - else() - # Will be executed after the 'project()' command - set(CMAKE_PROJECT_INCLUDE "{{ conan_project_include_cmake }}") - endif() + # Will be executed after the 'project()' command + set(CMAKE_PROJECT_INCLUDE "{{ conan_project_include_cmake }}") {% endif %} {% block main %} diff --git a/conan/tools/cmake/generic.py b/conan/tools/cmake/generic.py index 6fef03abccc..433962a44db 100644 --- a/conan/tools/cmake/generic.py +++ b/conan/tools/cmake/generic.py @@ -1,7 +1,9 @@ import os +import re import textwrap from conans.client.tools import cpu_count +from conans.util.files import load from conans.errors import ConanException from conan.tools.cmake.base import CMakeToolchainBase from conan.tools.cmake.utils import get_generator, is_multi_configuration, architecture_flag @@ -123,32 +125,16 @@ class CMakeGenericToolchain(CMakeToolchainBase): message(FATAL_ERROR "This file is expected to be used together with the Conan toolchain") endif() - ########### Utility macros and functions ########### - function(conan_get_policy policy_id policy) - if(POLICY "${policy_id}") - cmake_policy(GET "${policy_id}" _policy) - set(${policy} "${_policy}" PARENT_SCOPE) - else() - set(${policy} "" PARENT_SCOPE) - endif() - endfunction() - ########### End of Utility macros and functions ########### - - # Adjustments that depends on the build_type - {% if vs_static_runtime %} - conan_get_policy(CMP0091 policy_0091) - if(policy_0091 STREQUAL "NEW") - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - else() - foreach(flag CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE - CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO - CMAKE_C_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL - CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG) - if(DEFINED ${flag}) - string(REPLACE "/MD" "/MT" ${flag} "${${flag}}") - endif() - endforeach() - endif() + message(STATUS "Using CMAKE_PROJECT_INCLUDE included file") + + # Adjustments that depends on the build_type/configuration + {% if vs_runtimes %} + {% set genexpr = namespace(str='') %} + {%- for config, value in vs_runtimes.items() -%} + {%- set genexpr.str = genexpr.str + + '$<$' + value|string + '>' %} + {%- endfor -%} + set(CMAKE_MSVC_RUNTIME_LIBRARY "{{ genexpr.str }}") {% endif %} """) @@ -157,7 +143,7 @@ def __init__(self, conanfile, generator=None, generator_platform=None, build_typ super(CMakeGenericToolchain, self).__init__(conanfile) self.fpic = self._deduce_fpic() - self.vs_static_runtime = self._deduce_vs_static_runtime() + self.vs_runtimes = self._runtimes() self.parallel = parallel self.generator = generator or get_generator(self._conanfile) @@ -219,15 +205,33 @@ def _get_architecture(self): # This should be factorized and make it toolchain-private return architecture_flag(self._conanfile.settings) - def _deduce_vs_static_runtime(self): + def _runtimes(self): + # Parsing existing file to get existing configured runtimes + config_dict = {} + if os.path.exists(self.project_include_filename): + existing_include = load(self.project_include_filename) + existing_configs = re.search(r"set\(CMAKE_MSVC_RUNTIME_LIBRARY \"([^)]*)\"\)", + existing_include) + capture = existing_configs.group(1) + matches = re.findall(r"\$<\$([A-Za-z]*)>", capture) + config_dict = dict(matches) + settings = self._conanfile.settings compiler = settings.get_safe("compiler") + build_type = settings.get_safe("build_type") # FIXME: change for configuration runtime = settings.get_safe("compiler.runtime") - if compiler == "Visual Studio" and "MT" in runtime: - return True - if compiler == "msvc" and runtime == "static": - return True - return False + if compiler == "Visual Studio": + config_dict[build_type] = {"MT": "MultiThreaded", + "MTd": "MultiThreadedDebug", + "MD": "MultiThreadedDLL", + "MDd": "MultiThreadedDebugDLL"}[runtime] + if compiler == "msvc": + runtime_type = settings.get_safe("compiler.runtime_type") + rt = "MultiThreadedDebug" if runtime_type == "Debug" else "MultiThreaded" + if runtime != "static": + rt += "DLL" + config_dict[build_type] = rt + return config_dict def _get_libcxx(self): libcxx = self._conanfile.settings.get_safe("compiler.libcxx") @@ -288,5 +292,5 @@ def _get_template_context_data(self): "architecture": self.architecture, "compiler": self.compiler }) - ctxt_project_include.update({'vs_static_runtime': self.vs_static_runtime}) + ctxt_project_include.update({'vs_runtimes': self.vs_runtimes}) return ctxt_toolchain, ctxt_project_include diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py index 6bbb2da8b7c..8602b5f9c54 100644 --- a/conans/client/conf/__init__.py +++ b/conans/client/conf/__init__.py @@ -76,6 +76,7 @@ "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16", "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"] runtime: [static, dynamic] + runtime_type: [Debug, Release] cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] diff --git a/conans/client/settings_preprocessor.py b/conans/client/settings_preprocessor.py index 83db56048d1..8730b765959 100644 --- a/conans/client/settings_preprocessor.py +++ b/conans/client/settings_preprocessor.py @@ -49,17 +49,22 @@ def check_flag_available(values_range, value, setting_id): def _fill_runtime(settings): try: - runtime = "MDd" if settings.get_safe("build_type") == "Debug" else "MD" if settings.compiler == "Visual Studio": if settings.get_safe("compiler.runtime") is None: + runtime = "MDd" if settings.get_safe("build_type") == "Debug" else "MD" settings.compiler.runtime = runtime msg = "Setting 'compiler.runtime' not declared, automatically adjusted to '%s'" logger.info(msg % runtime) elif settings.compiler == "intel" and settings.get_safe("compiler.base") == "Visual Studio": if settings.get_safe("compiler.base.runtime") is None: + runtime = "MDd" if settings.get_safe("build_type") == "Debug" else "MD" settings.compiler.base.runtime = runtime msg = "Setting 'compiler.base.runtime' not declared, automatically adjusted to '%s'" logger.info(msg % runtime) + elif settings.compiler == "msvc": + if settings.get_safe("compiler.runtime_type") is None: + runtime = "Debug" if settings.get_safe("build_type") == "Debug" else "Release" + settings.compiler.runtime_type = runtime except Exception: # If the settings structure doesn't match these general # asumptions, like unexistant runtime pass diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 4f5bc25f661..7b2c814e2d4 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -93,6 +93,7 @@ def build(self): def setUp(self): self.client = TestClient(path_with_spaces=True) + print(self.client.current_folder) conanfile = textwrap.dedent(""" from conans import ConanFile from conans.tools import save @@ -193,6 +194,7 @@ def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arc self.assertIn("Microsoft Visual Studio/2017", self.client.out) runtime = "MT" if "MT" in runtime or runtime == "static" else "MD" + runtime = "MD" generator_platform = "x64" if arch == "x86_64" else "Win32" arch = "x64" if arch == "x86_64" else "X86" shared_str = "ON" if shared else "OFF" @@ -229,7 +231,8 @@ def _verify_out(marker=">>"): self._run_build(settings, options) # The generated toolchain files must be identical because it is a multi-config self.assertEqual(toolchain, self.client.load("build/conan_toolchain.cmake")) - self.assertEqual(include, self.client.load("build/conan_project_include.cmake")) + # It is not, the Runtime is added incrementally now + # self.assertEqual(include, self.client.load("build/conan_project_include.cmake")) self._run_app("Release", bin_folder=True) self._run_app("Debug", bin_folder=True) From b245c43e44b2740c07c760ef988ad6f533a2cae7 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 13:20:53 +0100 Subject: [PATCH 07/32] extracting toolchain checkers to use in CMake --- .../test/integration/toolchains/test_cmake.py | 10 ++++++ .../integration/toolchains/test_msbuild.py | 29 +++------------ conans/test/integration/utils.py | 36 +++++++++++++++++++ 3 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 conans/test/integration/utils.py diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 2a580624800..b7e198c7cf8 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -1,5 +1,6 @@ import os import platform +import re import textwrap import time import unittest @@ -10,6 +11,7 @@ from conans.model.ref import ConanFileReference, PackageReference from conans.test.assets.sources import gen_function_cpp, gen_function_h +from conans.test.integration.utils import check_vs_runtime, check_msc_ver from conans.test.utils.tools import TestClient @@ -228,7 +230,15 @@ def _verify_out(marker=">>"): self.assertEqual(include, self.client.load("build/conan_project_include.cmake")) self._run_app("Release", bin_folder=True) + check_msc_ver(toolset or "v141", self.client.out) + self.assertIn("main _MSVC_LANG20{}".format(cppstd), self.client.out) self._run_app("Debug", bin_folder=True) + check_msc_ver(toolset or "v141", self.client.out) + self.assertIn("main _MSVC_LANG20{}".format(cppstd), self.client.out) + check_vs_runtime("build/Release/app.exe", self.client, "15", build_type="Release", + static="MT" in runtime) + check_vs_runtime("build/Debug/app.exe", self.client, "15", build_type="Debug", + static="MT" in runtime) self._modify_code() time.sleep(1) diff --git a/conans/test/integration/toolchains/test_msbuild.py b/conans/test/integration/toolchains/test_msbuild.py index b7df26f1101..581b75865f8 100644 --- a/conans/test/integration/toolchains/test_msbuild.py +++ b/conans/test/integration/toolchains/test_msbuild.py @@ -1,14 +1,13 @@ import os import platform -import re import textwrap import unittest import pytest -from conan.tools.microsoft.visual import vcvars_command from conans.client.tools import vs_installation_path from conans.test.assets.sources import gen_function_cpp +from conans.test.integration.utils import check_vs_runtime, check_msc_ver from conans.test.utils.tools import TestClient @@ -297,17 +296,7 @@ def test_toolchain_win(self): self.assertIn("Visual Studio 2017", client.out) self.assertIn("[vcvarsall.bat] Environment initialized for: 'x86'", client.out) self._run_app(client, "x86", "Release") - version = re.search("main _MSC_VER19([0-9]*)", str(client.out)).group(1) - version = int(version) - self.assertTrue(10 <= version < 20) - self.assertIn("main _MSVC_LANG2017", client.out) - - vcvars = vcvars_command(version="15", architecture="x86") - cmd = ('%s && dumpbin /dependents "Release\\MyApp.exe"' % vcvars) - client.run_command(cmd) - # No other DLLs dependencies rather than kernel, it was MT, statically linked - self.assertIn("KERNEL32.dll", client.out) - self.assertEqual(1, str(client.out).count(".dll")) + check_msc_ver("v141", client.out) @pytest.mark.tool_cmake def test_toolchain_win_debug(self): @@ -340,14 +329,9 @@ def test_toolchain_win_debug(self): self.assertIn("Visual Studio 2017", client.out) self.assertIn("[vcvarsall.bat] Environment initialized for: 'x64'", client.out) self._run_app(client, "x64", "Debug") - self.assertIn("main _MSC_VER1900", client.out) + check_msc_ver("v140", client.out) self.assertIn("main _MSVC_LANG2014", client.out) - - vcvars = vcvars_command(version="15", architecture="amd64") - cmd = ('%s && dumpbin /dependents "x64\\Debug\\MyApp.exe"' % vcvars) - client.run_command(cmd) - self.assertIn("MSVCP140D.dll", client.out) - self.assertIn("VCRUNTIME140D.dll", client.out) + check_vs_runtime("x64/Debug/MyApp.exe", client, "15", static=False, build_type="Debug") @pytest.mark.tool_cmake def test_toolchain_win_multi(self): @@ -389,7 +373,4 @@ def test_toolchain_win_multi(self): self.assertIn("Visual Studio 2017", client.out) self.assertIn("[vcvarsall.bat] Environment initialized for: 'x64'", client.out) self._run_app(client, arch, build_type) - version = re.search("main _MSC_VER19([0-9]*)", str(client.out)).group(1) - version = int(version) - self.assertTrue(10 <= version < 20) - self.assertIn("main _MSVC_LANG2017", client.out) + check_msc_ver("v141", client.out) diff --git a/conans/test/integration/utils.py b/conans/test/integration/utils.py new file mode 100644 index 00000000000..f6f764f2fef --- /dev/null +++ b/conans/test/integration/utils.py @@ -0,0 +1,36 @@ +import re + +from conan.tools.microsoft.visual import vcvars_command + + +def check_vs_runtime(exe, client, vs_version, build_type, static, architecture="amd64"): + vcvars = vcvars_command(version=vs_version, architecture=architecture) + exe = exe.replace("/", "\\") + cmd = ('%s && dumpbin /dependents "%s"' % (vcvars, exe)) + client.run_command(cmd) + + if static: + assert "KERNEL32.dll" in client.out, "Error:{}".format(client.out) + assert "MSVC" not in client.out, "Error:{}".format(client.out) + assert "VCRUNTIME" not in client.out, "Error:{}".format(client.out) + else: + if vs_version == "15": + if build_type == "Debug": + assert "MSVCP140D.dll" in client.out, "Error:{}".format(client.out) + assert "VCRUNTIME140D.dll" in client.out, "Error:{}".format(client.out) + else: + assert "MSVCP140.dll" in client.out, "Error:{}".format(client.out) + assert "VCRUNTIME140.dll" in client.out, "Error:{}".format(client.out) + else: + raise NotImplementedError() + + +def check_msc_ver(toolset, output): + if toolset == "v140": + assert "main _MSC_VER1900" in output, "Error:{}".format(output) + elif toolset == "v141": + version = re.search("main _MSC_VER19([0-9]*)", str(output)).group(1) + version = int(version) + assert 10 <= version < 20, "Error:{}".format(output) + else: + raise NotImplementedError() From c363312ecabf08fcdb4da2cb49bafd0a37a53603 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 13:22:14 +0100 Subject: [PATCH 08/32] removed unused import --- conans/test/integration/toolchains/test_cmake.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index b7e198c7cf8..fa534f7ab69 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -1,6 +1,5 @@ import os import platform -import re import textwrap import time import unittest From fb6b57b147fd961b5f943db5460f593445006d16 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 13:25:38 +0100 Subject: [PATCH 09/32] adding checks --- conans/test/integration/toolchains/test_msbuild.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conans/test/integration/toolchains/test_msbuild.py b/conans/test/integration/toolchains/test_msbuild.py index 581b75865f8..a94fdcac251 100644 --- a/conans/test/integration/toolchains/test_msbuild.py +++ b/conans/test/integration/toolchains/test_msbuild.py @@ -297,6 +297,8 @@ def test_toolchain_win(self): self.assertIn("[vcvarsall.bat] Environment initialized for: 'x86'", client.out) self._run_app(client, "x86", "Release") check_msc_ver("v141", client.out) + self.assertIn("main _MSVC_LANG2017", client.out) + check_vs_runtime("Release/MyApp.exe", client, "15", static=True, build_type="Release") @pytest.mark.tool_cmake def test_toolchain_win_debug(self): From e98d911b7a3b761d2feae19d7973efdf82a9f62c Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 13:27:29 +0100 Subject: [PATCH 10/32] adding check --- conans/test/integration/toolchains/test_msbuild.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conans/test/integration/toolchains/test_msbuild.py b/conans/test/integration/toolchains/test_msbuild.py index a94fdcac251..433f224d469 100644 --- a/conans/test/integration/toolchains/test_msbuild.py +++ b/conans/test/integration/toolchains/test_msbuild.py @@ -376,3 +376,4 @@ def test_toolchain_win_multi(self): self.assertIn("[vcvarsall.bat] Environment initialized for: 'x64'", client.out) self._run_app(client, arch, build_type) check_msc_ver("v141", client.out) + self.assertIn("main _MSVC_LANG2017", client.out) From 3c3a7b32336a820b38cd5bedaf92e027a5d148a8 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 13:39:27 +0100 Subject: [PATCH 11/32] first proposal --- conan/tools/cmake/generic.py | 13 +++++++------ conans/test/functional/generators/cmake_test.py | 1 - conans/test/integration/toolchains/test_cmake.py | 2 -- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/conan/tools/cmake/generic.py b/conan/tools/cmake/generic.py index 433962a44db..60c1ec0dc2e 100644 --- a/conan/tools/cmake/generic.py +++ b/conan/tools/cmake/generic.py @@ -206,15 +206,16 @@ def _get_architecture(self): return architecture_flag(self._conanfile.settings) def _runtimes(self): - # Parsing existing file to get existing configured runtimes + # Parsing existing toolchain file to get existing configured runtimes config_dict = {} if os.path.exists(self.project_include_filename): existing_include = load(self.project_include_filename) - existing_configs = re.search(r"set\(CMAKE_MSVC_RUNTIME_LIBRARY \"([^)]*)\"\)", - existing_include) - capture = existing_configs.group(1) - matches = re.findall(r"\$<\$([A-Za-z]*)>", capture) - config_dict = dict(matches) + msvc_runtime_value = re.search(r"set\(CMAKE_MSVC_RUNTIME_LIBRARY \"([^)]*)\"\)", + existing_include) + if msvc_runtime_value: + capture = msvc_runtime_value.group(1) + matches = re.findall(r"\$<\$([A-Za-z]*)>", capture) + config_dict = dict(matches) settings = self._conanfile.settings compiler = settings.get_safe("compiler") diff --git a/conans/test/functional/generators/cmake_test.py b/conans/test/functional/generators/cmake_test.py index bde04dcd351..cb4a1f964f8 100644 --- a/conans/test/functional/generators/cmake_test.py +++ b/conans/test/functional/generators/cmake_test.py @@ -484,7 +484,6 @@ def build(self): message("comp compile options: ${tmp}") """) run_test("cmake_find_package", cmakelists) - print(client.out) # Test cmake_find_package generator without components run_test("cmake_find_package", cmakelists, with_components=False) diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 02c8458f348..0ddc0d35422 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -94,7 +94,6 @@ def build(self): def setUp(self): self.client = TestClient(path_with_spaces=True) - print(self.client.current_folder) conanfile = textwrap.dedent(""" from conans import ConanFile from conans.tools import save @@ -505,5 +504,4 @@ def build(self): "CMakeLists.txt": cmakelist}) client.run("install .") client.run("build .") - print(client.out) self.assertIn("VALUE OF CONFIG STRING: my new value", client.out) From 3bb3e4da14f1754e4119a772356abbcf4c076faf Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 17:30:13 +0100 Subject: [PATCH 12/32] msvc proposal for runtime --- conan/tools/cmake/android.py | 4 +- conan/tools/cmake/base.py | 19 ++------ conan/tools/cmake/generic.py | 48 +++++++------------ conan/tools/cmake/ios.py | 5 +- .../test/integration/toolchains/test_cmake.py | 33 +++++-------- 5 files changed, 37 insertions(+), 72 deletions(-) diff --git a/conan/tools/cmake/android.py b/conan/tools/cmake/android.py index edaf0599e56..7d7ef390559 100644 --- a/conan/tools/cmake/android.py +++ b/conan/tools/cmake/android.py @@ -82,7 +82,7 @@ def _guess_android_ndk(self): return android_ndk def _get_template_context_data(self): - ctxt_toolchain, _ = super(CMakeAndroidToolchain, self)._get_template_context_data() + ctxt_toolchain = super(CMakeAndroidToolchain, self)._get_template_context_data() ctxt_toolchain.update({ 'CMAKE_SYSTEM_NAME': 'Android', 'CMAKE_SYSTEM_VERSION': self._conanfile.settings.os.api_level, @@ -90,4 +90,4 @@ def _get_template_context_data(self): 'CMAKE_ANDROID_STL_TYPE': self._get_android_stl(), 'CMAKE_ANDROID_NDK': self._guess_android_ndk(), }) - return ctxt_toolchain, {} + return ctxt_toolchain diff --git a/conan/tools/cmake/base.py b/conan/tools/cmake/base.py index b025e580c3b..9dd7710836c 100644 --- a/conan/tools/cmake/base.py +++ b/conan/tools/cmake/base.py @@ -1,4 +1,3 @@ -import os import textwrap import warnings from collections import OrderedDict, defaultdict @@ -33,7 +32,6 @@ def configuration_types(self): class CMakeToolchainBase(object): filename = "conan_toolchain.cmake" - project_include_filename = "conan_project_include.cmake" _toolchain_macros_tpl = textwrap.dedent(""" {% macro iterate_configs(var_config, action) -%} @@ -137,8 +135,7 @@ def _get_templates(self): } def _get_template_context_data(self): - """ Returns two dictionaries, the context for the '_template_toolchain' and - the context for the '_template_project_include' templates. + """ Returns dict, the context for the '_template_toolchain' """ ctxt_toolchain = { "variables": self.variables, @@ -149,7 +146,7 @@ def _get_template_context_data(self): "cmake_module_path": self.cmake_module_path, "build_type": self.build_type, } - return ctxt_toolchain, {} + return ctxt_toolchain def write_toolchain_files(self): # Warning @@ -171,17 +168,7 @@ def generate(self): dict_loader = DictLoader(self._get_templates()) env = Environment(loader=dict_loader) - ctxt_toolchain, ctxt_project_include = self._get_template_context_data() - if ctxt_project_include: - # Make it absolute, wrt to current folder, set by the caller - conan_project_include_cmake = os.path.abspath(self.project_include_filename) - conan_project_include_cmake = conan_project_include_cmake.replace("\\", "/") - t = env.get_template(self.project_include_filename) - content = t.render(**ctxt_project_include) - save(conan_project_include_cmake, content) - - ctxt_toolchain.update({'conan_project_include_cmake': conan_project_include_cmake}) - + ctxt_toolchain = self._get_template_context_data() t = env.get_template(self.filename) content = t.render(**ctxt_toolchain) save(self.filename, content) diff --git a/conan/tools/cmake/generic.py b/conan/tools/cmake/generic.py index 60c1ec0dc2e..a05040fd42b 100644 --- a/conan/tools/cmake/generic.py +++ b/conan/tools/cmake/generic.py @@ -110,6 +110,15 @@ class CMakeGenericToolchain(CMakeToolchainBase): set(CMAKE_CXX_EXTENSIONS {{ cppstd_extensions }}) {%- endif %} + {% if vs_runtimes %} + {% set genexpr = namespace(str='') %} + {%- for config, value in vs_runtimes.items() -%} + {%- set genexpr.str = genexpr.str + + '$<$:' + value|string + '>' %} + {%- endfor -%} + set(CMAKE_MSVC_RUNTIME_LIBRARY "{{ genexpr.str }}") + {% endif %} + set(CMAKE_CXX_FLAGS_INIT "${CONAN_CXX_FLAGS}" CACHE STRING "" FORCE) set(CMAKE_C_FLAGS_INIT "${CONAN_C_FLAGS}" CACHE STRING "" FORCE) set(CMAKE_SHARED_LINKER_FLAGS_INIT "${CONAN_SHARED_LINKER_FLAGS}" CACHE STRING "" FORCE) @@ -117,27 +126,6 @@ class CMakeGenericToolchain(CMakeToolchainBase): {% endblock %} """) - _project_include_filename_tpl = textwrap.dedent(""" - # When using a Conan toolchain, this file is included as the last step of `project()` calls. - # https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_INCLUDE.html - - if (NOT CONAN_TOOLCHAIN_INCLUDED) - message(FATAL_ERROR "This file is expected to be used together with the Conan toolchain") - endif() - - message(STATUS "Using CMAKE_PROJECT_INCLUDE included file") - - # Adjustments that depends on the build_type/configuration - {% if vs_runtimes %} - {% set genexpr = namespace(str='') %} - {%- for config, value in vs_runtimes.items() -%} - {%- set genexpr.str = genexpr.str + - '$<$' + value|string + '>' %} - {%- endfor -%} - set(CMAKE_MSVC_RUNTIME_LIBRARY "{{ genexpr.str }}") - {% endif %} - """) - def __init__(self, conanfile, generator=None, generator_platform=None, build_type=None, toolset=None, parallel=True): super(CMakeGenericToolchain, self).__init__(conanfile) @@ -181,8 +169,7 @@ def __init__(self, conanfile, generator=None, generator_platform=None, build_typ def _get_templates(self): templates = super(CMakeGenericToolchain, self)._get_templates() templates.update({ - CMakeToolchainBase.filename: self._toolchain_tpl, - CMakeToolchainBase.project_include_filename: self._project_include_filename_tpl + CMakeToolchainBase.filename: self._toolchain_tpl }) return templates @@ -208,13 +195,13 @@ def _get_architecture(self): def _runtimes(self): # Parsing existing toolchain file to get existing configured runtimes config_dict = {} - if os.path.exists(self.project_include_filename): - existing_include = load(self.project_include_filename) + if os.path.exists(self.filename): + existing_include = load(self.filename) msvc_runtime_value = re.search(r"set\(CMAKE_MSVC_RUNTIME_LIBRARY \"([^)]*)\"\)", existing_include) if msvc_runtime_value: capture = msvc_runtime_value.group(1) - matches = re.findall(r"\$<\$([A-Za-z]*)>", capture) + matches = re.findall(r"\$<\$:([A-Za-z]*)>", capture) config_dict = dict(matches) settings = self._conanfile.settings @@ -277,8 +264,7 @@ def _cppstd(self): return cppstd, cppstd_extensions def _get_template_context_data(self): - ctxt_toolchain, ctxt_project_include = \ - super(CMakeGenericToolchain, self)._get_template_context_data() + ctxt_toolchain = super(CMakeGenericToolchain, self)._get_template_context_data() ctxt_toolchain.update({ "generator_platform": self.generator_platform, "toolset": self.toolset, @@ -291,7 +277,7 @@ def _get_template_context_data(self): "cppstd_extensions": self.cppstd_extensions, "shared_libs": self._build_shared_libs, "architecture": self.architecture, - "compiler": self.compiler + "compiler": self.compiler, + 'vs_runtimes': self.vs_runtimes }) - ctxt_project_include.update({'vs_runtimes': self.vs_runtimes}) - return ctxt_toolchain, ctxt_project_include + return ctxt_toolchain diff --git a/conan/tools/cmake/ios.py b/conan/tools/cmake/ios.py index 397f875e128..04db1f6ab58 100644 --- a/conan/tools/cmake/ios.py +++ b/conan/tools/cmake/ios.py @@ -72,7 +72,6 @@ def _get_architecture(self): "x86_64": "x86_64", "armv8": "arm64", "armv8_32": "arm64_32"}.get(arch, arch) - return None # TODO: refactor, comes from conans.client.tools.apple.py def _apple_sdk_name(self): @@ -92,11 +91,11 @@ def _apple_sdk_name(self): 'tvOS': 'appletvos'}.get(str(os_), None) def _get_template_context_data(self): - ctxt_toolchain, _ = super(CMakeiOSToolchain, self)._get_template_context_data() + ctxt_toolchain = super(CMakeiOSToolchain, self)._get_template_context_data() ctxt_toolchain.update({ "CMAKE_OSX_ARCHITECTURES": self.host_architecture, "CMAKE_SYSTEM_NAME": self.host_os, "CMAKE_SYSTEM_VERSION": self.host_os_version, "CMAKE_OSX_SYSROOT": self.host_sdk_name }) - return ctxt_toolchain, {} + return ctxt_toolchain diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 0ddc0d35422..b887ac2737b 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -54,11 +54,9 @@ def build(self): main = gen_function_cpp(name="main", includes=["app"], calls=["app"]) cmakelist = textwrap.dedent(""" - cmake_minimum_required(VERSION 2.8) + cmake_minimum_required(VERSION 3.15) project(App C CXX) - if(CONAN_TOOLCHAIN_INCLUDED AND CMAKE_VERSION VERSION_LESS "3.15") - include("${CMAKE_BINARY_DIR}/conan_project_include.cmake") - endif() + if(NOT CMAKE_TOOLCHAIN_FILE) message(FATAL ">> Not using toolchain") endif() @@ -173,6 +171,7 @@ class WinTest(Base): ) def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arch, toolset, shared): + print(self.client.current_folder) settings = {"compiler": compiler, "compiler.version": version, "compiler.toolset": toolset, @@ -183,6 +182,7 @@ def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arc } options = {"shared": shared} install_out = self._run_build(settings, options) + print(self.client.out) self.assertIn("WARN: Toolchain: Ignoring fPIC option defined for Windows", install_out) # FIXME: Hardcoded VS version and partial toolset check @@ -193,19 +193,17 @@ def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arc else: self.assertIn("Microsoft Visual Studio/2017", self.client.out) - runtime = "MT" if "MT" in runtime or runtime == "static" else "MD" - runtime = "MD" generator_platform = "x64" if arch == "x86_64" else "Win32" arch = "x64" if arch == "x86_64" else "X86" shared_str = "ON" if shared else "OFF" vals = {"CMAKE_GENERATOR_PLATFORM": generator_platform, "CMAKE_BUILD_TYPE": "", - "CMAKE_CXX_FLAGS": "/MP1 /DWIN32 /D_WINDOWS /W3 /GR /EHsc", - "CMAKE_CXX_FLAGS_DEBUG": "/%sd /Zi /Ob0 /Od /RTC1" % runtime, - "CMAKE_CXX_FLAGS_RELEASE": "/%s /O2 /Ob2 /DNDEBUG" % runtime, - "CMAKE_C_FLAGS": "/MP1 /DWIN32 /D_WINDOWS /W3", - "CMAKE_C_FLAGS_DEBUG": "/%sd /Zi /Ob0 /Od /RTC1" % runtime, - "CMAKE_C_FLAGS_RELEASE": "/%s /O2 /Ob2 /DNDEBUG" % runtime, + "CMAKE_CXX_FLAGS": "/MP1 /DWIN32 /D_WINDOWS /GR /EHsc", + "CMAKE_CXX_FLAGS_DEBUG": "/Zi /Ob0 /Od /RTC1", + "CMAKE_CXX_FLAGS_RELEASE": "/O2 /Ob2 /DNDEBUG", + "CMAKE_C_FLAGS": "/MP1 /DWIN32 /D_WINDOWS", + "CMAKE_C_FLAGS_DEBUG": "/Zi /Ob0 /Od /RTC1", + "CMAKE_C_FLAGS_RELEASE": "/O2 /Ob2 /DNDEBUG", "CMAKE_SHARED_LINKER_FLAGS": "/machine:%s" % arch, "CMAKE_EXE_LINKER_FLAGS": "/machine:%s" % arch, "CMAKE_CXX_STANDARD": cppstd, @@ -224,15 +222,9 @@ def _verify_out(marker=">>"): _verify_out() - toolchain = self.client.load("build/conan_toolchain.cmake") - include = self.client.load("build/conan_project_include.cmake") opposite_build_type = "Release" if build_type == "Debug" else "Debug" settings["build_type"] = opposite_build_type self._run_build(settings, options) - # The generated toolchain files must be identical because it is a multi-config - self.assertEqual(toolchain, self.client.load("build/conan_toolchain.cmake")) - # It is not, the Runtime is added incrementally now - # self.assertEqual(include, self.client.load("build/conan_project_include.cmake")) self._run_app("Release", bin_folder=True) check_msc_ver(toolset or "v141", self.client.out) @@ -240,10 +232,11 @@ def _verify_out(marker=">>"): self._run_app("Debug", bin_folder=True) check_msc_ver(toolset or "v141", self.client.out) self.assertIn("main _MSVC_LANG20{}".format(cppstd), self.client.out) + static = (runtime == "static" or "MT" in runtime) check_vs_runtime("build/Release/app.exe", self.client, "15", build_type="Release", - static="MT" in runtime) + static=static) check_vs_runtime("build/Debug/app.exe", self.client, "15", build_type="Debug", - static="MT" in runtime) + static=static) self._modify_code() time.sleep(1) From ef36fd2e00cff3df904d83a46d69f02e8536bcf1 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 17:43:28 +0100 Subject: [PATCH 13/32] fix migration test --- conans/client/migrations_settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conans/client/migrations_settings.py b/conans/client/migrations_settings.py index 8eab7c0477b..90cbeb7f939 100644 --- a/conans/client/migrations_settings.py +++ b/conans/client/migrations_settings.py @@ -1883,6 +1883,7 @@ "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16", "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"] runtime: [static, dynamic] + runtime_type: [Debug, Release] cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] From 2000c850eaeaebb994062a819aa30b4142e1a875 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 16 Dec 2020 18:36:28 +0100 Subject: [PATCH 14/32] fixing tests --- .../integration/toolchains/cmake/test_ninja.py | 14 ++++---------- conans/test/integration/toolchains/test_cmake.py | 6 ++++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/conans/test/integration/toolchains/cmake/test_ninja.py b/conans/test/integration/toolchains/cmake/test_ninja.py index e2ebef0003c..af4e422dfa0 100644 --- a/conans/test/integration/toolchains/cmake/test_ninja.py +++ b/conans/test/integration/toolchains/cmake/test_ninja.py @@ -4,6 +4,7 @@ from conan.tools.microsoft.visual import vcvars_command from conans.test.assets.sources import gen_function_cpp +from conans.test.integration.utils import check_vs_runtime from conans.test.utils.tools import TestClient from conans.client.tools import which @@ -13,11 +14,8 @@ class CMakeNinjaTestCase(unittest.TestCase): main_cpp = gen_function_cpp(name="main") cmake = textwrap.dedent(""" - cmake_minimum_required(VERSION 2.8.12) + cmake_minimum_required(VERSION 3.15) project(App CXX) - if(CMAKE_VERSION VERSION_LESS "3.15") - include(${CMAKE_BINARY_DIR}/conan_project_include.cmake) - endif() set(CMAKE_VERBOSE_MAKEFILE ON) add_executable(App main.cpp) install(TARGETS App RUNTIME DESTINATION bin) @@ -106,9 +104,7 @@ def test_locally_build_windows(self): self.assertIn("main _MSC_VER19", client.out) self.assertIn("main _MSVC_LANG2014", client.out) - client.run_command('{} && dumpbin /dependents /summary /directives "App.exe"'.format(vcvars)) - self.assertIn("MSVCP140.dll", client.out) - self.assertIn("VCRUNTIME140.dll", client.out) + check_vs_runtime("App.exe", client, "15", build_type="Release", static=False) @unittest.skipIf(platform.system() != "Windows", "Only windows") def test_locally_build_windows_debug(self): @@ -142,6 +138,4 @@ def test_locally_build_windows_debug(self): self.assertIn("main _MSC_VER19", client.out) self.assertIn("main _MSVC_LANG2014", client.out) - client.run_command('{} && dumpbin /dependents /summary /directives "App.exe"'.format(vcvars)) - self.assertIn("KERNEL32.dll", client.out) - self.assertEqual(1, str(client.out).count(".dll")) + check_vs_runtime("App.exe", client, "15", build_type="Debug", static=True) diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index b887ac2737b..427d0d0056d 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -171,7 +171,6 @@ class WinTest(Base): ) def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arch, toolset, shared): - print(self.client.current_folder) settings = {"compiler": compiler, "compiler.version": version, "compiler.toolset": toolset, @@ -182,7 +181,6 @@ def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arc } options = {"shared": shared} install_out = self._run_build(settings, options) - print(self.client.out) self.assertIn("WARN: Toolchain: Ignoring fPIC option defined for Windows", install_out) # FIXME: Hardcoded VS version and partial toolset check @@ -224,6 +222,10 @@ def _verify_out(marker=">>"): opposite_build_type = "Release" if build_type == "Debug" else "Debug" settings["build_type"] = opposite_build_type + if runtime == "MTd": + settings["compiler.runtime"] = "MT" + if runtime == "MD": + settings["compiler.runtime"] = "MDd" self._run_build(settings, options) self._run_app("Release", bin_folder=True) From 640b1348d15ea2e086eec0e2ec7b6298cdc04633 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 17 Dec 2020 00:41:11 +0100 Subject: [PATCH 15/32] binary compatibility --- conans/client/graph/graph_binaries.py | 3 +++ conans/model/info.py | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index aa74c5acfb6..bac67a77584 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -339,6 +339,9 @@ def _compute_package_id(self, node, default_package_id_mode, default_python_requ python_requires=python_requires, default_python_requires_id_mode= default_python_requires_id_mode) + msvc_compatible = conanfile.info.msvc_compatible() + if msvc_compatible: + conanfile.compatible_packages.append(msvc_compatible) # Once we are done, call package_id() to narrow and change possible values with conanfile_exception_formatter(str(conanfile), "package_id"): diff --git a/conans/model/info.py b/conans/model/info.py index e5d492d4cbf..587963a85dc 100644 --- a/conans/model/info.py +++ b/conans/model/info.py @@ -575,6 +575,27 @@ def header_only(self): self.options.clear() self.requires.clear() + def msvc_compatible(self): + if self.settings.compiler != "msvc": + return + + compatible = self.clone() + version = compatible.settings.compiler.version + runtime = compatible.settings.compiler.runtime + runtime_type = compatible.settings.compiler.runtime_type + + compatible.settings.compiler = "Visual Studio" + version = str(version)[:4] + _visuals = {'19.0': '14', + '19.1': '15', + '19.2': '16'} + compatible.settings.compiler.version = _visuals[version] + runtime = "MT" if runtime == "static" else "MD" + if runtime_type == "Debug": + runtime = "{}d".format(runtime) + compatible.settings.compiler.runtime = runtime + return compatible + def vs_toolset_compatible(self): """Default behaviour, same package for toolset v140 with compiler=Visual Studio 15 than using Visual Studio 14""" From 1994d1f137569b4f2838a4eac199296dceb47147 Mon Sep 17 00:00:00 2001 From: memsharded Date: Sun, 20 Dec 2020 00:54:39 +0100 Subject: [PATCH 16/32] command conan new generates files with new toolchains --- conanfile.py | 41 ++++++ conans/client/cmd/new.py | 137 ++++++++++++++++-- .../test/integration/toolchains/test_cmake.py | 17 +++ conans/util/conan_v2_mode.py | 11 ++ src/CMakeLists.txt | 4 + src/pkg.cpp | 10 ++ src/pkg.h | 9 ++ test_package/CMakeLists.txt | 14 ++ test_package/conanfile.py | 29 ++++ test_package/example.cpp | 5 + 10 files changed, 266 insertions(+), 11 deletions(-) create mode 100644 conanfile.py create mode 100644 src/CMakeLists.txt create mode 100644 src/pkg.cpp create mode 100644 src/pkg.h create mode 100644 test_package/CMakeLists.txt create mode 100644 test_package/conanfile.py create mode 100644 test_package/example.cpp diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000000..a7fc612ecda --- /dev/null +++ b/conanfile.py @@ -0,0 +1,41 @@ +from conans import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake + + +class PkgConan(ConanFile): + name = "pkg" + version = "0.1" + license = "" + author = " " + url = "" + description = "" + topics = ("", "", "") + settings = "os", "compiler", "build_type", "arch" + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} + exports_sources = "src/*" + + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def generate(self): + tc = CMakeToolchain(self) + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure(source_folder="src") + cmake.build() + + def package(self): + self.copy("*.h", dst="include", src="src") + self.copy("*.lib", dst="lib", keep_path=False) + self.copy("*.dll", dst="bin", keep_path=False) + self.copy("*.dylib*", dst="lib", keep_path=False) + self.copy("*.so", dst="lib", keep_path=False) + self.copy("*.a", dst="lib", keep_path=False) + + def package_info(self): + self.cpp_info.libs = ["pkg"] diff --git a/conans/client/cmd/new.py b/conans/client/cmd/new.py index 7cffa7af59c..d62bc91ab94 100644 --- a/conans/client/cmd/new.py +++ b/conans/client/cmd/new.py @@ -7,6 +7,7 @@ from conans.client.cmd.new_ci import ci_get_files from conans.errors import ConanException from conans.model.ref import ConanFileReference +from conans.util.conan_v2_mode import conan2_behavior from conans.util.files import load @@ -126,6 +127,49 @@ def package_info(self): self.cpp_info.libs = ["{name}"] """ +conanfile_sources_v2 = """from conans import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake + + +class {package_name}Conan(ConanFile): + name = "{name}" + version = "{version}" + license = "" + author = " " + url = "" + description = "" + topics = ("", "", "") + settings = "os", "compiler", "build_type", "arch" + options = {{"shared": [True, False], "fPIC": [True, False]}} + default_options = {{"shared": False, "fPIC": True}} + exports_sources = "src/*" + +{configure} + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def generate(self): + tc = CMakeToolchain(self) + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure(source_folder="src") + cmake.build() + + def package(self): + self.copy("*.h", dst="include", src="src") + self.copy("*.lib", dst="lib", keep_path=False) + self.copy("*.dll", dst="bin", keep_path=False) + self.copy("*.dylib*", dst="lib", keep_path=False) + self.copy("*.so", dst="lib", keep_path=False) + self.copy("*.a", dst="lib", keep_path=False) + + def package_info(self): + self.cpp_info.libs = ["{name}"] +""" + conanfile_header = """import os from conans import ConanFile, tools @@ -186,6 +230,37 @@ def test(self): self.run(".%sexample" % os.sep) """ +test_conanfile_v2 = """import os + +from conans import ConanFile, tools +from conan.tools.cmake import CMakeToolchain, CMake, CMakeDeps + + +class {package_name}TestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self) + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def imports(self): + self.copy("*.dll", dst="bin", src="bin") + self.copy("*.dylib*", dst="bin", src="lib") + self.copy('*.so*', dst='bin', src='lib') + + def test(self): + if not tools.cross_building(self): + os.chdir("bin") + self.run(".%sexample" % os.sep) +""" + test_cmake = """cmake_minimum_required(VERSION 3.1) project(PackageTest CXX) @@ -202,6 +277,22 @@ def test(self): # COMMAND example) """ +test_cmake_v2 = """cmake_minimum_required(VERSION 3.15) +project(PackageTest CXX) + +# TODO: Remove this when layouts are available +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${{CMAKE_CURRENT_BINARY_DIR}}/bin) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${{CMAKE_RUNTIME_OUTPUT_DIRECTORY}}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${{CMAKE_RUNTIME_OUTPUT_DIRECTORY}}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${{CMAKE_RUNTIME_OUTPUT_DIRECTORY}}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${{CMAKE_RUNTIME_OUTPUT_DIRECTORY}}) + +find_package({name}) + +add_executable(example example.cpp) +target_link_libraries(example {name}::{name}) +""" + test_cmake_pure_c = """cmake_minimum_required(VERSION 3.1) project(PackageTest C) @@ -279,6 +370,13 @@ def test(self): add_library({name} {name}.cpp) """ +cmake_v2 = """cmake_minimum_required(VERSION 3.15) +project({name} CXX) + +add_library({name} {name}.cpp) +""" + + gitignore_template = """ *.pyc test_package/build @@ -356,12 +454,20 @@ def cmd_new(ref, header=False, pure_c=False, test=False, exports_sources=False, package_name=package_name)} elif exports_sources: if not pure_c: - files = {"conanfile.py": conanfile_sources.format(name=name, version=version, - package_name=package_name, - configure=""), - "src/{}.cpp".format(name): hello_cpp.format(name=name, version=version), - "src/{}.h".format(name): hello_h.format(name=name, version=version), - "src/CMakeLists.txt": cmake.format(name=name, version=version)} + if conan2_behavior("Using new CMakeToolchain helper"): + files = {"conanfile.py": conanfile_sources_v2.format(name=name, version=version, + package_name=package_name, + configure=""), + "src/{}.cpp".format(name): hello_cpp.format(name=name, version=version), + "src/{}.h".format(name): hello_h.format(name=name, version=version), + "src/CMakeLists.txt": cmake_v2.format(name=name, version=version)} + else: + files = {"conanfile.py": conanfile_sources.format(name=name, version=version, + package_name=package_name, + configure=""), + "src/{}.cpp".format(name): hello_cpp.format(name=name, version=version), + "src/{}.h".format(name): hello_h.format(name=name, version=version), + "src/CMakeLists.txt": cmake.format(name=name, version=version)} else: config = ("\n def configure(self):\n" " del self.settings.compiler.libcxx\n" @@ -405,16 +511,25 @@ def cmd_new(ref, header=False, pure_c=False, test=False, exports_sources=False, package_name=package_name)} if test: - files["test_package/conanfile.py"] = test_conanfile.format(name=name, version=version, - user=user, channel=channel, - package_name=package_name) + if conan2_behavior("Using new CMakeToolchain helper in test_package"): + files["test_package/conanfile.py"] = test_conanfile_v2.format(name=name, version=version, + user=user, channel=channel, + package_name=package_name) + else: + files["test_package/conanfile.py"] = test_conanfile.format(name=name, version=version, + user=user, channel=channel, + package_name=package_name) if pure_c: files["test_package/example.c"] = test_main.format(name=name) files["test_package/CMakeLists.txt"] = test_cmake_pure_c else: include_name = name if exports_sources else "hello" - files["test_package/example.cpp"] = test_main.format(name=include_name) - files["test_package/CMakeLists.txt"] = test_cmake + if conan2_behavior(): + files["test_package/example.cpp"] = test_main.format(name=include_name) + files["test_package/CMakeLists.txt"] = test_cmake_v2.format(name=name) + else: + files["test_package/example.cpp"] = test_main.format(name=include_name) + files["test_package/CMakeLists.txt"] = test_cmake if gitignore: files[".gitignore"] = gitignore_template diff --git a/conans/test/integration/toolchains/test_cmake.py b/conans/test/integration/toolchains/test_cmake.py index 25c9ccdf49d..22538fa32f4 100644 --- a/conans/test/integration/toolchains/test_cmake.py +++ b/conans/test/integration/toolchains/test_cmake.py @@ -8,6 +8,7 @@ from nose.plugins.attrib import attr from parameterized.parameterized import parameterized +from conans.client.tools import environment_append from conans.model.ref import ConanFileReference, PackageReference from conans.test.assets.sources import gen_function_cpp, gen_function_h from conans.test.integration.utils import check_vs_runtime, check_msc_ver @@ -164,6 +165,22 @@ def _run_app(self, build_type, bin_folder=False, msg="App", dyld_path=None): self.assertIn("MYDEFINE_CONFIG: MYDEF_%s" % build_type.upper(), self.client.out) +class TestNew(unittest.TestCase): + def test_new(self): + client = TestClient() + with environment_append({"CONAN_V2_BEHAVIOR": "1"}): + client.run("new pkg/0.1 -s -t") + conanfile = client.load("conanfile.py") + self.assertIn("CMakeToolchain", conanfile) + conanfile = client.load("test_package/conanfile.py") + self.assertIn("CMakeToolchain", conanfile) + cmake = client.load("test_package/CMakeLists.txt") + self.assertIn("find_package", cmake) + + client.run("create .") + self.assertIn("pkg/0.1: Hello World Release!", client.out) + + @unittest.skipUnless(platform.system() == "Windows", "Only for windows") class WinTest(Base): @parameterized.expand([("Debug", "MTd", "15", "14", "x86", "v140", True), diff --git a/conans/util/conan_v2_mode.py b/conans/util/conan_v2_mode.py index ab0bb47a507..0e55bb2d04f 100644 --- a/conans/util/conan_v2_mode.py +++ b/conans/util/conan_v2_mode.py @@ -5,9 +5,20 @@ from conans.errors import ConanV2Exception CONAN_V2_MODE_ENVVAR = "CONAN_V2_MODE" +CONAN_V2_BEHAVIOR = "CONAN_V2_BEHAVIOR" + + +def conan2_behavior(msg=""): + """ this should be used for pure behavior changes, not for deprecations errors """ + if os.environ.get(CONAN_V2_BEHAVIOR, False): + if msg: + print("Conan 2.0 behavior: {}".format(msg)) + return True + return False def conan_v2_behavior(msg, v1_behavior=None): + # FIXME: to deprecate replace this by a "conan_v2_deprecate" that only raises if enabled if os.environ.get(CONAN_V2_MODE_ENVVAR, False): raise ConanV2Exception(msg) else: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000000..82d8416c6f4 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.15) +project(pkg CXX) + +add_library(pkg pkg.cpp) diff --git a/src/pkg.cpp b/src/pkg.cpp new file mode 100644 index 00000000000..1f856e058b5 --- /dev/null +++ b/src/pkg.cpp @@ -0,0 +1,10 @@ +#include +#include "pkg.h" + +void pkg(){ + #ifdef NDEBUG + std::cout << "pkg/0.1: Hello World Release!" < Date: Sun, 20 Dec 2020 00:56:43 +0100 Subject: [PATCH 17/32] removed conanfile --- conanfile.py | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 conanfile.py diff --git a/conanfile.py b/conanfile.py deleted file mode 100644 index a7fc612ecda..00000000000 --- a/conanfile.py +++ /dev/null @@ -1,41 +0,0 @@ -from conans import ConanFile -from conan.tools.cmake import CMakeToolchain, CMake - - -class PkgConan(ConanFile): - name = "pkg" - version = "0.1" - license = "" - author = " " - url = "" - description = "" - topics = ("", "", "") - settings = "os", "compiler", "build_type", "arch" - options = {"shared": [True, False], "fPIC": [True, False]} - default_options = {"shared": False, "fPIC": True} - exports_sources = "src/*" - - - def config_options(self): - if self.settings.os == "Windows": - del self.options.fPIC - - def generate(self): - tc = CMakeToolchain(self) - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.configure(source_folder="src") - cmake.build() - - def package(self): - self.copy("*.h", dst="include", src="src") - self.copy("*.lib", dst="lib", keep_path=False) - self.copy("*.dll", dst="bin", keep_path=False) - self.copy("*.dylib*", dst="lib", keep_path=False) - self.copy("*.so", dst="lib", keep_path=False) - self.copy("*.a", dst="lib", keep_path=False) - - def package_info(self): - self.cpp_info.libs = ["pkg"] From e66dbe2bb00cbcf6e4390a3489ae9a77834844a6 Mon Sep 17 00:00:00 2001 From: memsharded Date: Sun, 20 Dec 2020 00:57:54 +0100 Subject: [PATCH 18/32] removed files --- src/CMakeLists.txt | 4 ---- src/pkg.cpp | 10 ---------- src/pkg.h | 9 --------- test_package/CMakeLists.txt | 14 -------------- test_package/conanfile.py | 29 ----------------------------- test_package/example.cpp | 5 ----- 6 files changed, 71 deletions(-) delete mode 100644 src/CMakeLists.txt delete mode 100644 src/pkg.cpp delete mode 100644 src/pkg.h delete mode 100644 test_package/CMakeLists.txt delete mode 100644 test_package/conanfile.py delete mode 100644 test_package/example.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 82d8416c6f4..00000000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -cmake_minimum_required(VERSION 3.15) -project(pkg CXX) - -add_library(pkg pkg.cpp) diff --git a/src/pkg.cpp b/src/pkg.cpp deleted file mode 100644 index 1f856e058b5..00000000000 --- a/src/pkg.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include "pkg.h" - -void pkg(){ - #ifdef NDEBUG - std::cout << "pkg/0.1: Hello World Release!" < Date: Sun, 20 Dec 2020 01:40:16 +0100 Subject: [PATCH 19/32] msbuild working for msvc --- conan/tools/microsoft/msbuild.py | 9 +++++---- conan/tools/microsoft/toolchain.py | 9 ++++++++- conans/test/integration/toolchains/test_msbuild.py | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/conan/tools/microsoft/msbuild.py b/conan/tools/microsoft/msbuild.py index 21e06ef2f15..0a318e3ba3e 100644 --- a/conan/tools/microsoft/msbuild.py +++ b/conan/tools/microsoft/msbuild.py @@ -9,10 +9,11 @@ def __init__(self, conanfile): self.version = conanfile.settings.get_safe("compiler.base.version") or \ conanfile.settings.get_safe("compiler.version") if self.compiler == "msvc": - _visuals = {'140': '14', # TODO: This is common to CMake, refactor - '141': '15', - '142': '16'} - self.version = _visuals[self.version] + version = self.version[:4] # Remove the latest version number 19.1X if existing + _visuals = {'19.0': '14', # TODO: This is common to CMake, refactor + '19.1': '15', + '19.2': '16'} + self.version = _visuals[version] self.vcvars_arch = vcvars_arch(conanfile) self.build_type = conanfile.settings.get_safe("build_type") msvc_arch = {'x86': 'x86', diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index 0ee246e1467..7baca468d34 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -54,12 +54,13 @@ def format_macro(k, value): return '%s="%s"' % (k, value) if value is not None else k compiler = self._conanfile.settings.get_safe("compiler") + compiler_version = self._conanfile.settings.get_safe("compiler.version") runtime = self._conanfile.settings.get_safe("compiler.runtime") cppstd = self._conanfile.settings.get_safe("compiler.cppstd") toolset = msvs_toolset(self._conanfile.settings) if compiler == "msvc": build_type = self._conanfile.settings.get_safe("build_type") - if build_type == "Debug": + if build_type != "Debug": runtime_library = {"static": "MultiThreaded", "dyanmic": "MultiThreadedDLL"}.get(runtime, "") else: @@ -93,6 +94,12 @@ def format_macro(k, value): # It is useless to set PlatformToolset in the config file, because the conditional checks it cppstd = "stdcpp%s" % cppstd if cppstd else "" toolset = toolset or "" + if compiler == "msvc": + version = compiler_version[:4] # Remove the latest version number 19.1X if existing + _visuals = {'19.0': 'v140', # TODO: This is common to CMake, refactor + '19.1': 'v141', + '19.2': 'v142'} + toolset = _visuals[version] config_props = content.format(preprocessor_definitions, runtime_library, cppstd, toolset) config_filepath = os.path.abspath(config_filename) self._conanfile.output.info("MSBuildToolchain created %s" % config_filename) diff --git a/conans/test/integration/toolchains/test_msbuild.py b/conans/test/integration/toolchains/test_msbuild.py index 720724f1cb5..6f3c21a272e 100644 --- a/conans/test/integration/toolchains/test_msbuild.py +++ b/conans/test/integration/toolchains/test_msbuild.py @@ -6,7 +6,7 @@ import pytest from parameterized import parameterized -from conans.client.tools import vs_installation_path +from conans.client.tools import vs_installation_path, environment_append from conans.test.assets.sources import gen_function_cpp from conans.test.integration.utils import check_vs_runtime, check_msc_ver from conans.test.utils.tools import TestClient @@ -267,7 +267,7 @@ def _run_app(self, client, arch, build_type, msg="main"): @pytest.mark.tool_cmake @parameterized.expand([("Visual Studio", "15", "MT"), - ("msvc", "141", "static")] + ("msvc", "19.1", "static")] ) def test_toolchain_win(self, compiler, version, runtime): client = TestClient(path_with_spaces=False) @@ -281,9 +281,9 @@ def test_toolchain_win(self, compiler, version, runtime): # Build the profile according to the settings provided settings = " ".join('-s %s="%s"' % (k, v) for k, v in settings.items() if v) - client.run("new hello/0.1 -s") + with environment_append({"CONAN_V2_BEHAVIOR": "1"}): + client.run("new hello/0.1 -s") client.run("create . hello/0.1@ %s" % (settings, )) - print(client.out) # Prepare the actual consumer package client.save({"conanfile.py": self.conanfile, From c0c445ccbf21d6d608edf5fb407ab7c55f29e2a0 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 14 Jan 2021 19:24:38 +0100 Subject: [PATCH 20/32] fixing tests --- conan/tools/microsoft/msbuild.py | 1 + conans/client/cmd/new.py | 10 --------- conans/client/graph/graph_binaries.py | 2 +- conans/client/migrations_settings.py | 7 ------- .../test/functional/toolchains/test_cmake.py | 21 ------------------- .../functional/toolchains/test_msbuild.py | 5 ++--- 6 files changed, 4 insertions(+), 42 deletions(-) diff --git a/conan/tools/microsoft/msbuild.py b/conan/tools/microsoft/msbuild.py index cce36acf399..80279cad0d9 100644 --- a/conan/tools/microsoft/msbuild.py +++ b/conan/tools/microsoft/msbuild.py @@ -15,6 +15,7 @@ class MSBuild(object): def __init__(self, conanfile): self._conanfile = conanfile self.compiler = conanfile.settings.get_safe("compiler") + # This is assuming this is the Visual Studio IDE version, used for the vcvars self.version = (conanfile.settings.get_safe("compiler.base.version") or conanfile.settings.get_safe("compiler.version")) if self.compiler == "msvc": diff --git a/conans/client/cmd/new.py b/conans/client/cmd/new.py index 5b4821cd10b..71c301ceea1 100644 --- a/conans/client/cmd/new.py +++ b/conans/client/cmd/new.py @@ -126,7 +126,6 @@ def package_info(self): self.cpp_info.libs = ["{name}"] """ - conanfile_header = """import os from conans import ConanFile, tools @@ -187,7 +186,6 @@ def test(self): self.run(".%sexample" % os.sep) """ - test_cmake = """cmake_minimum_required(VERSION 3.1) project(PackageTest CXX) @@ -204,7 +202,6 @@ def test(self): # COMMAND example) """ - test_cmake_pure_c = """cmake_minimum_required(VERSION 3.1) project(PackageTest C) @@ -282,13 +279,6 @@ def test(self): add_library({name} {name}.cpp) """ -cmake_v2 = """cmake_minimum_required(VERSION 3.15) -project({name} CXX) - -add_library({name} {name}.cpp) -""" - - gitignore_template = """ *.pyc test_package/build diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index 8531909e683..e2bcb8602ba 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -340,7 +340,7 @@ def _compute_package_id(self, node, default_package_id_mode, default_python_requ default_python_requires_id_mode= default_python_requires_id_mode) - if not self._cache.new_conf["core.package_id"].msvc_visual_incompatible: + if not self._cache.new_config["core.package_id"].msvc_visual_incompatible: msvc_compatible = conanfile.info.msvc_compatible() if msvc_compatible: conanfile.compatible_packages.append(msvc_compatible) diff --git a/conans/client/migrations_settings.py b/conans/client/migrations_settings.py index 54eb6e19c0c..1333ed58bfc 100644 --- a/conans/client/migrations_settings.py +++ b/conans/client/migrations_settings.py @@ -1881,13 +1881,6 @@ threads: [None, posix, win32] # Windows MinGW exception: [None, dwarf2, sjlj, seh] # Windows MinGW cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] - msvc: - version: ["19.0", - "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16", - "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"] - runtime: [static, dynamic] - runtime_type: [Debug, Release] - cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] version: ["8", "9", "10", "11", "12", "14", "15", "16"] diff --git a/conans/test/functional/toolchains/test_cmake.py b/conans/test/functional/toolchains/test_cmake.py index 4353c1fe1a4..a8be13d638a 100644 --- a/conans/test/functional/toolchains/test_cmake.py +++ b/conans/test/functional/toolchains/test_cmake.py @@ -7,7 +7,6 @@ import pytest from parameterized.parameterized import parameterized -from conans.client.tools import environment_append from conans.model.ref import ConanFileReference, PackageReference from conans.test.assets.sources import gen_function_cpp, gen_function_h from conans.test.functional.utils import check_vs_runtime, check_msc_ver @@ -161,27 +160,7 @@ def _run_app(self, build_type, bin_folder=False, msg="App", dyld_path=None): self.assertIn("MYDEFINE_CONFIG: MYDEF_%s" % build_type.upper(), self.client.out) -<<<<<<< HEAD:conans/test/integration/toolchains/test_cmake.py -class TestNew(unittest.TestCase): - def test_new(self): - client = TestClient() - with environment_append({"CONAN_V2_BEHAVIOR": "1"}): - client.run("new pkg/0.1 -s -t") - conanfile = client.load("conanfile.py") - self.assertIn("CMakeToolchain", conanfile) - conanfile = client.load("test_package/conanfile.py") - self.assertIn("CMakeToolchain", conanfile) - cmake = client.load("test_package/CMakeLists.txt") - self.assertIn("find_package", cmake) - - client.run("create .") - self.assertIn("pkg/0.1: Hello World Release!", client.out) - - -@unittest.skipUnless(platform.system() == "Windows", "Only for windows") -======= @pytest.mark.skipif(platform.system() != "Windows", reason="Only for windows") ->>>>>>> develop:conans/test/functional/toolchains/test_cmake.py class WinTest(Base): @parameterized.expand([("Visual Studio", "Debug", "MTd", "15", "14", "x86", "v140", True), ("Visual Studio", "Release", "MD", "15", "17", "x86_64", "", False), diff --git a/conans/test/functional/toolchains/test_msbuild.py b/conans/test/functional/toolchains/test_msbuild.py index 7f9e088bf5f..0051336e002 100644 --- a/conans/test/functional/toolchains/test_msbuild.py +++ b/conans/test/functional/toolchains/test_msbuild.py @@ -12,7 +12,7 @@ from conans.client.tools import chdir from conans.util.files import mkdir from conan.tools.microsoft.visual import vcvars_command -from conans.client.tools import vs_installation_path, environment_append +from conans.client.tools import vs_installation_path from conans.test.assets.sources import gen_function_cpp from conans.test.functional.utils import check_vs_runtime, check_msc_ver from conans.test.utils.tools import TestClient @@ -416,8 +416,7 @@ def test_toolchain_win(self, compiler, version, runtime): # Build the profile according to the settings provided settings = " ".join('-s %s="%s"' % (k, v) for k, v in settings.items() if v) - with environment_append({"CONAN_V2_BEHAVIOR": "1"}): - client.run("new hello/0.1 -s") + client.run("new hello/0.1 -m=v2_cmake") client.run("create . hello/0.1@ %s" % (settings, )) # Prepare the actual consumer package From f6528c4687f790fe482daabc3ac7c79f09b4d905 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 14 Jan 2021 19:45:06 +0100 Subject: [PATCH 21/32] fixing tests --- conans/client/conf/__init__.py | 7 ------ .../integration/package_id/compatible_test.py | 25 +++++++++++++------ .../unittests/model/transitive_reqs_test.py | 3 ++- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py index 59990624cea..bb31ba1b41c 100644 --- a/conans/client/conf/__init__.py +++ b/conans/client/conf/__init__.py @@ -76,13 +76,6 @@ threads: [None, posix, win32] # Windows MinGW exception: [None, dwarf2, sjlj, seh] # Windows MinGW cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] - msvc: - version: ["19.0", - "19.1", "19.10", "19.11", "19.12", "19.13", "19.14", "19.15", "19.16", - "19.2", "19.20", "19.21", "19.22", "19.23", "19.24", "19.25", "19.26", "19.27", "19.28"] - runtime: [static, dynamic] - runtime_type: [Debug, Release] - cppstd: [None, 14, 17, 20] Visual Studio: &visual_studio runtime: [MD, MT, MTd, MDd] version: ["8", "9", "10", "11", "12", "14", "15", "16"] diff --git a/conans/test/integration/package_id/compatible_test.py b/conans/test/integration/package_id/compatible_test.py index a54b9a47592..e5b4fa9f655 100644 --- a/conans/test/integration/package_id/compatible_test.py +++ b/conans/test/integration/package_id/compatible_test.py @@ -4,6 +4,7 @@ from conans.model.ref import ConanFileReference from conans.test.utils.tools import TestClient, GenConanfile +from conans.util.files import save class CompatibleIDsTest(unittest.TestCase): @@ -497,15 +498,23 @@ def package_id(self): def test_msvc_visual_incompatible(): conanfile = GenConanfile().with_settings("os", "compiler", "build_type", "arch") client = TestClient() - client.save({"conanfile.py": conanfile}) + profile = textwrap.dedent(""" + [settings] + os=Windows + compiler=msvc + compiler.version=19.1 + compiler.runtime=dynamic + compiler.cppstd=14 + build_type=Release + arch=x86_64 + """) + client.save({"conanfile.py": conanfile, + "profile": profile}) client.run('create . pkg/0.1@ -s os=Windows -s compiler="Visual Studio" -s compiler.version=15 ' '-s compiler.runtime=MD -s build_type=Release -s arch=x86_64') - client.run("install pkg/0.1@ -s os=Windows -s compiler=msvc -s compiler.version=19.1 " - "-s compiler.runtime=dynamic -s build_type=Release -s arch=x86_64 " - "-s compiler.cppstd=14") + client.run("install pkg/0.1@ -pr=profile") assert "Using compatible package" in client.out - client.run("config set general.msvc_visual_incompatible=1") - client.run("install pkg/0.1@ -s os=Windows -s compiler=msvc -s compiler.version=19.1 " - "-s compiler.runtime=dynamic -s build_type=Release -s arch=x86_64 " - "-s compiler.cppstd=14", assert_error=True) + new_config = "core.package_id:msvc_visual_incompatible=1" + save(client.cache.new_config_path, new_config) + client.run("install pkg/0.1@ -pr=profile", assert_error=True) assert "ERROR: Missing prebuilt package for 'pkg/0.1'" in client.out diff --git a/conans/test/unittests/model/transitive_reqs_test.py b/conans/test/unittests/model/transitive_reqs_test.py index cb20373ff65..de855677775 100644 --- a/conans/test/unittests/model/transitive_reqs_test.py +++ b/conans/test/unittests/model/transitive_reqs_test.py @@ -1,5 +1,5 @@ import unittest -from collections import namedtuple, Counter +from collections import namedtuple, Counter, defaultdict import six from mock import Mock @@ -87,6 +87,7 @@ def setUp(self): self.resolver, None) cache = Mock() cache.config.default_package_id_mode = "semver_direct_mode" + cache.new_config = defaultdict(Mock) self.binaries_analyzer = GraphBinariesAnalyzer(cache, self.output, self.remote_manager) def build_graph(self, content, options="", settings=""): From da8689fab2080bf6263ccdffd6505ce6e6b947d8 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 15 Jan 2021 01:11:27 +0100 Subject: [PATCH 22/32] refactors --- conan/tools/microsoft/toolchain.py | 73 ++++++++++++++++++++---------- conans/client/tools/win.py | 2 - 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index 8b5f0708b77..e0919de940a 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -3,7 +3,6 @@ import warnings from xml.dom import minidom -from conans.client.tools import msvs_toolset from conans.errors import ConanException from conans.util.files import save, load @@ -17,6 +16,9 @@ def __init__(self, conanfile): self.preprocessor_definitions = {} self.compile_options = {} self.configuration = conanfile.settings.build_type + self.runtime_library = self._runtime_library(conanfile.settings) + self.cppstd = conanfile.settings.get_safe("compiler.cppstd") + self.toolset = self._msvs_toolset(conanfile.settings) def _name_condition(self, settings): props = [("Configuration", self.configuration), @@ -49,18 +51,40 @@ def generate(self): self._write_config_toolchain(config_filename) self._write_main_toolchain(config_filename, condition) - def _write_config_toolchain(self, config_filename): - - def format_macro(k, value): - return '%s="%s"' % (k, value) if value is not None else k - - compiler = self._conanfile.settings.get_safe("compiler") - compiler_version = self._conanfile.settings.get_safe("compiler.version") - runtime = self._conanfile.settings.get_safe("compiler.runtime") - cppstd = self._conanfile.settings.get_safe("compiler.cppstd") - toolset = msvs_toolset(self._conanfile.settings) + @staticmethod + def _msvs_toolset(settings): + compiler = settings.get_safe("compiler") + compiler_version = settings.get_safe("compiler.version") if compiler == "msvc": - build_type = self._conanfile.settings.get_safe("build_type") + version = compiler_version[:4] # Remove the latest version number 19.1X if existing + toolsets = {'19.0': 'v140', # TODO: This is common to CMake, refactor + '19.1': 'v141', + '19.2': 'v142'} + return toolsets[version] + if compiler == "intel": + compiler_version = compiler_version if "." in compiler_version else \ + "%s.0" % compiler_version + return "Intel C++ Compiler " + compiler_version + if compiler == "Visual Studio": + toolset = settings.get_safe("compiler.toolset") + if not toolset: + toolsets = {"16": "v142", + "15": "v141", + "14": "v140", + "12": "v120", + "11": "v110", + "10": "v100", + "9": "v90", + "8": "v80"} + toolset = toolsets.get(compiler_version) + return toolset or "" + + @staticmethod + def _runtime_library(settings): + compiler = settings.compiler + runtime = settings.get_safe("compiler.runtime") + if compiler == "msvc": + build_type = settings.get_safe("build_type") if build_type != "Debug": runtime_library = {"static": "MultiThreaded", "dyanmic": "MultiThreadedDLL"}.get(runtime, "") @@ -72,8 +96,14 @@ def format_macro(k, value): "MTd": "MultiThreadedDebug", "MD": "MultiThreadedDLL", "MDd": "MultiThreadedDebugDLL"}.get(runtime, "") + return runtime_library - content = textwrap.dedent("""\ + def _write_config_toolchain(self, config_filename): + + def format_macro(k, value): + return '%s="%s"' % (k, value) if value is not None else k + + toolchain_file = textwrap.dedent("""\ @@ -92,25 +122,18 @@ def format_macro(k, value): """) preprocessor_definitions = ";".join([format_macro(k, v) for k, v in self.preprocessor_definitions.items()]) - # It is useless to set PlatformToolset in the config file, because the conditional checks it - cppstd = "stdcpp%s" % cppstd if cppstd else "" - toolset = toolset or "" - - if compiler == "msvc": - version = compiler_version[:4] # Remove the latest version number 19.1X if existing - _visuals = {'19.0': 'v140', # TODO: This is common to CMake, refactor - '19.1': 'v141', - '19.2': 'v142'} - toolset = _visuals[version] + cppstd = "stdcpp%s" % self.cppstd if self.cppstd else "" + runtime_library = self.runtime_library + toolset = self.toolset compile_options = self._conanfile.conf["tools.microsoft.msbuildtoolchain"].compile_options if compile_options is not None: compile_options = eval(compile_options) self.compile_options.update(compile_options) compile_options = "".join("\n <{k}>{v}".format(k=k, v=v) for k, v in self.compile_options.items()) - config_props = content.format(preprocessor_definitions, runtime_library, cppstd, - compile_options, toolset) + config_props = toolchain_file.format(preprocessor_definitions, runtime_library, cppstd, + compile_options, toolset) config_filepath = os.path.abspath(config_filename) self._conanfile.output.info("MSBuildToolchain created %s" % config_filename) save(config_filepath, config_props) diff --git a/conans/client/tools/win.py b/conans/client/tools/win.py index 146010b42cb..8852245ee0b 100644 --- a/conans/client/tools/win.py +++ b/conans/client/tools/win.py @@ -144,8 +144,6 @@ def msvs_toolset(conanfile): compiler_version = compiler_version if "." in compiler_version else \ "%s.0" % compiler_version toolset = "Intel C++ Compiler " + compiler_version - elif compiler == "msvc": - toolset = "v{}".format(compiler_version) else: toolset = MSVS_DEFAULT_TOOLSETS.get(compiler_version) return toolset From a311923a19ded214a0d0c7741fe61c82c40aa2eb Mon Sep 17 00:00:00 2001 From: James Date: Mon, 18 Jan 2021 17:16:46 +0100 Subject: [PATCH 23/32] Update conan/tools/microsoft/toolchain.py Co-authored-by: Carlos Zoido --- conan/tools/microsoft/toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index e0919de940a..31a737eff20 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -87,7 +87,7 @@ def _runtime_library(settings): build_type = settings.get_safe("build_type") if build_type != "Debug": runtime_library = {"static": "MultiThreaded", - "dyanmic": "MultiThreadedDLL"}.get(runtime, "") + "dynamic": "MultiThreadedDLL"}.get(runtime, "") else: runtime_library = {"static": "MultiThreadedDebug", "dyanmic": "MultiThreadedDebugDLL"}.get(runtime, "") From 59ed3b0fcc9511e69d7d3a433630415b81e8b083 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 18 Jan 2021 17:16:52 +0100 Subject: [PATCH 24/32] Update conan/tools/microsoft/toolchain.py Co-authored-by: Carlos Zoido --- conan/tools/microsoft/toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index 31a737eff20..b450141c8a9 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -90,7 +90,7 @@ def _runtime_library(settings): "dynamic": "MultiThreadedDLL"}.get(runtime, "") else: runtime_library = {"static": "MultiThreadedDebug", - "dyanmic": "MultiThreadedDebugDLL"}.get(runtime, "") + "dynamic": "MultiThreadedDebugDLL"}.get(runtime, "") else: runtime_library = {"MT": "MultiThreaded", "MTd": "MultiThreadedDebug", From ef7053c306548fa9bd229a125ff5e169bf1e003d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20G=C3=BCrtler?= Date: Thu, 14 Jan 2021 19:22:25 +0100 Subject: [PATCH 25/32] Fix #7715, in rpath_flags use host OS instead of build OS to determine -rpath separator (#7716) * Fix #7715, in rpath_flags use host OS instead of build OS to determine the separator for the ld -rpath flag which is neccessary for cross-compiling to Mac OS * For #7715, don't pass os_host to rpath_flags but extract from settings, pass os_build again and only set rpath_separator to , if compiling for Mac OS from Linux or Mac OS via GCC_LIKE * Fix test_compiler_args for cross-compiling Mac OS X -> Linux * Update conans/client/build/compiler_flags.py Co-authored-by: SSE4 * Update conans/client/build/compiler_flags.py Co-authored-by: SSE4 * Update conans/test/unittests/client/generators/compiler_args_test.py * Update conans/client/build/compiler_flags.py * Use -rpath, in all tests for all platforms * fixing tests Co-authored-by: James Co-authored-by: SSE4 --- conans/client/build/compiler_flags.py | 2 +- conans/test/functional/generators/pkg_config_test.py | 6 ++---- .../client/build/autotools_environment_test.py | 2 +- .../unittests/client/generators/compiler_args_test.py | 10 +++++----- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/conans/client/build/compiler_flags.py b/conans/client/build/compiler_flags.py index 095d0eb52de..936ecb325ce 100644 --- a/conans/client/build/compiler_flags.py +++ b/conans/client/build/compiler_flags.py @@ -28,7 +28,7 @@ def rpath_flags(settings, os_build, lib_paths): if not os_build: return [] if compiler in GCC_LIKE: - rpath_separator = "," if is_apple_os(os_build) else "=" + rpath_separator = "," return ['-Wl,-rpath%s"%s"' % (rpath_separator, x.replace("\\", "/")) for x in lib_paths if x] return [] diff --git a/conans/test/functional/generators/pkg_config_test.py b/conans/test/functional/generators/pkg_config_test.py index 1a9a459fb05..f24fe8167d5 100644 --- a/conans/test/functional/generators/pkg_config_test.py +++ b/conans/test/functional/generators/pkg_config_test.py @@ -44,9 +44,7 @@ def package_info(self): self.assertTrue(os.path.exists(pc_path)) pc_content = load(pc_path) expected_rpaths = "" - if platform.system() == "Linux": - expected_rpaths = ' -Wl,-rpath="${libdir}" -Wl,-rpath="${libdir2}"' - elif platform.system() == "Darwin": + if platform.system() in ("Linux", "Darwin"): expected_rpaths = ' -Wl,-rpath,"${libdir}" -Wl,-rpath,"${libdir2}"' expected_content = """libdir=/my_absoulte_path/fake/mylib/lib libdir2=${prefix}/lib2 @@ -138,7 +136,7 @@ def package_info(self): pc_path = os.path.join(client.current_folder, "MyLib.pc") self.assertTrue(os.path.exists(pc_path)) pc_content = load(pc_path) - self.assertIn("-Wl,-rpath=\"${libdir}\"", pc_content) + self.assertIn("-Wl,-rpath,\"${libdir}\"", pc_content) def test_system_libs(self): conanfile = """ diff --git a/conans/test/unittests/client/build/autotools_environment_test.py b/conans/test/unittests/client/build/autotools_environment_test.py index bd1354846f3..1d9157b0d68 100644 --- a/conans/test/unittests/client/build/autotools_environment_test.py +++ b/conans/test/unittests/client/build/autotools_environment_test.py @@ -388,7 +388,7 @@ def test_rpath_optin(self): 'CXXFLAGS': 'a_c_flag -m64 -O3 -s --sysroot=/path/to/folder a_cxx_flag', 'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework -framework twoframework ' '-F one/framework/path -m64 --sysroot=/path/to/folder ' - '-Wl,-rpath="one/lib/path" -Lone/lib/path', + '-Wl,-rpath,"one/lib/path" -Lone/lib/path', 'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib'} be = AutoToolsBuildEnvironment(conanfile, include_rpath_flags=True) self.assertEqual(be.vars, expected) diff --git a/conans/test/unittests/client/generators/compiler_args_test.py b/conans/test/unittests/client/generators/compiler_args_test.py index 6ebfbe5a3d9..52423562cd6 100644 --- a/conans/test/unittests/client/generators/compiler_args_test.py +++ b/conans/test/unittests/client/generators/compiler_args_test.py @@ -76,7 +76,7 @@ def test_gcc(self): gcc = GCCGenerator(conan_file) self.assertEqual('-Dmydefine1 -I/root/include -I/root/path/to/include1' ' cxx_flag1 c_flag1 -m32 -O3 -s -DNDEBUG' - ' -Wl,-rpath="/root/lib" -Wl,-rpath="/root/path/to/lib1"' + ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"' ' -L/root/lib -L/root/path/to/lib1 -lmylib' ' -F /root/Frameworks -std=gnu++17', gcc.content) @@ -87,7 +87,7 @@ def test_gcc(self): gcc = GCCGenerator(conan_file) self.assertEqual('-Dmydefine1 -I/root/include -I/root/path/to/include1' ' cxx_flag1 c_flag1 -m64 -g' - ' -Wl,-rpath="/root/lib" -Wl,-rpath="/root/path/to/lib1"' + ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"' ' -L/root/lib -L/root/path/to/lib1 -lmylib' ' -D_GLIBCXX_USE_CXX11_ABI=1 -F /root/Frameworks -std=gnu++17', gcc.content) @@ -96,7 +96,7 @@ def test_gcc(self): gcc = GCCGenerator(conan_file) self.assertEqual('-Dmydefine1 -I/root/include -I/root/path/to/include1' ' cxx_flag1 c_flag1 -m64 -g' - ' -Wl,-rpath="/root/lib" -Wl,-rpath="/root/path/to/lib1"' + ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"' ' -L/root/lib -L/root/path/to/lib1 -lmylib' ' -D_GLIBCXX_USE_CXX11_ABI=0 -F /root/Frameworks -std=gnu++17', gcc.content) @@ -110,7 +110,7 @@ def test_gcc(self): # GCC generator ignores the compiler setting, it is always gcc self.assertEqual('-Dmydefine1 -I/root/include -I/root/path/to/include1' ' cxx_flag1 c_flag1 -m32 -O3 -s -DNDEBUG' - ' -Wl,-rpath="/root/lib" -Wl,-rpath="/root/path/to/lib1"' + ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"' ' -L/root/lib -L/root/path/to/lib1 -lmylib' ' -D_GLIBCXX_USE_CXX11_ABI=0 -F /root/Frameworks -std=gnu++17', gcc.content) @@ -190,6 +190,6 @@ def test_system_libs(self): args = CompilerArgsGenerator(conan_file) self.assertEqual('-Dmydefine1 -I/root/include -I/root/path/to/include1' ' cxx_flag1 c_flag1 -m64 -O3 -s -DNDEBUG' - ' -Wl,-rpath="/root/lib" -Wl,-rpath="/root/path/to/lib1"' + ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"' ' -L/root/lib -L/root/path/to/lib1 -lmylib -lsystem_lib1' ' -F /root/Frameworks', args.content) From b4fd9771e3504681063cff801f2e709fcd34d38a Mon Sep 17 00:00:00 2001 From: James Date: Fri, 15 Jan 2021 13:47:38 +0100 Subject: [PATCH 26/32] modernizing tests (#8340) --- .../graph/package_id_modes_test.py | 67 ------------------- .../full_revision_mode_test.py | 18 +++++ .../package_id/package_id_modes_test.py | 63 +++++++++++++++++ 3 files changed, 81 insertions(+), 67 deletions(-) delete mode 100644 conans/test/integration/graph/package_id_modes_test.py rename conans/test/integration/{graph => package_id}/full_revision_mode_test.py (94%) create mode 100644 conans/test/integration/package_id/package_id_modes_test.py diff --git a/conans/test/integration/graph/package_id_modes_test.py b/conans/test/integration/graph/package_id_modes_test.py deleted file mode 100644 index 03bf8861b54..00000000000 --- a/conans/test/integration/graph/package_id_modes_test.py +++ /dev/null @@ -1,67 +0,0 @@ -from conans.client.tools import environment_append -from conans.model.ref import ConanFileReference -from conans.test.integration.graph.graph_manager_base import GraphManagerTest -from conans.test.utils.tools import GenConanfile - - -class PackageIDGraphTests(GraphManagerTest): - - def test_recipe_modes(self): - configs = [] - mode = "semver_mode" - configs.append((mode, "liba/1.1.1@user/testing", "8ecbf93ba63522ffb32573610c80ab4dcb399b52")) - configs.append((mode, "liba/1.1.2@user/testing", "8ecbf93ba63522ffb32573610c80ab4dcb399b52")) - configs.append((mode, "liba/1.2.1@other/stable", "8ecbf93ba63522ffb32573610c80ab4dcb399b52")) - mode = "patch_mode" - configs.append((mode, "liba/1.1.1@user/testing", "bd664570d5174c601d5d417bc19257c4dba48f2e")) - configs.append((mode, "liba/1.1.2@user/testing", "fb1f766173191d44b67156c6b9ac667422e99286")) - configs.append((mode, "liba/1.1.1@other/stable", "bd664570d5174c601d5d417bc19257c4dba48f2e")) - mode = "full_recipe_mode" - configs.append((mode, "liba/1.1.1@user/testing", "9cbe703e1dee73a2a6807f71d8551c5f1e1b08fd")) - configs.append((mode, "liba/1.1.2@user/testing", "42a9ff9024adabbd54849331cf01be7d95139948")) - configs.append((mode, "liba/1.1.1@user/stable", "b41d6c026473cffed4abded4b0eaa453497be1d2")) - - def _assert_recipe_mode(ref_arg, package_id_arg): - libb_ref = ConanFileReference.loads("libb/0.1@user/testing") - self._cache_recipe(ref_arg, GenConanfile().with_name("liba").with_version("0.1.1")) - self._cache_recipe(libb_ref, GenConanfile().with_name("libb").with_version("0.1") - .with_require(ref_arg)) - deps_graph = self.build_graph(GenConanfile().with_name("app").with_version("0.1") - .with_require(libb_ref)) - - self.assertEqual(3, len(deps_graph.nodes)) - app = deps_graph.root - libb = app.dependencies[0].dst - liba = libb.dependencies[0].dst - - self.assertEqual(liba.package_id, "5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9") - self.assertEqual(libb.package_id, package_id_arg) - - for package_id_mode, ref, package_id in configs: - self.cache.config.set_item("general.default_package_id_mode", package_id_mode) - _assert_recipe_mode(ConanFileReference.loads(ref), package_id) - - for package_id_mode, ref, package_id in configs: - with environment_append({"CONAN_DEFAULT_PACKAGE_ID_MODE": package_id_mode}): - _assert_recipe_mode(ConanFileReference.loads(ref), package_id) - - def test_package_revision_mode(self): - self.cache.config.set_item("general.default_package_id_mode", "package_revision_mode") - - liba_ref1 = ConanFileReference.loads("liba/0.1.1@user/testing") - libb_ref = ConanFileReference.loads("libb/0.1@user/testing") - self._cache_recipe(liba_ref1, GenConanfile().with_name("liba").with_version("0.1.1")) - self._cache_recipe(libb_ref, GenConanfile().with_name("libb").with_version("0.1") - .with_require(liba_ref1)) - - deps_graph = self.build_graph(GenConanfile().with_name("app").with_version("0.1") - .with_require(libb_ref), - install=True) - - self.assertEqual(3, len(deps_graph.nodes)) - app = deps_graph.root - libb = app.dependencies[0].dst - liba = libb.dependencies[0].dst - - self.assertEqual(liba.package_id, "5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9") - self.assertEqual(libb.package_id, "d22462afa90bb9e1c2b35ce413111fff04504399") diff --git a/conans/test/integration/graph/full_revision_mode_test.py b/conans/test/integration/package_id/full_revision_mode_test.py similarity index 94% rename from conans/test/integration/graph/full_revision_mode_test.py rename to conans/test/integration/package_id/full_revision_mode_test.py index 33b58133d28..c52130e079e 100644 --- a/conans/test/integration/graph/full_revision_mode_test.py +++ b/conans/test/integration/package_id/full_revision_mode_test.py @@ -319,3 +319,21 @@ def test_full_dependency_graph(self): self.client.run("install StationinterfaceRpm.py") for pkg, id_ in ids.items(): self.assertIn("%s:%s - Cache" % (pkg, id_), self.client.out) + + +def test_package_revision_mode_full_transitive_package_id(): + # https://github.com/conan-io/conan/issues/8310 + client = TestClient() + client.run("config set general.default_package_id_mode=package_revision_mode") + client.run("config set general.full_transitive_package_id=1") + client.save({"pkga/conanfile.py": GenConanfile(), + "pkgb/conanfile.py": GenConanfile().with_require("pkga/0.1"), + "pkgc/conanfile.py": GenConanfile().with_require("pkgb/0.1"), + "pkgd/conanfile.py": GenConanfile().with_require("pkgc/0.1")}) + client.run("export pkga pkga/0.1@") + client.run("export pkgb pkgb/0.1@") + client.run("export pkgc pkgc/0.1@") + client.run("create pkgd pkgd/0.1@ --build=missing") + assert "pkgc/0.1:Package_ID_unknown - Unknown" in client.out + assert "pkgc/0.1: Unknown binary for pkgc/0.1, computing updated ID" in client.out + assert "pkgc/0.1: Package '1d602da5278b24bf3aa0e19e6e199126cdfb7094' created" in client.out diff --git a/conans/test/integration/package_id/package_id_modes_test.py b/conans/test/integration/package_id/package_id_modes_test.py new file mode 100644 index 00000000000..f594953f6ab --- /dev/null +++ b/conans/test/integration/package_id/package_id_modes_test.py @@ -0,0 +1,63 @@ +from conans.client.tools import environment_append +from conans.test.utils.tools import GenConanfile, TestClient +from conans.util.files import save + + +def test_recipe_modes(): + configs = [] + mode = "semver_mode" + configs.append((mode, "liba/1.1.1@user/testing", "8ecbf93ba63522ffb32573610c80ab4dcb399b52")) + configs.append((mode, "liba/1.1.2@user/testing", "8ecbf93ba63522ffb32573610c80ab4dcb399b52")) + configs.append((mode, "liba/1.2.1@other/stable", "8ecbf93ba63522ffb32573610c80ab4dcb399b52")) + mode = "patch_mode" + configs.append((mode, "liba/1.1.1@user/testing", "bd664570d5174c601d5d417bc19257c4dba48f2e")) + configs.append((mode, "liba/1.1.2@user/testing", "fb1f766173191d44b67156c6b9ac667422e99286")) + configs.append((mode, "liba/1.1.1@other/stable", "bd664570d5174c601d5d417bc19257c4dba48f2e")) + mode = "full_recipe_mode" + configs.append((mode, "liba/1.1.1@user/testing", "9cbe703e1dee73a2a6807f71d8551c5f1e1b08fd")) + configs.append((mode, "liba/1.1.2@user/testing", "42a9ff9024adabbd54849331cf01be7d95139948")) + configs.append((mode, "liba/1.1.1@user/stable", "b41d6c026473cffed4abded4b0eaa453497be1d2")) + + client = TestClient() + # TODO: These 2 little simplifications can reduce test time by 30-40%, to do in test framework + save(client.cache.settings_path, "") + save(client.cache.default_profile_path, "") + + def _assert_recipe_mode(liba_ref, package_id_arg): + client.save({"liba/conanfile.py": GenConanfile("liba"), + "libb/conanfile.py": GenConanfile("libb", "0.1").with_require(liba_ref), + "app/conanfile.py": GenConanfile("app", "0.1").with_require("libb/0.1")}) + client.run("create liba {}".format(liba_ref)) + client.run("create libb") + client.run("create app") + + assert "{}:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Cache".format(liba_ref) in client.out + assert "libb/0.1:{} - Cache".format(package_id_arg) in client.out + + for package_id_mode, ref, package_id in configs: + client.run("config set general.default_package_id_mode={}".format(package_id_mode)) + _assert_recipe_mode(ref, package_id) + + for package_id_mode, ref, package_id in configs: + with environment_append({"CONAN_DEFAULT_PACKAGE_ID_MODE": package_id_mode}): + _assert_recipe_mode(ref, package_id) + + +def test_package_revision_mode(): + client = TestClient() + # TODO: These 2 little simplifications can reduce test time by 30-40%, to do in test framework + save(client.cache.settings_path, "") + save(client.cache.default_profile_path, "") + + client.run("config set general.default_package_id_mode=package_revision_mode") + + client.save({"liba/conanfile.py": GenConanfile("liba", "0.1.1"), + "libb/conanfile.py": GenConanfile("libb", "0.1").with_require("liba/0.1.1"), + "app/conanfile.py": GenConanfile("app", "0.1").with_require("libb/0.1")}) + + client.run("create liba") + client.run("create libb") + client.run("create app") + + assert "liba/0.1.1:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Cache" in client.out + assert "libb/0.1:f2431acdad185a6626b90ee1dffb06445f887cbb - Cache" in client.out From 0f2a41665b599b828e818f5479b920efff407dfd Mon Sep 17 00:00:00 2001 From: James Date: Sat, 16 Jan 2021 23:10:55 +0100 Subject: [PATCH 27/32] extracting some common code to base class (#8341) --- conan/tools/cmake/android.py | 25 ------------------------- conan/tools/cmake/base.py | 21 +++++++++++++++++++++ conan/tools/cmake/generic.py | 21 --------------------- conan/tools/cmake/ios.py | 20 -------------------- 4 files changed, 21 insertions(+), 66 deletions(-) diff --git a/conan/tools/cmake/android.py b/conan/tools/cmake/android.py index 7d7ef390559..1093b9eda9e 100644 --- a/conan/tools/cmake/android.py +++ b/conan/tools/cmake/android.py @@ -19,31 +19,6 @@ class CMakeAndroidToolchain(CMakeToolchainBase): set(CMAKE_ANDROID_STL_TYPE {{ CMAKE_ANDROID_STL_TYPE }}) set(CMAKE_ANDROID_NDK {{ CMAKE_ANDROID_NDK }}) {% endblock %} - - {% block main %} - {{ super() }} - - {% if shared_libs -%} - message(STATUS "Conan toolchain: Setting BUILD_SHARED_LIBS= {{ shared_libs }}") - set(BUILD_SHARED_LIBS {{ shared_libs }}) - {%- endif %} - - {% if parallel -%} - set(CONAN_CXX_FLAGS "${CONAN_CXX_FLAGS} {{ parallel }}") - set(CONAN_C_FLAGS "${CONAN_C_FLAGS} {{ parallel }}") - {%- endif %} - - {% if cppstd -%} - message(STATUS "Conan C++ Standard {{ cppstd }} with extensions {{ cppstd_extensions }}}") - set(CMAKE_CXX_STANDARD {{ cppstd }}) - set(CMAKE_CXX_EXTENSIONS {{ cppstd_extensions }}) - {%- endif %} - - set(CMAKE_CXX_FLAGS_INIT "${CONAN_CXX_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_C_FLAGS_INIT "${CONAN_C_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_SHARED_LINKER_FLAGS_INIT "${CONAN_SHARED_LINKER_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_EXE_LINKER_FLAGS_INIT "${CONAN_EXE_LINKER_FLAGS}" CACHE STRING "" FORCE) - {% endblock %} """) # TODO: fPIC, fPIE diff --git a/conan/tools/cmake/base.py b/conan/tools/cmake/base.py index ee1616f983c..8fd2d2ea9d4 100644 --- a/conan/tools/cmake/base.py +++ b/conan/tools/cmake/base.py @@ -95,6 +95,27 @@ class CMakeToolchainBase(object): {%- endif %} {% endblock %} + {% if shared_libs -%} + message(STATUS "Conan toolchain: Setting BUILD_SHARED_LIBS= {{ shared_libs }}") + set(BUILD_SHARED_LIBS {{ shared_libs }}) + {%- endif %} + + {% if parallel -%} + set(CONAN_CXX_FLAGS "${CONAN_CXX_FLAGS} {{ parallel }}") + set(CONAN_C_FLAGS "${CONAN_C_FLAGS} {{ parallel }}") + {%- endif %} + + {% if cppstd -%} + message(STATUS "Conan C++ Standard {{ cppstd }} with extensions {{ cppstd_extensions }}}") + set(CMAKE_CXX_STANDARD {{ cppstd }}) + set(CMAKE_CXX_EXTENSIONS {{ cppstd_extensions }}) + {%- endif %} + + set(CMAKE_CXX_FLAGS_INIT "${CONAN_CXX_FLAGS}" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_INIT "${CONAN_C_FLAGS}" CACHE STRING "" FORCE) + set(CMAKE_SHARED_LINKER_FLAGS_INIT "${CONAN_SHARED_LINKER_FLAGS}" CACHE STRING "" FORCE) + set(CMAKE_EXE_LINKER_FLAGS_INIT "${CONAN_EXE_LINKER_FLAGS}" CACHE STRING "" FORCE) + # Variables {% for it, value in variables.items() %} set({{ it }} "{{ value }}" CACHE STRING "Variable {{ it }} conan-toolchain defined") diff --git a/conan/tools/cmake/generic.py b/conan/tools/cmake/generic.py index a05040fd42b..0bd3b136929 100644 --- a/conan/tools/cmake/generic.py +++ b/conan/tools/cmake/generic.py @@ -68,11 +68,6 @@ class CMakeGenericToolchain(CMakeToolchainBase): {% block main %} {{ super() }} - {% if shared_libs -%} - message(STATUS "Conan toolchain: Setting BUILD_SHARED_LIBS= {{ shared_libs }}") - set(BUILD_SHARED_LIBS {{ shared_libs }}) - {%- endif %} - {% if fpic -%} message(STATUS "Conan toolchain: Setting CMAKE_POSITION_INDEPENDENT_CODE=ON (options.fPIC)") set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -85,11 +80,6 @@ class CMakeGenericToolchain(CMakeToolchainBase): set(CMAKE_INSTALL_NAME_DIR "") {% endif -%} - {% if parallel -%} - set(CONAN_CXX_FLAGS "${CONAN_CXX_FLAGS} {{ parallel }}") - set(CONAN_C_FLAGS "${CONAN_C_FLAGS} {{ parallel }}") - {%- endif %} - {% if architecture -%} set(CONAN_CXX_FLAGS "${CONAN_CXX_FLAGS} {{ architecture }}") set(CONAN_C_FLAGS "${CONAN_C_FLAGS} {{ architecture }}") @@ -104,12 +94,6 @@ class CMakeGenericToolchain(CMakeToolchainBase): add_definitions(-D_GLIBCXX_USE_CXX11_ABI={{ glibcxx }}) {%- endif %} - {% if cppstd -%} - message(STATUS "Conan C++ Standard {{ cppstd }} with extensions {{ cppstd_extensions }}") - set(CMAKE_CXX_STANDARD {{ cppstd }}) - set(CMAKE_CXX_EXTENSIONS {{ cppstd_extensions }}) - {%- endif %} - {% if vs_runtimes %} {% set genexpr = namespace(str='') %} {%- for config, value in vs_runtimes.items() -%} @@ -118,11 +102,6 @@ class CMakeGenericToolchain(CMakeToolchainBase): {%- endfor -%} set(CMAKE_MSVC_RUNTIME_LIBRARY "{{ genexpr.str }}") {% endif %} - - set(CMAKE_CXX_FLAGS_INIT "${CONAN_CXX_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_C_FLAGS_INIT "${CONAN_C_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_SHARED_LINKER_FLAGS_INIT "${CONAN_SHARED_LINKER_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_EXE_LINKER_FLAGS_INIT "${CONAN_EXE_LINKER_FLAGS}" CACHE STRING "" FORCE) {% endblock %} """) diff --git a/conan/tools/cmake/ios.py b/conan/tools/cmake/ios.py index 04db1f6ab58..1ea8edef234 100644 --- a/conan/tools/cmake/ios.py +++ b/conan/tools/cmake/ios.py @@ -21,26 +21,6 @@ class CMakeiOSToolchain(CMakeToolchainBase): set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "123456789A" CACHE INTERNAL "") endif() {% endblock %} - {% block main %} - {{ super() }} - {% if shared_libs -%} - message(STATUS "Conan toolchain: Setting BUILD_SHARED_LIBS= {{ shared_libs }}") - set(BUILD_SHARED_LIBS {{ shared_libs }}) - {%- endif %} - {% if parallel -%} - set(CONAN_CXX_FLAGS "${CONAN_CXX_FLAGS} {{ parallel }}") - set(CONAN_C_FLAGS "${CONAN_C_FLAGS} {{ parallel }}") - {%- endif %} - {% if cppstd -%} - message(STATUS "Conan C++ Standard {{ cppstd }} with extensions {{ cppstd_extensions }}}") - set(CMAKE_CXX_STANDARD {{ cppstd }}) - set(CMAKE_CXX_EXTENSIONS {{ cppstd_extensions }}) - {%- endif %} - set(CMAKE_CXX_FLAGS_INIT "${CONAN_CXX_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_C_FLAGS_INIT "${CONAN_C_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_SHARED_LINKER_FLAGS_INIT "${CONAN_SHARED_LINKER_FLAGS}" CACHE STRING "" FORCE) - set(CMAKE_EXE_LINKER_FLAGS_INIT "${CONAN_EXE_LINKER_FLAGS}" CACHE STRING "" FORCE) - {% endblock %} """) def __init__(self, conanfile, build_type=None, **kwargs): From 52d5e426764702711c7095195debba0f822a0306 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 18 Jan 2021 12:18:59 +0100 Subject: [PATCH 28/32] modernizing tests (#8345) --- conans/test/functional/package_id/__init__.py | 0 .../functional/package_id/package_id_test.py | 141 --- .../py_requires/python_requires_test.py | 850 +---------------- .../integration/package_id/package_id_test.py | 136 +++ .../py_requires/python_requires_test.py | 855 ++++++++++++++++++ 5 files changed, 992 insertions(+), 990 deletions(-) delete mode 100644 conans/test/functional/package_id/__init__.py delete mode 100644 conans/test/functional/package_id/package_id_test.py create mode 100644 conans/test/integration/package_id/package_id_test.py create mode 100644 conans/test/integration/py_requires/python_requires_test.py diff --git a/conans/test/functional/package_id/__init__.py b/conans/test/functional/package_id/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/conans/test/functional/package_id/package_id_test.py b/conans/test/functional/package_id/package_id_test.py deleted file mode 100644 index 529edb9444e..00000000000 --- a/conans/test/functional/package_id/package_id_test.py +++ /dev/null @@ -1,141 +0,0 @@ -import textwrap -import unittest - -import pytest - -from conans.test.utils.tools import NO_SETTINGS_PACKAGE_ID, TestClient, TestServer - - -class PackageIdTest(unittest.TestCase): - - def test_double_package_id_call(self): - # https://github.com/conan-io/conan/issues/3085 - conanfile = """from conans import ConanFile - -class TestConan(ConanFile): - settings = "os", "arch" - - def package_id(self): - self.output.info("Calling package_id()") -""" - client = TestClient() - client.save({"conanfile.py": conanfile}) - client.run("create . Pkg/0.1@user/testing") - out = str(client.out) - self.assertEqual(1, out.count("Pkg/0.1@user/testing: Calling package_id()")) - - def test_remove_option_setting(self): - # https://github.com/conan-io/conan/issues/2826 - conanfile = """from conans import ConanFile - -class TestConan(ConanFile): - settings = "os" - options = {"opt": [True, False]} - default_options = "opt=False" - - def package_id(self): - self.output.info("OPTION OPT=%s" % self.info.options.opt) - del self.info.settings.os - del self.info.options.opt -""" - client = TestClient() - client.save({"conanfile.py": conanfile}) - client.run("create . Pkg/0.1@user/testing -s os=Windows") - self.assertIn("Pkg/0.1@user/testing: OPTION OPT=False", client.out) - self.assertIn("Pkg/0.1@user/testing: Package " - "'%s' created" % NO_SETTINGS_PACKAGE_ID, - client.out) - client.run("create . Pkg/0.1@user/testing -s os=Linux -o Pkg:opt=True") - self.assertIn("Pkg/0.1@user/testing: OPTION OPT=True", client.out) - self.assertIn("Pkg/0.1@user/testing: Package " - "'%s' created" % NO_SETTINGS_PACKAGE_ID, - client.out) - - @pytest.mark.tool_compiler - def test_value_parse(self): - # https://github.com/conan-io/conan/issues/2816 - conanfile = """ -from conans import ConanFile - -class TestConan(ConanFile): - name = "test" - version = "0.1" - settings = "os", "compiler", "arch", "build_type" - exports_sources = "header.h" - - def package_id(self): - self.info.settings.compiler.version = "kk=kk" - - def package(self): - self.copy("header.h", dst="include", keep_path=True) -""" - server = TestServer([("*/*@*/*", "*")], [("*/*@*/*", "*")], users={"lasote": "mypass"}) - servers = {"default": server} - client = TestClient(servers=servers, users={"default": [("lasote", "mypass")]}) - client.save({"conanfile.py": conanfile, - "header.h": "header content"}) - client.run("create . danimtb/testing") - client.run("search test/0.1@danimtb/testing") - self.assertIn("compiler.version: kk=kk", client.out) - client.run("upload test/0.1@danimtb/testing --all") - client.run("remove test/0.1@danimtb/testing --force") - client.run("install test/0.1@danimtb/testing") - client.run("search test/0.1@danimtb/testing") - self.assertIn("compiler.version: kk=kk", client.out) - - def test_option_in(self): - # https://github.com/conan-io/conan/issues/7299 - conanfile = textwrap.dedent(""" - from conans import ConanFile - - class TestConan(ConanFile): - options = {"fpic": [True, False]} - default_options = {"fpic": True} - def package_id(self): - if "fpic" in self.options: - self.output.info("fpic is an option!!!") - if "fpic" in self.info.options: # Not documented - self.output.info("fpic is an info.option!!!") - if "other" not in self.options: - self.output.info("other is not an option!!!") - if "other" not in self.info.options: # Not documented - self.output.info("other is not an info.option!!!") - try: - self.options.whatever - except Exception as e: - self.output.error("OPTIONS: %s" % e) - try: - self.info.options.whatever - except Exception as e: - self.output.error("INFO: %s" % e) - - """) - client = TestClient() - client.save({"conanfile.py": conanfile}) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("fpic is an option!!!", client.out) - self.assertIn("fpic is an info.option!!!", client.out) - self.assertIn("other is not an option!!!", client.out) - self.assertIn("other is not an info.option!!!", client.out) - self.assertIn("ERROR: OPTIONS: option 'whatever' doesn't exist", client.out) - self.assertIn("ERROR: INFO: option 'whatever' doesn't exist", client.out) - - def test_build_type_remove_windows(self): - # https://github.com/conan-io/conan/issues/7603 - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class Pkg(ConanFile): - settings = "os", "compiler", "arch", "build_type" - def package_id(self): - if self.settings.os == "Windows" and self.settings.compiler == "Visual Studio": - del self.info.settings.build_type - del self.info.settings.compiler.runtime - """) - client.save({"conanfile.py": conanfile}) - client.run('create . pkg/0.1@ -s os=Windows -s compiler="Visual Studio" ' - '-s compiler.version=14 -s build_type=Release') - self.assertIn("pkg/0.1:e1f7c8ffe5f9342d04ab704810faf93060ae3d70 - Build", client.out) - client.run('install pkg/0.1@ -s os=Windows -s compiler="Visual Studio" ' - '-s compiler.version=14 -s build_type=Debug') - self.assertIn("pkg/0.1:e1f7c8ffe5f9342d04ab704810faf93060ae3d70 - Cache", client.out) diff --git a/conans/test/functional/py_requires/python_requires_test.py b/conans/test/functional/py_requires/python_requires_test.py index ab46a9910bb..c0db3eec0c0 100644 --- a/conans/test/functional/py_requires/python_requires_test.py +++ b/conans/test/functional/py_requires/python_requires_test.py @@ -1,288 +1,14 @@ import json -import os import textwrap -import time import unittest import pytest -from parameterized import parameterized -from conans.model.ref import ConanFileReference -from conans.paths import CONANFILE -from conans.test.utils.tools import TestClient, GenConanfile +from conans.test.utils.tools import TestClient class PyRequiresExtendTest(unittest.TestCase): - @staticmethod - def _define_base(client): - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - def source(self): - self.output.info("My cool source!") - def build(self): - self.output.info("My cool build!") - def package(self): - self.output.info("My cool package!") - def package_info(self): - self.output.info("My cool package_info!") - """) - client.save({"conanfile.py": conanfile}) - client.run("export . base/1.1@user/testing") - - def test_reuse(self): - client = TestClient(default_server_user=True) - self._define_base(client) - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/1.1@user/testing" - python_requires_extend = "base.MyConanfileBase" - """) - client.save({"conanfile.py": reuse}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) - - client.run("upload * --all --confirm") - client.run("remove * -f") - client.run("install Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) - client.run("remove * -f") - client.run("download Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: Package installed " - "69265e58ddc68274e0c5510905003ff78c9db5de", client.out) - - def test_reuse_dot(self): - client = TestClient(default_server_user=True) - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - def build(self): - self.output.info("My cool build!") - """) - client.save({"conanfile.py": conanfile}) - client.run("export . my.base/1.1@user/testing") - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "my.base/1.1@user/testing" - python_requires_extend = "my.base.MyConanfileBase" - """) - client.save({"conanfile.py": reuse}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) - - def test_with_alias(self): - client = TestClient() - self._define_base(client) - client.run("alias base/LATEST@user/testing base/1.1@user/testing") - - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/LATEST@user/testing" - python_requires_extend = "base.MyConanfileBase" - """) - client.save({"conanfile.py": reuse}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) - - def test_reuse_version_ranges(self): - client = TestClient() - self._define_base(client) - - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/[>1.0,<1.2]@user/testing" - python_requires_extend = "base.MyConanfileBase" - """) - - client.save({"conanfile.py": reuse}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Python requires", str(client.out).splitlines()) - self.assertIn(" base/1.1@user/testing", str(client.out).splitlines()) - self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) - - def test_multiple_reuse(self): - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class SourceBuild(ConanFile): - def source(self): - self.output.info("My cool source!") - def build(self): - self.output.info("My cool build!") - """) - client.save({"conanfile.py": conanfile}) - client.run("export . SourceBuild/1.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - class PackageInfo(ConanFile): - def package(self): - self.output.info("My cool package!") - def package_info(self): - self.output.info("My cool package_info!") - """) - client.save({"conanfile.py": conanfile}) - client.run("export . PackageInfo/1.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - python_requires = "SourceBuild/1.0@user/channel", "PackageInfo/1.0@user/channel" - python_requires_extend = "SourceBuild.SourceBuild", "PackageInfo.PackageInfo" - """) - client.save({"conanfile.py": conanfile}) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) - - def test_transitive_access_error(self): - # https://github.com/conan-io/conan/issues/5529 - client = TestClient() - client.save({"conanfile.py": GenConanfile()}) - client.run("export . base/1.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - class Helper(ConanFile): - python_requires = "base/1.0@user/channel" - """) - client.save({"conanfile.py": conanfile}) - client.run("export . helper/1.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - class Pkg(ConanFile): - python_requires = "helper/1.0@user/channel" - def build(self): - self.python_requires["base"] - """) - client.save({"conanfile.py": conanfile}) - client.run("create . pkg/0.1@user/channel", assert_error=True) - self.assertIn("'base' is not a python_require", client.out) - - conanfile = textwrap.dedent(""" - from conans import ConanFile - class Pkg(ConanFile): - python_requires = "helper/1.0@user/channel" - python_requires_extend = "base.HelloConan" - """) - client.save({"conanfile.py": conanfile}) - client.run("create . pkg/0.1@user/channel", assert_error=True) - self.assertIn("'base' is not a python_require", client.out) - - def test_multiple_requires_error(self): - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - myvar = 123 - def myfunct(): - return 123 - class Pkg(ConanFile): - pass - """) - client.save({"conanfile.py": conanfile}) - client.run("export . pkg1/1.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - myvar = 234 - def myfunct(): - return 234 - class Pkg(ConanFile): - pass - """) - client.save({"conanfile.py": conanfile}) - client.run("export . pkg2/1.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - python_requires = "pkg1/1.0@user/channel", "pkg2/1.0@user/channel" - def build(self): - self.output.info("PKG1 N: %s" % self.python_requires["pkg1"].conanfile.name) - self.output.info("PKG1 V: %s" % self.python_requires["pkg1"].conanfile.version) - self.output.info("PKG1 U: %s" % self.python_requires["pkg1"].conanfile.user) - self.output.info("PKG1 C: %s" % self.python_requires["pkg1"].conanfile.channel) - self.output.info("PKG1 : %s" % self.python_requires["pkg1"].module.myvar) - self.output.info("PKG2 : %s" % self.python_requires["pkg2"].module.myvar) - self.output.info("PKG1F : %s" % self.python_requires["pkg1"].module.myfunct()) - self.output.info("PKG2F : %s" % self.python_requires["pkg2"].module.myfunct()) - """) - client.save({"conanfile.py": conanfile}) - client.run("create . Consumer/0.1@user/testing") - self.assertIn("Consumer/0.1@user/testing: PKG1 N: pkg1", client.out) - self.assertIn("Consumer/0.1@user/testing: PKG1 V: 1.0", client.out) - self.assertIn("Consumer/0.1@user/testing: PKG1 U: user", client.out) - self.assertIn("Consumer/0.1@user/testing: PKG1 C: channel", client.out) - self.assertIn("Consumer/0.1@user/testing: PKG1 : 123", client.out) - self.assertIn("Consumer/0.1@user/testing: PKG2 : 234", client.out) - self.assertIn("Consumer/0.1@user/testing: PKG1F : 123", client.out) - self.assertIn("Consumer/0.1@user/testing: PKG2F : 234", client.out) - - def test_local_import(self): - client = TestClient(default_server_user=True) - conanfile = textwrap.dedent(""" - from conans import ConanFile - import mydata - class MyConanfileBase(ConanFile): - exports = "*.py" - def source(self): - self.output.info(mydata.src) - def build(self): - self.output.info(mydata.build) - def package(self): - self.output.info(mydata.pkg) - def package_info(self): - self.output.info(mydata.info) - """) - mydata = textwrap.dedent(""" - src = "My cool source!" - build = "My cool build!" - pkg = "My cool package!" - info = "My cool package_info!" - """) - client.save({"conanfile.py": conanfile, - "mydata.py": mydata}) - client.run("export . base/1.1@user/testing") - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/1.1@user/testing" - python_requires_extend = "base.MyConanfileBase" - """) - - client.save({"conanfile.py": reuse}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) - - client.run("upload * --all --confirm") - client.run("remove * -f") - client.run("install Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) - client.run("remove * -f") - client.run("download Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: Package installed " - "69265e58ddc68274e0c5510905003ff78c9db5de", client.out) - @pytest.mark.tool_git def test_reuse_scm(self): client = TestClient() @@ -395,577 +121,3 @@ class PkgTest(ConanFile): self.assertNotEqual(base_rev, reuse1_rev) self.assertNotEqual(base_rev, reuse2_rev) self.assertNotEqual(reuse2_rev, reuse1_rev) - - def test_reuse_class_members(self): - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - license = "MyLicense" - author = "author@company.com" - exports = "*.txt" - exports_sources = "*.h" - short_paths = True - generators = "cmake" - """) - client.save({"conanfile.py": conanfile, - "header.h": "some content"}) - client.run("export . base/1.1@user/testing") - - reuse = textwrap.dedent(""" - from conans import ConanFile - from conans.tools import load - import os - class PkgTest(ConanFile): - python_requires = "base/1.1@user/testing" - python_requires_extend = "base.MyConanfileBase" - def build(self): - self.output.info("Exports sources! %s" % self.exports_sources) - self.output.info("HEADER CONTENT!: %s" % load("header.h")) - self.output.info("Short paths! %s" % self.short_paths) - self.output.info("License! %s" % self.license) - self.output.info("Author! %s" % self.author) - assert os.path.exists("conanbuildinfo.cmake") - """) - client.save({"conanfile.py": reuse, - "header.h": "pkg new header contents", - "other.txt": "text"}) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: Exports sources! *.h", client.out) - self.assertIn("Pkg/0.1@user/testing exports: Copied 1 '.txt' file: other.txt", - client.out) - self.assertIn("Pkg/0.1@user/testing exports_sources: Copied 1 '.h' file: header.h", - client.out) - self.assertIn("Pkg/0.1@user/testing: Short paths! True", client.out) - self.assertIn("Pkg/0.1@user/testing: License! MyLicense", client.out) - self.assertIn("Pkg/0.1@user/testing: Author! author@company.com", client.out) - self.assertIn("Pkg/0.1@user/testing: HEADER CONTENT!: pkg new header contents", client.out) - ref = ConanFileReference.loads("Pkg/0.1@user/testing") - self.assertTrue(os.path.exists(os.path.join(client.cache.package_layout(ref).export(), - "other.txt"))) - - def test_reuse_system_requirements(self): - # https://github.com/conan-io/conan/issues/7718 - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - def system_requirements(self): - self.output.info("My system_requirements %s being called!" % self.name) - """) - client.save({"conanfile.py": conanfile}) - client.run("export . base/1.1@user/testing") - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/1.1@user/testing" - python_requires_extend = "base.MyConanfileBase" - """) - client.save({"conanfile.py": reuse}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My system_requirements Pkg being called!", client.out) - - def test_overwrite_class_members(self): - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - license = "MyLicense" - author = "author@company.com" - settings = "os", # tuple! - """) - client.save({"conanfile.py": conanfile}) - client.run("export . base/1.1@user/testing") - - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - license = "MIT" - author = "frodo" - settings = "arch", # tuple! - python_requires = "base/1.1@user/testing" - python_requires_extend = "base.MyConanfileBase" - - def init(self): - base = self.python_requires["base"].module.MyConanfileBase - self.settings = base.settings + self.settings - self.license = base.license - - def build(self): - self.output.info("License! %s" % self.license) - self.output.info("Author! %s" % self.author) - self.output.info("os: %s arch: %s" % (self.settings.get_safe("os"), - self.settings.arch)) - """) - client.save({"conanfile.py": reuse}) - client.run("create . Pkg/0.1@user/testing -s os=Windows -s arch=armv7") - self.assertIn("Pkg/0.1@user/testing: License! MyLicense", client.out) - self.assertIn("Pkg/0.1@user/testing: Author! frodo", client.out) - self.assertIn("Pkg/0.1@user/testing: os: Windows arch: armv7", client.out) - - @pytest.mark.tool_compiler - def test_failure_init_method(self): - client = TestClient() - base = textwrap.dedent(""" - from conans import ConanFile - class MyBase(object): - settings = "os", "compiler", "build_type", "arch" - options = {"base_option": [True, False]} - default_options = {"base_option": False} - - class BaseConanFile(ConanFile): - pass - """) - client.save({"conanfile.py": base}) - client.run("export . base/1.0@") - derived = textwrap.dedent(""" - from conans import ConanFile - class DerivedConan(ConanFile): - settings = "os", "compiler", "build_type", "arch" - - python_requires = "base/1.0" - python_requires_extend = 'base.MyBase' - - options = {"derived_option": [True, False]} - default_options = {"derived_option": False} - - def init(self): - base = self.python_requires['base'].module.MyBase - self.options.update(base.options) - self.default_options.update(base.default_options) - """) - client.save({"conanfile.py": derived}) - client.run("create . pkg/0.1@ -o base_option=True") - self.assertIn("pkg/0.1: Created package", client.out) - - def test_transitive_imports_conflicts(self): - # https://github.com/conan-io/conan/issues/3874 - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - import myhelper - class SourceBuild(ConanFile): - exports = "*.py" - """) - helper = textwrap.dedent(""" - def myhelp(output): - output.info("MyHelperOutput!") - """) - client.save({"conanfile.py": conanfile, - "myhelper.py": helper}) - client.run("export . base1/1.0@user/channel") - client.save({"myhelper.py": helper.replace("MyHelperOutput!", "MyOtherHelperOutput!")}) - client.run("export . base2/1.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - - class MyConanfileBase(ConanFile): - python_requires = "base2/1.0@user/channel", "base1/1.0@user/channel" - def build(self): - self.python_requires["base1"].module.myhelper.myhelp(self.output) - self.python_requires["base2"].module.myhelper.myhelp(self.output) - """) - # This should work, even if there is a local "myhelper.py" file, which could be - # accidentaly imported (and it was, it was a bug) - client.save({"conanfile.py": conanfile}) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: MyHelperOutput!", client.out) - self.assertIn("Pkg/0.1@user/testing: MyOtherHelperOutput!", client.out) - - # Now, the same, but with "clean_first=True", should keep working - client.save({"conanfile.py": conanfile}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: MyHelperOutput!", client.out) - self.assertIn("Pkg/0.1@user/testing: MyOtherHelperOutput!", client.out) - - def test_update(self): - client = TestClient(default_server_user=True) - conanfile = textwrap.dedent(""" - from conans import ConanFile - somevar = 42 - class MyConanfileBase(ConanFile): - pass - """) - client.save({"conanfile.py": conanfile}) - client.run("export . base/1.1@user/testing") - client.run("upload * --confirm") - - client2 = TestClient(servers=client.servers, users={"default": [("user", "mypass")]}) - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/1.1@user/testing" - python_requires_extend = "base.MyConanfileBase" - def configure(self): - self.output.info("PYTHON REQUIRE VAR %s" - % self.python_requires["base"].module.somevar) - """) - - client2.save({"conanfile.py": reuse}) - client2.run("install .") - self.assertIn("conanfile.py: PYTHON REQUIRE VAR 42", client2.out) - - client.save({"conanfile.py": conanfile.replace("42", "143")}) - time.sleep(1) # guarantee time offset - client.run("export . base/1.1@user/testing") - client.run("upload * --confirm") - - client2.run("install . --update") - self.assertIn("conanfile.py: PYTHON REQUIRE VAR 143", client2.out) - - def test_update_ranges(self): - # Same as the above, but using a version range, and no --update - # https://github.com/conan-io/conan/issues/4650#issuecomment-497464305 - client = TestClient(default_server_user=True) - conanfile = textwrap.dedent(""" - from conans import ConanFile - somevar = 42 - class MyConanfileBase(ConanFile): - pass - """) - client.save({"conanfile.py": conanfile}) - client.run("export . base/1.1@user/testing") - client.run("upload * --confirm") - - client2 = TestClient(servers=client.servers, users={"default": [("user", "password")]}) - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/[>1.0]@user/testing" - python_requires_extend = "base.MyConanfileBase" - def configure(self): - self.output.info("PYTHON REQUIRE VAR %s" - % self.python_requires["base"].module.somevar) - """) - - client2.save({"conanfile.py": reuse}) - client2.run("install .") - self.assertIn("conanfile.py: PYTHON REQUIRE VAR 42", client2.out) - - client.save({"conanfile.py": conanfile.replace("42", "143")}) - # Make sure to bump the version! - client.run("export . base/1.2@user/testing") - client.run("upload * --confirm") - - client2.run("install . --update") - self.assertIn("conanfile.py: PYTHON REQUIRE VAR 143", client2.out) - - def test_duplicate_pyreq(self): - t = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class PyReq(ConanFile): - pass - """) - t.save({"conanfile.py": conanfile}) - t.run("export . pyreq/1.0@user/channel") - t.run("export . pyreq/2.0@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile - class Lib(ConanFile): - python_requires = "pyreq/1.0@user/channel", "pyreq/2.0@user/channel" - """) - t.save({"conanfile.py": conanfile}) - t.run("create . name/version@user/channel", assert_error=True) - self.assertIn("ERROR: Error loading conanfile", t.out) - self.assertIn("The python_require 'pyreq' already exists", t.out) - - def test_local_build(self): - client = TestClient() - client.save({"conanfile.py": "var=42\n"+str(GenConanfile())}) - client.run("export . tool/0.1@user/channel") - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - python_requires = "tool/0.1@user/channel" - def source(self): - self.output.info("Pkg1 source: %s" % self.python_requires["tool"].module.var) - def build(self): - self.output.info("Pkg1 build: %s" % self.python_requires["tool"].module.var) - def package(self): - self.output.info("Pkg1 package: %s" % self.python_requires["tool"].module.var) - """) - client.save({"conanfile.py": conanfile}) - client.run("source .") - self.assertIn("conanfile.py: Pkg1 source: 42", client.out) - client.run("install .") - client.run("build .") - self.assertIn("conanfile.py: Pkg1 build: 42", client.out) - client.run("package .") - self.assertIn("conanfile.py: Pkg1 package: 42", client.out) - client.run("export-pkg . pkg1/0.1@user/testing") - - def test_reuse_name_version(self): - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - from conans.tools import load - import os - - class Source(object): - def set_name(self): - self.name = load("name.txt") - - def set_version(self): - self.version = load("version.txt") - - class MyConanfileBase(ConanFile): - pass - """) - client.save({"conanfile.py": conanfile}) - client.run("export . tool/0.1@user/channel") - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - python_requires = "tool/0.1@user/channel" - python_requires_extend = "tool.Source" - def source(self): - self.output.info("Pkg1 source: %s:%s" % (self.name, self.version)) - def build(self): - self.output.info("Pkg1 build: %s:%s" % (self.name, self.version)) - def package(self): - self.output.info("Pkg1 package: %s:%s" % (self.name, self.version)) - """) - client.save({"conanfile.py": conanfile, - "name.txt": "MyPkg", - "version.txt": "MyVersion"}) - client.run("export .") - self.assertIn("MyPkg/MyVersion: A new conanfile.py version was exported", client.out) - client.run("create .") - self.assertIn("MyPkg/MyVersion: Pkg1 source: MyPkg:MyVersion", client.out) - self.assertIn("MyPkg/MyVersion: Pkg1 build: MyPkg:MyVersion", client.out) - self.assertIn("MyPkg/MyVersion: Pkg1 package: MyPkg:MyVersion", client.out) - - @parameterized.expand([(False, False), (True, False), (True, True), ]) - def test_python_requires_with_alias(self, use_alias, use_alias_of_alias): - assert use_alias if use_alias_of_alias else True - version_str = "latest2" if use_alias_of_alias else "latest" if use_alias else "1.0" - client = TestClient() - - # Create python_requires - client.save({CONANFILE: textwrap.dedent(""" - from conans import ConanFile - class PythonRequires0(ConanFile): - def build(self): - super(PythonRequires0, self).build() - self.output.info("PythonRequires0::build") - """)}) - client.run("export . python_requires0/1.0@user/test") - client.run("alias python_requires0/latest@user/test python_requires0/1.0@user/test") - client.run("alias python_requires0/latest2@user/test python_requires0/latest@user/test") - - # Create python requires, that require the previous one - client.save({CONANFILE: textwrap.dedent(""" - from conans import ConanFile - class PythonRequires1(ConanFile): - python_requires = "python_requires0/{v}@user/test" - python_requires_extend = "python_requires0.PythonRequires0" - def build(self): - super(PythonRequires1, self).build() - self.output.info("PythonRequires1::build") - """).format(v=version_str)}) - client.run("export . python_requires1/1.0@user/test") - client.run("alias python_requires1/latest@user/test python_requires1/1.0@user/test") - client.run("alias python_requires1/latest2@user/test python_requires1/latest@user/test") - - # Create python requires - client.save({CONANFILE: textwrap.dedent(""" - from conans import ConanFile - class PythonRequires11(ConanFile): - def build(self): - super(PythonRequires11, self).build() - self.output.info("PythonRequires11::build") - """)}) - client.run("export . python_requires11/1.0@user/test") - client.run("alias python_requires11/latest@user/test python_requires11/1.0@user/test") - client.run("alias python_requires11/latest2@user/test python_requires11/latest@user/test") - - # Create python requires, that require the previous one - client.save({CONANFILE: textwrap.dedent(""" - from conans import ConanFile - class PythonRequires22(ConanFile): - python_requires = "python_requires0/{v}@user/test" - python_requires_extend = "python_requires0.PythonRequires0" - def build(self): - super(PythonRequires22, self).build() - self.output.info("PythonRequires22::build") - """).format(v=version_str)}) - client.run("export . python_requires22/1.0@user/test") - client.run("alias python_requires22/latest@user/test python_requires22/1.0@user/test") - client.run("alias python_requires22/latest2@user/test python_requires22/latest@user/test") - - # Another python_requires, that requires the previous python requires - client.save({CONANFILE: textwrap.dedent(""" - from conans import ConanFile - class PythonRequires2(ConanFile): - python_requires = "python_requires1/{v}@user/test", "python_requires11/{v}@user/test" - python_requires_extend = ("python_requires1.PythonRequires1", - "python_requires11.PythonRequires11") - def build(self): - super(PythonRequires2, self).build() - self.output.info("PythonRequires2::build") - """).format(v=version_str)}) - client.run("export . python_requires2/1.0@user/test") - client.run("alias python_requires2/latest@user/test python_requires2/1.0@user/test") - client.run("alias python_requires2/latest2@user/test python_requires2/latest@user/test") - - # My project, will consume the latest python requires - client.save({CONANFILE: textwrap.dedent(""" - from conans import ConanFile - class Project(ConanFile): - python_requires = "python_requires2/{v}@user/test", "python_requires22/{v}@user/test" - python_requires_extend = ("python_requires2.PythonRequires2", - "python_requires22.PythonRequires22") - def build(self): - super(Project, self).build() - self.output.info("Project::build") - """).format(v=version_str)}) - - client.run("create . project/1.0@user/test --build=missing") - - # Check that everything is being built - self.assertIn("project/1.0@user/test: PythonRequires11::build", client.out) - self.assertIn("project/1.0@user/test: PythonRequires0::build", client.out) - self.assertIn("project/1.0@user/test: PythonRequires22::build", client.out) - self.assertIn("project/1.0@user/test: PythonRequires1::build", client.out) - self.assertIn("project/1.0@user/test: PythonRequires2::build", client.out) - self.assertIn("project/1.0@user/test: Project::build", client.out) - - # Check that all the graph is printed properly - # - requirements - self.assertIn(" project/1.0@user/test from local cache - Cache", client.out) - # - python requires - self.assertIn(" python_requires11/1.0@user/test", client.out) - self.assertIn(" python_requires0/1.0@user/test", client.out) - self.assertIn(" python_requires22/1.0@user/test", client.out) - self.assertIn(" python_requires1/1.0@user/test", client.out) - self.assertIn(" python_requires2/1.0@user/test", client.out) - # - packages - self.assertIn(" project/1.0@user/test:88cd9e14eae0af6c823ed619608b6883037e5cbc - Build", - client.out) - - # - no mention to alias - self.assertNotIn("alias", client.out) - self.assertNotIn("alias2", client.out) - - def test_reuse_export_sources(self): - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - exports = "*" - """) - client.save({"conanfile.py": conanfile, - "file.h": "myheader", - "folder/other.h": "otherheader"}) - client.run("export . tool/0.1@user/channel") - conanfile = textwrap.dedent(""" - from conans import ConanFile, load - import os - class MyConanfileBase(ConanFile): - python_requires = "tool/0.1@user/channel" - def source(self): - sources = self.python_requires["tool"].path - file_h = os.path.join(sources, "file.h") - other_h = os.path.join(sources, "folder/other.h") - self.output.info("Source: tool header: %s" % load(file_h)) - self.output.info("Source: tool other: %s" % load(other_h)) - def build(self): - sources = self.python_requires["tool"].path - file_h = os.path.join(sources, "file.h") - other_h = os.path.join(sources, "folder/other.h") - self.output.info("Build: tool header: %s" % load(file_h)) - self.output.info("Build: tool other: %s" % load(other_h)) - def package(self): - sources = self.python_requires["tool"].path - file_h = os.path.join(sources, "file.h") - other_h = os.path.join(sources, "folder/other.h") - self.output.info("Package: tool header: %s" % load(file_h)) - self.output.info("Package: tool other: %s" % load(other_h)) - """) - client.save({"conanfile.py": conanfile, - "name.txt": "MyPkg", - "version.txt": "MyVersion"}) - client.run("export . pkg/1.0@user/channel") - self.assertIn("pkg/1.0@user/channel: A new conanfile.py version was exported", client.out) - client.run("create . pkg/1.0@user/channel") - self.assertIn("pkg/1.0@user/channel: Source: tool header: myheader", client.out) - self.assertIn("pkg/1.0@user/channel: Source: tool other: otherheader", client.out) - self.assertIn("pkg/1.0@user/channel: Build: tool header: myheader", client.out) - self.assertIn("pkg/1.0@user/channel: Build: tool other: otherheader", client.out) - self.assertIn("pkg/1.0@user/channel: Package: tool header: myheader", client.out) - self.assertIn("pkg/1.0@user/channel: Package: tool other: otherheader", client.out) - - # The local flow - client.run("install .") - client.run("source .") - self.assertIn("conanfile.py: Source: tool header: myheader", client.out) - self.assertIn("conanfile.py: Source: tool other: otherheader", client.out) - client.run("build .") - self.assertIn("conanfile.py: Build: tool header: myheader", client.out) - self.assertIn("conanfile.py: Build: tool other: otherheader", client.out) - - def test_reuse_exports(self): - client = TestClient() - conanfile = textwrap.dedent(""" - from conans import ConanFile - class MyConanfileBase(ConanFile): - exports = "*" - """) - client.save({"conanfile.py": conanfile, - "file.h": "myheader", - "folder/other.h": "otherheader"}) - client.run("editable add . tool/0.1@user/channel") - - conanfile = textwrap.dedent(""" - from conans import ConanFile, load - import os - class MyConanfileBase(ConanFile): - python_requires = "tool/0.1@user/channel" - def source(self): - sources = self.python_requires["tool"].path - file_h = os.path.join(sources, "file.h") - other_h = os.path.join(sources, "folder/other.h") - self.output.info("Source: tool header: %s" % load(file_h)) - self.output.info("Source: tool other: %s" % load(other_h)) - def build(self): - sources = self.python_requires["tool"].path - file_h = os.path.join(sources, "file.h") - other_h = os.path.join(sources, "folder/other.h") - self.output.info("Build: tool header: %s" % load(file_h)) - self.output.info("Build: tool other: %s" % load(other_h)) - """) - - client2 = TestClient(cache_folder=client.cache_folder) - client2.save({"conanfile.py": conanfile, - "name.txt": "MyPkg", - "version.txt": "MyVersion"}) - - # The local flow - client2.run("install .") - client2.run("source .") - self.assertIn("conanfile.py: Source: tool header: myheader", client2.out) - self.assertIn("conanfile.py: Source: tool other: otherheader", client2.out) - client2.run("build .") - self.assertIn("conanfile.py: Build: tool header: myheader", client2.out) - self.assertIn("conanfile.py: Build: tool other: otherheader", client2.out) - - def test_build_id(self): - client = TestClient(default_server_user=True) - self._define_base(client) - reuse = textwrap.dedent(""" - from conans import ConanFile - class PkgTest(ConanFile): - python_requires = "base/1.1@user/testing" - python_requires_extend = "base.MyConanfileBase" - def build_id(self): - pass - """) - client.save({"conanfile.py": reuse}, clean_first=True) - client.run("create . Pkg/0.1@user/testing") - self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) - self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) diff --git a/conans/test/integration/package_id/package_id_test.py b/conans/test/integration/package_id/package_id_test.py new file mode 100644 index 00000000000..568a6325efe --- /dev/null +++ b/conans/test/integration/package_id/package_id_test.py @@ -0,0 +1,136 @@ +import textwrap + +from conans.test.utils.tools import NO_SETTINGS_PACKAGE_ID, TestClient, TestServer + + +def test_double_package_id_call(): + # https://github.com/conan-io/conan/issues/3085 + conanfile = textwrap.dedent(""" + from conans import ConanFile + class TestConan(ConanFile): + settings = "os", "arch" + + def package_id(self): + self.output.info("Calling package_id()") + """) + client = TestClient() + client.save({"conanfile.py": conanfile}) + client.run("create . Pkg/0.1@user/testing") + out = str(client.out) + assert 1 == out.count("Pkg/0.1@user/testing: Calling package_id()") + + +def test_remove_option_setting(): + # https://github.com/conan-io/conan/issues/2826 + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class TestConan(ConanFile): + settings = "os" + options = {"opt": [True, False]} + default_options = "opt=False" + + def package_id(self): + self.output.info("OPTION OPT=%s" % self.info.options.opt) + del self.info.settings.os + del self.info.options.opt + """) + client = TestClient() + client.save({"conanfile.py": conanfile}) + client.run("create . Pkg/0.1@user/testing -s os=Windows") + assert "Pkg/0.1@user/testing: OPTION OPT=False" in client.out + assert "Pkg/0.1@user/testing: Package '%s' created" % NO_SETTINGS_PACKAGE_ID in client.out + client.run("create . Pkg/0.1@user/testing -s os=Linux -o Pkg:opt=True") + assert "Pkg/0.1@user/testing: OPTION OPT=True" in client.out + assert "Pkg/0.1@user/testing: Package '%s' created" % NO_SETTINGS_PACKAGE_ID in client.out + + +def test_value_parse(): + # https://github.com/conan-io/conan/issues/2816 + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class TestConan(ConanFile): + name = "test" + version = "0.1" + settings = "os", "arch", "build_type" + exports_sources = "header.h" + + def package_id(self): + self.info.settings.arch = "kk=kk" + + def package(self): + self.copy("header.h", dst="include", keep_path=True) + """) + server = TestServer([("*/*@*/*", "*")], [("*/*@*/*", "*")], users={"lasote": "mypass"}) + servers = {"default": server} + client = TestClient(servers=servers, users={"default": [("lasote", "mypass")]}) + client.save({"conanfile.py": conanfile, + "header.h": "header content"}) + client.run("create . danimtb/testing") + client.run("search test/0.1@danimtb/testing") + assert "arch: kk=kk" in client.out + client.run("upload test/0.1@danimtb/testing --all") + client.run("remove test/0.1@danimtb/testing --force") + client.run("install test/0.1@danimtb/testing") + client.run("search test/0.1@danimtb/testing") + assert "arch: kk=kk" in client.out + + +def test_option_in(): + # https://github.com/conan-io/conan/issues/7299 + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class TestConan(ConanFile): + options = {"fpic": [True, False]} + default_options = {"fpic": True} + def package_id(self): + if "fpic" in self.options: + self.output.info("fpic is an option!!!") + if "fpic" in self.info.options: # Not documented + self.output.info("fpic is an info.option!!!") + if "other" not in self.options: + self.output.info("other is not an option!!!") + if "other" not in self.info.options: # Not documented + self.output.info("other is not an info.option!!!") + try: + self.options.whatever + except Exception as e: + self.output.error("OPTIONS: %s" % e) + try: + self.info.options.whatever + except Exception as e: + self.output.error("INFO: %s" % e) + + """) + client = TestClient() + client.save({"conanfile.py": conanfile}) + client.run("create . Pkg/0.1@user/testing") + assert "fpic is an option!!!" in client.out + assert "fpic is an info.option!!!" in client.out + assert "other is not an option!!!" in client.out + assert "other is not an info.option!!!" in client.out + assert "ERROR: OPTIONS: option 'whatever' doesn't exist" in client.out + assert "ERROR: INFO: option 'whatever' doesn't exist" in client.out + + +def test_build_type_remove_windows(): + # https://github.com/conan-io/conan/issues/7603 + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class Pkg(ConanFile): + settings = "os", "compiler", "arch", "build_type" + def package_id(self): + if self.settings.os == "Windows" and self.settings.compiler == "Visual Studio": + del self.info.settings.build_type + del self.info.settings.compiler.runtime + """) + client.save({"conanfile.py": conanfile}) + client.run('create . pkg/0.1@ -s os=Windows -s compiler="Visual Studio" ' + '-s compiler.version=14 -s build_type=Release') + assert "pkg/0.1:e1f7c8ffe5f9342d04ab704810faf93060ae3d70 - Build" in client.out + client.run('install pkg/0.1@ -s os=Windows -s compiler="Visual Studio" ' + '-s compiler.version=14 -s build_type=Debug') + assert "pkg/0.1:e1f7c8ffe5f9342d04ab704810faf93060ae3d70 - Cache" in client.out diff --git a/conans/test/integration/py_requires/python_requires_test.py b/conans/test/integration/py_requires/python_requires_test.py new file mode 100644 index 00000000000..73bfa7f8ed1 --- /dev/null +++ b/conans/test/integration/py_requires/python_requires_test.py @@ -0,0 +1,855 @@ +import os +import textwrap +import time +import unittest + +from parameterized import parameterized + +from conans.model.ref import ConanFileReference +from conans.paths import CONANFILE +from conans.test.utils.tools import TestClient, GenConanfile + + +class PyRequiresExtendTest(unittest.TestCase): + + @staticmethod + def _define_base(client): + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + def source(self): + self.output.info("My cool source!") + def build(self): + self.output.info("My cool build!") + def package(self): + self.output.info("My cool package!") + def package_info(self): + self.output.info("My cool package_info!") + """) + client.save({"conanfile.py": conanfile}) + client.run("export . base/1.1@user/testing") + + def test_reuse(self): + client = TestClient(default_server_user=True) + self._define_base(client) + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/1.1@user/testing" + python_requires_extend = "base.MyConanfileBase" + """) + client.save({"conanfile.py": reuse}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) + + client.run("upload * --all --confirm") + client.run("remove * -f") + client.run("install Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) + client.run("remove * -f") + client.run("download Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: Package installed " + "69265e58ddc68274e0c5510905003ff78c9db5de", client.out) + + def test_reuse_dot(self): + client = TestClient(default_server_user=True) + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + def build(self): + self.output.info("My cool build!") + """) + client.save({"conanfile.py": conanfile}) + client.run("export . my.base/1.1@user/testing") + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "my.base/1.1@user/testing" + python_requires_extend = "my.base.MyConanfileBase" + """) + client.save({"conanfile.py": reuse}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) + + def test_with_alias(self): + client = TestClient() + self._define_base(client) + client.run("alias base/LATEST@user/testing base/1.1@user/testing") + + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/LATEST@user/testing" + python_requires_extend = "base.MyConanfileBase" + """) + client.save({"conanfile.py": reuse}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) + + def test_reuse_version_ranges(self): + client = TestClient() + self._define_base(client) + + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/[>1.0,<1.2]@user/testing" + python_requires_extend = "base.MyConanfileBase" + """) + + client.save({"conanfile.py": reuse}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Python requires", str(client.out).splitlines()) + self.assertIn(" base/1.1@user/testing", str(client.out).splitlines()) + self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) + + def test_multiple_reuse(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class SourceBuild(ConanFile): + def source(self): + self.output.info("My cool source!") + def build(self): + self.output.info("My cool build!") + """) + client.save({"conanfile.py": conanfile}) + client.run("export . SourceBuild/1.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class PackageInfo(ConanFile): + def package(self): + self.output.info("My cool package!") + def package_info(self): + self.output.info("My cool package_info!") + """) + client.save({"conanfile.py": conanfile}) + client.run("export . PackageInfo/1.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + python_requires = "SourceBuild/1.0@user/channel", "PackageInfo/1.0@user/channel" + python_requires_extend = "SourceBuild.SourceBuild", "PackageInfo.PackageInfo" + """) + client.save({"conanfile.py": conanfile}) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) + + def test_transitive_access_error(self): + # https://github.com/conan-io/conan/issues/5529 + client = TestClient() + client.save({"conanfile.py": GenConanfile()}) + client.run("export . base/1.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class Helper(ConanFile): + python_requires = "base/1.0@user/channel" + """) + client.save({"conanfile.py": conanfile}) + client.run("export . helper/1.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class Pkg(ConanFile): + python_requires = "helper/1.0@user/channel" + def build(self): + self.python_requires["base"] + """) + client.save({"conanfile.py": conanfile}) + client.run("create . pkg/0.1@user/channel", assert_error=True) + self.assertIn("'base' is not a python_require", client.out) + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class Pkg(ConanFile): + python_requires = "helper/1.0@user/channel" + python_requires_extend = "base.HelloConan" + """) + client.save({"conanfile.py": conanfile}) + client.run("create . pkg/0.1@user/channel", assert_error=True) + self.assertIn("'base' is not a python_require", client.out) + + def test_multiple_requires_error(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + myvar = 123 + def myfunct(): + return 123 + class Pkg(ConanFile): + pass + """) + client.save({"conanfile.py": conanfile}) + client.run("export . pkg1/1.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + myvar = 234 + def myfunct(): + return 234 + class Pkg(ConanFile): + pass + """) + client.save({"conanfile.py": conanfile}) + client.run("export . pkg2/1.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + python_requires = "pkg1/1.0@user/channel", "pkg2/1.0@user/channel" + def build(self): + self.output.info("PKG1 N: %s" % self.python_requires["pkg1"].conanfile.name) + self.output.info("PKG1 V: %s" % self.python_requires["pkg1"].conanfile.version) + self.output.info("PKG1 U: %s" % self.python_requires["pkg1"].conanfile.user) + self.output.info("PKG1 C: %s" % self.python_requires["pkg1"].conanfile.channel) + self.output.info("PKG1 : %s" % self.python_requires["pkg1"].module.myvar) + self.output.info("PKG2 : %s" % self.python_requires["pkg2"].module.myvar) + self.output.info("PKG1F : %s" % self.python_requires["pkg1"].module.myfunct()) + self.output.info("PKG2F : %s" % self.python_requires["pkg2"].module.myfunct()) + """) + client.save({"conanfile.py": conanfile}) + client.run("create . Consumer/0.1@user/testing") + self.assertIn("Consumer/0.1@user/testing: PKG1 N: pkg1", client.out) + self.assertIn("Consumer/0.1@user/testing: PKG1 V: 1.0", client.out) + self.assertIn("Consumer/0.1@user/testing: PKG1 U: user", client.out) + self.assertIn("Consumer/0.1@user/testing: PKG1 C: channel", client.out) + self.assertIn("Consumer/0.1@user/testing: PKG1 : 123", client.out) + self.assertIn("Consumer/0.1@user/testing: PKG2 : 234", client.out) + self.assertIn("Consumer/0.1@user/testing: PKG1F : 123", client.out) + self.assertIn("Consumer/0.1@user/testing: PKG2F : 234", client.out) + + def test_local_import(self): + client = TestClient(default_server_user=True) + conanfile = textwrap.dedent(""" + from conans import ConanFile + import mydata + class MyConanfileBase(ConanFile): + exports = "*.py" + def source(self): + self.output.info(mydata.src) + def build(self): + self.output.info(mydata.build) + def package(self): + self.output.info(mydata.pkg) + def package_info(self): + self.output.info(mydata.info) + """) + mydata = textwrap.dedent(""" + src = "My cool source!" + build = "My cool build!" + pkg = "My cool package!" + info = "My cool package_info!" + """) + client.save({"conanfile.py": conanfile, + "mydata.py": mydata}) + client.run("export . base/1.1@user/testing") + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/1.1@user/testing" + python_requires_extend = "base.MyConanfileBase" + """) + + client.save({"conanfile.py": reuse}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) + + client.run("upload * --all --confirm") + client.run("remove * -f") + client.run("install Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) + client.run("remove * -f") + client.run("download Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: Package installed " + "69265e58ddc68274e0c5510905003ff78c9db5de", client.out) + + def test_reuse_class_members(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + license = "MyLicense" + author = "author@company.com" + exports = "*.txt" + exports_sources = "*.h" + short_paths = True + generators = "cmake" + """) + client.save({"conanfile.py": conanfile, + "header.h": "some content"}) + client.run("export . base/1.1@user/testing") + + reuse = textwrap.dedent(""" + from conans import ConanFile + from conans.tools import load + import os + class PkgTest(ConanFile): + python_requires = "base/1.1@user/testing" + python_requires_extend = "base.MyConanfileBase" + def build(self): + self.output.info("Exports sources! %s" % self.exports_sources) + self.output.info("HEADER CONTENT!: %s" % load("header.h")) + self.output.info("Short paths! %s" % self.short_paths) + self.output.info("License! %s" % self.license) + self.output.info("Author! %s" % self.author) + assert os.path.exists("conanbuildinfo.cmake") + """) + client.save({"conanfile.py": reuse, + "header.h": "pkg new header contents", + "other.txt": "text"}) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: Exports sources! *.h", client.out) + self.assertIn("Pkg/0.1@user/testing exports: Copied 1 '.txt' file: other.txt", + client.out) + self.assertIn("Pkg/0.1@user/testing exports_sources: Copied 1 '.h' file: header.h", + client.out) + self.assertIn("Pkg/0.1@user/testing: Short paths! True", client.out) + self.assertIn("Pkg/0.1@user/testing: License! MyLicense", client.out) + self.assertIn("Pkg/0.1@user/testing: Author! author@company.com", client.out) + self.assertIn("Pkg/0.1@user/testing: HEADER CONTENT!: pkg new header contents", client.out) + ref = ConanFileReference.loads("Pkg/0.1@user/testing") + self.assertTrue(os.path.exists(os.path.join(client.cache.package_layout(ref).export(), + "other.txt"))) + + def test_reuse_system_requirements(self): + # https://github.com/conan-io/conan/issues/7718 + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + def system_requirements(self): + self.output.info("My system_requirements %s being called!" % self.name) + """) + client.save({"conanfile.py": conanfile}) + client.run("export . base/1.1@user/testing") + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/1.1@user/testing" + python_requires_extend = "base.MyConanfileBase" + """) + client.save({"conanfile.py": reuse}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My system_requirements Pkg being called!", client.out) + + def test_overwrite_class_members(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + license = "MyLicense" + author = "author@company.com" + settings = "os", # tuple! + """) + client.save({"conanfile.py": conanfile}) + client.run("export . base/1.1@user/testing") + + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + license = "MIT" + author = "frodo" + settings = "arch", # tuple! + python_requires = "base/1.1@user/testing" + python_requires_extend = "base.MyConanfileBase" + + def init(self): + base = self.python_requires["base"].module.MyConanfileBase + self.settings = base.settings + self.settings + self.license = base.license + + def build(self): + self.output.info("License! %s" % self.license) + self.output.info("Author! %s" % self.author) + self.output.info("os: %s arch: %s" % (self.settings.get_safe("os"), + self.settings.arch)) + """) + client.save({"conanfile.py": reuse}) + client.run("create . Pkg/0.1@user/testing -s os=Windows -s arch=armv7") + self.assertIn("Pkg/0.1@user/testing: License! MyLicense", client.out) + self.assertIn("Pkg/0.1@user/testing: Author! frodo", client.out) + self.assertIn("Pkg/0.1@user/testing: os: Windows arch: armv7", client.out) + + def test_failure_init_method(self): + client = TestClient() + base = textwrap.dedent(""" + from conans import ConanFile + class MyBase(object): + settings = "os", "build_type", "arch" + options = {"base_option": [True, False]} + default_options = {"base_option": False} + + class BaseConanFile(ConanFile): + pass + """) + client.save({"conanfile.py": base}) + client.run("export . base/1.0@") + derived = textwrap.dedent(""" + from conans import ConanFile + class DerivedConan(ConanFile): + settings = "os", "build_type", "arch" + + python_requires = "base/1.0" + python_requires_extend = 'base.MyBase' + + options = {"derived_option": [True, False]} + default_options = {"derived_option": False} + + def init(self): + base = self.python_requires['base'].module.MyBase + self.options.update(base.options) + self.default_options.update(base.default_options) + """) + client.save({"conanfile.py": derived}) + client.run("create . pkg/0.1@ -o base_option=True") + self.assertIn("pkg/0.1: Created package", client.out) + + def test_transitive_imports_conflicts(self): + # https://github.com/conan-io/conan/issues/3874 + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + import myhelper + class SourceBuild(ConanFile): + exports = "*.py" + """) + helper = textwrap.dedent(""" + def myhelp(output): + output.info("MyHelperOutput!") + """) + client.save({"conanfile.py": conanfile, + "myhelper.py": helper}) + client.run("export . base1/1.0@user/channel") + client.save({"myhelper.py": helper.replace("MyHelperOutput!", "MyOtherHelperOutput!")}) + client.run("export . base2/1.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class MyConanfileBase(ConanFile): + python_requires = "base2/1.0@user/channel", "base1/1.0@user/channel" + def build(self): + self.python_requires["base1"].module.myhelper.myhelp(self.output) + self.python_requires["base2"].module.myhelper.myhelp(self.output) + """) + # This should work, even if there is a local "myhelper.py" file, which could be + # accidentaly imported (and it was, it was a bug) + client.save({"conanfile.py": conanfile}) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: MyHelperOutput!", client.out) + self.assertIn("Pkg/0.1@user/testing: MyOtherHelperOutput!", client.out) + + # Now, the same, but with "clean_first=True", should keep working + client.save({"conanfile.py": conanfile}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: MyHelperOutput!", client.out) + self.assertIn("Pkg/0.1@user/testing: MyOtherHelperOutput!", client.out) + + def test_update(self): + client = TestClient(default_server_user=True) + conanfile = textwrap.dedent(""" + from conans import ConanFile + somevar = 42 + class MyConanfileBase(ConanFile): + pass + """) + client.save({"conanfile.py": conanfile}) + client.run("export . base/1.1@user/testing") + client.run("upload * --confirm") + + client2 = TestClient(servers=client.servers, users={"default": [("user", "mypass")]}) + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/1.1@user/testing" + python_requires_extend = "base.MyConanfileBase" + def configure(self): + self.output.info("PYTHON REQUIRE VAR %s" + % self.python_requires["base"].module.somevar) + """) + + client2.save({"conanfile.py": reuse}) + client2.run("install .") + self.assertIn("conanfile.py: PYTHON REQUIRE VAR 42", client2.out) + + client.save({"conanfile.py": conanfile.replace("42", "143")}) + time.sleep(1) # guarantee time offset + client.run("export . base/1.1@user/testing") + client.run("upload * --confirm") + + client2.run("install . --update") + self.assertIn("conanfile.py: PYTHON REQUIRE VAR 143", client2.out) + + def test_update_ranges(self): + # Same as the above, but using a version range, and no --update + # https://github.com/conan-io/conan/issues/4650#issuecomment-497464305 + client = TestClient(default_server_user=True) + conanfile = textwrap.dedent(""" + from conans import ConanFile + somevar = 42 + class MyConanfileBase(ConanFile): + pass + """) + client.save({"conanfile.py": conanfile}) + client.run("export . base/1.1@user/testing") + client.run("upload * --confirm") + + client2 = TestClient(servers=client.servers, users={"default": [("user", "password")]}) + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/[>1.0]@user/testing" + python_requires_extend = "base.MyConanfileBase" + def configure(self): + self.output.info("PYTHON REQUIRE VAR %s" + % self.python_requires["base"].module.somevar) + """) + + client2.save({"conanfile.py": reuse}) + client2.run("install .") + self.assertIn("conanfile.py: PYTHON REQUIRE VAR 42", client2.out) + + client.save({"conanfile.py": conanfile.replace("42", "143")}) + # Make sure to bump the version! + client.run("export . base/1.2@user/testing") + client.run("upload * --confirm") + + client2.run("install . --update") + self.assertIn("conanfile.py: PYTHON REQUIRE VAR 143", client2.out) + + def test_duplicate_pyreq(self): + t = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class PyReq(ConanFile): + pass + """) + t.save({"conanfile.py": conanfile}) + t.run("export . pyreq/1.0@user/channel") + t.run("export . pyreq/2.0@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + class Lib(ConanFile): + python_requires = "pyreq/1.0@user/channel", "pyreq/2.0@user/channel" + """) + t.save({"conanfile.py": conanfile}) + t.run("create . name/version@user/channel", assert_error=True) + self.assertIn("ERROR: Error loading conanfile", t.out) + self.assertIn("The python_require 'pyreq' already exists", t.out) + + def test_local_build(self): + client = TestClient() + client.save({"conanfile.py": "var=42\n"+str(GenConanfile())}) + client.run("export . tool/0.1@user/channel") + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + python_requires = "tool/0.1@user/channel" + def source(self): + self.output.info("Pkg1 source: %s" % self.python_requires["tool"].module.var) + def build(self): + self.output.info("Pkg1 build: %s" % self.python_requires["tool"].module.var) + def package(self): + self.output.info("Pkg1 package: %s" % self.python_requires["tool"].module.var) + """) + client.save({"conanfile.py": conanfile}) + client.run("source .") + self.assertIn("conanfile.py: Pkg1 source: 42", client.out) + client.run("install .") + client.run("build .") + self.assertIn("conanfile.py: Pkg1 build: 42", client.out) + client.run("package .") + self.assertIn("conanfile.py: Pkg1 package: 42", client.out) + client.run("export-pkg . pkg1/0.1@user/testing") + + def test_reuse_name_version(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + from conans.tools import load + import os + + class Source(object): + def set_name(self): + self.name = load("name.txt") + + def set_version(self): + self.version = load("version.txt") + + class MyConanfileBase(ConanFile): + pass + """) + client.save({"conanfile.py": conanfile}) + client.run("export . tool/0.1@user/channel") + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + python_requires = "tool/0.1@user/channel" + python_requires_extend = "tool.Source" + def source(self): + self.output.info("Pkg1 source: %s:%s" % (self.name, self.version)) + def build(self): + self.output.info("Pkg1 build: %s:%s" % (self.name, self.version)) + def package(self): + self.output.info("Pkg1 package: %s:%s" % (self.name, self.version)) + """) + client.save({"conanfile.py": conanfile, + "name.txt": "MyPkg", + "version.txt": "MyVersion"}) + client.run("export .") + self.assertIn("MyPkg/MyVersion: A new conanfile.py version was exported", client.out) + client.run("create .") + self.assertIn("MyPkg/MyVersion: Pkg1 source: MyPkg:MyVersion", client.out) + self.assertIn("MyPkg/MyVersion: Pkg1 build: MyPkg:MyVersion", client.out) + self.assertIn("MyPkg/MyVersion: Pkg1 package: MyPkg:MyVersion", client.out) + + @parameterized.expand([(False, False), (True, False), (True, True), ]) + def test_python_requires_with_alias(self, use_alias, use_alias_of_alias): + assert use_alias if use_alias_of_alias else True + version_str = "latest2" if use_alias_of_alias else "latest" if use_alias else "1.0" + client = TestClient() + + # Create python_requires + client.save({CONANFILE: textwrap.dedent(""" + from conans import ConanFile + class PythonRequires0(ConanFile): + def build(self): + super(PythonRequires0, self).build() + self.output.info("PythonRequires0::build") + """)}) + client.run("export . python_requires0/1.0@user/test") + client.run("alias python_requires0/latest@user/test python_requires0/1.0@user/test") + client.run("alias python_requires0/latest2@user/test python_requires0/latest@user/test") + + # Create python requires, that require the previous one + client.save({CONANFILE: textwrap.dedent(""" + from conans import ConanFile + class PythonRequires1(ConanFile): + python_requires = "python_requires0/{v}@user/test" + python_requires_extend = "python_requires0.PythonRequires0" + def build(self): + super(PythonRequires1, self).build() + self.output.info("PythonRequires1::build") + """).format(v=version_str)}) + client.run("export . python_requires1/1.0@user/test") + client.run("alias python_requires1/latest@user/test python_requires1/1.0@user/test") + client.run("alias python_requires1/latest2@user/test python_requires1/latest@user/test") + + # Create python requires + client.save({CONANFILE: textwrap.dedent(""" + from conans import ConanFile + class PythonRequires11(ConanFile): + def build(self): + super(PythonRequires11, self).build() + self.output.info("PythonRequires11::build") + """)}) + client.run("export . python_requires11/1.0@user/test") + client.run("alias python_requires11/latest@user/test python_requires11/1.0@user/test") + client.run("alias python_requires11/latest2@user/test python_requires11/latest@user/test") + + # Create python requires, that require the previous one + client.save({CONANFILE: textwrap.dedent(""" + from conans import ConanFile + class PythonRequires22(ConanFile): + python_requires = "python_requires0/{v}@user/test" + python_requires_extend = "python_requires0.PythonRequires0" + def build(self): + super(PythonRequires22, self).build() + self.output.info("PythonRequires22::build") + """).format(v=version_str)}) + client.run("export . python_requires22/1.0@user/test") + client.run("alias python_requires22/latest@user/test python_requires22/1.0@user/test") + client.run("alias python_requires22/latest2@user/test python_requires22/latest@user/test") + + # Another python_requires, that requires the previous python requires + client.save({CONANFILE: textwrap.dedent(""" + from conans import ConanFile + class PythonRequires2(ConanFile): + python_requires = "python_requires1/{v}@user/test", "python_requires11/{v}@user/test" + python_requires_extend = ("python_requires1.PythonRequires1", + "python_requires11.PythonRequires11") + def build(self): + super(PythonRequires2, self).build() + self.output.info("PythonRequires2::build") + """).format(v=version_str)}) + client.run("export . python_requires2/1.0@user/test") + client.run("alias python_requires2/latest@user/test python_requires2/1.0@user/test") + client.run("alias python_requires2/latest2@user/test python_requires2/latest@user/test") + + # My project, will consume the latest python requires + client.save({CONANFILE: textwrap.dedent(""" + from conans import ConanFile + class Project(ConanFile): + python_requires = "python_requires2/{v}@user/test", "python_requires22/{v}@user/test" + python_requires_extend = ("python_requires2.PythonRequires2", + "python_requires22.PythonRequires22") + def build(self): + super(Project, self).build() + self.output.info("Project::build") + """).format(v=version_str)}) + + client.run("create . project/1.0@user/test --build=missing") + + # Check that everything is being built + self.assertIn("project/1.0@user/test: PythonRequires11::build", client.out) + self.assertIn("project/1.0@user/test: PythonRequires0::build", client.out) + self.assertIn("project/1.0@user/test: PythonRequires22::build", client.out) + self.assertIn("project/1.0@user/test: PythonRequires1::build", client.out) + self.assertIn("project/1.0@user/test: PythonRequires2::build", client.out) + self.assertIn("project/1.0@user/test: Project::build", client.out) + + # Check that all the graph is printed properly + # - requirements + self.assertIn(" project/1.0@user/test from local cache - Cache", client.out) + # - python requires + self.assertIn(" python_requires11/1.0@user/test", client.out) + self.assertIn(" python_requires0/1.0@user/test", client.out) + self.assertIn(" python_requires22/1.0@user/test", client.out) + self.assertIn(" python_requires1/1.0@user/test", client.out) + self.assertIn(" python_requires2/1.0@user/test", client.out) + # - packages + self.assertIn(" project/1.0@user/test:88cd9e14eae0af6c823ed619608b6883037e5cbc - Build", + client.out) + + # - no mention to alias + self.assertNotIn("alias", client.out) + self.assertNotIn("alias2", client.out) + + def test_reuse_export_sources(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + exports = "*" + """) + client.save({"conanfile.py": conanfile, + "file.h": "myheader", + "folder/other.h": "otherheader"}) + client.run("export . tool/0.1@user/channel") + conanfile = textwrap.dedent(""" + from conans import ConanFile, load + import os + class MyConanfileBase(ConanFile): + python_requires = "tool/0.1@user/channel" + def source(self): + sources = self.python_requires["tool"].path + file_h = os.path.join(sources, "file.h") + other_h = os.path.join(sources, "folder/other.h") + self.output.info("Source: tool header: %s" % load(file_h)) + self.output.info("Source: tool other: %s" % load(other_h)) + def build(self): + sources = self.python_requires["tool"].path + file_h = os.path.join(sources, "file.h") + other_h = os.path.join(sources, "folder/other.h") + self.output.info("Build: tool header: %s" % load(file_h)) + self.output.info("Build: tool other: %s" % load(other_h)) + def package(self): + sources = self.python_requires["tool"].path + file_h = os.path.join(sources, "file.h") + other_h = os.path.join(sources, "folder/other.h") + self.output.info("Package: tool header: %s" % load(file_h)) + self.output.info("Package: tool other: %s" % load(other_h)) + """) + client.save({"conanfile.py": conanfile, + "name.txt": "MyPkg", + "version.txt": "MyVersion"}) + client.run("export . pkg/1.0@user/channel") + self.assertIn("pkg/1.0@user/channel: A new conanfile.py version was exported", client.out) + client.run("create . pkg/1.0@user/channel") + self.assertIn("pkg/1.0@user/channel: Source: tool header: myheader", client.out) + self.assertIn("pkg/1.0@user/channel: Source: tool other: otherheader", client.out) + self.assertIn("pkg/1.0@user/channel: Build: tool header: myheader", client.out) + self.assertIn("pkg/1.0@user/channel: Build: tool other: otherheader", client.out) + self.assertIn("pkg/1.0@user/channel: Package: tool header: myheader", client.out) + self.assertIn("pkg/1.0@user/channel: Package: tool other: otherheader", client.out) + + # The local flow + client.run("install .") + client.run("source .") + self.assertIn("conanfile.py: Source: tool header: myheader", client.out) + self.assertIn("conanfile.py: Source: tool other: otherheader", client.out) + client.run("build .") + self.assertIn("conanfile.py: Build: tool header: myheader", client.out) + self.assertIn("conanfile.py: Build: tool other: otherheader", client.out) + + def test_reuse_exports(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class MyConanfileBase(ConanFile): + exports = "*" + """) + client.save({"conanfile.py": conanfile, + "file.h": "myheader", + "folder/other.h": "otherheader"}) + client.run("editable add . tool/0.1@user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile, load + import os + class MyConanfileBase(ConanFile): + python_requires = "tool/0.1@user/channel" + def source(self): + sources = self.python_requires["tool"].path + file_h = os.path.join(sources, "file.h") + other_h = os.path.join(sources, "folder/other.h") + self.output.info("Source: tool header: %s" % load(file_h)) + self.output.info("Source: tool other: %s" % load(other_h)) + def build(self): + sources = self.python_requires["tool"].path + file_h = os.path.join(sources, "file.h") + other_h = os.path.join(sources, "folder/other.h") + self.output.info("Build: tool header: %s" % load(file_h)) + self.output.info("Build: tool other: %s" % load(other_h)) + """) + + client2 = TestClient(cache_folder=client.cache_folder) + client2.save({"conanfile.py": conanfile, + "name.txt": "MyPkg", + "version.txt": "MyVersion"}) + + # The local flow + client2.run("install .") + client2.run("source .") + self.assertIn("conanfile.py: Source: tool header: myheader", client2.out) + self.assertIn("conanfile.py: Source: tool other: otherheader", client2.out) + client2.run("build .") + self.assertIn("conanfile.py: Build: tool header: myheader", client2.out) + self.assertIn("conanfile.py: Build: tool other: otherheader", client2.out) + + def test_build_id(self): + client = TestClient(default_server_user=True) + self._define_base(client) + reuse = textwrap.dedent(""" + from conans import ConanFile + class PkgTest(ConanFile): + python_requires = "base/1.1@user/testing" + python_requires_extend = "base.MyConanfileBase" + def build_id(self): + pass + """) + client.save({"conanfile.py": reuse}, clean_first=True) + client.run("create . Pkg/0.1@user/testing") + self.assertIn("Pkg/0.1@user/testing: My cool source!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool build!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package!", client.out) + self.assertIn("Pkg/0.1@user/testing: My cool package_info!", client.out) From 07570f8ea12f0571278490594f9616d25510d803 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 18 Jan 2021 12:19:49 +0100 Subject: [PATCH 29/32] Fix help message in command remove --outdated (#8350) --- conans/client/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/client/command.py b/conans/client/command.py index 748eb229dcb..c0a0d78accd 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -1091,7 +1091,7 @@ def remove(self, *args): help="Remove locks") parser.add_argument("-o", "--outdated", default=False, action="store_true", help="Remove only outdated from recipe packages. " - "This flag can only be used with a reference") + "This flag can only be used with a pattern or a reference") parser.add_argument('-p', '--packages', nargs="*", action=Extender, help="Remove all packages of the specified reference if " "no specific package ID is provided") From c8b4897da3a4847e71435880b9cb4bf4dc274ec5 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Mon, 18 Jan 2021 15:50:02 +0100 Subject: [PATCH 30/32] [test] Add test creating a target without namespaces (CMake) (#8338) * use target without namespace * add marks * use target from the build-module * remove line * build-module per generator * revert changes in build_info * make it explicit it is PATH * even without build-type, compiler.runtime is different for Release/Debug * use x64 for Windows generator --- .../cmake_find_package_multi_test.py | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/conans/test/functional/generators/cmake_find_package_multi_test.py b/conans/test/functional/generators/cmake_find_package_multi_test.py index 9278cc0e5ed..85253a2e1fe 100644 --- a/conans/test/functional/generators/cmake_find_package_multi_test.py +++ b/conans/test/functional/generators/cmake_find_package_multi_test.py @@ -526,3 +526,125 @@ def build(self): self.assertIn("component libs: $<$:;>;$<$:;>;" "$<$:;>;$<$:system_lib_component;", t.out) + + +@pytest.mark.tool_cmake +class TestNoNamespaceTarget: + """ This test case uses build-modules feature to create a target without a namespace. This + target uses targets create by Conan (build_modules are included after Conan targets) + """ + + conanfile = textwrap.dedent(""" + import os + from conans import ConanFile, CMake + + class Recipe(ConanFile): + settings = "os", "compiler", "arch", "build_type" + exports_sources = ["src/*", "build-module.cmake"] + generators = "cmake" + + def build(self): + cmake = CMake(self) + cmake.configure(source_folder="src") + cmake.build() + + def package(self): + self.copy("*.h", dst="include", src="src") + self.copy("*.lib", dst="lib", keep_path=False) + self.copy("*.dll", dst="bin", keep_path=False) + self.copy("*.dylib*", dst="lib", keep_path=False) + self.copy("*.so", dst="lib", keep_path=False) + self.copy("*.a", dst="lib", keep_path=False) + self.copy("build-module.cmake", dst="share/cmake") + + def package_info(self): + self.cpp_info.libs = ["library"] + module = os.path.join("share", "cmake", "build-module.cmake") + self.cpp_info.build_modules['cmake_find_package'] = [module, ] + self.cpp_info.build_modules['cmake_find_package_multi'] = [module, ] + """) + + build_module = textwrap.dedent(""" + message(">> Build-module is included") + + if(NOT TARGET nonamespace) + add_library(nonamespace INTERFACE IMPORTED) + target_link_libraries(nonamespace INTERFACE library::library) + endif() + """) + + consumer = textwrap.dedent(""" + cmake_minimum_required(VERSION 3.0) + set(CMAKE_CXX_COMPILER_WORKS 1) + set(CMAKE_CXX_ABI_COMPILED 1) + project(consumer) + + find_package(library) + + get_target_property(LIBS1 library::library INTERFACE_LINK_LIBRARIES) + message(">> library::library libs: ${LIBS1}") + + get_target_property(LIBS2 nonamespace INTERFACE_LINK_LIBRARIES) + message(">> nonamespace libs: ${LIBS2}") + + add_executable(consumer main.cpp) + target_link_libraries(consumer nonamespace) + """) + + main = textwrap.dedent(""" + #include "library.h" + + int main() { + library(); + } + """) + + @classmethod + def setup_class(cls): + cls.t = t = TestClient() + # Create a library providing a build-module + t.run('new library/version -s') + t.save({'conanfile.py': cls.conanfile, + 'build-module.cmake': cls.build_module}) + t.run('create conanfile.py library/version@ -s build_type=Debug') + t.run('create conanfile.py library/version@ -s build_type=Release') + # Prepare project to consume the targets + t.save({'CMakeLists.txt': cls.consumer, 'main.cpp': cls.main}, clean_first=True) + + @pytest.mark.tool_compiler + def test_non_multi_generator(self): + t = self.t + with t.chdir('not_multi'): + t.run('install library/version@ -g cmake_find_package -s build_type=Release') + generator = '-G "Visual Studio 15 Win64"' if platform.system() == "Windows" else '' + t.run_command( + 'cmake .. {} -DCMAKE_MODULE_PATH:PATH="{}"'.format(generator, t.current_folder)) + assert str(t.out).count('>> Build-module is included') == 1 + assert '>> nonamespace libs: library::library' in t.out + t.run_command('cmake --build .') # Compiles and links. + + @pytest.mark.skipif(platform.system() != "Windows", reason="Only windows") + @pytest.mark.tool_visual_studio + def test_multi_generator_windows(self): + t = self.t + with t.chdir('multi_windows'): + t.run('install library/version@ -g cmake_find_package_multi -s build_type=Release') + t.run('install library/version@ -g cmake_find_package_multi -s build_type=Debug') + generator = '-G "Visual Studio 15 Win64"' + t.run_command( + 'cmake .. {} -DCMAKE_PREFIX_PATH:PATH="{}"'.format(generator, t.current_folder)) + assert str(t.out).count('>> Build-module is included') == 2 # FIXME: Known bug + assert '>> nonamespace libs: library::library' in t.out + t.run_command('cmake --build . --config Release') # Compiles and links. + + @pytest.mark.skipif(platform.system() != "Darwin", reason="Requires Macos") + @pytest.mark.tool_xcode + def test_multi_generator_macos(self): + t = self.t + with t.chdir('multi_macos'): + t.run('install library/version@ -g cmake_find_package_multi -s build_type=Release') + t.run('install library/version@ -g cmake_find_package_multi -s build_type=Debug') + t.run_command('cmake .. -G Xcode -DCMAKE_PREFIX_PATH:PATH="{}"'.format(t.current_folder)) + assert str(t.out).count('>> Build-module is included') == 2 # FIXME: Known bug + assert '>> nonamespace libs: library::library' in t.out + t.run_command('cmake --build . --config Release') # Compiles and links. From 7d81f9dcd41b6d4c0663dd1bfd2eea99501cbe8b Mon Sep 17 00:00:00 2001 From: Carlos Zoido Date: Mon, 18 Jan 2021 16:02:04 +0100 Subject: [PATCH 31/32] update tests (#8354) --- .../conan_v2/build_helpers/test_autotools.py | 18 +++++++++++---- .../conan_v2/build_helpers/test_cmake.py | 23 +++++++++++++------ .../conan_v2/build_helpers/test_meson.py | 17 ++++++++++---- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/conans/test/integration/conan_v2/build_helpers/test_autotools.py b/conans/test/integration/conan_v2/build_helpers/test_autotools.py index d791f321d62..bfa4c336404 100644 --- a/conans/test/integration/conan_v2/build_helpers/test_autotools.py +++ b/conans/test/integration/conan_v2/build_helpers/test_autotools.py @@ -17,14 +17,24 @@ def build(self): autotools.make() """) + profile = textwrap.dedent(""" + [settings] + os = Linux + arch = x86_64 + build_type = Release + compiler=gcc + compiler.version=4.9 + compiler.libcxx=libstdc++ + """) + def test_no_build_type(self): t = self.get_client() - t.save({"conanfile.py": self.conanfile.format("compiler")}) - t.run("create . pkg/0.1@user/testing", assert_error=True) + t.save({"conanfile.py": self.conanfile.format("compiler"), "myprofile": self.profile}) + t.run("create . pkg/0.1@user/testing -pr myprofile", assert_error=True) self.assertIn("Conan v2 incompatible: build_type setting should be defined.", t.out) def test_no_compiler(self): t = self.get_client() - t.save({"conanfile.py": self.conanfile.format("build_type")}) - t.run("create . pkg/0.1@user/testing", assert_error=True) + t.save({"conanfile.py": self.conanfile.format("build_type"), "myprofile": self.profile}) + t.run("create . pkg/0.1@user/testing -pr myprofile", assert_error=True) self.assertIn("Conan v2 incompatible: compiler setting should be defined.", t.out) diff --git a/conans/test/integration/conan_v2/build_helpers/test_cmake.py b/conans/test/integration/conan_v2/build_helpers/test_cmake.py index 7de110bd67e..b9207e353a1 100644 --- a/conans/test/integration/conan_v2/build_helpers/test_cmake.py +++ b/conans/test/integration/conan_v2/build_helpers/test_cmake.py @@ -4,6 +4,15 @@ class CMakeBuildHelperTestCase(ConanV2ModeTestCase): + profile = textwrap.dedent(""" + [settings] + os = Linux + arch = x86_64 + build_type = Release + compiler=gcc + compiler.version=4.9 + compiler.libcxx=libstdc++ + """) def test_no_build_type(self): t = self.get_client() @@ -15,8 +24,8 @@ def build(self): cmake = CMake(self) cmake.build() """) - t.save({"conanfile.py": conanfile}) - t.run("create . pkg/0.1@user/testing", assert_error=True) + t.save({"conanfile.py": conanfile, "myprofile": self.profile}) + t.run("create . pkg/0.1@user/testing -pr myprofile", assert_error=True) self.assertIn("Conan v2 incompatible: build_type setting should be defined.", t.out) def test_no_compiler(self): @@ -30,8 +39,8 @@ def build(self): cmake = CMake(self) cmake.build() """) - t.save({"conanfile.py": conanfile}) - t.run("create . pkg/0.1@user/testing", assert_error=True) + t.save({"conanfile.py": conanfile, "myprofile": self.profile}) + t.run("create . pkg/0.1@user/testing -pr myprofile", assert_error=True) self.assertIn("Conan v2 incompatible: compiler setting should be defined.", t.out) def test_toolchain_no_build_type(self): @@ -40,11 +49,11 @@ def test_toolchain_no_build_type(self): from conans import ConanFile, CMake class Pkg(ConanFile): toolchain = "cmake" - + def build(self): cmake = CMake(self) cmake.build() """) - t.save({"conanfile.py": conanfile}) - t.run("create . pkg/0.1@user/testing", assert_error=True) + t.save({"conanfile.py": conanfile, "myprofile": self.profile}) + t.run("create . pkg/0.1@user/testing -pr myprofile", assert_error=True) self.assertIn("Conan v2 incompatible: build_type setting should be defined.", t.out) diff --git a/conans/test/integration/conan_v2/build_helpers/test_meson.py b/conans/test/integration/conan_v2/build_helpers/test_meson.py index c2bede5a9f8..ae74dc98575 100644 --- a/conans/test/integration/conan_v2/build_helpers/test_meson.py +++ b/conans/test/integration/conan_v2/build_helpers/test_meson.py @@ -4,6 +4,15 @@ class MesonBuildHelperTestCase(ConanV2ModeTestCase): + profile = textwrap.dedent(""" + [settings] + os = Linux + arch = x86_64 + build_type = Release + compiler=gcc + compiler.version=4.9 + compiler.libcxx=libstdc++ + """) def test_no_build_type(self): t = self.get_client() @@ -15,8 +24,8 @@ def build(self): meson = Meson(self) meson.build() """) - t.save({"conanfile.py": conanfile}) - t.run("create . pkg/0.1@user/testing", assert_error=True) + t.save({"conanfile.py": conanfile, "myprofile": self.profile}) + t.run("create . pkg/0.1@user/testing -pr myprofile", assert_error=True) self.assertIn("Conan v2 incompatible: build_type setting should be defined.", t.out) def test_no_compiler(self): @@ -30,6 +39,6 @@ def build(self): meson = Meson(self) meson.build() """) - t.save({"conanfile.py": conanfile}) - t.run("create . pkg/0.1@user/testing", assert_error=True) + t.save({"conanfile.py": conanfile, "myprofile": self.profile}) + t.run("create . pkg/0.1@user/testing -pr myprofile", assert_error=True) self.assertIn("Conan v2 incompatible: compiler setting should be defined.", t.out) From 7e2beca39b474d09e39d177d8023ce07b993ee42 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 18 Jan 2021 17:32:30 +0100 Subject: [PATCH 32/32] added integration test for msbuild --- .../toolchain/test_msbuild_toolchain.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 conans/test/integration/toolchain/test_msbuild_toolchain.py diff --git a/conans/test/integration/toolchain/test_msbuild_toolchain.py b/conans/test/integration/toolchain/test_msbuild_toolchain.py new file mode 100644 index 00000000000..a185610a52c --- /dev/null +++ b/conans/test/integration/toolchain/test_msbuild_toolchain.py @@ -0,0 +1,43 @@ +import textwrap + +from parameterized import parameterized + +from conans.test.utils.tools import TestClient + + +@parameterized.expand([("msvc", "19.0", "dynamic"), + ("msvc", "19.1", "static")] + ) +def test_toolchain_win(compiler, version, runtime): + client = TestClient(path_with_spaces=False) + settings = {"compiler": compiler, + "compiler.version": version, + "compiler.cppstd": "17", + "compiler.runtime": runtime, + "build_type": "Release", + "arch": "x86_64"} + + # Build the profile according to the settings provided + settings = " ".join('-s %s="%s"' % (k, v) for k, v in settings.items() if v) + + conanfile = textwrap.dedent(""" + from conans import ConanFile + from conan.tools.microsoft import MSBuildToolchain + class Pkg(ConanFile): + settings = "os", "compiler", "build_type", "arch" + def generate(self): + msbuild = MSBuildToolchain(self) + msbuild.generate() + """) + client.save({"conanfile.py": conanfile}) + client.run("install . {}".format(settings)) + props = client.load("conantoolchain_release_x64.props") + assert "stdcpp17" in props + if version == "19.0": + assert "v140" in props + else: + assert "v141" in props + if runtime == "dynamic": + assert "MultiThreadedDLL" in props + else: + assert "MultiThreaded" in props