Repository: conan-io/conan
Pull request #12349 (2022-10-20 14:28:45)

Do not add architecture to system packages by default, only when cross-compiling
Changelog: Feature: Do not add architecture to system packages by default, only when cross-compiling
Docs: TODO

The most common situation when installing system packages is that you don't use the architecture in the package name unless you are cross-compiling, so this defaults to that behaviour.
Also it's testing how to install archless packages even with cross-compilation, but that's something we probably want to change as the code would look a bit ugly. You can workaround that with an empty dictionary as arch_names in classes that accept the argument:

```
Apt(self).install(["libudev-dev"], update=True, check=True)
Apt(self, arch_names={}).install(["archless-package"], update=True, check=True)
```



Closes: https://github.com/conan-io/conan/issues/12320

czoido: > I don't think this closes #12320, because the situation stays the same during cross compilation: for a given recipe either:
> 
> * all system packages have an arch suffix (if the recipe has an arch setting) or
> * no system package has an arch suffix (if the recipe does not have an arch setting)
> 
> To fix the issue, we would need to have a method which installs the system packages it receives as argument, with `noarch`/`all`/`any` architecture suffix, depending on the package manager. Just to be clear, there is no need for this feature currently in CCI. The offending case in CCI (`xorg/system`) was solved by removing all the arch-less system packages from `xorg/system`, and putting them in a dedicated recipe without arch setting

Hi @ericLemanissier, thanks for the comments. The intention of this PR is to:
- Change the default when invoking system package managers and don't add the architecture to the package names for the most common case that is not cross-compiling. As you say this would not close the issue.
- Provide a way of forcing installing packages without the architecture appended to the package name even if you are cross-compiling. This is not yet covered in the PR with a solution, I commented above that this can be workarounded with something like this:

```
Apt(self, arch_names={}).install(["archless-package"], update=True, check=True)
```

Passing `arch_names` as an empty dictionary in the constructor will make that the name resolution skips adding the architecture for all cases (cross-compiling and not). But that is ugly and probably we want to pass a new argument to cover this case. That workaround I think would close https://github.com/conan-io/conan/issues/12320 as then you also could mix archless packages with packages with arch in the same recipe without having to write a new recipe for the archless ones which I think would be more convinient. Am I missing something?

Thanks a lot.

Patch:
diff --git a/conan/tools/apple/apple.py b/conan/tools/apple/apple.py
index a68b5d355..0feb41eec 100644
--- a/conan/tools/apple/apple.py
+++ b/conan/tools/apple/apple.py
@@ -4,6 +4,7 @@ import os
 
 from conans.util.runners import check_output_runner
 from conans.client.tools.apple import to_apple_arch as _to_apple_arch
+from conans.errors import ConanException
 
 
 def is_apple_os(conanfile):
@@ -158,8 +159,8 @@ def fix_apple_shared_install_name(conanfile):
         install_name = check_output_runner(command).strip().split(":")[1].strip()
         return install_name
 
