Repository: conan-io/conan

Issue:
AutoToolsBuildEnvironment improvements
1. Should AutoToolsBuildEnvironment.configure adjust --prefix to self.package_folder?

The same way we are doing it with CMake.
Be aware: Could be breaking, opt-in?

2. The "vars" should be a real list (not a dynamic property) precalculated to let the user change it before calling the configure
3. The triplets for cross-building should be also pre-calculated and we should allow to change them. Probably to a "args" list.

In general, if someone doesn't want to use the ".configure()":

```python
   env_build = AutoToolsBuildEnvironment(self)
   # Here I modify the env_build.vars
   # Here I modify the env_buidl.args
   with  #tools.environment_append(env_build.vars):
         self.run("./myconfigure %s" % env_build.args)
```

Note: Inspired by the libcurl recipe, where the above issues make a lot more complex the recipe.

Discussion:
danimtb: My rework on the libcurl library: https://github.com/danimtb/conan-libcurl/pull/1

Some commented code, not deleted as still not tested.
I have not changed the code of unused function to keep the diff readable.

This PR improves the usability in general but the helper is not as easy to use as the cmake one, but also autotools is not as "easy" as cmake is 😆 
lasote: I agree, still not an ideal recipe, but it is a very special recipe and with this PR it is improved in the cross build flags and the env vars.
danimtb: Something else:

Original libcurl recipe was doing this

```python
params.append('--prefix=%s' % self.package_folder.replace('\\', '/'))
```

As the helper now takes care of the `--prefix`, is it needed to add the replace in the helper to be safe?
lasote: good catch. Yes, do it.
danimtb: Build failed due to pip issues. Relaunch if possible

Patch:
diff --git a/conans/client/build/autotools_environment.py b/conans/client/build/autotools_environment.py
index 0106e1cb0..a73d55b7f 100644
--- a/conans/client/build/autotools_environment.py
+++ b/conans/client/build/autotools_environment.py
@@ -12,7 +12,7 @@ from conans.client.build.cppstd_flags import cppstd_flag
 from conans.client.tools.oss import OSInfo
 from conans.client.tools.win import unix_path
 from conans.tools import (environment_append, args_to_string, cpu_count, cross_building,
-                          detected_architecture)
+                          detected_architecture, get_gnu_triplet)
 
 
 class AutoToolsBuildEnvironment(object):
@@ -57,68 +57,32 @@ class AutoToolsBuildEnvironment(object):
         # Not declared by default
         self.fpic = None
 
-    def _get_triplet(self, the_arch, the_os):
-        """
-        machine-vendor-op_system, But vendor can be omitted in practice
-        """
-
-        # Calculate the arch
-        machine = {"x86": "i686" if the_os != "Linux" else "x86",
-                   "x86_64": "x86_64",
-                   "armv6": "arm",
-                   "armv7": "arm",
-                   "armv7s": "arm",
-                   "armv7k": "arm",
-                   "armv7hf": "arm",
-                   "armv8": "aarch64"}.get(the_arch, None)
-        if machine is None:
-            self._conanfile.output.warn("Unknown '%s' machine, Conan doesn't know how to "
-                                        "translate it to the GNU triplet, please report at "
-                                        " https://github.com/conan-io/conan/issues" % the_arch)
-            return "unknown"
-
-        # Calculate the OS
-        compiler = self._conanfile.settings.get_safe("compiler")
-        if compiler == "gcc":
-            windows_op = "w64-mingw32"
-        elif compiler == "Visual Studio":
-            windows_op = "windows-msvc"
-        else:
-            windows_op = "windows"
-
-        op_system = {"Windows": windows_op,
-                     "Linux": "linux-gnu",
-                     "Darwin": "apple-darwin",
-                     "Android": "linux-android",
-                     "Macos": "apple-darwin",
-                     "iOS": "apple-darwin",
-                     "watchOS": "apple-darwin",
-                     "tvOS": "apple-darwin"}.get(the_os, the_os.lower())
-
-        if the_os in ("Linux", "Android"):
-            if "arm" in the_arch and the_arch != "armv8":
-                op_system += "eabi"
-
-            if the_arch == "armv7hf" and the_os == "Linux":
-                op_system += "hf"
-
-        return "%s-%s" % (machine, op_system)
+        # Precalculate build, host, target triplets
+        self.build, self.host, self.target = self._get_host_build_target_flags()
 
