Repository: conan-io/conan
Pull request: Feature/autotools new improvements
Changelog: Feature: Improved the new `AutotoolsToolchain`, `AutotoolsDeps` and `Autotools` build helper.
Docs: https://github.com/conan-io/docs/pull/2135

Closes https://github.com/conan-io/conan/issues/9069 

Problem statement:
[feature] Keep modernizing and testing the new ``conan.tools.gnu`` Autotools integration
It is necessary to keep pushing the new Autotools integration:

- Migrate helpers like ``cppstd_flag_new`` that still live in the old context. 
- Modernize them: using always 2 profiles, no auto-detection at all (for example the one in ``_detected_os()`` in ``get_cross_building()``
- Keep implementing TODOS like:
```python
    def _rpaths_link(self):
        # TODO: Not implemented yet
        pass

    # TODO: Apple: tools.apple_deployment_target_flag,
    # TODO:  tools.XCRun(self._conanfile.settings).sdk_path
    # TODO: "-arch", tools.to_apple_arch(self._arch)
```
- More comprehensive testing coverage of features.
- Check configurability and extensitibility of provided tools is good, or check alternatives.
- Usage of new cpp info

Hints from issue discussion:

Commit message: Fix win test

Patch to review:
diff --git a/conan/tools/apple/__init__.py b/conan/tools/apple/__init__.py
new file mode 100644
index 00000000000..8c89798b32b
--- /dev/null
+++ b/conan/tools/apple/__init__.py
@@ -0,0 +1,7 @@
+# Keep everything private until we review what is really needed and refactor passing "conanfile"
+# from conan.tools.apple.apple import XCRun
+# from conan.tools.apple.apple import apple_dot_clean
+# from conan.tools.apple.apple import is_apple_os
+# from conan.tools.apple.apple import apple_sdk_name
+# from conan.tools.apple.apple import apple_deployment_target_flag
+# from conan.tools.apple.apple import to_apple_arch
diff --git a/conan/tools/apple/apple.py b/conan/tools/apple/apple.py
new file mode 100644
index 00000000000..e53a1dbf825
--- /dev/null
+++ b/conan/tools/apple/apple.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os
+
+from conans.util.runners import check_output_runner
+
+
+def is_apple_os(os_):
+    """returns True if OS is Apple one (Macos, iOS, watchOS or tvOS"""
+    return str(os_) in ['Macos', 'iOS', 'watchOS', 'tvOS']
+
+
+def to_apple_arch(arch):
+    """converts conan-style architecture into Apple-style arch"""
+    return {'x86': 'i386',
+            'x86_64': 'x86_64',
+            'armv7': 'armv7',
+            'armv8': 'arm64',
+            'armv8_32': 'arm64_32',
+            'armv8.3': 'arm64e',
+            'armv7s': 'armv7s',
+            'armv7k': 'armv7k'}.get(str(arch))
+
+
+def _guess_apple_sdk_name(os_, arch):
+    if str(arch).startswith('x86'):
+        return {'Macos': 'macosx',
+                'iOS': 'iphonesimulator',
+                'watchOS': 'watchsimulator',
+                'tvOS': 'appletvsimulator'}.get(str(os_))
+    else:
+        return {'Macos': 'macosx',
+                'iOS': 'iphoneos',
+                'watchOS': 'watchos',
+                'tvOS': 'appletvos'}.get(str(os_), None)
+
+
+def apple_sdk_name(settings):
+    """returns proper SDK name suitable for OS and architecture
+    we're building for (considering simulators)"""
+    arch = settings.get_safe('arch')
+    os_ = settings.get_safe('os')
+    os_sdk = settings.get_safe('os.sdk')
+    return os_sdk or _guess_apple_sdk_name(os_, arch)
+
+
+def apple_min_version_flag(conanfile):
+    """compiler flag name which controls deployment target"""
+    os_version = conanfile.settings.get_safe("os.version")
+    if not os_version:
+        return ''
+
+    os_ = conanfile.settings.get_safe("os")
+    os_sdk = conanfile.settings.get_safe("os.sdk")
+    os_subsystem = conanfile.settings.get_safe("os.subsystem")
+    arch = conanfile.settings.get_safe("arch")
+
+    if not os_version:
+        return ''
+    os_sdk = os_sdk if os_sdk else _guess_apple_sdk_name(os_, arch)
+    flag = {'macosx': '-mmacosx-version-min',
+            'iphoneos': '-mios-version-min',
+            'iphonesimulator': '-mios-simulator-version-min',
+            'watchos': '-mwatchos-version-min',
+            'watchsimulator': '-mwatchos-simulator-version-min',
+            'appletvos': '-mtvos-version-min',
+            'appletvsimulator': '-mtvos-simulator-version-min'}.get(str(os_sdk))
+    if os_subsystem == 'catalyst':
+        # especial case, despite Catalyst is macOS, it requires an iOS version argument
+        flag = '-mios-version-min'
+    if not flag:
+        return ''
+    return "%s=%s" % (flag, os_version)
+
+
+def apple_sdk_path(conanfile):
+    sdk_path = conanfile.conf["tools.apple:sdk_path"]
+    if not sdk_path:
+        sdk_path = XCRun(conanfile.settings).sdk_path
+    return sdk_path
+
+
+class XCRun(object):
+
+    def __init__(self, settings, sdk=None):
+        """sdk=False will skip the flag
+           sdk=None will try to adjust it automatically"""
+        if sdk is None and settings:
+            sdk = apple_sdk_name(settings)
+        self.sdk = sdk
+
+    def _invoke(self, args):
+        def cmd_output(cmd):
+            return check_output_runner(cmd).strip()
+
+        command = ['xcrun']
+        if self.sdk:
+            command.extend(['-sdk', self.sdk])
+        command.extend(args)
+        return cmd_output(command)
+
+    def find(self, tool):
+        """find SDK tools (e.g. clang, ar, ranlib, lipo, codesign, etc.)"""
+        return self._invoke(['--find', tool])
+
+    @property
+    def sdk_path(self):
+        """obtain sdk path (aka apple sysroot or -isysroot"""
+        return self._invoke(['--show-sdk-path'])
+
+    @property
+    def sdk_version(self):
+        """obtain sdk version"""
+        return self._invoke(['--show-sdk-version'])
+
+    @property
+    def sdk_platform_path(self):
+        """obtain sdk platform path"""
+        return self._invoke(['--show-sdk-platform-path'])
+
+    @property
+    def sdk_platform_version(self):
+        """obtain sdk platform version"""
+        return self._invoke(['--show-sdk-platform-version'])
+
+    @property
+    def cc(self):
+        """path to C compiler (CC)"""
+        return self.find('clang')
+
+    @property
+    def cxx(self):
+        """path to C++ compiler (CXX)"""
+        return self.find('clang++')
+
+    @property
+    def ar(self):
+        """path to archiver (AR)"""
+        return self.find('ar')
+
+    @property
+    def ranlib(self):
+        """path to archive indexer (RANLIB)"""
+        return self.find('ranlib')
+
+    @property
+    def strip(self):
+        """path to symbol removal utility (STRIP)"""
+        return self.find('strip')
+
+    @property
+    def libtool(self):
+        """path to libtool"""
+        return self.find('libtool')
diff --git a/conan/tools/cross_building.py b/conan/tools/cross_building.py
new file mode 100644
index 00000000000..86660952d5f
--- /dev/null
+++ b/conan/tools/cross_building.py
@@ -0,0 +1,29 @@
+
+
+def cross_building(conanfile):
+    ret = get_cross_building_settings(conanfile)
+
+    build_os, build_arch, host_os, host_arch = ret
+
+    if host_os is not None and (build_os != host_os):
+        return True
+    if host_arch is not None and (build_arch != host_arch):
+        return True
+
+    return False
+
+
+def get_cross_building_settings(conanfile):
+    os_host = conanfile.settings.get_safe("os")
+    arch_host = conanfile.settings.get_safe("arch")
+
+    if hasattr(conanfile, 'settings_build'):
+        return (conanfile.settings_build.get_safe('os'),
+                conanfile.settings_build.get_safe('arch'),
+                os_host,
+                arch_host)
+    else:
+        return (os_host,
+                arch_host,
+                os_host,
+                arch_host)
diff --git a/conan/tools/env/environment.py b/conan/tools/env/environment.py
index 76cd69d3825..f91acf77838 100644
--- a/conan/tools/env/environment.py
+++ b/conan/tools/env/environment.py
@@ -1,6 +1,7 @@
 import fnmatch
 import os
 import textwrap
+import platform
 from collections import OrderedDict
 from contextlib import contextmanager
 
@@ -27,9 +28,9 @@ def environment_wrap_command(filename, cmd, cwd=None):
     for f in filenames:
         full_path = os.path.join(cwd, f) if cwd else f
         if os.path.isfile("{}.bat".format(full_path)):
-            bats.append("{}.bat".format(f))
+            bats.append("{}.bat".format(full_path))
         elif os.path.isfile("{}.sh".format(full_path)):
-            shs.append("{}.sh".format(f))
+            shs.append("{}.sh".format(full_path))
     if bats and shs:
         raise ConanException("Cannot wrap command with different envs, {} - {}".format(bats, shs))
 
@@ -37,7 +38,8 @@ def environment_wrap_command(filename, cmd, cwd=None):
         command = " && ".join('"{}"'.format(b) for b in bats)
         return "{} && {}".format(command, cmd)
     elif shs:
-        command = " && ".join(". ./{}".format(f) for f in shs)
+        curdir = "./" if cwd is None else ""
+        command = " && ".join('. "{}{}"'.format(curdir, f) for f in shs)
         return "{} && {}".format(command, cmd)
     else:
         return cmd
@@ -197,6 +199,13 @@ def save_sh(self, filename, generate_deactivate=False, pathsep=os.pathsep):
         content = "\n".join(result)
         save(filename, content)
 
+    def save_script(self, name):
+        # FIXME: using platform is not ideal but settings might be incomplete
+        if platform.system() == "Windows":
+            self.save_bat("{}.bat".format(name))
+        else:
+            self.save_sh("{}.sh".format(name))
+
     def compose(self, other):
         """
         self has precedence, the "other" will add/append if possible and not conflicting, but
diff --git a/conan/tools/files/__init__.py b/conan/tools/files/__init__.py
index 3a557c172b9..e26cf55064e 100644
--- a/conan/tools/files/__init__.py
+++ b/conan/tools/files/__init__.py
@@ -1,2 +1,3 @@
-from conan.tools.files.files import load, save, mkdir, ftp_download, download, get, rename
+from conan.tools.files.files import load, save, mkdir, ftp_download, download, get, rename, \
+    load_build_json, save_build_json
 from conan.tools.files.patches import patch, apply_conandata_patches
diff --git a/conan/tools/files/files.py b/conan/tools/files/files.py
index a1543bbb506..30ea7565100 100644
--- a/conan/tools/files/files.py
+++ b/conan/tools/files/files.py
@@ -1,8 +1,10 @@
 import errno
+import json
 import os
 import platform
 import subprocess
 
+from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
 from conans.client.downloaders.download import run_downloader
 from conans.client.tools.files import unzip, which
 from conans.errors import ConanException
@@ -181,3 +183,15 @@ def rename(conanfile, src, dst):
             os.rename(src, dst)
         except Exception as err:
             raise ConanException("rename {} to {} failed: {}".format(src, dst, err))
+
+
+def load_build_json(conanfile):
+    path = os.path.join(conanfile.generators_folder, CONAN_TOOLCHAIN_ARGS_FILE)
+    contents = load(conanfile, path)
+    data = json.loads(contents)
+    return data
+
+
+def save_build_json(conanfile, contents):
+    path = os.path.join(conanfile.generators_folder, CONAN_TOOLCHAIN_ARGS_FILE)
+    save(conanfile, path, json.dumps(contents))
diff --git a/conan/tools/gnu/__init__.py b/conan/tools/gnu/__init__.py
index 8b5d9a8b57a..0e60df9ed31 100644
--- a/conan/tools/gnu/__init__.py
+++ b/conan/tools/gnu/__init__.py
@@ -1,4 +1,3 @@
 from conan.tools.gnu.autotoolstoolchain import AutotoolsToolchain
 from conan.tools.gnu.autotoolsdeps import AutotoolsDeps
 from conan.tools.gnu.autotools import Autotools
-from conan.tools.gnu.autotoolsgen import AutotoolsGen
diff --git a/conan/tools/gnu/autotools.py b/conan/tools/gnu/autotools.py
index 93300936075..322fbce3d68 100644
--- a/conan/tools/gnu/autotools.py
+++ b/conan/tools/gnu/autotools.py
@@ -3,69 +3,50 @@
 
 from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
 from conan.tools._compilers import use_win_mingw
+from conan.tools.gnu.make import make_jobs_cmd_line_arg
+from conans.client.build import join_arguments
 from conans.util.files import load
 
 
 class Autotools(object):
 
     def __init__(self, conanfile):
-        """
-        FIXME: include_rpath_flags CONAN 2.0 to default True? Could break many packages in center
-        """
         self._conanfile = conanfile
-        self._win_bash = False
-        self._include_rpath_flags = False
-        self._os = conanfile.settings.get_safe("os")
-        self._os_version = conanfile.settings.get_safe("os.version")
-        self._os_sdk = conanfile.settings.get_safe("os.sdk")
-        self._os_subsystem = conanfile.settings.get_safe("os.subsystem")
-        self._arch = conanfile.settings.get_safe("arch")
-        self._build_type = conanfile.settings.get_safe("build_type")
-        self._compiler = conanfile.settings.get_safe("compiler")
-        self._compiler_version = conanfile.settings.get_safe("compiler.version")
-        self._build = None
-        self._host = None
-        self._target = None
-        if os.path.isfile(CONAN_TOOLCHAIN_ARGS_FILE):
-            args = json.loads(load(CONAN_TOOLCHAIN_ARGS_FILE))
-            self._build = args["build"] if "build" in args else None
-            self._host = args["host"] if "host" in args else None
-            self._target = args["target"] if "target" in args else None
+        self.environment_files = ["conanbuildenv", "conanautotoolstoolchain", "conanautotoolsdeps",
+                                  "conanvcvars"]
+
+        args_path = os.path.join(conanfile.generators_folder, CONAN_TOOLCHAIN_ARGS_FILE)
+        if os.path.isfile(args_path):
+            args = json.loads(load(args_path))
+            self._configure_args = args.get("configure_args")
+            self._make_args = args.get("make_args")
 
     def configure(self):
         """
         http://jingfenghanmax.blogspot.com.es/2010/09/configure-with-host-target-and-build.html
         https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html
         """
+        # FIXME: Conan 2.0 Are we keeping the "should_XXX" properties???
         if not self._conanfile.should_configure:
             return
-        configure_dir = "."
-
-        # TODO: Management of PKG_CONFIG_PATH
-        # TODO: Implement management of --prefix, bindir, sbindir, libexecdir, libdir, includedir
 
-        cmd = "%s/configure" % configure_dir
-        cmd += ' --host=%s' % self._host if self._host else ''
-        cmd += ' --build=%s' % self._build if self._build else ''
-        cmd += ' --target=%s' % self._target if self._target else ''
+        cmd = "{}/configure {}".format(self._conanfile.source_folder, self._configure_args)
         self._conanfile.output.info("Calling:\n > %s" % cmd)
-        self._conanfile.run(cmd)
-
-    def make(self):
-        """if not self._build_type:
-            raise ConanException("build_type setting should be defined.")
-        with environment_append(vars or self.vars):
-            str_args = args_to_string(args)
-            cpu_count_option = (("-j%s" % cpu_count(output=self._conanfile.output))
-                                if ("-j" not in str_args and "nmake" not in make_program.lower())
-                                else None)
-            self._conanfile.run("%s" % join_arguments([make_program, target, str_args,
-                                                       cpu_count_option]),
-                                win_bash=self._win_bash, subsystem=self.subsystem)"""
+        self._conanfile.run(cmd, env=self.environment_files)
 
+    def make(self, target=None):
         make_program = self._conanfile.conf["tools.gnu:make_program"]
         if make_program is None:
             make_program = "mingw32-make" if use_win_mingw(self._conanfile) else "make"
-        # Need to activate the buildenv if existing
-        command = make_program
-        self._conanfile.run(command)
+
+        str_args = self._make_args
+        jobs = ""
+        if "-j" not in str_args and "nmake" not in make_program.lower():
+            jobs = make_jobs_cmd_line_arg(self._conanfile) or ""
+        command = join_arguments([make_program, target, str_args, jobs])
+        self._conanfile.run(command, env=self.environment_files)
+
+    def install(self):
+        if not self._conanfile.should_install:
+            return
+        self.make(target="install")
diff --git a/conan/tools/gnu/autotoolsdeps.py b/conan/tools/gnu/autotoolsdeps.py
index 5b53d195d0b..4c9e25923ee 100644
--- a/conan/tools/gnu/autotoolsdeps.py
+++ b/conan/tools/gnu/autotoolsdeps.py
@@ -1,5 +1,6 @@
 from conan.tools.env import Environment
-from conans.model.build_info import DepCppInfo
+from conan.tools.gnu.autotoolsdeps_flags import AutoToolsDepsFlags
+from conans.model.new_build_info import NewCppInfo
 
 
 class AutotoolsDeps:
@@ -7,85 +8,56 @@ def __init__(self, conanfile):
         # Set the generic objects before mapping to env vars to let the user
         # alter some value
         self._conanfile = conanfile
-
-        self.libs = []
-        self.system_libs = []
-        self.include_paths = []
-        self.lib_paths = []
-        self.defines = []
-        self.cflags = []
-        self.cxxflags = []
-        self.sharedlinkflags = []
-        self.exelinkflags = []
-        self.frameworks = []
-        self.framework_paths = []
-        self.sysroot = None
-
-        def merge_lists(seq1, seq2):
-            return [s for s in seq1 if s not in seq2] + seq2
-
-        def merge(dep):
-            dep_cpp_info = DepCppInfo(dep.cpp_info)  # To deal with components
-            self.system_libs = merge_lists(self.system_libs, dep_cpp_info.system_libs)
-            self.include_paths = merge_lists(self.include_paths, dep_cpp_info.include_paths)
-            self.lib_paths = merge_lists(self.lib_paths, dep_cpp_info.lib_paths)
-            self.framework_paths = merge_lists(self.framework_paths, dep_cpp_info.framework_paths)
-            self.libs = merge_lists(self.libs, dep_cpp_info.libs)
-            self.frameworks = merge_lists(self.frameworks, dep_cpp_info.frameworks)
-
-            # Note these are in reverse order
-            self.defines = merge_lists(dep_cpp_info.defines, self.defines)
-            self.cxxflags = merge_lists(dep_cpp_info.cxxflags, self.cxxflags)
-            self.cflags = merge_lists(dep_cpp_info.cflags, self.cflags)
-            self.sharedlinkflags = merge_lists(dep_cpp_info.sharedlinkflags, self.sharedlinkflags)
-            self.exelinkflags = merge_lists(dep_cpp_info.exelinkflags, self.exelinkflags)
-
-            if not self.sysroot:
-                self.sysroot = dep_cpp_info.sysroot
-
-        for d in self._conanfile.dependencies.host.values():
-            merge(d)
+        self._cpp_info = None
+
+    @property
+    def cpp_info(self):
+        if self._cpp_info is None:
+            self._cpp_info = NewCppInfo()
+            for dep in self._conanfile.dependencies.host.values():
+                dep_cppinfo = dep.new_cpp_info.copy()
+                dep_cppinfo.set_relative_base_folder(dep.package_folder)
+                # In case we have components, aggregate them, we do not support isolated
+                # "targets" with autotools
+                dep_cppinfo.aggregate_components()
+                self._cpp_info.merge(dep_cppinfo)
+        return self._cpp_info
 
     def environment(self):
+        flags = AutoToolsDepsFlags(self._conanfile, self.cpp_info)
+
         # cpp_flags
         cpp_flags = []
-        include_paths = ['-I"%s"' % p for p in self.include_paths]
-        cpp_flags.extend(include_paths)
-        cpp_flags.extend(["-D%s" % define for define in self.defines])
-
-        # Libs
-        libs = ["-l%s" % library for library in self.libs]
+        cpp_flags.extend(flags.include_paths)
+        cpp_flags.extend(flags.defines)
 
         # Ldflags
-        # TODO: Discuss, should the helper filter frameworks based on compiler?
-        frameworks = ["-framework %s" % framework for framework in self.frameworks]
-        frameworks_paths = ["-F %s" % framework_path for framework_path in self.framework_paths]
-        ldflags = self.sharedlinkflags
-        ldflags.extend(self.exelinkflags)
-        ldflags.extend(frameworks)
-        ldflags.extend(frameworks_paths)
-        lib_paths = ['-L"%s"' % p for p in self.lib_paths]
-        ldflags.extend(lib_paths)
+        ldflags = flags.sharedlinkflags
+        ldflags.extend(flags.exelinkflags)
+        ldflags.extend(flags.frameworks)
+        ldflags.extend(flags.framework_paths)
+        ldflags.extend(flags.lib_paths)
+        # FIXME: Previously we had an argument "include_rpath_flags" defaulted to False
+        ldflags.extend(flags.rpath_flags)
 
         # cflags
-        cflags = self.cflags
-        cxxflags = self.cxxflags
+        cflags = flags.cflags
+        cxxflags = flags.cxxflags
 
-        if self.sysroot:
-            srf = '--sysroot={}'.format(self.sysroot)
+        srf = flags.sysroot
+        if srf:
             cflags.append(srf)
             cxxflags.append(srf)
             ldflags.append(srf)
 
         env = Environment()
         env.append("CPPFLAGS", cpp_flags)
-        env.append("LIBS", libs)
+        env.append("LIBS", flags.libs)
         env.append("LDFLAGS", ldflags)
         env.append("CXXFLAGS", cxxflags)
         env.append("CFLAGS", cflags)
         return env
 
-    def generate(self):
-        env = self.environment()
-        env.save_sh("conanautotoolsdeps.sh")
-        env.save_bat("conanautotoolsdeps.bat")
+    def generate(self, env=None):
+        env = env or self.environment()
+        env.save_script("conanautotoolsdeps")
diff --git a/conan/tools/gnu/autotoolsdeps_flags.py b/conan/tools/gnu/autotoolsdeps_flags.py
new file mode 100644
index 00000000000..8f76374fa7e
--- /dev/null
+++ b/conan/tools/gnu/autotoolsdeps_flags.py
@@ -0,0 +1,124 @@
+from conans.model.new_build_info import NewCppInfo
+
+
+class AutoToolsDepsFlags(object):
+
+    def __init__(self, conanfile, cpp_info):
+        self._conanfile = conanfile
+
+        # From cppinfo, calculated flags
+        self.include_paths = self._format_include_paths(cpp_info.includedirs)
+        self.lib_paths = self._format_library_paths(cpp_info.libdirs)
+        self.rpath_flags = self._rpath_flags(cpp_info.libdirs)
+        self.defines = self._format_defines(cpp_info.defines)
+        self.libs = self._format_libraries(cpp_info.libs)
+        self.frameworks = self._format_frameworks(cpp_info.frameworks)
+        self.framework_paths = self._format_framework_paths(cpp_info.frameworkdirs)
+        self.sysroot = self._sysroot_flag(cpp_info.sysroot)
+
+        # Direct flags
+        self.cxxflags = cpp_info.cxxflags or []
+        self.cflags = cpp_info.cflags or []
+        self.sharedlinkflags = cpp_info.sharedlinkflags or []
+        self.exelinkflags = cpp_info.exelinkflags or []
+        self.system_libs = cpp_info.system_libs or []
+
+        # Not used?
+        # self.bin_paths
+        # self.build_paths
+        # self.src_paths
+
+    _GCC_LIKE = ['clang', 'apple-clang', 'gcc']
+
+    def _rpath_flags(self, lib_paths):
+        if not lib_paths:
+            return []
+        if self._base_compiler in self._GCC_LIKE:
+            rpath_separator = ","
+            return ['-Wl,-rpath%s"%s"' % (rpath_separator, x.replace("\\", "/"))
+                    for x in lib_paths if x]
+        return []
+
+    def _format_defines(self, defines):
+        return ["-D%s" % define for define in defines] if defines else []
+
+    def _format_frameworks(self, frameworks):
+        """
+        returns an appropriate compiler flags to link with Apple Frameworks
+        or an empty array, if Apple Frameworks aren't supported by the given compiler
+        """
+        if not frameworks:
+            return []
+        # FIXME: Missing support for subsystems
+        compiler = self._conanfile.settings.get_safe("compiler")
+        compiler_base = self._conanfile.settings.get_safe("compiler.base")
+        if (str(compiler) not in self._GCC_LIKE) and (str(compiler_base) not in self._GCC_LIKE):
+            return []
+        return ["-framework %s" % framework for framework in frameworks]
+
+    def _format_framework_paths(self, framework_paths):
+        """
+        returns an appropriate compiler flags to specify Apple Frameworks search paths
+        or an empty array, if Apple Frameworks aren't supported by the given compiler
+        """
+        if not framework_paths:
+            return []
+        compiler = self._conanfile.settings.get_safe("compiler")
+        compiler_base = self._conanfile.settings.get_safe("compiler.base")
+        if (str(compiler) not in self._GCC_LIKE) and (str(compiler_base) not in self._GCC_LIKE):
+            return []
+        return ["-F %s" % self._adjust_path(framework_path) for framework_path in
+                framework_paths]
+
+    def _sysroot_flag(self, sysroot):
+        # FIXME: Missing support for subsystems
+        if self._base_compiler != 'Visual Studio' and sysroot:
+            sysroot = self._adjust_path(sysroot)
+            return '--sysroot=%s' % sysroot
+        return ""
+
+    def _format_include_paths(self, include_paths):
+        if not include_paths:
+            return []
+        # FIXME: Missing support for subsystems
+        return ["-I%s" % (self._adjust_path(include_path))
+                for include_path in include_paths if include_path]
+
+    def _format_library_paths(self, library_paths):
+        if not library_paths:
+            return []
+        # FIXME: Missing support for subsystems
+        pattern = "-LIBPATH:%s" if self._base_compiler == 'Visual Studio' else "-L%s"
+        return [pattern % self._adjust_path(library_path)
+                for library_path in library_paths if library_path]
+
+    def _format_libraries(self, libraries):
+        if not libraries:
+            return []
+
+        result = []
+        compiler = self._conanfile.settings.get_safe("compiler")
+        compiler_base = self._conanfile.settings.get_safe("compiler.base")
+        for library in libraries:
+            if str(compiler) == 'Visual Studio' or str(compiler_base) == 'Visual Studio':
+                if not library.endswith(".lib"):
+                    library += ".lib"
+                result.append(library)
+            else:
+                result.append("-l%s" % library)
+        return result
+
+    def _adjust_path(self, path):
+        # FIXME: Missing support for subsystems
+        if self._base_compiler == 'Visual Studio':
+            path = path.replace('/', '\\')
+        else:
+            path = path.replace('\\', '/')
+        # if win_bash:
+        #    path = unix_path(path, subsystem)
+        return '"%s"' % path if ' ' in path else path
+
+    @property
+    def _base_compiler(self):
+        return str(self._conanfile.settings.get_safe("compiler.base") or
+                   self._conanfile.settings.get_safe("compiler"))
diff --git a/conan/tools/gnu/autotoolsgen.py b/conan/tools/gnu/autotoolsgen.py
deleted file mode 100644
index ef3d459c443..00000000000
--- a/conan/tools/gnu/autotoolsgen.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import platform
-
-from conan.tools.env import VirtualEnv
-from conan.tools.gnu import AutotoolsToolchain, AutotoolsDeps
-
-
-class AutotoolsGen:
-    def __init__(self, conanfile):
-        self.toolchain = AutotoolsToolchain(conanfile)
-        self.deps = AutotoolsDeps(conanfile)
-        self.env = VirtualEnv(conanfile)
-
-    def build_environment(self):
-        envtoolchain = self.toolchain.environment()
-        envdeps = self.deps.environment()
-        build_env = self.env.build_environment()
-        build_env.compose(envtoolchain)
-        build_env.compose(envdeps)
-        return build_env
-
-    def run_environment(self):
-        run_env = self.env.run_environment()
-        return run_env
-
-    def generate(self):
-        build_env = self.build_environment()
-        run_env = self.run_environment()
-        # FIXME: Use settings, not platform Not always defined :(
-        # os_ = self._conanfile.settings_build.get_safe("os")
-        if platform.system() == "Windows":
-            build_env.save_bat("conanbuildenv.bat")
-            run_env.save_bat("conanrunenv.bat")
-        else:
-            build_env.save_sh("conanbuildenv.sh")
-            run_env.save_sh("conanrunenv.sh")
-
-        self.toolchain.generate_args()
diff --git a/conan/tools/gnu/autotoolstoolchain.py b/conan/tools/gnu/autotoolstoolchain.py
index 5313c8864bd..d77f680121c 100644
--- a/conan/tools/gnu/autotoolstoolchain.py
+++ b/conan/tools/gnu/autotoolstoolchain.py
@@ -2,13 +2,14 @@
 
 from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
 from conan.tools._compilers import architecture_flag, build_type_flags
+from conan.tools.apple.apple import apple_min_version_flag, to_apple_arch, \
+    apple_sdk_path
+from conan.tools.cross_building import cross_building, get_cross_building_settings
 from conan.tools.env import Environment
-from conan.tools.gnu.cross_building import _cross_building
-from conan.tools.gnu.get_cross_building_settings import _get_cross_building_settings
+from conan.tools.files import save
+from conan.tools.gnu.get_cppstd import cppstd_flag
 from conan.tools.gnu.get_gnu_triplet import _get_gnu_triplet
-# FIXME: need to refactor this import and bring to conan.tools
-from conans.client.build.cppstd_flags import cppstd_flag_new
-from conans.util.files import save
+from conans.tools import args_to_string
 
 
 class AutotoolsToolchain:
@@ -16,6 +17,10 @@ def __init__(self, conanfile):
         self._conanfile = conanfile
         build_type = self._conanfile.settings.get_safe("build_type")
 
+        self.configure_args = []
+        self.make_args = []
+        self.default_configure_install_args = False
+
         # TODO: compiler.runtime for Visual studio?
         # defines
         self.ndebug = None
@@ -31,28 +36,32 @@ def __init__(self, conanfile):
         self.libcxx = self._libcxx()
         self.fpic = self._conanfile.options.get_safe("fPIC")
 
-        # FIXME: This needs to be imported here into conan.tools
-        self.cppstd = cppstd_flag_new(self._conanfile.settings)
+        self.cppstd = cppstd_flag(self._conanfile.settings)
         self.arch_flag = architecture_flag(self._conanfile.settings)
         # TODO: This is also covering compilers like Visual Studio, necessary to test it (&remove?)
         self.build_type_flags = build_type_flags(self._conanfile.settings)
 
+        # Cross build
         self._host = None
         self._build = None
         self._target = None
 
-        if _cross_building(self._conanfile):
-            os_build, arch_build, os_host, arch_host = _get_cross_building_settings(self._conanfile)
+        self.apple_arch_flag = self.apple_isysroot_flag = None
+
+        self.apple_min_version_flag = apple_min_version_flag(self._conanfile)
+        if cross_building(self._conanfile):
+            os_build, arch_build, os_host, arch_host = get_cross_building_settings(self._conanfile)
             self._host = _get_gnu_triplet(os_host, arch_host)
             self._build = _get_gnu_triplet(os_build, arch_build)
 
-    def _rpaths_link(self):
-        # TODO: Not implemented yet
-        pass
-
-    # TODO: Apple: tools.apple_deployment_target_flag,
-    # TODO:  tools.XCRun(self._conanfile.settings).sdk_path
-    # TODO: "-arch", tools.to_apple_arch(self._arch)
+            # Apple Stuff
+            if os_build == "Macos":
+                sdk_path = apple_sdk_path(conanfile)
+                apple_arch = to_apple_arch(self._conanfile.settings.get_safe("arch"))
+                # https://man.archlinux.org/man/clang.1.en#Target_Selection_Options
+                self.apple_arch_flag = "-arch {}".format(apple_arch) if apple_arch else None
+                # -isysroot makes all includes for your library relative to the build directory
+                self.apple_isysroot_flag = "-isysroot {}".format(sdk_path) if sdk_path else None
 
     def _cxx11_abi_define(self):
         # https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
@@ -115,21 +124,46 @@ def environment(self):
             self.cxxflags.append("-fPIC")
             self.cflags.append("-fPIC")
 
+        # FIXME: Previously these flags where checked if already present at env 'CFLAGS', 'CXXFLAGS'
+        #        and 'self.cxxflags', 'self.cflags' before adding them
+        for f in list(filter(bool, [self.apple_isysroot_flag,
+                                    self.apple_arch_flag,
+                                    self.apple_min_version_flag])):
+            self.cxxflags.append(f)
+            self.cflags.append(f)
+            self.ldflags.append(f)
+
         env.append("CPPFLAGS", ["-D{}".format(d) for d in self.defines])
         env.append("CXXFLAGS", self.cxxflags)
         env.append("CFLAGS", self.cflags)
         env.append("LDFLAGS", self.ldflags)
         return env
 
-    def generate(self):
-        env = self.environment()
-        env.save_sh("conanautotoolstoolchain.sh")
-        env.save_bat("conanautotoolstoolchain.bat")
+    def generate(self, env=None):
+        env = env or self.environment()
+        env.save_script("conanautotoolstoolchain")
         self.generate_args()
 
     def generate_args(self):
-        args = {"build": self._build,
-                "host": self._host,
-                "target": self._target}
-        args = {k: v for k, v in args.items() if v is not None}
-        save(CONAN_TOOLCHAIN_ARGS_FILE, json.dumps(args))
+        configure_args = []
+        configure_args.extend(self.configure_args)
+
+        if self.default_configure_install_args:
+            # If someone want arguments but not the defaults can pass them in args manually
+            configure_args.extend(
+                    ["--prefix=%s" % self._conanfile.package_folder.replace("\\", "/"),
+                     "--bindir=${prefix}/bin",
+                     "--sbindir=${prefix}/bin",
+                     "--libdir=${prefix}/lib",
+                     "--includedir=${prefix}/include",
+                     "--oldincludedir=${prefix}/include",
+                     "--datarootdir=${prefix}/share"])
+        user_args_str = args_to_string(self.configure_args)
+        for flag, var in (("host", self._host), ("build", self._build), ("target", self._target)):
+            if var and flag not in user_args_str:
+                configure_args.append('--{}={}'.format(flag, var))
+
+        args = {"configure_args": args_to_string(configure_args),
+                "make_args":  args_to_string(self.make_args)}
+
+        save(self._conanfile, CONAN_TOOLCHAIN_ARGS_FILE, json.dumps(args))
diff --git a/conan/tools/gnu/cross_building.py b/conan/tools/gnu/cross_building.py
deleted file mode 100644
index f1df1e86d4a..00000000000
--- a/conan/tools/gnu/cross_building.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from conan.tools.gnu.get_cross_building_settings import _get_cross_building_settings
-
-
-def _cross_building(conanfile, self_os=None, self_arch=None, skip_x64_x86=False):
-    ret = _get_cross_building_settings(conanfile, self_os, self_arch)
-
-    build_os, build_arch, host_os, host_arch = ret
-
-    if skip_x64_x86 and host_os is not None and (build_os == host_os) and \
-            host_arch is not None and ((build_arch == "x86_64") and (host_arch == "x86") or
-                                       (build_arch == "sparcv9") and (host_arch == "sparc") or
-                                       (build_arch == "ppc64") and (host_arch == "ppc32")):
-        return False
-
-    if host_os is not None and (build_os != host_os):
-        return True
-    if host_arch is not None and (build_arch != host_arch):
-        return True
-
-    return False
diff --git a/conan/tools/gnu/get_cppstd.py b/conan/tools/gnu/get_cppstd.py
new file mode 100644
index 00000000000..33ad9f8cb89
--- /dev/null
+++ b/conan/tools/gnu/get_cppstd.py
@@ -0,0 +1,270 @@
+from conans.model.version import Version
+
+
+def cppstd_flag(settings):
+    compiler = settings.get_safe("compiler")
+    compiler_version = settings.get_safe("compiler.version")
+    compiler_base = settings.get_safe("compiler.base")
+    cppstd = settings.get_safe("compiler.cppstd")
+
+    if not compiler or not compiler_version or not cppstd:
+        return ""
+
+    cppstd_intel = _cppstd_intel_visualstudio if compiler_base == "Visual Studio" else \
+        _cppstd_intel_gcc
+    func = {"gcc": _cppstd_gcc,
+            "clang": _cppstd_clang,
+            "apple-clang": _cppstd_apple_clang,
+            "Visual Studio": _cppstd_visualstudio,
+            "msvc": _cppstd_msvc,
+            "intel": cppstd_intel,
+            "mcst-lcc": _cppstd_mcst_lcc}.get(str(compiler), None)
+    flag = None
+    if func:
+        flag = func(str(compiler_version), str(cppstd))
+    return flag
+
+
+def _cppstd_visualstudio(visual_version, cppstd):
+    # https://docs.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version
+    v14 = None
+    v17 = None
+    v20 = None
+
+    if Version(visual_version) >= "14":
+        v14 = "c++14"
+        v17 = "c++latest"
+    if Version(visual_version) >= "15":
+        v17 = "c++17"
+        v20 = "c++latest"
+
+    flag = {"14": v14, "17": v17, "20": v20}.get(str(cppstd), None)
+    return "/std:%s" % flag if flag else None
+
+
+def _cppstd_msvc(visual_version, cppstd):
+    # https://docs.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version
+    v14 = None
+    v17 = None
+    v20 = None
+
+    if Version(visual_version) >= "19.0":
+        v14 = "c++14"
+        v17 = "c++latest"
+    if Version(visual_version) >= "19.1":
+        v17 = "c++17"
+        v20 = "c++latest"
+
+    flag = {"14": v14, "17": v17, "20": v20}.get(str(cppstd), None)
+    return "/std:%s" % flag if flag else None
+
+
+def _cppstd_apple_clang(clang_version, cppstd):
+    """
+    Inspired in:
+    https://github.com/Kitware/CMake/blob/master/Modules/Compiler/AppleClang-CXX.cmake
+    """
+
+    v98 = vgnu98 = v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = None
+
+    if Version(clang_version) >= "4.0":
+        v98 = "c++98"
+        vgnu98 = "gnu++98"
+        v11 = "c++11"
+        vgnu11 = "gnu++11"
+
+    if Version(clang_version) >= "6.1":
+        v14 = "c++14"
+        vgnu14 = "gnu++14"
+    elif Version(clang_version) >= "5.1":
+        v14 = "c++1y"
+        vgnu14 = "gnu++1y"
+
+    if Version(clang_version) >= "6.1":
+        v17 = "c++1z"
+        vgnu17 = "gnu++1z"
+
+    if Version(clang_version) >= "9.1":
+        # Not confirmed that it didn't work before 9.1 but 1z is still valid, so we are ok
+        v17 = "c++17"
+        vgnu17 = "gnu++17"
+
+    if Version(clang_version) >= "10.0":
+        v20 = "c++2a"
+        vgnu20 = "gnu++2a"
+
+    flag = {"98": v98, "gnu98": vgnu98,
+            "11": v11, "gnu11": vgnu11,
+            "14": v14, "gnu14": vgnu14,
+            "17": v17, "gnu17": vgnu17,
+            "20": v20, "gnu20": vgnu20}.get(cppstd, None)
+
+    return "-std=%s" % flag if flag else None
+
+
+def _cppstd_clang(clang_version, cppstd):
+    """
+    Inspired in:
+    https://github.com/Kitware/CMake/blob/
+    1fe2dc5ef2a1f262b125a2ba6a85f624ce150dd2/Modules/Compiler/Clang-CXX.cmake
+
+    https://clang.llvm.org/cxx_status.html
+    """
+    v98 = vgnu98 = v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = v23 = vgnu23 = None
+
+    if Version(clang_version) >= "2.1":
+        v98 = "c++98"
+        vgnu98 = "gnu++98"
+
+    if Version(clang_version) >= "3.1":
+        v11 = "c++11"
+        vgnu11 = "gnu++11"
+    elif Version(clang_version) >= "2.1":
+        v11 = "c++0x"
+        vgnu11 = "gnu++0x"
+
+    if Version(clang_version) >= "3.5":
+        v14 = "c++14"
+        vgnu14 = "gnu++14"
+    elif Version(clang_version) >= "3.4":
+        v14 = "c++1y"
+        vgnu14 = "gnu++1y"
+
+    if Version(clang_version) >= "5":
+        v17 = "c++17"
+        vgnu17 = "gnu++17"
+    elif Version(clang_version) >= "3.5":
+        v17 = "c++1z"
+        vgnu17 = "gnu++1z"
+
+    if Version(clang_version) >= "6":
+        v20 = "c++2a"
+        vgnu20 = "gnu++2a"
+
+    if Version(clang_version) >= "12":
+        v20 = "c++20"
+        vgnu20 = "gnu++20"
+
+        v23 = "c++2b"
+        vgnu23 = "gnu++2b"
+
+    flag = {"98": v98, "gnu98": vgnu98,
+            "11": v11, "gnu11": vgnu11,
+            "14": v14, "gnu14": vgnu14,
+            "17": v17, "gnu17": vgnu17,
+            "20": v20, "gnu20": vgnu20,
+            "23": v23, "gnu23": vgnu23}.get(cppstd, None)
+    return "-std=%s" % flag if flag else None
+
+
+def _cppstd_gcc(gcc_version, cppstd):
+    """https://github.com/Kitware/CMake/blob/master/Modules/Compiler/GNU-CXX.cmake"""
+    # https://gcc.gnu.org/projects/cxx-status.html
+    v98 = vgnu98 = v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = v23 = vgnu23 = None
+
+    if Version(gcc_version) >= "3.4":
+        v98 = "c++98"
+        vgnu98 = "gnu++98"
+
+    if Version(gcc_version) >= "4.7":
+        v11 = "c++11"
+        vgnu11 = "gnu++11"
+    elif Version(gcc_version) >= "4.3":
+        v11 = "c++0x"
+        vgnu11 = "gnu++0x"
+
+    if Version(gcc_version) >= "4.9":
+        v14 = "c++14"
+        vgnu14 = "gnu++14"
+    elif Version(gcc_version) >= "4.8":
+        v14 = "c++1y"
+        vgnu14 = "gnu++1y"
+
+    if Version(gcc_version) >= "5.1":
+        v17 = "c++1z"
+        vgnu17 = "gnu++1z"
+
+    if Version(gcc_version) >= "5.2":  # Not sure if even in 5.1 gnu17 is valid, but gnu1z is
+        v17 = "c++17"
+        vgnu17 = "gnu++17"
+
+    if Version(gcc_version) >= "8":
+        v20 = "c++2a"
+        vgnu20 = "gnu++2a"
+
+    if Version(gcc_version) >= "11":
+        v23 = "c++2b"
+        vgnu23 = "gnu++2b"
+
+    flag = {"98": v98, "gnu98": vgnu98,
+            "11": v11, "gnu11": vgnu11,
+            "14": v14, "gnu14": vgnu14,
+            "17": v17, "gnu17": vgnu17,
+            "20": v20, "gnu20": vgnu20,
+            "23": v23, "gnu23": vgnu23}.get(cppstd)
+    return "-std=%s" % flag if flag else None
+
+
+def _cppstd_intel_common(intel_version, cppstd, vgnu98, vgnu0x):
+    # https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-std-qstd
+    # https://software.intel.com/en-us/articles/intel-cpp-compiler-release-notes
+    # NOTE: there are only gnu++98 and gnu++0x, and only for Linux/macOS
+    v98 = v11 = v14 = v17 = v20 = None
+    vgnu11 = vgnu14 = vgnu17 = vgnu20 = None
+
+    if Version(intel_version) >= "12":
+        v11 = "c++0x"
+        vgnu11 = vgnu0x
+    if Version(intel_version) >= "14":
+        v11 = "c++11"
+        vgnu11 = vgnu0x
+    if Version(intel_version) >= "16":
+        v14 = "c++14"
+    if Version(intel_version) >= "18":
+        v17 = "c++17"
+    if Version(intel_version) >= "19.1":
+        v20 = "c++20"
+
+    return {"98": v98, "gnu98": vgnu98,
+            "11": v11, "gnu11": vgnu11,
+            "14": v14, "gnu14": vgnu14,
+            "17": v17, "gnu17": vgnu17,
+            "20": v20, "gnu20": vgnu20}.get(cppstd)
+
+
+def _cppstd_intel_gcc(intel_version, cppstd):
+    flag = _cppstd_intel_common(intel_version, cppstd, "gnu++98", "gnu++0x")
+    return "-std=%s" % flag if flag else None
+
+
+def _cppstd_intel_visualstudio(intel_version, cppstd):
+    flag = _cppstd_intel_common(intel_version, cppstd, None, None)
+    return "/Qstd=%s" % flag if flag else None
+
+
+def _cppstd_mcst_lcc(mcst_lcc_version, cppstd):
+    v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = None
+
+    if Version(mcst_lcc_version) >= "1.21":
+        v11 = "c++11"
+        vgnu11 = "gnu++11"
+        v14 = "c++14"
+        vgnu14 = "gnu++14"
+
+    if Version(mcst_lcc_version) >= "1.24":
+        v17 = "c++17"
+        vgnu17 = "gnu++17"
+
+    if Version(mcst_lcc_version) >= "1.25":
+        v20 = "c++2a"
+        vgnu20 = "gnu++2a"
+
+    flag = {"98": "c++98", "gnu98": "gnu++98",
+            "03": "c++03", "gnu03": "gnu++03",
+            "11": v11, "gnu11": vgnu11,
+            "14": v14, "gnu14": vgnu14,
+            "17": v17, "gnu17": vgnu17,
+            "20": v20, "gnu20": vgnu20}.get(cppstd)
+    return "-std=%s" % flag if flag else None
+
+
diff --git a/conan/tools/gnu/get_cross_building_settings.py b/conan/tools/gnu/get_cross_building_settings.py
deleted file mode 100644
index c2e2304b24e..00000000000
--- a/conan/tools/gnu/get_cross_building_settings.py
+++ /dev/null
@@ -1,175 +0,0 @@
-import os
-import platform
-
-from conans.errors import ConanException
-from conans.model.version import Version
-from conans.util.runners import check_output_runner
-
-
-class _OSInfo(object):
-    """ Usage:
-        (os_info.is_linux) # True/False
-        (os_info.is_windows) # True/False
-        (os_info.is_macos) # True/False
-        (os_info.is_freebsd) # True/False
-        (os_info.is_solaris) # True/False
-
-        (os_info.linux_distro)  # debian, ubuntu, fedora, centos...
-
-        (os_info.os_version) # 5.1
-        (os_info.os_version_name) # Windows 7, El Capitan
-
-        if os_info.os_version > "10.1":
-            pass
-        if os_info.os_version == "10.1.0":
-            pass
-    """
-
-    def __init__(self):
-        system = platform.system()
-        self.os_version = None
-
-        self.is_linux = system == "Linux"
-        self.linux_distro = None
-        self.is_msys = system.startswith("MING") or system.startswith("MSYS_NT")
-        self.is_cygwin = system.startswith("CYGWIN_NT")
-        self.is_windows = system == "Windows" or self.is_msys or self.is_cygwin
-        self.is_macos = system == "Darwin"
-        self.is_freebsd = system == "FreeBSD"
-        self.is_solaris = system == "SunOS"
-        self.is_aix = system == "AIX"
-        self.is_posix = os.pathsep == ':'
-
-    def _get_linux_distro_info(self):
-        import distro
-        self.linux_distro = distro.id()
-        self.os_version = Version(distro.version())
-
-    @staticmethod
-    def get_aix_architecture():
-        processor = platform.processor()
-        if "powerpc" in processor:
-            kernel_bitness = _OSInfo().get_aix_conf("KERNEL_BITMODE")
-            if kernel_bitness:
-                return "ppc64" if kernel_bitness == "64" else "ppc32"
-        elif "rs6000" in processor:
-            return "ppc32"
-
-    @staticmethod
-    def get_aix_conf(options=None):
-        options = " %s" % options if options else ""
-        if not _OSInfo().is_aix:
-            raise ConanException("Command only for AIX operating system")
-
-        try:
-            ret = check_output_runner("getconf%s" % options).strip()
-            return ret
-        except Exception:
-            return None
-
-    @staticmethod
-    def get_solaris_architecture():
-        # under intel solaris, platform.machine()=='i86pc' so we need to handle
-        # it early to suport 64-bit
-        processor = platform.processor()
-        kernel_bitness, elf = platform.architecture()
-        if "sparc" in processor:
-            return "sparcv9" if kernel_bitness == "64bit" else "sparc"
-        elif "i386" in processor:
-            return "x86_64" if kernel_bitness == "64bit" else "x86"
-
-    @staticmethod
-    def get_e2k_architecture():
-        return {
-            "E1C+": "e2k-v4",  # Elbrus 1C+ and Elbrus 1CK
-            "E2C+": "e2k-v2",  # Elbrus 2CM
-            "E2C+DSP": "e2k-v2",  # Elbrus 2C+
-            "E2C3": "e2k-v6",  # Elbrus 2C3
-            "E2S": "e2k-v3",  # Elbrus 2S (aka Elbrus 4C)
-            "E8C": "e2k-v4",  # Elbrus 8C and Elbrus 8C1
-            "E8C2": "e2k-v5",  # Elbrus 8C2 (aka Elbrus 8CB)
-            "E12C": "e2k-v6",  # Elbrus 12C
-            "E16C": "e2k-v6",  # Elbrus 16C
-            "E32C": "e2k-v7",  # Elbrus 32C
-        }.get(platform.processor())
-
-
-def _detected_os():
-    if _OSInfo().is_macos:
-        return "Macos"
-    if _OSInfo().is_windows:
-        return "Windows"
-    return platform.system()
-
-
-def _detected_architecture():
-    # FIXME: Very weak check but not very common to run conan in other architectures
-    machine = platform.machine()
-    os_info = _OSInfo()
-    arch = None
-
-    if os_info.is_solaris:
-        arch = _OSInfo.get_solaris_architecture()
-    elif os_info.is_aix:
-        arch = _OSInfo.get_aix_architecture()
-
-    if arch:
-        return arch
-
-    if "ppc64le" in machine:
-        return "ppc64le"
-    elif "ppc64" in machine:
-        return "ppc64"
-    elif "ppc" in machine:
-        return "ppc32"
-    elif "mips64" in machine:
-        return "mips64"
-    elif "mips" in machine:
-        return "mips"
-    elif "sparc64" in machine:
-        return "sparcv9"
-    elif "sparc" in machine:
-        return "sparc"
-    elif "aarch64" in machine:
-        return "armv8"
-    elif "arm64" in machine:
-        return "armv8"
-    elif "64" in machine:
-        return "x86_64"
-    elif "86" in machine:
-        return "x86"
-    elif "armv8" in machine:
-        return "armv8"
-    elif "armv7" in machine:
-        return "armv7"
-    elif "arm" in machine:
-        return "armv6"
-    elif "s390x" in machine:
-        return "s390x"
-    elif "s390" in machine:
-        return "s390"
-    elif "sun4v" in machine:
-        return "sparc"
-    elif "e2k" in machine:
-        return _OSInfo.get_e2k_architecture()
-
-
-def _get_build_os_arch(conanfile):
-    """ Returns the value for the 'os' and 'arch' settings for the build context """
-    if hasattr(conanfile, 'settings_build'):
-        return conanfile.settings_build.get_safe('os'), conanfile.settings_build.get_safe('arch')
-    else:
-        return conanfile.settings.get_safe('os_build'), conanfile.settings.get_safe('arch_build')
-
-
-def _get_cross_building_settings(conanfile, self_os=None, self_arch=None):
-    os_build, arch_build = _get_build_os_arch(conanfile)
-    if not hasattr(conanfile, 'settings_build'):
-        # Let it override from outside only if no 'profile_build' is used
-        os_build = self_os or os_build or _detected_os()
-        arch_build = self_arch or arch_build or _detected_architecture()
-
-    os_host = conanfile.settings.get_safe("os")
-    arch_host = conanfile.settings.get_safe("arch")
-
-    return os_build, arch_build, os_host, arch_host
diff --git a/conan/tools/meson/meson.py b/conan/tools/meson/meson.py
index bd982d3d785..beca3b6cf18 100644
--- a/conan/tools/meson/meson.py
+++ b/conan/tools/meson/meson.py
@@ -1,7 +1,7 @@
 import os
 
+from conan.tools.cross_building import cross_building
 from conan.tools.meson import MesonToolchain
-from conans.client.tools.oss import cross_building
 
 
 def ninja_jobs_cmd_line_arg(conanfile):
diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py
index fae73704f65..dfd8000adba 100644
--- a/conans/client/generators/__init__.py
+++ b/conans/client/generators/__init__.py
@@ -67,7 +67,7 @@ def __init__(self):
                             "markdown": MarkdownGenerator}
         self._new_generators = ["CMakeToolchain", "CMakeDeps", "MSBuildToolchain",
                                 "MesonToolchain", "MSBuildDeps", "QbsToolchain", "msbuild",
-                                "VirtualEnv", "AutotoolsDeps", "AutotoolsToolchain", "AutotoolsGen",
+                                "VirtualEnv", "AutotoolsDeps", "AutotoolsToolchain",
                                 "BazelDeps", "BazelToolchain"]
 
     def add(self, name, generator_class, custom=False):