-    def _osx_collect_dylibs(lib_folder):
-        return [os.path.join(full_folder, f) for f in os.listdir(lib_folder) if f.endswith(".dylib")
+    def _darwin_collect_dylibs(lib_folder):
+        return [os.path.join(lib_folder, f) for f in os.listdir(lib_folder) if f.endswith(".dylib")
                 and not os.path.islink(os.path.join(lib_folder, f))]
 
     def _fix_install_name(dylib_path, new_name):
@@ -170,16 +171,48 @@ def fix_apple_shared_install_name(conanfile):
         command = f"install_name_tool {dylib_path} -change {old_name} {new_name}"
         conanfile.run(command)
 
-    substitutions = {}
-
-    if is_apple_os(conanfile) and conanfile.options.get_safe("shared", False):
+    def _darwin_collect_executables(bin_folder):
+        ret = []
+        for f in os.listdir(bin_folder):
+            full_path = os.path.join(bin_folder, f)
+
+            # Run "otool -hv" to verify it is an executable
+            check_bin = "otool -hv {}".format(full_path)
+            if "EXECUTE" in check_output_runner(check_bin):
+                ret.append(full_path)
+        return ret
+
+    def _get_rpath_entries(binary_file):
+        entries = []
+        command = "otool -l {}".format(binary_file)
+        otool_output = check_output_runner(command).splitlines()
+        for count, text in enumerate(otool_output):
+            pass
+            if "LC_RPATH" in text:
+                rpath_entry = otool_output[count+2].split("path ")[1].split(" ")[0]
+                entries.append(rpath_entry)
+        return entries
+
+    def _get_shared_dependencies(binary_file):
+        command = "otool -L {}".format(binary_file)
+        all_shared = check_output_runner(command).strip().split(":")[1].strip()
+        ret = [s.split("(")[0].strip() for s in all_shared.splitlines()]
+        return ret
+
+    def _fix_dylib_files(conanfile):
+        substitutions = {}
         libdirs = getattr(conanfile.cpp.package, "libdirs")
         for libdir in libdirs:
             full_folder = os.path.join(conanfile.package_folder, libdir)
-            shared_libs = _osx_collect_dylibs(full_folder)
+            if not os.path.exists(full_folder):
+                raise ConanException(f"Trying to locate shared libraries, but `{libdir}` "
+                                     f" not found inside package folder {conanfile.package_folder}")
+            shared_libs = _darwin_collect_dylibs(full_folder)
             # fix LC_ID_DYLIB in first pass
             for shared_lib in shared_libs:
                 install_name = _get_install_name(shared_lib)
+                #TODO: we probably only want to fix the install the name if
+                # it starts with `/`.
                 rpath_name = f"@rpath/{os.path.basename(install_name)}"
                 _fix_install_name(shared_lib, rpath_name)
                 substitutions[install_name] = rpath_name
@@ -188,3 +221,45 @@ def fix_apple_shared_install_name(conanfile):
             for shared_lib in shared_libs:
                 for old, new in substitutions.items():
                     _fix_dep_name(shared_lib, old, new)
+
+        return substitutions
+
+    def _fix_executables(conanfile, substitutions):
+        # Fix the install name for executables inside the package
+        # that reference libraries we just patched
+        bindirs = getattr(conanfile.cpp.package, "bindirs")
+        for bindir in bindirs:
+            full_folder = os.path.join(conanfile.package_folder, bindir)
+            if not os.path.exists(full_folder):
+                # Skip if the folder does not exist inside the package
+                # (e.g. package does not contain executables but bindirs is defined)
+                continue
+            executables = _darwin_collect_executables(full_folder)
+            for executable in executables:
+
+                # Fix install names of libraries from within the same package
+                deps = _get_shared_dependencies(executable)
+                for dep in deps:
+                    dep_base = os.path.join(os.path.dirname(dep), os.path.basename(dep).split('.')[0])
+                    match = [k for k in substitutions.keys() if k.startswith(dep_base)]
+                    if match:
+                        _fix_dep_name(executable, dep, substitutions[match[0]])
+
+                # Add relative rpath to library directories, avoiding possible
+                # existing duplicates
+                libdirs = getattr(conanfile.cpp.package, "libdirs")
+                libdirs = [os.path.join(conanfile.package_folder, dir) for dir in libdirs]
+                rel_paths = [f"@executable_path/{os.path.relpath(dir, full_folder)}" for dir in libdirs]
+                existing_rpaths = _get_rpath_entries(executable)
+                rpaths_to_add = list(set(rel_paths) - set(existing_rpaths))
+                for entry in rpaths_to_add:
+                    command = f"install_name_tool {executable} -add_rpath {entry}"
+                    conanfile.run(command)
+
+    if is_apple_os(conanfile) and conanfile.options.get_safe("shared", False):
+        substitutions = _fix_dylib_files(conanfile)
+
+        # Only "fix" executables if dylib files were patched, otherwise 
+        # there is nothing to do.
+        if substitutions:
+            _fix_executables(conanfile, substitutions)
diff --git a/conan/tools/env/environment.py b/conan/tools/env/environment.py
index 18c5de0b7..4d43ed19a 100644
--- a/conan/tools/env/environment.py
+++ b/conan/tools/env/environment.py
@@ -350,7 +350,7 @@ class EnvVars:
         filepath, filename = os.path.split(file_location)
         deactivate_file = os.path.join(filepath, "deactivate_{}".format(filename))
         deactivate = textwrap.dedent("""\
-           echo "echo Restoring environment" >> "{deactivate_file}"
+           echo "echo Restoring environment" > "{deactivate_file}"
            for v in {vars}
            do
                is_defined="true"
diff --git a/conan/tools/gnu/autotoolstoolchain.py b/conan/tools/gnu/autotoolstoolchain.py
index 7269fa2f7..7b0f735df 100644
--- a/conan/tools/gnu/autotoolstoolchain.py
+++ b/conan/tools/gnu/autotoolstoolchain.py
@@ -43,8 +43,8 @@ class AutotoolsToolchain:
         self.fpic = self._conanfile.options.get_safe("fPIC")
         self.msvc_runtime_flag = self._get_msvc_runtime_flag()
 
-        # Cross build
-        self._host = None
+        # Cross build triplets
+        self._host = self._conanfile.conf.get("tools.gnu:host_triplet")
         self._build = None
         self._target = None
 
@@ -56,7 +56,8 @@ class AutotoolsToolchain:
         if cross_building(self._conanfile):
             os_build, arch_build, os_host, arch_host = get_cross_building_settings(self._conanfile)
             compiler = self._conanfile.settings.get_safe("compiler")
-            self._host = _get_gnu_triplet(os_host, arch_host, compiler=compiler)
+            if not self._host:
+                self._host = _get_gnu_triplet(os_host, arch_host, compiler=compiler)
             self._build = _get_gnu_triplet(os_build, arch_build, compiler=compiler)
 
             # Apple Stuff
diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py
index d97116943..b75fec4bd 100644
--- a/conan/tools/meson/toolchain.py
+++ b/conan/tools/meson/toolchain.py
@@ -317,6 +317,7 @@ class MesonToolchain(object):
 
         if self.libcxx:
             self.cpp_args.append(self.libcxx)
+            self.cpp_link_args.append(self.libcxx)
         if self.gcc_cxx11_abi:
             self.cpp_args.append("-D{}".format(self.gcc_cxx11_abi))
 
diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py
index 52353f433..3c3d2739c 100644
--- a/conan/tools/microsoft/msbuilddeps.py
+++ b/conan/tools/microsoft/msbuilddeps.py
@@ -25,7 +25,6 @@ class MSBuildDeps(object):
           <PropertyGroup Label="ConanVariables">
             <Conan{{name}}RootFolder>{{root_folder}}</Conan{{name}}RootFolder>
             <Conan{{name}}BinaryDirectories>{{bin_dirs}}</Conan{{name}}BinaryDirectories>
-            <Conan{{name}}Dependencies>{{dependencies}}</Conan{{name}}Dependencies>
             {% if host_context %}
             <Conan{{name}}CompilerFlags>{{compiler_flags}}</Conan{{name}}CompilerFlags>
             <Conan{{name}}LinkerFlags>{{linker_flags}}</Conan{{name}}LinkerFlags>
@@ -134,7 +133,7 @@ class MSBuildDeps(object):
     def _get_valid_xml_format(name):
         return re.compile(r"[.+]").sub("_", name)
 
-    def _vars_props_file(self, dep, name, cpp_info, deps, build):
+    def _vars_props_file(self, dep, name, cpp_info, build):
         """
         content for conan_vars_poco_x86_release.props, containing the variables for 1 config
         This will be for 1 package or for one component of a package
@@ -180,7 +179,6 @@ class MSBuildDeps(object):
             'definitions': "".join("%s;" % d for d in cpp_info.defines),
             'compiler_flags': " ".join(cpp_info.cxxflags + cpp_info.cflags),
             'linker_flags': " ".join(cpp_info.sharedlinkflags + cpp_info.exelinkflags),
-            'dependencies': ";".join(deps),
             'host_context': not build
         }
         formatted_template = Template(self._vars_props, trim_blocks=True,
@@ -291,15 +289,16 @@ class MSBuildDeps(object):
                 comp_filename = "conan_%s.props" % full_comp_name
                 pkg_filename = "conan_%s.props" % dep_name
 
-                public_deps = []
+                public_deps = []  # To store the xml dependencies/file names
                 for r in comp_info.requires:
                     if "::" in r:  # Points to a component of a different package
                         pkg, cmp_name = r.split("::")
                         public_deps.append(pkg if pkg == cmp_name else "{}_{}".format(pkg, cmp_name))
                     else:  # Points to a component of same package
                         public_deps.append("{}_{}".format(dep_name, r))
+                public_deps = [self._get_valid_xml_format(d) for d in public_deps]
                 result[vars_filename] = self._vars_props_file(dep, full_comp_name, comp_info,
-                                                              public_deps, build=build)
+                                                              build=build)
                 result[activate_filename] = self._activate_props_file(full_comp_name, vars_filename,
                                                                       public_deps, build=build)
                 result[comp_filename] = self._dep_props_file(full_comp_name, comp_filename,
@@ -317,7 +316,7 @@ class MSBuildDeps(object):
             public_deps = [self._dep_name(d, build)
                            for r, d in dep.dependencies.direct_host.items() if r.visible]
             result[vars_filename] = self._vars_props_file(dep, dep_name, cpp_info,
-                                                          public_deps, build=build)
+                                                          build=build)
             result[activate_filename] = self._activate_props_file(dep_name, vars_filename,
                                                                   public_deps, build=build)
             result[pkg_filename] = self._dep_props_file(dep_name, pkg_filename, activate_filename,
diff --git a/conan/tools/system/package_manager.py b/conan/tools/system/package_manager.py
index ef281980f..927e8ecd1 100644
--- a/conan/tools/system/package_manager.py
+++ b/conan/tools/system/package_manager.py
@@ -1,5 +1,6 @@
 import platform
 
+from conan.tools.build import cross_building
 from conans.client.graph.graph import CONTEXT_BUILD
 from conans.errors import ConanException
 
@@ -57,7 +58,7 @@ class _SystemPackageManagerTool(object):
 
     def get_package_name(self, package):
         # TODO: should we only add the arch if cross-building?
-        if self._arch in self._arch_names:
+        if self._arch in self._arch_names and cross_building(self._conanfile):
             return "{}{}{}".format(package, self._arch_separator,
                                    self._arch_names.get(self._arch))
         return package
diff --git a/conans/client/command.py b/conans/client/command.py
index 9c1469ac8..5b548b805 100644
--- a/conans/client/command.py
+++ b/conans/client/command.py
@@ -1575,7 +1575,7 @@ class Command(object):
         parser_add.add_argument('remote', help='Name of the remote')
         parser_add.add_argument('url', help='URL of the remote')
         parser_add.add_argument('verify_ssl', nargs="?", default="True",
-                                help='Verify SSL certificated. Default True')
+                                help='Verify SSL certificate. Defaulted to True')
         parser_add.add_argument("-i", "--insert", nargs="?", const=0, type=int, action=OnceArgument,
                                 help="insert remote at specific index")
         parser_add.add_argument("-f", "--force", default=False, action='store_true',
@@ -1587,7 +1587,7 @@ class Command(object):
 
         parser_upd.add_argument('url', help='URL')
         parser_upd.add_argument('verify_ssl', nargs="?", default="True",
-                                help='Verify SSL certificated. Default True')
+                                help='Verify SSL certificate. Defaulted to True')
         parser_upd.add_argument("-i", "--insert", nargs="?", const=0, type=int, action=OnceArgument,
                                 help="Insert remote at specific index")
         parser_rename = subparsers.add_parser('rename', help='Update the remote name')
diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py
index 246af0a51..86d19ae10 100644
--- a/conans/client/generators/__init__.py
+++ b/conans/client/generators/__init__.py
@@ -254,6 +254,7 @@ def write_toolchain(conanfile, path, output):
 
     # tools.env.virtualenv:auto_use will be always True in Conan 2.0
     if conanfile.conf["tools.env.virtualenv:auto_use"]:
+        mkdir(path)
         with chdir(path):
             if conanfile.virtualbuildenv:
                 from conan.tools.env.virtualbuildenv import VirtualBuildEnv
diff --git a/conans/model/conf.py b/conans/model/conf.py
index 4df28790e..b7044625b 100644
--- a/conans/model/conf.py
+++ b/conans/model/conf.py
@@ -28,6 +28,7 @@ BUILT_IN_CONFS = {
     "tools.files.download:retry_wait": "Seconds to wait between download attempts",
     "tools.gnu:make_program": "Indicate path to make program",
     "tools.gnu:define_libcxx11_abi": "Force definition of GLIBCXX_USE_CXX11_ABI=1 for libstdc++11",
+    "tools.gnu:host_triplet": "Custom host triplet to pass to Autotools scripts",
     "tools.google.bazel:configs": "Define Bazel config file",
     "tools.google.bazel:bazelrc_path": "Defines Bazel rc-path",
     "tools.microsoft.msbuild:verbosity": "Verbosity level for MSBuild: 'Quiet', 'Minimal', 'Normal', 'Detailed', 'Diagnostic'",


Test patch:
diff --git a/conans/test/functional/layout/test_editables_layout.py b/conans/test/functional/layout/test_editables_layout.py
index d81dad552..277798608 100644
--- a/conans/test/functional/layout/test_editables_layout.py
+++ b/conans/test/functional/layout/test_editables_layout.py
@@ -253,3 +253,30 @@ def test_cpp_info_components_editable():
     assert "**VAR libs:['hello_var']**" in out
     assert "**VAR cxxflags:['my_cxx_flag_var']**" in out
     assert "**VAR cflags:['my_c_flag_var']**" in out
+
+
+def test_editable_package_folder():
+    """ This test checks the behavior that self.package_folder is NOT defined (i.e = None)
+    for editable packages, so it cannot be used in ``package_info()`` method
+    """
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        from conan.tools.cmake import cmake_layout
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "0.1"
+            settings = "os", "compiler", "arch", "build_type"
+
+            def package_info(self):
+                self.output.info("PKG FOLDER={}!!!".format(self.package_folder))
+
+            def layout(self):
+                cmake_layout(self)
+        """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create .")
+    c.run("editable add . pkg/0.1")
+    c.run("install pkg/0.1@")
+    assert "pkg/0.1: PKG FOLDER=None!!!"
diff --git a/conans/test/functional/toolchains/gnu/autotools/test_crossbuild_triplet.py b/conans/test/functional/toolchains/gnu/autotools/test_crossbuild_triplet.py
new file mode 100644
index 000000000..d379b17b4
--- /dev/null
+++ b/conans/test/functional/toolchains/gnu/autotools/test_crossbuild_triplet.py
@@ -0,0 +1,53 @@
+import platform
+import pytest
+import textwrap
+
+from conans.test.utils.tools import TestClient
+
+@pytest.mark.skipif(platform.system() not in  ["Darwin", "Linux"], reason="Autotools on Linux or macOS")
+def test_crossbuild_triplet_from_conf():
+
+    settings_yml = textwrap.dedent("""
+        os:
+            Linux:
+            Windows:
+        arch: [x86_64, hexagon]
+        compiler:
+            gcc:
+                version: ["10", "11"]
+                libcxx: [libstdc++11]
+        build_type: [None, Debug, Release]
+        """)
+    
+    host_profile = textwrap.dedent("""
+        [settings]
+        os=Linux
+        arch=hexagon
+        compiler=gcc
+        compiler.version=10
+        compiler.libcxx=libstdc++11
+        build_type=Release
+        [conf]
+        tools.gnu:host_triplet=hexagon-acme-linux-gnu
+    """)
+
+    build_profile = textwrap.dedent("""
+        [settings]
+        os=Linux
+        arch=x86_64
+        compiler=gcc
+        compiler.version=11
+        compiler.libcxx=libstdc++11
+        build_type=Release   
+    """)
+
+    client = TestClient(path_with_spaces=False)
+    client.save({client.cache.settings_path: settings_yml})
+    client.save({"host_profile": host_profile})
+    client.save({"build_profile": build_profile})
+
+    client.run("new hello/0.1 --template=autotools_lib")
+    client.run("create . --profile:build=build_profile --profile:host=host_profile -tf None")
+
+    assert "--host=hexagon-acme-linux-gnu" in client.out
+    assert "checking host system type... hexagon-acme-linux-gnu" in client.out
diff --git a/conans/test/functional/toolchains/gnu/test_v2_autotools_template.py b/conans/test/functional/toolchains/gnu/test_v2_autotools_template.py
index 81685594a..240f3213b 100644
--- a/conans/test/functional/toolchains/gnu/test_v2_autotools_template.py
+++ b/conans/test/functional/toolchains/gnu/test_v2_autotools_template.py
@@ -26,6 +26,23 @@ def test_autotools_lib_template():
     package_folder = client.cache.package_layout(pref.ref).package(pref)
     assert os.path.exists(os.path.join(package_folder, "include", "hello.h"))
 
+    # Local flow for shared library works
+    client.save({}, clean_first=True)
+    client.run("new hello/0.1 --template=autotools_lib")
+    client.run("install . -if install_shared -o hello:shared=True")
+    client.run("build . -if=install_shared")
+    client.run("export-pkg . hello/0.1@ -if=install_shared -o hello:shared=True")
+    package_id = re.search(r"Packaging to (\S+)", str(client.out)).group(1)
+    pref = PackageReference(ConanFileReference.loads("hello/0.1"), package_id)
+    package_folder = client.cache.package_layout(pref.ref).package(pref)
+
+    if platform.system() == "Darwin":
+        # Ensure that install name of dylib is patched
+        client.run_command(f"otool -L {package_folder}/lib/libhello.0.dylib")
+        assert "@rpath/libhello.0.dylib" in client.out
+    elif platform.system() == "Linux":
+        assert os.path.exists(os.path.join(package_folder, "lib", "libhello.so.0"))
+
     # Create works
     client.run("create .")
     assert "hello/0.1: Hello World Release!" in client.out
@@ -269,6 +286,10 @@ def test_autotools_fix_shared_libs():
         libbye_la_HEADERS = bye.h
         libbye_ladir = $(includedir)
         libbye_la_LIBADD = libhello.la
+
+        bin_PROGRAMS = main
+        main_SOURCES = main.cpp
+        main_LDADD = libhello.la libbye.la
     """)
 
     test_src = textwrap.dedent("""
@@ -280,6 +301,7 @@ def test_autotools_fix_shared_libs():
         "src/makefile.am": makefile_am,
         "src/bye.cpp": bye_cpp,
         "src/bye.h": bye_h,
+        "src/main.cpp": test_src,
         "test_package/main.cpp": test_src,
         "conanfile.py": conanfile,
     })
@@ -304,5 +326,13 @@ def test_autotools_fix_shared_libs():
     assert "@rpath/libhello.dylib (compatibility version 1.0.0, current version 1.0.0)" in client.out
     assert "@rpath/libbye.dylib (compatibility version 1.0.0, current version 1.0.0)" in client.out
 
+    # app rpath fixed in executable
+    exe_path = os.path.join(package_folder, "bin", "main")
+    client.run_command("otool -L {}".format(exe_path))
+    assert "@rpath/libhello.dylib" in client.out
+    client.run_command(exe_path)
+    assert "Bye, bye!" in client.out
+
+    # Running the test-package also works
     client.run("test test_package hello/0.1@ -o hello:shared=True")
     assert "Bye, bye!" in client.out
diff --git a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
index 9c6a9120b..f36d3bede 100644
--- a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
+++ b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
@@ -1008,4 +1008,4 @@ def test_build_requires_transitives():
     assert "conan_dep_build.props" in tool
     assert "conan_dep.props" not in tool
     tool_vars = c.load("conan_tool_build_vars_release_x64.props")
-    assert "<Conantool_buildDependencies>dep_build</Conantool_buildDependencies>" in tool_vars
+    assert "<Conantool_buildRootFolder>" in tool_vars
diff --git a/conans/test/functional/tools/system/package_manager_test.py b/conans/test/functional/tools/system/package_manager_test.py
index 210f6434d..89d27e705 100644
--- a/conans/test/functional/tools/system/package_manager_test.py
+++ b/conans/test/functional/tools/system/package_manager_test.py
@@ -50,11 +50,10 @@ def test_apt_install_substitutes():
     client.save({"conanfile.py": conanfile_py.format(installs)})
     client.run("create . test/1.0@ -c tools.system.package_manager:mode=install "
                "-c tools.system.package_manager:sudo=True", assert_error=True)
-
-    assert "dpkg-query: no packages found matching non-existing1:amd64" in client.out
-    assert "dpkg-query: no packages found matching non-existing2:amd64" in client.out
-    assert "dpkg-query: no packages found matching non-existing3:amd64" in client.out
-    assert "dpkg-query: no packages found matching non-existing4:amd64" in client.out
+    assert "dpkg-query: no packages found matching non-existing1" in client.out
+    assert "dpkg-query: no packages found matching non-existing2" in client.out
+    assert "dpkg-query: no packages found matching non-existing3" in client.out
+    assert "dpkg-query: no packages found matching non-existing4" in client.out
     assert "ERROR: while executing system_requirements(): " \
            "None of the installs for the package substitutes succeeded." in client.out
 
@@ -88,8 +87,8 @@ def test_build_require():
             tool_requires = "tool_require/1.0"
         """)})
     client.run("create consumer.py consumer/1.0@ -s:b arch=armv8 -s:h arch=x86 --build=missing")