-    def _get_host_build_target_flags(self, arch_detected, os_detected):
+    def _get_host_build_target_flags(self):
         """Based on google search for build/host triplets, it could need a lot
         and complex verification"""
 
+        arch_detected = detected_architecture() or platform.machine()
+        os_detected = platform.system()
+        arch_settings = self._conanfile.settings.get_safe("arch")
+        os_settings = self._conanfile.settings.get_safe("os")
+        compiler = self._conanfile.settings.get_safe("compiler")
+
+        if (os_detected is None or arch_detected is None or arch_settings is None or
+                os_settings is None):
+            return False, False, False
         if not cross_building(self._conanfile.settings, os_detected, arch_detected):
             return False, False, False
 
-        build = self._get_triplet(arch_detected, os_detected)
-        host = self._get_triplet(self._conanfile.settings.get_safe("arch"),
-                                 self._conanfile.settings.get_safe("os"))
+        build = get_gnu_triplet(os_detected, arch_detected, compiler)
+        host = get_gnu_triplet(os_settings, arch_settings, compiler)
 
         return build, host, None
 
     def configure(self, configure_dir=None, args=None, build=None, host=None, target=None,
-                  pkg_config_paths=None):
+                  pkg_config_paths=None, vars=None):
         """
         :param pkg_config_paths: Optional paths to locate the *.pc files
         :param configure_dir: Absolute or relative path to the configure script
@@ -141,25 +105,20 @@ class AutoToolsBuildEnvironment(object):
             configure_dir = configure_dir.rstrip("/")
         else:
             configure_dir = "."
-        auto_build, auto_host, auto_target = None, None, None
-        if build is None or host is None or target is None:
-            arch_detected = detected_architecture() or platform.machine()
-            os_detected = platform.system()
-            flags = self._get_host_build_target_flags(arch_detected, os_detected)
-            auto_build, auto_host, auto_target = flags
+
         triplet_args = []
 
         if build is not False:  # Skipped by user
-            if build or auto_build:  # User specified value or automatic
-                triplet_args.append("--build=%s" % (build or auto_build))
+            if build or self.build:  # User specified value or automatic
+                triplet_args.append("--build=%s" % (build or self.build))
 
         if host is not False:   # Skipped by user
-            if host or auto_host:  # User specified value or automatic
-                triplet_args.append("--host=%s" % (host or auto_host))
+            if host or self.host:  # User specified value or automatic
+                triplet_args.append("--host=%s" % (host or self.host))
 
         if target is not False:  # Skipped by user
-            if target or auto_target:  # User specified value or automatic
-                triplet_args.append("--target=%s" % (target or auto_target))
+            if target or self.target:  # User specified value or automatic
+                triplet_args.append("--target=%s" % (target or self.target))
 
         if pkg_config_paths:
             pkg_env = {"PKG_CONFIG_PATH": os.pathsep.join(pkg_config_paths)}
@@ -169,8 +128,14 @@ class AutoToolsBuildEnvironment(object):
             pkg_env = {"PKG_CONFIG_PATH": self._conanfile.build_folder} \
                 if "pkg_config" in self._conanfile.generators else {}
 
+        if self._conanfile.package_folder is not None:
+            if not args:
+                args = ["--prefix=%s" % self._conanfile.package_folder.replace("\\", "/")]
+            elif not any(["--prefix=" in arg for arg in args]):
+                args.append("--prefix=%s" % self._conanfile.package_folder.replace("\\", "/"))
+
         with environment_append(pkg_env):
-            with environment_append(self.vars):
+            with environment_append(vars or self.vars):
                 configure_dir = self._adjust_path(configure_dir)
                 command = '%s/configure %s %s' % (configure_dir,
                                                   args_to_string(args), " ".join(triplet_args))
@@ -184,17 +149,20 @@ class AutoToolsBuildEnvironment(object):
             path = unix_path(path, path_flavor=self.subsystem)
         return '"%s"' % path if " " in path else path
 
-    def make(self, args="", make_program=None, target=None):
+    def make(self, args="", make_program=None, target=None, vars=None):
         if not self._conanfile.should_build:
             return
         make_program = os.getenv("CONAN_MAKE_PROGRAM") or make_program or "make"
-        with environment_append(self.vars):
+        with environment_append(vars or self.vars):
             str_args = args_to_string(args)
             cpu_count_option = ("-j%s" % cpu_count()) if "-j" not in str_args else None
             self._conanfile.run("%s" % join_arguments([make_program, target, str_args,
                                                        cpu_count_option]),
                                 win_bash=self._win_bash, subsystem=self.subsystem)
 
+    def install(self, args="", make_program=None, vars=None):
+        self.make(args=args, make_program=make_program, target="install", vars=vars)
+
     def _configure_link_flags(self):
         """Not the -L"""
         ret = copy.copy(self._deps_cpp_info.sharedlinkflags)
@@ -313,7 +281,6 @@ class AutoToolsBuildEnvironment(object):
 
     @property
     def vars(self):
-
         ld_flags, cpp_flags, libs, cxx_flags, c_flags = self._get_vars()
 
         cpp_flags = " ".join(cpp_flags) + _environ_value_prefix("CPPFLAGS")
@@ -328,7 +295,6 @@ class AutoToolsBuildEnvironment(object):
                "LDFLAGS": ldflags.strip(),
                "LIBS": libs.strip(),
                }
-
         return ret
 
 
diff --git a/conans/client/tools/oss.py b/conans/client/tools/oss.py
index 014224365..fb9398b74 100644
--- a/conans/client/tools/oss.py
+++ b/conans/client/tools/oss.py
@@ -307,6 +307,60 @@ def get_cross_building_settings(settings, self_os=None, self_arch=None):
     return build_os, build_arch, host_os, host_arch
 
 
+def get_gnu_triplet(os, arch, compiler=None):
+    """
+    Returns string with <machine>-<vendor>-<op_system> triplet (<vendor> can be omitted in practice)
+
+    :param os: os to be used to create the triplet
+    :param arch: arch to be used to create the triplet
+    :param compiler: compiler used to create the triplet (only needed fo windows)
+    """
+
+    if os == "Windows" and compiler is None:
+        raise ConanException("'compiler' parameter for 'get_gnu_triplet()' is not specified and "
+                             "needed for os=Windows")
+
+    # Calculate the arch
+    machine = {"x86": "i686" if os != "Linux" else "x86",
+                "x86_64": "x86_64",
+                "armv6": "arm",
+                "armv7": "arm",
+                "armv7s": "arm",
+                "armv7k": "arm",
+                "armv7hf": "arm",
+                "armv8": "aarch64"}.get(arch, None)
+    if machine is None:
+        raise ConanException("Unknown '%s' machine. Conan doesn't know how to "
+                                "translate it to the GNU triplet, please report at "
+                                "https://github.com/conan-io/conan/issues" % arch)
+
+    # Calculate the OS
+    if compiler == "gcc":
+        windows_op = "w64-mingw32"
+    elif compiler == "Visual Studio":
+        windows_op = "windows-msvc"
+    else:
+        windows_op = "windows"
+
+    op_system = {"Windows": windows_op,
+                 "Linux": "linux-gnu",
+                 "Darwin": "apple-darwin",
+                 "Android": "linux-android",
+                 "Macos": "apple-darwin",
+                 "iOS": "apple-darwin",
+                 "watchOS": "apple-darwin",
+                 "tvOS": "apple-darwin"}.get(os, os.lower())
+
+    if os in ("Linux", "Android"):
+        if "arm" in arch and arch != "armv8":
+            op_system += "eabi"
+
+        if arch == "armv7hf" and os == "Linux":
+            op_system += "hf"
+
+    return "%s-%s" % (machine, op_system)
+
+
 try:
     os_info = OSInfo()
 except Exception as exc:


Test patch:
diff --git a/conans/test/build_helpers/autotools_configure_test.py b/conans/test/build_helpers/autotools_configure_test.py
index 83eced2eb..f89722174 100644
--- a/conans/test/build_helpers/autotools_configure_test.py
+++ b/conans/test/build_helpers/autotools_configure_test.py
@@ -379,142 +379,14 @@ class AutoToolsConfigureTest(unittest.TestCase):
 
     def test_previous_env(self):
         settings = MockSettings({"arch": "x86",
-                                 "os": "Linux"})
+                                 "os": "Linux",
+                                 "compiler": "gcc"})
         conanfile = MockConanfile(settings)
 
         with tools.environment_append({"CPPFLAGS": "MyCppFlag"}):
             be = AutoToolsBuildEnvironment(conanfile)
             self.assertEquals(be.vars["CPPFLAGS"], "MyCppFlag")
 
-    def cross_build_flags_test(self):
-
-        def get_values(this_os, this_arch, setting_os, setting_arch, compiler=None):
-            settings = MockSettings({"arch": setting_arch,
-                                     "os": setting_os,
-                                     "compiler": compiler})
-            conanfile = MockConanfile(settings)
-            conanfile.settings = settings
-            be = AutoToolsBuildEnvironment(conanfile)
-            return be._get_host_build_target_flags(this_arch, this_os)
-
-        build, host, target = get_values("Linux", "x86_64", "Linux", "armv7hf")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "arm-linux-gnueabihf")
-
-        build, host, target = get_values("Linux", "x86", "Linux", "armv7hf")
-        self.assertEquals(build, "x86-linux-gnu")
-        self.assertEquals(host, "arm-linux-gnueabihf")
-
-        build, host, target = get_values("Linux", "x86", "Linux", "x86")
-        self.assertFalse(build)
-        self.assertFalse(host)
-        self.assertFalse(target)
-
-        build, host, target = get_values("Linux", "x86_64", "Linux", "x86_64")
-        self.assertFalse(build)
-        self.assertFalse(host)
-        self.assertFalse(target)
-
-        build, host, target = get_values("Linux", "x86_64", "Linux", "x86")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "x86-linux-gnu")
-        self.assertFalse(target)
-
-        build, host, target = get_values("Linux", "x86_64", "Windows", "x86", compiler="gcc")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "i686-w64-mingw32")
-        self.assertFalse(target)
-
-        build, host, target = get_values("Linux", "x86_64", "Windows", "x86", compiler="Visual Studio")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "i686-windows-msvc")  # Not very common but exists sometimes
-        self.assertFalse(target)
-
-        build, host, target = get_values("Linux", "x86_64", "Linux", "armv7hf")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "arm-linux-gnueabihf")
-
-        build, host, target = get_values("Linux", "x86_64", "Linux", "armv7")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "arm-linux-gnueabi")
-
-        build, host, target = get_values("Linux", "x86_64", "Linux", "armv6")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "arm-linux-gnueabi")
-
-        build, host, target = get_values("Linux", "x86_64", "Android", "x86")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "i686-linux-android")
-
-        build, host, target = get_values("Linux", "x86_64", "Android", "x86_64")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "x86_64-linux-android")
-
-        build, host, target = get_values("Linux", "x86_64", "Android", "armv7")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "arm-linux-androideabi")
-
-        build, host, target = get_values("Linux", "x86_64", "Android", "armv7hf")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "arm-linux-androideabi")
-
-        build, host, target = get_values("Linux", "x86_64", "Android", "armv8")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "aarch64-linux-android")
-
-        build, host, target = get_values("Linux", "x86_64", "Android", "armv6")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "arm-linux-androideabi")
-
-        build, host, target = get_values("Linux", "x86_64", "Windows", "x86", compiler="gcc")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "i686-w64-mingw32")
-
-        build, host, target = get_values("Linux", "x86_64", "Windows", "x86_64", compiler="gcc")
-        self.assertEquals(build, "x86_64-linux-gnu")
-        self.assertEquals(host, "x86_64-w64-mingw32")
-
-        build, host, target = get_values("Windows", "x86_64", "Windows", "x86_64")
-        self.assertFalse(build)
-        self.assertFalse(host)
-        self.assertFalse(target)
-
-        build, host, target = get_values("Windows", "x86", "Windows", "x86")
-        self.assertFalse(build)
-        self.assertFalse(host)
-        self.assertFalse(target)
-
-        build, host, target = get_values("Windows", "x86_64", "Windows", "x86", compiler="gcc")
-        self.assertEquals(build, "x86_64-w64-mingw32")
-        self.assertEquals(host, "i686-w64-mingw32")
-        self.assertFalse(target)
-
-        build, host, target = get_values("Windows", "x86_64", "Linux", "armv7hf", compiler="gcc")
-        self.assertEquals(build, "x86_64-w64-mingw32")
-        self.assertEquals(host, "arm-linux-gnueabihf")
-        self.assertFalse(target)
-
-        build, host, target = get_values("Darwin", "x86_64", "Android", "armv7hf")
-
-        self.assertEquals(build, "x86_64-apple-darwin")
-        self.assertEquals(host, "arm-linux-androideabi")
-
-        build, host, target = get_values("Darwin", "x86_64", "Macos", "x86")
-        self.assertEquals(build, "x86_64-apple-darwin")
-        self.assertEquals(host, "i686-apple-darwin")
-
-        build, host, target = get_values("Darwin", "x86_64", "iOS", "armv7")
-        self.assertEquals(build, "x86_64-apple-darwin")
-        self.assertEquals(host, "arm-apple-darwin")
-
-        build, host, target = get_values("Darwin", "x86_64", "watchOS", "armv7k")
-        self.assertEquals(build, "x86_64-apple-darwin")
-        self.assertEquals(host, "arm-apple-darwin")
-
-        build, host, target = get_values("Darwin", "x86_64", "tvOS", "armv8")
-        self.assertEquals(build, "x86_64-apple-darwin")
-        self.assertEquals(host, "aarch64-apple-darwin")
-
     def test_pkg_config_paths(self):
         if platform.system() == "Windows":
             return
@@ -552,6 +424,10 @@ class HelloConan(ConanFile):
         runner = RunnerMock()
         conanfile = MockConanfile(MockSettings({}), None, runner)
         ab = AutoToolsBuildEnvironment(conanfile)
+        self.assertFalse(ab.build)
+        self.assertFalse(ab.host)
+        self.assertFalse(ab.target)
+
         ab.configure()
         self.assertEquals(runner.command_called, "./configure  ")
 
@@ -564,13 +440,106 @@ class HelloConan(ConanFile):
         ab.configure(target="i686-apple-darwin")
         self.assertEquals(runner.command_called, "./configure  --target=i686-apple-darwin")
 
-    def test_make_targets(self):
+        conanfile = MockConanfile(MockSettings({"build_type": "Debug",
+                                                "arch": "x86_64",
+                                                "os": "Windows",
+                                                "compiler": "gcc",
+                                                "compiler.libcxx": "libstdc++"}),
+                                  None, runner)
+        ab = AutoToolsBuildEnvironment(conanfile)
+        ab.configure()
+        if platform.system() == "Windows":
+            # Not crossbuilding
+            self.assertFalse(ab.host)
+            self.assertFalse(ab.build)
+            self.assertIn("./configure", runner.command_called)
+            self.assertNotIn("--build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32",
+                             runner.command_called)
+        elif platform.system() == "Linux":
+            self.assertIn("x86_64-w64-mingw32", ab.host)
+            self.assertIn("x86_64-linux-gnu", ab.build)
+            self.assertIn("./configure  --build=x86_64-linux-gnu --host=x86_64-w64-mingw32",
+                          runner.command_called)
+        else:
+            self.assertIn("x86_64-w64-mingw32", ab.host)
+            self.assertIn("x86_64-apple-darwin", ab.build)
+            self.assertIn("./configure  --build=x86_64-apple-darwin --host=x86_64-w64-mingw32",
+                          runner.command_called)
+
+        ab.configure(build="fake_build_triplet", host="fake_host_triplet")
+        self.assertIn("./configure  --build=fake_build_triplet --host=fake_host_triplet",
+                      runner.command_called)
+
+        ab.build = "superfake_build_triplet"
+        ab.host = "superfake_host_triplet"
+        ab.configure()
+        self.assertIn("./configure  --build=superfake_build_triplet --host=superfake_host_triplet",
+                      runner.command_called)
+
+    def test_make_targets_install(self):
         runner = RunnerMock()
         conanfile = MockConanfile(MockSettings({}), None, runner)
-        
+
         ab = AutoToolsBuildEnvironment(conanfile)
         ab.configure()
-        
+
         ab.make(target="install")
-        self.assertEquals(runner.command_called,"make install -j%s" % cpu_count())        
+        self.assertEquals(runner.command_called, "make install -j%s" % cpu_count())
+        ab.install()
+        self.assertEquals(runner.command_called, "make install -j%s" % cpu_count())
+
+    def autotools_prefix_test(self):
+        runner = RunnerMock()
+        conanfile = MockConanfile(MockSettings({}), None, runner)
+        # Package folder is not defined
+        ab = AutoToolsBuildEnvironment(conanfile)
+        ab.configure()
+        self.assertNotIn("--prefix", runner.command_called)
+        # package folder defined
+        conanfile.package_folder = "/package_folder"
+        ab.configure()
+        if platform.system() == "Windows":
+            self.assertIn("./configure --prefix=/package_folder", runner.command_called)
+        else:
+            self.assertIn("./configure '--prefix=/package_folder'", runner.command_called)
+        # --prefix already used in args
+        ab.configure(args=["--prefix=/my_package_folder"])
+        if platform.system() == "Windows":
+            self.assertIn("./configure --prefix=/my_package_folder", runner.command_called)
+            self.assertNotIn("--prefix=/package_folder", runner.command_called)
+        else:
+            self.assertIn("./configure '--prefix=/my_package_folder'", runner.command_called)
+            self.assertNotIn("'--prefix=/package_folder'", runner.command_called)
+
+    def autotools_configure_vars_test(self):
+        from mock import patch
+
+        runner = RunnerMock()
+        settings = MockSettings({"build_type": "Debug",
+                                 "arch": "x86_64",
+                                 "compiler": "gcc",
+                                 "compiler.libcxx": "libstdc++"})
+        conanfile = MockConanfile(settings, None, runner)
+        conanfile.settings = settings
+        self._set_deps_info(conanfile)
+
+        def custom_configure(obj, configure_dir=None, args=None, build=None, host=None, target=None,
+                             pkg_config_paths=None, vars=None):  # @UnusedVariable
+            self.assertNotEqual(obj.vars, vars)
+            return vars or obj.vars
+
+        with patch.object(AutoToolsBuildEnvironment, 'configure', new=custom_configure):
+            be = AutoToolsBuildEnvironment(conanfile)
+
+            # Get vars and modify them
+            my_vars = be.vars
+            my_vars["fake_var"] = "fake"
+            my_vars["super_fake_var"] = "fakefake"
+
+            # TEST with default vars
+            mocked_result = be.configure()
+            self.assertEqual(mocked_result, be.vars)
 
+            # TEST with custom vars
+            mocked_result = be.configure(vars=my_vars)
+            self.assertEqual(mocked_result, my_vars)
diff --git a/conans/test/util/tools_test.py b/conans/test/util/tools_test.py
index 78da180b2..f8bc63a4b 100644
--- a/conans/test/util/tools_test.py
+++ b/conans/test/util/tools_test.py
@@ -685,6 +685,126 @@ class MyConan(ConanFile):
         tools.download("https://httpbin.org/basic-auth/user/passwd", dest,
                        headers={"Authorization": "Basic dXNlcjpwYXNzd2Q="}, overwrite=True)
 
+    def get_gnu_triplet_test(self):
+        def get_values(this_os, this_arch, setting_os, setting_arch, compiler=None):
+            build = tools.get_gnu_triplet(this_os, this_arch, compiler)
+            host = tools.get_gnu_triplet(setting_os, setting_arch, compiler)
+            return build, host
+
+        build, host = get_values("Linux", "x86_64", "Linux", "armv7hf")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "arm-linux-gnueabihf")
+
+        build, host = get_values("Linux", "x86", "Linux", "armv7hf")
+        self.assertEquals(build, "x86-linux-gnu")
+        self.assertEquals(host, "arm-linux-gnueabihf")
+
+        build, host = get_values("Linux", "x86_64", "Linux", "x86")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "x86-linux-gnu")
+
+        build, host = get_values("Linux", "x86_64", "Windows", "x86", compiler="gcc")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "i686-w64-mingw32")
+
+        build, host = get_values("Linux", "x86_64", "Windows", "x86", compiler="Visual Studio")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "i686-windows-msvc")  # Not very common but exists sometimes
+
+        build, host = get_values("Linux", "x86_64", "Linux", "armv7hf")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "arm-linux-gnueabihf")
+
+        build, host = get_values("Linux", "x86_64", "Linux", "armv7")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "arm-linux-gnueabi")
+
+        build, host = get_values("Linux", "x86_64", "Linux", "armv6")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "arm-linux-gnueabi")
+
+        build, host = get_values("Linux", "x86_64", "Android", "x86")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "i686-linux-android")
+
+        build, host = get_values("Linux", "x86_64", "Android", "x86_64")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "x86_64-linux-android")
+
+        build, host = get_values("Linux", "x86_64", "Android", "armv7")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "arm-linux-androideabi")
+
+        build, host = get_values("Linux", "x86_64", "Android", "armv7hf")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "arm-linux-androideabi")
+
+        build, host = get_values("Linux", "x86_64", "Android", "armv8")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "aarch64-linux-android")
+
+        build, host = get_values("Linux", "x86_64", "Android", "armv6")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "arm-linux-androideabi")
+
+        build, host = get_values("Linux", "x86_64", "Windows", "x86", compiler="gcc")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "i686-w64-mingw32")
+
+        build, host = get_values("Linux", "x86_64", "Windows", "x86_64", compiler="gcc")
+        self.assertEquals(build, "x86_64-linux-gnu")
+        self.assertEquals(host, "x86_64-w64-mingw32")
+
+        build, host = get_values("Windows", "x86_64", "Windows", "x86", compiler="gcc")
+        self.assertEquals(build, "x86_64-w64-mingw32")
+        self.assertEquals(host, "i686-w64-mingw32")
+
+        build, host = get_values("Windows", "x86_64", "Linux", "armv7hf", compiler="gcc")
+        self.assertEquals(build, "x86_64-w64-mingw32")
+        self.assertEquals(host, "arm-linux-gnueabihf")
+
+        build, host = get_values("Darwin", "x86_64", "Android", "armv7hf")
+        self.assertEquals(build, "x86_64-apple-darwin")
+        self.assertEquals(host, "arm-linux-androideabi")
+
+        build, host = get_values("Darwin", "x86_64", "Macos", "x86")
+        self.assertEquals(build, "x86_64-apple-darwin")
+        self.assertEquals(host, "i686-apple-darwin")
+
+        build, host = get_values("Darwin", "x86_64", "iOS", "armv7")
+        self.assertEquals(build, "x86_64-apple-darwin")
+        self.assertEquals(host, "arm-apple-darwin")
+
+        build, host = get_values("Darwin", "x86_64", "watchOS", "armv7k")
+        self.assertEquals(build, "x86_64-apple-darwin")
+        self.assertEquals(host, "arm-apple-darwin")
+
+        build, host = get_values("Darwin", "x86_64", "tvOS", "armv8")
+        self.assertEquals(build, "x86_64-apple-darwin")
+        self.assertEquals(host, "aarch64-apple-darwin")
+
+        for os in ["Windows", "Linux"]:
+            for arch in ["x86_64", "x86"]:
+                triplet = tools.get_gnu_triplet(os, arch, "gcc")
+
+                output = ""
+                if arch == "x86_64":
+                    output += "x86_64"
+                else:
+                    output += "i686" if os != "Linux" else "x86"
+
+                output += "-"
+                if os == "Windows":
+                    output += "w64-mingw32"
+                else:
+                    output += "linux-gnu"
+
+                self.assertIn(output, triplet)
+
+        # Compiler not specified for os="Windows"
+        with self.assertRaises(ConanException):
+            tools.get_gnu_triplet("Windows", "x86")
+
     def detect_windows_subsystem_test(self):
         # Dont raise test
         result = tools.os_info.detect_windows_subsystem()
diff --git a/conans/test/utils/conanfile.py b/conans/test/utils/conanfile.py
index aa42e7c3e..409d10cb7 100644
--- a/conans/test/utils/conanfile.py
+++ b/conans/test/utils/conanfile.py
@@ -41,6 +41,8 @@ class MockConanfile(object):
         self.should_build = True
         self.should_install = True
 
+        self.package_folder = None
+
     def run(self, *args, **kwargs):
         if self.runner:
             kwargs["output"] = None