@@ -100,9 +100,6 @@ def _new_generator(self, generator_name, output):
         elif generator_name == "AutotoolsToolchain":
             from conan.tools.gnu import AutotoolsToolchain
             return AutotoolsToolchain
-        elif generator_name == "AutotoolsGen":
-            from conan.tools.gnu import AutotoolsGen
-            return AutotoolsGen
         elif generator_name == "MSBuildToolchain":
             from conan.tools.microsoft import MSBuildToolchain
             return MSBuildToolchain
diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py
index 1db7cdc1c19..3e805e3fb56 100644
--- a/conans/model/conan_file.py
+++ b/conans/model/conan_file.py
@@ -387,7 +387,7 @@ def package_info(self):
     def run(self, command, output=True, cwd=None, win_bash=False, subsystem=None, msys_mingw=True,
             ignore_errors=False, run_environment=False, with_login=True, env="conanbuildenv"):
 
-        command = environment_wrap_command(env, command)
+        command = environment_wrap_command(env, command, cwd=self.generators_folder)
 
         def _run():
             if not win_bash:
diff --git a/conans/model/new_build_info.py b/conans/model/new_build_info.py
index 0a6b79c3802..f5b743b2fc6 100644
--- a/conans/model/new_build_info.py
+++ b/conans/model/new_build_info.py
@@ -104,6 +104,9 @@ def merge_list(o, d):
                 setattr(self, varname, [])
             merge_list(getattr(other, varname), getattr(self, varname))
 