-    assert "dpkg-query: no packages found matching non-existing1:arm64" in client.out
-    assert "dpkg-query: no packages found matching non-existing2:arm64" in client.out
+    assert "dpkg-query: no packages found matching non-existing1" in client.out
+    assert "dpkg-query: no packages found matching non-existing2" in client.out
     assert "missing: ['non-existing1', 'non-existing2']" in client.out
 
 
diff --git a/conans/test/integration/environment/test_env.py b/conans/test/integration/environment/test_env.py
index d81f55ef7..334936ae8 100644
--- a/conans/test/integration/environment/test_env.py
+++ b/conans/test/integration/environment/test_env.py
@@ -483,18 +483,19 @@ def test_multiple_deactivate():
     os.chmod(os.path.join(client.current_folder, "display.sh"), 0o777)
     client.run("install .")
 
-    if platform.system() == "Windows":
-        cmd = "conanbuild.bat && display.bat && deactivate_conanbuild.bat && display.bat"
-    else:
-        cmd = '. ./conanbuild.sh && ./display.sh && . ./deactivate_conanbuild.sh && ./display.sh'
-    out, _ = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
-                              shell=True, cwd=client.current_folder).communicate()
-    out = out.decode()
-    assert "VAR1=Value1!!" in out
-    assert "VAR2=Value2!!" in out
-    assert 2 == str(out).count("Restoring environment")
-    assert "VAR1=!!" in out
-    assert "VAR2=!!" in out
+    for _ in range(2):  # Just repeat it, so we can check things keep working
+        if platform.system() == "Windows":
+            cmd = "conanbuild.bat && display.bat && deactivate_conanbuild.bat && display.bat"
+        else:
+            cmd = '. ./conanbuild.sh && ./display.sh && . ./deactivate_conanbuild.sh && ./display.sh'
+        out, _ = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                                  shell=True, cwd=client.current_folder).communicate()
+        out = out.decode()
+        assert "VAR1=Value1!!" in out
+        assert "VAR2=Value2!!" in out
+        assert 2 == str(out).count("Restoring environment")
+        assert "VAR1=!!" in out
+        assert "VAR2=!!" in out
 
 
 @pytest.mark.skipif(platform.system() != "Windows", reason="Path problem in Windows only")
