Repository: conan-io/conan

Issue:
[feature] Ability to identify if binaries can be executed on a particular platform
Typically there is made use of `tools.cross_building(self.settings)` to identify that for example test binaries can't be executed on a particular platform. Though this particular solution is not really sufficient to handle for example the case of running on a macOS with Apple Silicon (M1) chipset, as in that particular case you can execute both x86_64 and armv8 binaries without any issue (even without Rosetta enabled). 

Extending `tools.cross_building` with yet another parameter similar to `skip_x64_x86` seems not a good option. Therefore it would be good to have a dedicated method for this usecase like for example `tools.can_run()`.

Discussion:

Patch:
diff --git a/conan/tools/build/__init__.py b/conan/tools/build/__init__.py
index bc8411633..f93b3a4dd 100644
--- a/conan/tools/build/__init__.py
+++ b/conan/tools/build/__init__.py
@@ -1,2 +1,2 @@
 from conan.tools.build.cpu import build_jobs
-from conan.tools.build.cross_building import cross_building
+from conan.tools.build.cross_building import cross_building, can_run
diff --git a/conan/tools/build/cross_building.py b/conan/tools/build/cross_building.py
index 0e92ace86..9e86fae95 100644
--- a/conan/tools/build/cross_building.py
+++ b/conan/tools/build/cross_building.py
@@ -28,3 +28,14 @@ def get_cross_building_settings(conanfile):
                 os_host, arch_host)
     else:
         return os_host, arch_host, os_host, arch_host
+
+
+def can_run(conanfile):
+    """
+    Validates if the current build platform can run a file which is not for same arch
+    See https://github.com/conan-io/conan/issues/11035
+    """
+    allowed = conanfile.conf.get("tools.build.cross_building:can_run", check_type=bool)
+    if allowed is None:
+        return not cross_building(conanfile)
+    return allowed


Test patch:
diff --git a/conans/test/unittests/tools/build/__init__.py b/conans/test/unittests/tools/build/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/conans/test/unittests/tools/build/test_can_run.py b/conans/test/unittests/tools/build/test_can_run.py
new file mode 100644
index 000000000..f9556109d
--- /dev/null
+++ b/conans/test/unittests/tools/build/test_can_run.py
@@ -0,0 +1,66 @@
+import pytest
+
+from conans.test.utils.mocks import MockSettings, ConanFileMock
+from conan.tools.build import can_run
+
+
+class ConfigMock:
+    def __init__(self, run=None):
+        self.can_run = run
+
+    def get(self, conf_name, default=None, check_type=None):
+        return self.can_run
+
+
+@pytest.mark.parametrize("expected", [False, True])
+def test_can_run_explicit_config(expected):
+    """ When the config tools.build.cross_building:can_run is declared and evaluated (True|False),
+        can_run must return the same value.
+    """
+    config = ConfigMock(expected)
+    settings = MockSettings({"os": "Macos",
+                             "compiler": "apple-clang",
+                             "compiler.version": "11.0",
+                             "arch": "armv8"})
+    conanfile = ConanFileMock(settings)
+    conanfile.conf = config
+    assert expected == can_run(conanfile)
+
+
+@pytest.mark.parametrize("arch, expected", [("x86_64", False), ("armv8", True)])
+def test_can_run_cross_building(arch, expected):
+    """ When the config is None, and is cross-building, can_run must return False.
+    """
+    config = ConfigMock(None)
+    settings_build = MockSettings({"os": "Macos",
+                             "compiler": "apple-clang",
+                             "compiler.version": "11.0",
+                             "arch": "armv8"})
+    settings = MockSettings({"os": "Macos",
+                             "compiler": "apple-clang",
+                             "compiler.version": "11.0",
+                             "arch": arch})
+    conanfile = ConanFileMock()
+    conanfile.settings = settings
+    conanfile.settings_build = settings_build
+    conanfile.conf = config
+    assert expected == can_run(conanfile)
+
+
+def test_can_run_cross_building_with_explicit():
+    """ When the config is True or False, and is cross-building, can_run must follow the config.
+    """
+    config = ConfigMock(True)
+    settings_build = MockSettings({"os": "Macos",
+                             "compiler": "apple-clang",
+                             "compiler.version": "11.0",
+                             "arch": "armv8"})
+    settings = MockSettings({"os": "Macos",
+                             "compiler": "apple-clang",
+                             "compiler.version": "11.0",
+                             "arch": "x86_64"})
+    conanfile = ConanFileMock()
+    conanfile.settings = settings
+    conanfile.settings_build = settings_build
+    conanfile.conf = config
+    assert True == can_run(conanfile)