+        if self.sysroot is None and other.sysroot:
+            self.sysroot = other.sysroot
+
         if other._generator_properties:
             if not self._generator_properties:
                 self._generator_properties = {}
diff --git a/conans/test/functional/toolchains/gnu/autotools/__init__.py b/conans/test/functional/toolchains/gnu/autotools/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/conans/test/functional/toolchains/gnu/autotools/test_apple_toolchain.py b/conans/test/functional/toolchains/gnu/autotools/test_apple_toolchain.py
new file mode 100644
index 00000000000..46c4b610a6d
--- /dev/null
+++ b/conans/test/functional/toolchains/gnu/autotools/test_apple_toolchain.py
@@ -0,0 +1,137 @@
+import os
+import textwrap
+import platform
+
+import pytest
+
+from conan.tools.apple.apple import to_apple_arch
+from conans.test.assets.autotools import gen_makefile
+from conans.test.assets.sources import gen_function_h, gen_function_cpp
+from conans.test.utils.tools import TestClient
+
+makefile = gen_makefile(apps=["app"], libs=["hello"])
+
+conanfile_py = textwrap.dedent("""
+    from conans import ConanFile, tools
+    from conan.tools.gnu import Autotools
+
+    class App(ConanFile):
+        settings = "os", "arch", "compiler", "build_type"
+        options = {"shared": [True, False], "fPIC": [True, False]}
+        default_options = {"shared": False, "fPIC": True}
+        generators = "AutotoolsToolchain"
+
+        def config_options(self):
+            if self.settings.os == "Windows":
+                del self.options.fPIC
+
+        def build(self):
+            env_build = Autotools(self)
+            env_build.make()
+    """)
+
+
+@pytest.mark.skipif(platform.system() != "Darwin", reason="Only OSX")
+@pytest.mark.parametrize("config", [("x86_64", "Macos", "10.14"),
+                                    ("armv8", "iOS", "10.0"),
+                                    ("armv7", "iOS", "10.0"),
+                                    ("x86", "iOS", "10.0"),
+                                    ("x86_64", "iOS", "10.0"),
+                                    ("armv8", "Macos", "10.14")  # M1
+                                    ])
+def test_makefile_arch(config):
+    arch, os_, os_version = config
+    profile = textwrap.dedent("""
+                include(default)
+                [settings]
+                os = {os}
+                os.version = {os_version}
+                arch = {arch}
+                """).format(os=os_, arch=arch, os_version=os_version)
+
+    t = TestClient()
+    hello_h = gen_function_h(name="hello")
+    hello_cpp = gen_function_cpp(name="hello")
+    main_cpp = gen_function_cpp(name="main", includes=["hello"], calls=["hello"])
+
+    t.save({"Makefile": makefile,
+            "hello.h": hello_h,
+            "hello.cpp": hello_cpp,
+            "app.cpp": main_cpp,
+            "conanfile.py": conanfile_py,
+            "profile": profile})
+
+    t.run("install . --profile:host=profile --profile:build=default")
+    t.run("build .")
+
+    libhello = os.path.join(t.current_folder, "libhello.a")
+    app = os.path.join(t.current_folder, "app")
+    assert os.path.isfile(libhello)
+    assert os.path.isfile(app)
+
+    expected_arch = to_apple_arch(arch)
+
+    t.run_command('lipo -info "%s"' % libhello)
+    assert "architecture: %s" % expected_arch in t.out
+
+    t.run_command('lipo -info "%s"' % app)
+    assert "architecture: %s" % expected_arch in t.out
+
+
+@pytest.mark.skipif(platform.system() != "Darwin", reason="Only OSX")
+@pytest.mark.parametrize("arch", ["x86_64", "armv8"])
+def test_catalyst(arch):
+    profile = textwrap.dedent("""
+        include(default)
+        [settings]
+        os = Macos
+        os.version = 13.0
+        os.sdk = macosx
+        os.subsystem = catalyst
+        arch = {arch}
+        """).format(arch=arch)
+
+    t = TestClient()
+    hello_h = gen_function_h(name="hello")
+    hello_cpp = gen_function_cpp(name="hello")
+    main_cpp = textwrap.dedent("""
+        #include "hello.h"
+        #include <TargetConditionals.h>
+        #include <iostream>
+
+        int main()
+        {
+        #if TARGET_OS_MACCATALYST
+            std::cout << "running catalyst " << __IPHONE_OS_VERSION_MIN_REQUIRED << std::endl;
+        #else
+            #error "not building for Apple Catalyst"
+        #endif
+        }
+        """)
+
+    t.save({"Makefile": makefile,
+            "hello.h": hello_h,
+            "hello.cpp": hello_cpp,
+            "app.cpp": main_cpp,
+            "conanfile.py": conanfile_py,
+            "profile": profile})
+
+    t.run("install . --profile:host=profile --profile:build=default")
+    t.run("build .")
+
+    libhello = os.path.join(t.current_folder, "libhello.a")
+    app = os.path.join(t.current_folder, "app")
+    assert os.path.isfile(libhello)
+    assert os.path.isfile(app)
+
+    expected_arch = to_apple_arch(arch)
+
+    t.run_command('lipo -info "%s"' % libhello)
+    assert "architecture: %s" % expected_arch in t.out
+
+    t.run_command('lipo -info "%s"' % app)
+    assert "architecture: %s" % expected_arch in t.out
+
+    if arch == "x86_64":
+        t.run_command('"%s"' % app)
+        assert "running catalyst 130000" in t.out
diff --git a/conans/test/functional/toolchains/gnu/test_autotools.py b/conans/test/functional/toolchains/gnu/autotools/test_basic.py
similarity index 94%
rename from conans/test/functional/toolchains/gnu/test_autotools.py
rename to conans/test/functional/toolchains/gnu/autotools/test_basic.py
index 8bf518023d3..da7a2e75a12 100644
--- a/conans/test/functional/toolchains/gnu/test_autotools.py
+++ b/conans/test/functional/toolchains/gnu/autotools/test_basic.py
@@ -32,7 +32,7 @@ class TestConan(ConanFile):
             requires = "hello/0.1"
             settings = "os", "compiler", "arch", "build_type"
             exports_sources = "configure.ac", "Makefile.am", "main.cpp"