diff --git a/conans/test/integration/toolchains/gnu/test_basic_layout.py b/conans/test/integration/toolchains/gnu/test_basic_layout.py
index 19cd9ebb6..968596115 100644
--- a/conans/test/integration/toolchains/gnu/test_basic_layout.py
+++ b/conans/test/integration/toolchains/gnu/test_basic_layout.py
@@ -23,3 +23,25 @@ def test_basic_layout_subproject():
     ext = "sh" if platform.system() != "Windows" else "bat"
     assert os.path.isfile(os.path.join(c.current_folder, "pkg", "build-release", "conan",
                                        "conanautotoolstoolchain.{}".format(ext)))
+
+
+# TODO: Remove this test in 2.0
+def test_basic_layout_no_generators():
+    """ test that conan doesn't crash for auto_use=True
+    because generator folder doesn't exist
+    # https://github.com/conan-io/conan/issues/12383
+    """
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conan.tools.layout import basic_layout
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "0.1"
+            settings = "os", "compiler", "build_type", "arch"
+            def layout(self):
+                basic_layout(self)
+        """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create . -c tools.env.virtualenv:auto_use=True")
+    # It used to fail, if it doesn't crash, it is good
diff --git a/conans/test/integration/toolchains/meson/test_mesontoolchain.py b/conans/test/integration/toolchains/meson/test_mesontoolchain.py
index 1f9a933c7..c5b273ada 100644
--- a/conans/test/integration/toolchains/meson/test_mesontoolchain.py
+++ b/conans/test/integration/toolchains/meson/test_mesontoolchain.py
@@ -58,8 +58,8 @@ def test_apple_meson_keep_user_custom_flags():
     content = t.load(MesonToolchain.cross_filename)
     assert "c_args = ['-isysroot', '/other/sdk/path', '-arch', 'myarch', '-otherminversion=10.7']" in content
     assert "c_link_args = ['-isysroot', '/other/sdk/path', '-arch', 'myarch', '-otherminversion=10.7']" in content
-    assert "cpp_args = ['-isysroot', '/other/sdk/path', '-arch', 'myarch', '-otherminversion=10.7']" in content
-    assert "cpp_link_args = ['-isysroot', '/other/sdk/path', '-arch', 'myarch', '-otherminversion=10.7']" in content
+    assert "cpp_args = ['-isysroot', '/other/sdk/path', '-arch', 'myarch', '-otherminversion=10.7', '-stdlib=libc++']" in content
+    assert "cpp_link_args = ['-isysroot', '/other/sdk/path', '-arch', 'myarch', '-otherminversion=10.7', '-stdlib=libc++']" in content
 
 
 @pytest.mark.skipif(sys.version_info.major == 2, reason="Meson not supported in Py2")
@@ -71,7 +71,7 @@ def test_extra_flags_via_conf():
         compiler=gcc
         compiler.version=9
         compiler.cppstd=17
-        compiler.libcxx=libstdc++11
+        compiler.libcxx=libstdc++
         build_type=Release
 
         [buildenv]
@@ -91,7 +91,7 @@ def test_extra_flags_via_conf():
 
     t.run("install . -pr=profile")
     content = t.load(MesonToolchain.native_filename)
-    assert "cpp_args = ['-flag0', '-other=val', '-flag1', '-flag2']" in content
+    assert "cpp_args = ['-flag0', '-other=val', '-flag1', '-flag2', '-D_GLIBCXX_USE_CXX11_ABI=0']" in content
     assert "c_args = ['-flag0', '-other=val', '-flag3', '-flag4']" in content
     assert "c_link_args = ['-flag0', '-other=val', '-flag5', '-flag6']" in content
     assert "cpp_link_args = ['-flag0', '-other=val', '-flag5', '-flag6']" in content
diff --git a/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py b/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py
index 0422276c3..32f40c7c2 100644
--- a/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py
+++ b/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py
@@ -45,6 +45,19 @@ def test_msbuilddeps_format_names():
     c.run("install pkg.name-more+/1.0@ -g MSBuildDeps -s build_type=Release -s arch=x86_64")
     # Checking that MSBuildDeps builds correctly the XML file
     # loading all .props and xml parse them to check no errors
+    pkg_more = c.load("conan_pkg_name-more_.props")
+    assert "$(conan_pkg_name-more__libmpdecimal___props_imported)" in pkg_more
+    assert "$(conan_pkg_name-more__mycomp_some-comp__props_imported)" in pkg_more
+
+    some_comp = c.load("conan_pkg_name-more__mycomp_some-comp_.props")
+    assert "<conan_pkg_name-more__mycomp_some-comp__props_imported>" in some_comp
+
+    libmpdecimal = c.load("conan_pkg_name-more__libmpdecimal__.props")
+    assert "<conan_pkg_name-more__libmpdecimal___props_imported>" in libmpdecimal
+
+    libmpdecimal_release = c.load("conan_pkg_name-more__libmpdecimal___release_x64.props")
+    assert "$(conan_pkg_name-more__mycomp_some-comp__props_imported)" in libmpdecimal_release
+
     counter = 0
     for f in os.listdir(c.current_folder):
         if f.endswith(".props"):
diff --git a/conans/test/integration/tools/system/package_manager_test.py b/conans/test/integration/tools/system/package_manager_test.py
index f63da31ec..dbac4cf19 100644
--- a/conans/test/integration/tools/system/package_manager_test.py
+++ b/conans/test/integration/tools/system/package_manager_test.py
@@ -10,7 +10,7 @@ from conan.tools.system.package_manager import Apt, Dnf, Yum, Brew, Pkg, PkgUtil
 from conans import Settings
 from conans.errors import ConanException
 from conans.model.conf import Conf
-from conans.test.utils.mocks import ConanFileMock
+from conans.test.utils.mocks import ConanFileMock, MockSettings
 
 
 @pytest.mark.parametrize("platform, tool", [
@@ -196,26 +196,66 @@ def test_dnf_yum_return_code_100(tool_class, result):
         assert f"Command '{result}' failed" == str(exc_info.value)
 
 
+@pytest.mark.parametrize("tool_class, arch_host, result", [
+    # not cross-compile -> do not add host architecture
+    (Apt, 'x86_64', 'apt-get install -y --no-install-recommends package1 package2'),
+    (Yum, 'x86_64', 'yum install -y package1 package2'),
+    (Dnf, 'x86_64', 'dnf install -y package1 package2'),
+    (Brew, 'x86_64', 'brew install package1 package2'),
+    (Pkg, 'x86_64', 'pkg install -y package1 package2'),
+    (PkgUtil, 'x86_64', 'pkgutil --install --yes package1 package2'),
+    (Chocolatey, 'x86_64', 'choco install --yes package1 package2'),
+    (PacMan, 'x86_64', 'pacman -S --noconfirm package1 package2'),
+    (Zypper, 'x86_64', 'zypper --non-interactive in package1 package2'),
+    # cross-compile -> add host architecture https://github.com/conan-io/conan/issues/12320
+    (Apt, 'x86', 'apt-get install -y --no-install-recommends package1:i386 package2:i386'),
+    (Yum, 'x86', 'yum install -y package1.i?86 package2.i?86'),
+    (Dnf, 'x86', 'dnf install -y package1.i?86 package2.i?86'),
+    (Brew, 'x86', 'brew install package1 package2'),
+    (Pkg, 'x86', 'pkg install -y package1 package2'),
+    (PkgUtil, 'x86', 'pkgutil --install --yes package1 package2'),
+    (Chocolatey, 'x86', 'choco install --yes package1 package2'),
+    (PacMan, 'x86', 'pacman -S --noconfirm package1-lib32 package2-lib32'),
+    (Zypper, 'x86', 'zypper --non-interactive in package1 package2'),
+])
+def test_tools_install_mode_install_different_archs(tool_class, arch_host, result):
+    conanfile = ConanFileMock()
+    conanfile.conf = Conf()
+    conanfile.settings = MockSettings({"arch": f"{arch_host}"})
+    conanfile.settings_build = MockSettings({"arch": "x86_64"})
+    conanfile.conf["tools.system.package_manager:tool"] = tool_class.tool_name
+    conanfile.conf["tools.system.package_manager:mode"] = "install"
+    with mock.patch('conans.ConanFile.context', new_callable=PropertyMock) as context_mock:
+        context_mock.return_value = "host"
+        tool = tool_class(conanfile)
+
+        def fake_check(*args, **kwargs):
+            return ["package1", "package2"]
+        from conan.tools.system.package_manager import _SystemPackageManagerTool
+        with patch.object(_SystemPackageManagerTool, 'check', MagicMock(side_effect=fake_check)):
+            tool.install(["package1", "package2"])
+
+    assert tool._conanfile.command == result
+
+
 @pytest.mark.parametrize("tool_class, result", [
+    # cross-compile but arch_names=None -> do not add host architecture
+    # https://github.com/conan-io/conan/issues/12320 because the package is archless
     (Apt, 'apt-get install -y --no-install-recommends package1 package2'),
     (Yum, 'yum install -y package1 package2'),
     (Dnf, 'dnf install -y package1 package2'),
-    (Brew, 'brew install package1 package2'),
-    (Pkg, 'pkg install -y package1 package2'),
-    (PkgUtil, 'pkgutil --install --yes package1 package2'),
-    (Chocolatey, 'choco --install --yes package1 package2'),
     (PacMan, 'pacman -S --noconfirm package1 package2'),
-    (Zypper, 'zypper --non-interactive in package1 package2'),
 ])
-def test_tools_install_mode_install(tool_class, result):
+def test_tools_install_archless(tool_class, result):
     conanfile = ConanFileMock()
     conanfile.conf = Conf()
-    conanfile.settings = Settings()
+    conanfile.settings = MockSettings({"arch": "x86"})
+    conanfile.settings_build = MockSettings({"arch": "x86_64"})
     conanfile.conf["tools.system.package_manager:tool"] = tool_class.tool_name
     conanfile.conf["tools.system.package_manager:mode"] = "install"
     with mock.patch('conans.ConanFile.context', new_callable=PropertyMock) as context_mock:
         context_mock.return_value = "host"
-        tool = tool_class(conanfile)
+        tool = tool_class(conanfile, arch_names={})
 
         def fake_check(*args, **kwargs):
             return ["package1", "package2"]
@@ -223,6 +263,8 @@ def test_tools_install_mode_install(tool_class, result):
         with patch.object(_SystemPackageManagerTool, 'check', MagicMock(side_effect=fake_check)):
             tool.install(["package1", "package2"])
 
+    assert tool._conanfile.command == result
+
 
 @pytest.mark.parametrize("tool_class, result", [
     (Apt, 'dpkg-query -W -f=\'${Status}\' package | grep -q "ok installed"'),
@@ -244,3 +286,5 @@ def test_tools_check(tool_class, result):
         context_mock.return_value = "host"
         tool = tool_class(conanfile)
         tool.check(["package"])
+
+    assert tool._conanfile.command == result
diff --git a/conans/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py b/conans/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
index acbe860bb..aedd2fdf9 100644
--- a/conans/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
+++ b/conans/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
@@ -58,6 +58,15 @@ def test_invalid_target_triple():
     assert "Unknown 'UNKNOWN_ARCH' machine, Conan doesn't know how " \
            "to translate it to the GNU triplet," in str(excinfo)
 
+def test_custom_host_triple():
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings({"os": "Linux", "arch": "x86"})
+    conanfile.settings_build = MockSettings({"os": "Linux", "arch": "x86_64"})
+    conanfile.conf.define("tools.gnu:host_triplet", "i686-pc-linux-gnu")
+    tc = AutotoolsToolchain(conanfile)
+    tc.generate_args()
+    obj = load_toolchain_args()
+    assert "--host=i686-pc-linux-gnu" in obj["configure_args"]
 
 def test_cppstd():
     # Using "cppstd" is discarded
diff --git a/conans/test/unittests/tools/apple/test_apple_tools.py b/conans/test/unittests/tools/apple/test_apple_tools.py
index 4146d0e50..6331c1dab 100644
--- a/conans/test/unittests/tools/apple/test_apple_tools.py
+++ b/conans/test/unittests/tools/apple/test_apple_tools.py
@@ -1,5 +1,8 @@
+import pytest
+
 from conans.test.utils.mocks import ConanFileMock, MockSettings
-from conan.tools.apple import is_apple_os, to_apple_arch
+from conans.test.utils.test_files import temp_folder
+from conan.tools.apple import is_apple_os, to_apple_arch, fix_apple_shared_install_name
 
 def test_tools_apple_is_apple_os():
     conanfile = ConanFileMock()
@@ -22,3 +25,14 @@ def test_tools_apple_to_apple_arch():
 
     conanfile.settings = MockSettings({"arch": "x86_64"})
     assert to_apple_arch(conanfile) == "x86_64"
+
+def test_fix_shared_install_name_no_libraries():
+    conanfile = ConanFileMock(
+        options="""{"shared": [True, False]}""",
+        options_values={"shared": True})
+    conanfile.settings = MockSettings({"os": "Macos"})
+    conanfile.folders.set_base_package(temp_folder())
+
+    with pytest.raises(Exception) as e:
+        fix_apple_shared_install_name(conanfile)
+        assert "not found inside package folder" in str(e.value)