-            generators = "AutotoolsGen"
+            generators = "AutotoolsDeps", "AutotoolsToolchain"
 
             def build(self):
                 self.run("aclocal")
@@ -79,7 +79,7 @@ class TestConan(ConanFile):
             requires = "hello/0.1"
             settings = "os", "compiler", "arch", "build_type"
             exports_sources = "Makefile"
-            generators = "AutotoolsGen"
+            generators = "AutotoolsDeps", "AutotoolsToolchain"
 
             def build(self):
                 autotools = Autotools(self)
@@ -91,7 +91,9 @@ def build(self):
                  "profile": profile}, clean_first=True)
 
     client.run("install . --profile=profile")
-    cmd = environment_wrap_command("conanbuildenv", make_program, cwd=client.current_folder)
+    cmd = environment_wrap_command(["conanbuildenv",
+                                    "conanautotoolstoolchain",
+                                    "conanautotoolsdeps"], make_program, cwd=client.current_folder)
     client.run_command(cmd)
     client.run_command("app")
     # TODO: fill compiler version when ready
diff --git a/conans/test/functional/toolchains/gnu/test_ios.py b/conans/test/functional/toolchains/gnu/autotools/test_ios.py
similarity index 94%
rename from conans/test/functional/toolchains/gnu/test_ios.py
rename to conans/test/functional/toolchains/gnu/autotools/test_ios.py
index 1b9ac6daf53..ff3e8685769 100644
--- a/conans/test/functional/toolchains/gnu/test_ios.py
+++ b/conans/test/functional/toolchains/gnu/autotools/test_ios.py
@@ -49,7 +49,7 @@ class TestConan(ConanFile):
             requires = "hello/0.1"
             settings = "os", "compiler", "arch", "build_type"
             exports_sources = "configure.ac", "Makefile.am", "main.cpp"
-            generators = "AutotoolsGen"
+            generators = "AutotoolsToolchain", "AutotoolsDeps"
 
             def build(self):
                 self.run("aclocal")
@@ -73,5 +73,5 @@ def build(self):
     assert "Non-fat file: main is architecture: arm64" in client.out
 
     js = client.load("conanbuild.json")
-    assert '"build": "x86_64-apple-darwin"' in js
-    assert '"host": "aarch64-apple-ios"' in js
+    assert '--host=aarch64-apple-ios' in js
+    assert '--build=x86_64-apple-darwin' in js
diff --git a/conans/test/unittests/client/toolchain/autotools/__init__.py b/conans/test/unittests/client/toolchain/autotools/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/conans/test/unittests/client/toolchain/autotools/autotools_deps_test.py b/conans/test/unittests/client/toolchain/autotools/autotools_deps_test.py
new file mode 100644
index 00000000000..56e181079d3
--- /dev/null
+++ b/conans/test/unittests/client/toolchain/autotools/autotools_deps_test.py
@@ -0,0 +1,89 @@
+from collections import OrderedDict
+
+import mock
+from mock import Mock
+
+from conan.tools.gnu import AutotoolsDeps
+from conans import ConanFile
+from conans.model.build_info import CppInfo
+from conans.model.conanfile_interface import ConanFileInterface
+from conans.model.dependencies import ConanFileDependencies, Requirement
+from conans.model.ref import ConanFileReference
+from conans.test.utils.mocks import MockSettings
+
+
+def get_cpp_info(name):
+    cppinfo = CppInfo("{}/1.0".format(name), "/tmp/root")
+    cppinfo.includedirs = []
+    cppinfo.includedirs.append("path/includes/{}".format(name))
+    cppinfo.includedirs.append("other\\include\\path\\{}".format(name))
+    # To test some path in win, to be used with MinGW make or MSYS etc
+    cppinfo.libdirs = []
+    cppinfo.libdirs.append("one\\lib\\path\\{}".format(name))
+    cppinfo.libs = []
+    cppinfo.libs.append("{}_onelib".format(name))
+    cppinfo.libs.append("{}_twolib".format(name))
+    cppinfo.defines = []
+    cppinfo.defines.append("{}_onedefinition".format(name))
+    cppinfo.defines.append("{}_twodefinition".format(name))
+    cppinfo.cflags = ["{}_a_c_flag".format(name)]
+    cppinfo.cxxflags = ["{}_a_cxx_flag".format(name)]
+    cppinfo.sharedlinkflags = ["{}_shared_link_flag".format(name)]
+    cppinfo.exelinkflags = ["{}_exe_link_flag".format(name)]
+    cppinfo.sysroot = "/path/to/folder/{}".format(name)
+    cppinfo.frameworks = []
+    cppinfo.frameworks.append("{}_oneframework".format(name))
+    cppinfo.frameworks.append("{}_twoframework".format(name))
+    cppinfo.system_libs = []
+    cppinfo.system_libs.append("{}_onesystemlib".format(name))
+    cppinfo.system_libs.append("{}_twosystemlib".format(name))
+    cppinfo.frameworkdirs = []
+    cppinfo.frameworkdirs.append("one/framework/path/{}".format(name))
+    return cppinfo
+
+
+def test_foo():
+    dep1 = ConanFile(Mock(), None)
+    dep1.cpp_info = get_cpp_info("dep1")
+    dep1._conan_node = Mock()
+    dep1._conan_node.ref = ConanFileReference.loads("dep1/1.0")
+    dep1.package_folder = "/path/to/folder_dep1"
+
+    dep2 = ConanFile(Mock(), None)
+    dep2.cpp_info = get_cpp_info("dep2")
+    dep2._conan_node = Mock()
+    dep2._conan_node.ref = ConanFileReference.loads("dep2/1.0")
+    dep2.package_folder = "/path/to/folder_dep2"
+
+    with mock.patch('conans.ConanFile.dependencies', new_callable=mock.PropertyMock) as mock_deps:
+        req1 = Requirement(ConanFileReference.loads("dep1/1.0"))
+        req2 = Requirement(ConanFileReference.loads("dep2/1.0"))
+        deps = OrderedDict()
+        deps[req1] = ConanFileInterface(dep1)
+        deps[req2] = ConanFileInterface(dep2)
+        mock_deps.return_value = ConanFileDependencies(deps)
+        consumer = ConanFile(Mock(), None)
+        consumer.settings = MockSettings(
+            {"build_type": "Release",
+             "arch": "x86",
+             "compiler": "gcc",
+             "compiler.libcxx": "libstdc++11",
+             "compiler.version": "7.1",
+             "cppstd": "17"})
+        deps = AutotoolsDeps(consumer)
+        # deps.generate()
+        env = deps.environment()
+        assert env["LDFLAGS"] == ' dep1_shared_link_flag dep2_shared_link_flag ' \
+                                 'dep1_exe_link_flag dep2_exe_link_flag ' \
+                                 '-framework dep1_oneframework -framework dep1_twoframework ' \
+                                 '-framework dep2_oneframework -framework dep2_twoframework ' \
+                                 '-F /path/to/folder_dep1/one/framework/path/dep1 ' \
+                                 '-F /path/to/folder_dep2/one/framework/path/dep2 ' \
+                                 '-L/path/to/folder_dep1/one/lib/path/dep1 ' \
+                                 '-L/path/to/folder_dep2/one/lib/path/dep2 ' \
+                                 '-Wl,-rpath,"/path/to/folder_dep1/one/lib/path/dep1" ' \
+                                 '-Wl,-rpath,"/path/to/folder_dep2/one/lib/path/dep2" ' \
+                                 '--sysroot=/path/to/folder/dep1'
+
+        assert env["CXXFLAGS"] == ' dep1_a_cxx_flag dep2_a_cxx_flag --sysroot=/path/to/folder/dep1'
+        assert env["CFLAGS"] == ' dep1_a_c_flag dep2_a_c_flag --sysroot=/path/to/folder/dep1'
diff --git a/conans/test/unittests/client/toolchain/autotools/autotools_test.py b/conans/test/unittests/client/toolchain/autotools/autotools_test.py
new file mode 100644
index 00000000000..f2959f49f1d
--- /dev/null
+++ b/conans/test/unittests/client/toolchain/autotools/autotools_test.py
@@ -0,0 +1,37 @@
+import os
+
+from mock import Mock
+
+from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
+from conan.tools.gnu import Autotools
+from conans import ConanFile
+from conans.client.tools.files import save
+from conans.model.conf import Conf
+from conans.test.unittests.util.tools_test import RunnerMock
+from conans.test.utils.mocks import MockSettings
+from conans.test.utils.test_files import temp_folder
+
+
+def test_configure_arguments():
+    tmp = temp_folder()
+    os.chdir(tmp)
+    save(CONAN_TOOLCHAIN_ARGS_FILE, """
+    {"configure_args": "my_configure_args",
+     "make_args": "my_make_args"}
+    """)
+    runner = RunnerMock()
+    conanfile = ConanFile(Mock(), runner=runner)
+    conanfile.settings = MockSettings({})
+    conanfile.folders.set_base_install(tmp)
+    conanfile.folders.set_base_source(tmp)
+    conanfile.conf = Conf()
+    conanfile.conf["tools.gnu:make_program"] = "my_make"
+    conanfile.conf["tools.gnu.make:jobs"] = "23"
+    ab = Autotools(conanfile)
+    ab.configure()
+    assert "configure my_configure_args" in runner.command_called
+
+    ab = Autotools(conanfile)
+    ab.make()
+    assert "my_make my_make_args -j23" in runner.command_called
+
diff --git a/conans/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py b/conans/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
new file mode 100644
index 00000000000..61d5fa7c4ef
--- /dev/null
+++ b/conans/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
@@ -0,0 +1,389 @@
+import json
+import platform
+from os import chdir
+
+import pytest
+
+from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
+from conan.tools.gnu import AutotoolsToolchain
+from conans.errors import ConanException
+from conans.model.conf import Conf
+from conans.test.utils.mocks import ConanFileMock, MockSettings, MockOptions
+from conans.test.utils.test_files import temp_folder
+
+
+def test_modify_environment():
+    """We can alter the environment generated by the toolchain passing the env to the generate"""
+    f = temp_folder()
+    chdir(f)
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings({"os": "Linux", "arch": "x86_64"})
+    conanfile.settings_build = MockSettings({"os": "Solaris", "arch": "x86"})
+    be = AutotoolsToolchain(conanfile)
+    env = be.environment()
+    env.define("foo", "var")
+    # We can pass the env to the generate once we adjusted or injected anything
+    be.generate(env)
+
+    bat = "conanautotoolstoolchain.{}".format("bat" if platform.system() == "Windows" else "sh")
+    with open(bat) as f:
+        content = f.read()
+        assert "foo" in content
+
+
+def test_target_triple():
+    f = temp_folder()
+    chdir(f)
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings({"os": "Linux", "arch": "x86_64"})
+    conanfile.settings_build = MockSettings({"os": "Solaris", "arch": "x86"})
+    conanfile.conf = Conf()
+    conanfile.conf["tools.gnu:make_program"] = "my_make"
+    conanfile.conf["tools.gnu.make:jobs"] = "23"
+
+    be = AutotoolsToolchain(conanfile)
+    be.make_args = ["foo", "var"]
+    be.generate_args()
+    with open(CONAN_TOOLCHAIN_ARGS_FILE) as f:
+        obj = json.load(f)
+
+    assert "--host=x86_64-linux-gnu" in obj["configure_args"]
+    assert "--build=i686-solaris" in obj["configure_args"]
+    assert obj["make_args"].replace("'", "") == "foo var"
+
+
+def test_invalid_target_triple():
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings({"os": "Linux", "arch": "UNKNOWN_ARCH"})
+    conanfile.settings_build = MockSettings({"os": "Solaris", "arch": "x86"})
+    with pytest.raises(ConanException) as excinfo:
+        AutotoolsToolchain(conanfile)
+    assert "Unknown 'UNKNOWN_ARCH' machine, Conan doesn't know how " \
+           "to translate it to the GNU triplet," in str(excinfo)
+
+
+def test_cppstd():
+    # Using "cppstd" is discarded
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "arch": "x86",
+         "compiler": "gcc",
+         "compiler.libcxx": "libstdc++11",
+         "compiler.version": "7.1",
+         "cppstd": "17"})
+    be = AutotoolsToolchain(conanfile)
+    env = be.environment()
+    assert not "-std=c++17" in env["CXXFLAGS"]
+
+    # Using "compiler.cppstd" works
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "arch": "x86",
+         "compiler": "gcc",
+         "compiler.libcxx": "libstdc++11",
+         "compiler.version": "7.1",
+         "compiler.cppstd": "17"})
+    be = AutotoolsToolchain(conanfile)
+    env = be.environment()
+    assert "-std=c++17" in env["CXXFLAGS"]
+
+    # With visual
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "arch": "x86",
+         "compiler": "Visual Studio",
+         "compiler.version": "14",
+         "compiler.cppstd": "17"})
+    be = AutotoolsToolchain(conanfile)
+    env = be.environment()
+    assert "/std:c++latest" in env["CXXFLAGS"]
+
+
+def test_fpic():
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings({"os": "Linux"})
+    conanfile.options = MockOptions({"fPIC": True})
+    be = AutotoolsToolchain(conanfile)
+    be.environment()
+    assert be.fpic is True
+    assert "-fPIC" in be.cxxflags
+
+    conanfile.options = MockOptions({"fPIC": False})
+    be = AutotoolsToolchain(conanfile)
+    be.environment()
+    assert be.fpic is False
+    assert "-fPIC" not in be.cxxflags
+
+    conanfile.options = MockOptions({"shared": False})
+    be = AutotoolsToolchain(conanfile)
+    be.environment()
+    assert be.fpic is None
+    assert "-fPIC" not in be.cxxflags
+
+
+def test_ndebug():
+    conanfile = ConanFileMock()
+    for bt in ['Release', 'RelWithDebInfo', 'MinSizeRel']:
+        conanfile.settings = MockSettings({"build_type": bt})
+        be = AutotoolsToolchain(conanfile)
+        assert be.ndebug == "NDEBUG"
+        env = be.environment()
+        assert "-DNDEBUG" in env["CPPFLAGS"]
+    for bt in ['Debug', 'DebWithDebInfo']:
+        conanfile.settings = MockSettings({"build_type": bt})
+        be = AutotoolsToolchain(conanfile)
+        assert be.ndebug is None
+        env = be.environment()
+        assert "-DNDEBUG" not in env["CPPFLAGS"]
+
+
+@pytest.mark.parametrize("config", [
+    ("gcc", 'libstdc++', None),
+    ("clang", 'libstdc++', '-stdlib=libstdc++'),
+    ("clang", 'libstdc++11', '-stdlib=libstdc++'),
+    ("clang", 'libc++', '-stdlib=libc++'),
+    ("apple-clang", 'libstdc++', '-stdlib=libstdc++'),
+    ("apple-clang", 'libstdc++11', '-stdlib=libstdc++'),
+    ("apple-clang", 'libc++', '-stdlib=libc++'),
+    ("sun-cc", 'libCstd', '-library=Cstd'),
+    ("sun-cc", 'libstdcxx', '-library=stdcxx4'),
+    ("sun-cc", 'libstlport', '-library=stlport4'),
+    ("sun-cc", 'libstdc++', '-library=stdcpp'),
+    ("qcc", 'libCstd', '-Y _libCstd'),
+    ("qcc", 'libstdcxx', '-Y _libstdcxx'),
+    ("qcc", 'libstlport', '-Y _libstlport'),
+    ("qcc", 'libstdc++', '-Y _libstdc++'),
+    ])
+def test_libcxx(config):
+    compiler, libcxx, expected_flag = config
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "arch": "x86",
+         "compiler": compiler,
+         "compiler.libcxx": libcxx,
+         "compiler.version": "7.1",
+         "compiler.cppstd": "17"})
+    be = AutotoolsToolchain(conanfile)
+    assert be.libcxx == expected_flag
+    env = be.environment()
+    if expected_flag:
+        assert expected_flag in env["CXXFLAGS"]
+
+
+def test_cxx11_abi_define():
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "arch": "x86",
+         "compiler": "gcc",
+         "compiler.libcxx": "libstdc++",
+         "compiler.version": "7.1",
+         "compiler.cppstd": "17"})
+    be = AutotoolsToolchain(conanfile)
+    assert be.gcc_cxx11_abi == "_GLIBCXX_USE_CXX11_ABI=0"
+    env = be.environment()
+    assert "-D_GLIBCXX_USE_CXX11_ABI=0" in env["CPPFLAGS"]
+
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "arch": "x86",
+         "compiler": "gcc",
+         "compiler.libcxx": "libstdc++11",
+         "compiler.version": "7.1",
+         "compiler.cppstd": "17"})
+    be = AutotoolsToolchain(conanfile)
+    env = be.environment()
+    assert be.gcc_cxx11_abi is None
+    assert "-D_GLIBCXX_USE_CXX11_ABI=0" not in env["CPPFLAGS"]
+
+
+@pytest.mark.parametrize("config", [
+    ('x86_64', "-m64"),
+    ('x86', "-m32"),])
+def test_architecture_flag(config):
+    """Architecture flag is set in CXXFLAGS, CFLAGS and LDFLAGS"""
+    arch, expected = config
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "os": "Macos",
+         "compiler": "gcc",
+         "arch": arch})
+    be = AutotoolsToolchain(conanfile)
+    assert be.arch_flag == expected
+    env = be.environment()
+    assert expected in env["CXXFLAGS"]
+    assert expected in env["CFLAGS"]
+    assert expected in env["LDFLAGS"]
+
+
+def test_build_type_flag():
+    """Architecture flag is set in CXXFLAGS, CFLAGS and LDFLAGS"""
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Debug",
+         "os": "Windows",
+         "compiler": "Visual Studio",
+         "arch": "x86_64"})
+    be = AutotoolsToolchain(conanfile)
+    assert be.build_type_flags == ["-Zi", "-Ob0", "-Od"]
+    env = be.environment()
+    assert "-Zi -Ob0 -Od" in env["CXXFLAGS"]
+    assert "-Zi -Ob0 -Od" in env["CFLAGS"]
+    assert "-Zi -Ob0 -Od" not in env["LDFLAGS"]
+
+
+def test_apple_arch_flag():
+    conanfile = ConanFileMock()
+    conanfile.conf = {"tools.apple:sdk_path": "/path/to/sdk"}
+    conanfile.settings_build = MockSettings(
+        {"build_type": "Debug",
+         "os": "Macos",
+         "arch": "x86_64"})
+    conanfile.settings = MockSettings(
+        {"build_type": "Debug",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    expected = "-arch arm64"
+    assert be.apple_arch_flag == expected
+    env = be.environment()
+    assert expected in env["CXXFLAGS"]
+    assert expected in env["CFLAGS"]
+    assert expected in env["LDFLAGS"]
+
+    # Only set when crossbuilding
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Debug",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    assert be.apple_arch_flag is None
+
+
+def test_apple_min_os_flag():
+    """Even when no cross building it is adjusted because it could target a Mac version"""
+    conanfile = ConanFileMock()
+    conanfile.conf = {"tools.apple:sdk_path": "/path/to/sdk"}
+    conanfile.settings = MockSettings(
+        {"build_type": "Debug",
+         "os": "Macos",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    expected = "-mmacosx-version-min=14"
+    assert be.apple_min_version_flag == expected
+    env = be.environment()
+    assert expected in env["CXXFLAGS"]
+    assert expected in env["CFLAGS"]
+    assert expected in env["LDFLAGS"]
+
+
+def test_apple_isysrootflag():
+    """Even when no cross building it is adjusted because it could target a Mac version"""
+    conanfile = ConanFileMock()
+    conanfile.conf = {"tools.apple:sdk_path": "/path/to/sdk"}
+    conanfile.settings_build = MockSettings(
+        {"build_type": "Debug",
+         "os": "Macos",
+         "arch": "x86_64"})
+    conanfile.settings = MockSettings(
+        {"build_type": "Debug",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    expected = "-isysroot /path/to/sdk"
+    assert be.apple_isysroot_flag == expected
+    env = be.environment()
+    assert expected in env["CXXFLAGS"]
+    assert expected in env["CFLAGS"]
+    assert expected in env["LDFLAGS"]
+
+    # Only set when crossbuilding
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Debug",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    assert be.apple_isysroot_flag is None
+
+
+def test_custom_defines():
+    conanfile = ConanFileMock()
+    conanfile.conf = {"tools.apple:sdk_path": "/path/to/sdk"}
+    conanfile.settings = MockSettings(
+        {"build_type": "RelWithDebInfo",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    be.defines = ["MyDefine1", "MyDefine2"]
+    env = be.environment()
+    assert "-DMyDefine1" in env["CPPFLAGS"]
+    assert "-DMyDefine2" in env["CPPFLAGS"]
+    assert "-DNDEBUG" in env["CPPFLAGS"]
+
+
+def test_custom_cxxflags():
+    conanfile = ConanFileMock()
+    conanfile.conf = {"tools.apple:sdk_path": "/path/to/sdk"}
+    conanfile.settings = MockSettings(
+        {"build_type": "RelWithDebInfo",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    be.cxxflags = ["MyFlag1", "MyFlag2"]
+    env = be.environment()
+    assert "MyFlag1" in env["CXXFLAGS"]
+    assert "MyFlag2" in env["CXXFLAGS"]
+    assert "-mios-version-min=14" in env["CXXFLAGS"]
+
+    assert "MyFlag" not in env["CFLAGS"]
+    assert "MyFlag" not in env["LDFLAGS"]
+
+
+def test_custom_cflags():
+    conanfile = ConanFileMock()
+    conanfile.conf = {"tools.apple:sdk_path": "/path/to/sdk"}
+    conanfile.settings = MockSettings(
+        {"build_type": "RelWithDebInfo",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    be.cflags = ["MyFlag1", "MyFlag2"]
+    env = be.environment()
+    assert "MyFlag1" in env["CFLAGS"]
+    assert "MyFlag2" in env["CFLAGS"]
+    assert "-mios-version-min=14" in env["CFLAGS"]
+
+    assert "MyFlag" not in env["CXXFLAGS"]
+    assert "MyFlag" not in env["LDFLAGS"]
+
+
+def test_custom_ldflags():
+    conanfile = ConanFileMock()
+    conanfile.conf = {"tools.apple:sdk_path": "/path/to/sdk"}
+    conanfile.settings = MockSettings(
+        {"build_type": "RelWithDebInfo",
+         "os": "iOS",
+         "os.version": "14",
+         "arch": "armv8"})
+    be = AutotoolsToolchain(conanfile)
+    be.ldflags = ["MyFlag1", "MyFlag2"]
+    env = be.environment()
+    assert "MyFlag1" in env["LDFLAGS"]
+    assert "MyFlag2" in env["LDFLAGS"]
+    assert "-mios-version-min=14" in env["LDFLAGS"]
+
+    assert "MyFlag" not in env["CXXFLAGS"]
+    assert "MyFlag" not in env["CFLAGS"]
diff --git a/conans/test/unittests/conan_build_info/new_build_info_test.py b/conans/test/unittests/conan_build_info/new_build_info_test.py
index 550bb0fcc56..678a0b7de19 100644
--- a/conans/test/unittests/conan_build_info/new_build_info_test.py
+++ b/conans/test/unittests/conan_build_info/new_build_info_test.py
@@ -96,6 +96,23 @@ def test_component_aggregation():
     assert ret.frameworkdirs == ["frameworkdir_c2", "frameworkdir_c1"]
 
 
+def test_cpp_info_sysroot_merge():
+    # If the value was already set is kept in the merge
+    one = NewCppInfo()
+    one.sysroot = "sys1"
+    two = NewCppInfo()
+    two.sysroot = "sys2"
+    one.merge(two)
+    assert one.sysroot == "sys1"
+
+    # If the value was not set it is assigned
+    one = NewCppInfo()
+    two = NewCppInfo()
+    two.sysroot = "sys2"
+    one.merge(two)
+    assert one.sysroot == "sys2"
+
+
 @pytest.mark.parametrize("aggregate_first", [True, False])
 def test_cpp_info_merge_aggregating_components_first(aggregate_first):
     cppinfo = NewCppInfo()


Code review comments:
diff_hunk: @@ -0,0 +1,270 @@
+from conans.model.version import Version
+
+
+def cppstd_flag(settings):
path: conan/tools/gnu/get_cppstd.py
text: @user1:
This file doesn't look like a ``gnu`` thing only, it might be common to cmake, meson and others

diff_hunk: @@ -0,0 +1,29 @@
+
+
+def cross_building(conanfile):
path: conan/tools/cross_building.py
text: @user1:
This is no longer true for 64->32 bits for example, and there is code in CMake that filters it. Not to change now, I understand this is an initial refactor moving things into scope, but we certainly need to consolidate all of this.