Repository: conan-io/conan

Issue:
add support for linux on s390/s390x
https://en.wikipedia.org/wiki/Linux_on_z_Systems

In our CI we are running "normal" Linux distributions like Ubuntu and Red Hat on s390/s390x.

To publish and fetch packages, we would need support for s390 (31bit, yes, gcc will need -m31) and s390x (64bit).

```
>>> import platform
>>> platform.system()
'Linux'
>>> platform.machine()
's390x'
>>> platform.processor()
's390x'
>>>
```
add support for linux on s390/s390x
https://en.wikipedia.org/wiki/Linux_on_z_Systems

In our CI we are running "normal" Linux distributions like Ubuntu and Red Hat on s390/s390x.

To publish and fetch packages, we would need support for s390 (31bit, yes, gcc will need -m31) and s390x (64bit).

```
>>> import platform
>>> platform.system()
'Linux'
>>> platform.machine()
's390x'
>>> platform.processor()
's390x'
>>>
```


Discussion:
Hi, we are going to need some help here. We have to know exactly which changes would Conan need to support this:

- Support new architectures in the `settings.yml` file.
- The flag for the architecture in the `compiler_flags.py` module
- CMake requires something? Other build helpers?

If you could try manually to add the changes and verify if it works for you would be nice, honestly, it is the first time I hear about these systems.
Hi, no problem, I can implement it myself and prepare a PR with all the changes as soon as I have some time.
Hi, we are going to need some help here. We have to know exactly which changes would Conan need to support this:

- Support new architectures in the `settings.yml` file.
- The flag for the architecture in the `compiler_flags.py` module
- CMake requires something? Other build helpers?

If you could try manually to add the changes and verify if it works for you would be nice, honestly, it is the first time I hear about these systems.
Hi, no problem, I can implement it myself and prepare a PR with all the changes as soon as I have some time.

Resolving patch:
diff --git a/conans/client/build/compiler_flags.py b/conans/client/build/compiler_flags.py
--- a/conans/client/build/compiler_flags.py
+++ b/conans/client/build/compiler_flags.py
@@ -31,10 +31,12 @@ def architecture_flag(compiler, arch):
         return ""
 
     if str(compiler) in ['gcc', 'apple-clang', 'clang', 'sun-cc']:
-        if str(arch) in ['x86_64', 'sparcv9']:
+        if str(arch) in ['x86_64', 'sparcv9', 's390x']:
             return '-m64'
         elif str(arch) in ['x86', 'sparc']:
             return '-m32'
+        elif str(arch) in ['s390']:
+            return '-m31'
     return ""
 
 
diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py
--- a/conans/client/conf/__init__.py
+++ b/conans/client/conf/__init__.py
@@ -13,12 +13,12 @@
 default_settings_yml = """
 # Only for cross building, 'os_build/arch_build' is the system that runs Conan
 os_build: [Windows, WindowsStore, Linux, Macos, FreeBSD, SunOS]
-arch_build: [x86, x86_64, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr]
+arch_build: [x86, x86_64, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x]
 
 # Only for building cross compilation tools, 'os_target/arch_target' is the system for
 # which the tools generate code
 os_target: [Windows, Linux, Macos, Android, iOS, watchOS, tvOS, FreeBSD, SunOS, Arduino]
-arch_target: [x86, x86_64, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr]
+arch_target: [x86, x86_64, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x]
 
 # Rest of the settings are "host" settings:
 # - For native building/cross building: Where the library/program will run.
@@ -43,7 +43,7 @@
     SunOS:
     Arduino:
         board: ANY
-arch: [x86, x86_64, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr]
+arch: [x86, x86_64, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x]
 compiler:
     sun-cc:
         version: ["5.10", "5.11", "5.12", "5.13", "5.14"]
diff --git a/conans/client/tools/oss.py b/conans/client/tools/oss.py
--- a/conans/client/tools/oss.py
+++ b/conans/client/tools/oss.py
@@ -70,6 +70,10 @@ def detected_architecture():
         return "armv7"
     elif "arm" in machine:
         return "armv6"
+    elif "s390x" in machine:
+        return "s390x"
+    elif "s390" in machine:
+        return "s390"
 
     return None
 
@@ -390,6 +394,10 @@ def get_gnu_triplet(os_, arch, compiler=None):
             machine = "sparc64"
         elif "sparc" in arch:
             machine = "sparc"
+        elif "s390x" in arch:
+            machine = "s390x-ibm"
+        elif "s390" in arch:
+            machine = "s390-ibm"
 
     if machine is None:
         raise ConanException("Unknown '%s' machine, Conan doesn't know how to "


Test patch:
diff --git a/conans/test/unittests/client/build/compiler_flags_test.py b/conans/test/unittests/client/build/compiler_flags_test.py
--- a/conans/test/unittests/client/build/compiler_flags_test.py
+++ b/conans/test/unittests/client/build/compiler_flags_test.py
@@ -32,12 +32,21 @@ def test_arch_flag(self):
             arch_flag = architecture_flag(arch='armv7', compiler=compiler)
             self.assertEqual(arch_flag, '')
 
+        for compiler in ("gcc", "clang", "sun-cc"):
+            arch_flag = architecture_flag(arch='s390', compiler=compiler)
+            self.assertEqual(arch_flag, '-m31')
+
+        for compiler in ("gcc", "clang", "sun-cc"):
+            arch_flag = architecture_flag(arch='s390x', compiler=compiler)
+            self.assertEqual(arch_flag, '-m64')
+
         arch_flag = architecture_flag(arch='x86', compiler='Visual Studio')
         self.assertEqual(arch_flag, '')
 
         arch_flag = architecture_flag(arch='x86_64', compiler='Visual Studio')
         self.assertEqual(arch_flag, '')
 
+
     def test_libcxx_flags(self):
         arch_define = libcxx_define(compiler='gcc', libcxx='libstdc++')
         self.assertEqual(arch_define, '_GLIBCXX_USE_CXX11_ABI=0')
diff --git a/conans/test/unittests/util/detected_architecture_test.py b/conans/test/unittests/util/detected_architecture_test.py
--- a/conans/test/unittests/util/detected_architecture_test.py
+++ b/conans/test/unittests/util/detected_architecture_test.py
@@ -3,63 +3,36 @@
 # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
 
 
+import mock
 import unittest
 
-from mock import mock
+from parameterized import parameterized
 
 from conans.client.tools.oss import detected_architecture
 
 
 class DetectedArchitectureTest(unittest.TestCase):
 
-    def test_various(self):
-
-        # x86
-        with mock.patch("platform.machine", mock.MagicMock(return_value='i386')):
-            self.assertEqual('x86', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='i686')):
-            self.assertEqual('x86', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='x86_64')):
-            self.assertEqual('x86_64', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='amd64')):
-            self.assertEqual('x86_64', detected_architecture())
-
-        # ARM
-        with mock.patch("platform.machine", mock.MagicMock(return_value='aarch64_be')):
-            self.assertEqual('armv8', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='armv8b')):
-            self.assertEqual('armv8', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='armv7l')):
-            self.assertEqual('armv7', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='armv6l')):
-            self.assertEqual('armv6', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='arm')):
-            self.assertEqual('armv6', detected_architecture())
-
-        # PowerPC
-        with mock.patch("platform.machine", mock.MagicMock(return_value='ppc64le')):
-            self.assertEqual('ppc64le', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='ppc64')):
-            self.assertEqual('ppc64', detected_architecture())
-
-        # MIPS
-        with mock.patch("platform.machine", mock.MagicMock(return_value='mips')):
-            self.assertEqual('mips', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='mips64')):
-            self.assertEqual('mips64', detected_architecture())
-
-        # SPARC
-        with mock.patch("platform.machine", mock.MagicMock(return_value='sparc')):
-            self.assertEqual('sparc', detected_architecture())
-
-        with mock.patch("platform.machine", mock.MagicMock(return_value='sparc64')):
-            self.assertEqual('sparcv9', detected_architecture())
+    @parameterized.expand([
+        ['i386', 'x86'],
+        ['i686', 'x86'],
+        ['x86_64', 'x86_64'],
+        ['amd64', 'x86_64'],
+        ['aarch64_be', 'armv8'],
+        ['armv8b', 'armv8'],
+        ['armv7l', 'armv7'],
+        ['armv6l', 'armv6'],
+        ['arm', 'armv6'],
+        ['ppc64le', 'ppc64le'],
+        ['ppc64', 'ppc64'],
+        ['mips', 'mips'],
+        ['mips64', 'mips64'],
+        ['sparc', 'sparc'],
+        ['sparc64', 'sparcv9'],
+        ['s390', 's390'],
+        ['s390x', 's390x']
+    ])
+    def test_various(self, mocked_machine, expected_arch):
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value=mocked_machine)):
+            self.assertEqual(expected_arch, detected_architecture(), "given '%s' expected '%s'" % (mocked_machine, expected_arch))
diff --git a/conans/test/unittests/util/tools_test.py b/conans/test/unittests/util/tools_test.py
--- a/conans/test/unittests/util/tools_test.py
+++ b/conans/test/unittests/util/tools_test.py
@@ -15,6 +15,7 @@
 from bottle import request, static_file
 from mock.mock import mock_open, patch
 from nose.plugins.attrib import attr
+from parameterized import parameterized
 from six import StringIO
 from six.moves.urllib.parse import quote
 
@@ -1162,171 +1163,50 @@ def get_manual_auth(user, password):
                        requester=requests, out=out)
         http_server.stop()
 
-    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", "armv6", "Linux", "armv6")
-        self.assertEqual(build, "arm-linux-gnueabi")
-        self.assertEqual(host, "arm-linux-gnueabi")
-
-        build, host = get_values("Linux", "sparc", "Linux", "sparcv9")
-        self.assertEqual(build, "sparc-linux-gnu")
-        self.assertEqual(host, "sparc64-linux-gnu")
-
-        build, host = get_values("Linux", "mips", "Linux", "mips64")
-        self.assertEqual(build, "mips-linux-gnu")
-        self.assertEqual(host, "mips64-linux-gnu")
-
-        build, host = get_values("Linux", "ppc64le", "Linux", "ppc64")
-        self.assertEqual(build, "powerpc64le-linux-gnu")
-        self.assertEqual(host, "powerpc64-linux-gnu")
-
-        build, host = get_values("Linux", "armv5te", "Linux", "arm_whatever")
-        self.assertEqual(build, "arm-linux-gnueabi")
-        self.assertEqual(host, "arm-linux-gnueabi")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "armv7hf")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-gnueabihf")
-
-        build, host = get_values("Linux", "x86", "Linux", "armv7hf")
-        self.assertEqual(build, "x86-linux-gnu")
-        self.assertEqual(host, "arm-linux-gnueabihf")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "x86")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "x86-linux-gnu")
-
-        build, host = get_values("Linux", "x86_64", "Windows", "x86", compiler="gcc")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "i686-w64-mingw32")
-
-        build, host = get_values("Linux", "x86_64", "Windows", "x86", compiler="Visual Studio")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "i686-windows-msvc")  # Not very common but exists sometimes
-
-        build, host = get_values("Linux", "x86_64", "Linux", "armv7hf")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-gnueabihf")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "armv7")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-gnueabi")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "armv6")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-gnueabi")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "armv8_32")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "aarch64-linux-gnu_ilp32")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "armv5el")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-gnueabi")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "armv5hf")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-gnueabihf")
-
-        build, host = get_values("Linux", "x86_64", "Android", "x86")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "i686-linux-android")
-
-        build, host = get_values("Linux", "x86_64", "Android", "x86_64")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "x86_64-linux-android")
-
-        build, host = get_values("Linux", "x86_64", "Android", "armv7")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-androideabi")
-
-        build, host = get_values("Linux", "x86_64", "Android", "armv7hf")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-androideabi")
-
-        build, host = get_values("Linux", "x86_64", "Android", "armv8")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "aarch64-linux-android")
-
-        build, host = get_values("Linux", "x86_64", "Android", "armv6")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "arm-linux-androideabi")
-
-        build, host = get_values("Linux", "x86_64", "Windows", "x86", compiler="gcc")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "i686-w64-mingw32")
-
-        build, host = get_values("Linux", "x86_64", "Windows", "x86_64", compiler="gcc")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "x86_64-w64-mingw32")
-
-        build, host = get_values("Windows", "x86_64", "Windows", "x86", compiler="gcc")
-        self.assertEqual(build, "x86_64-w64-mingw32")
-        self.assertEqual(host, "i686-w64-mingw32")
-
-        build, host = get_values("Windows", "x86_64", "Linux", "armv7hf", compiler="gcc")
-        self.assertEqual(build, "x86_64-w64-mingw32")
-        self.assertEqual(host, "arm-linux-gnueabihf")
-
-        build, host = get_values("Darwin", "x86_64", "Android", "armv7hf")
-        self.assertEqual(build, "x86_64-apple-darwin")
-        self.assertEqual(host, "arm-linux-androideabi")
-
-        build, host = get_values("Darwin", "x86_64", "Macos", "x86")
-        self.assertEqual(build, "x86_64-apple-darwin")
-        self.assertEqual(host, "i686-apple-darwin")
-
-        build, host = get_values("Darwin", "x86_64", "iOS", "armv7")
-        self.assertEqual(build, "x86_64-apple-darwin")
-        self.assertEqual(host, "arm-apple-darwin")
-
-        build, host = get_values("Darwin", "x86_64", "watchOS", "armv7k")
-        self.assertEqual(build, "x86_64-apple-darwin")
-        self.assertEqual(host, "arm-apple-darwin")
-
-        build, host = get_values("Darwin", "x86_64", "tvOS", "armv8")
-        self.assertEqual(build, "x86_64-apple-darwin")
-        self.assertEqual(host, "aarch64-apple-darwin")
-
-        build, host = get_values("Darwin", "x86_64", "tvOS", "armv8.3")
-        self.assertEqual(build, "x86_64-apple-darwin")
-        self.assertEqual(host, "aarch64-apple-darwin")
-
-        build, host = get_values("Darwin", "x86_64", "watchOS", "armv8_32")
-        self.assertEqual(build, "x86_64-apple-darwin")
-        self.assertEqual(host, "aarch64-apple-darwin")
-
-        build, host = get_values("Linux", "x86_64", "Linux", "ppc32")
-        self.assertEqual(build, "x86_64-linux-gnu")
-        self.assertEqual(host, "powerpc-linux-gnu")
-
-        build, host = get_values("Linux", "x86", "Linux", "ppc64")
-        self.assertEqual(build, "x86-linux-gnu")
-        self.assertEqual(host, "powerpc64-linux-gnu")
-
-        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"
+    @parameterized.expand([
+        ["Linux", "x86", None, "x86-linux-gnu"],
+        ["Linux", "x86_64", None, "x86_64-linux-gnu"],
+        ["Linux", "armv6", None, "arm-linux-gnueabi"],
+        ["Linux", "sparc", None, "sparc-linux-gnu"],
+        ["Linux", "sparcv9", None, "sparc64-linux-gnu"],
+        ["Linux", "mips", None, "mips-linux-gnu"],
+        ["Linux", "mips64", None, "mips64-linux-gnu"],
+        ["Linux", "ppc32", None, "powerpc-linux-gnu"],
+        ["Linux", "ppc64", None, "powerpc64-linux-gnu"],
+        ["Linux", "ppc64le", None, "powerpc64le-linux-gnu"],
+        ["Linux", "armv5te", None, "arm-linux-gnueabi"],
+        ["Linux", "arm_whatever", None, "arm-linux-gnueabi"],
+        ["Linux", "armv7hf", None, "arm-linux-gnueabihf"],
+        ["Linux", "armv6", None, "arm-linux-gnueabi"],
+        ["Linux", "armv7", None, "arm-linux-gnueabi"],
+        ["Linux", "armv8_32", None, "aarch64-linux-gnu_ilp32"],
+        ["Linux", "armv5el", None, "arm-linux-gnueabi"],
+        ["Linux", "armv5hf", None, "arm-linux-gnueabihf"],
+        ["Linux", "s390", None, "s390-ibm-linux-gnu"],
+        ["Linux", "s390x", None, "s390x-ibm-linux-gnu"],
+        ["Android", "x86", None, "i686-linux-android"],
+        ["Android", "x86_64", None, "x86_64-linux-android"],
+        ["Android", "armv6", None, "arm-linux-androideabi"],
+        ["Android", "armv7", None, "arm-linux-androideabi"],
+        ["Android", "armv7hf", None, "arm-linux-androideabi"],
+        ["Android", "armv8", None, "aarch64-linux-android"],
+        ["Windows", "x86", "Visual Studio", "i686-windows-msvc"],
+        ["Windows", "x86", "gcc", "i686-w64-mingw32"],
+        ["Windows", "x86_64", "gcc", "x86_64-w64-mingw32"],
+        ["Darwin", "x86_64", None, "x86_64-apple-darwin"],
+        ["Macos", "x86", None, "i686-apple-darwin"],
+        ["iOS", "armv7", None, "arm-apple-darwin"],
+        ["watchOS", "armv7k", None, "arm-apple-darwin"],
+        ["watchOS", "armv8_32", None, "aarch64-apple-darwin"],
+        ["tvOS", "armv8", None, "aarch64-apple-darwin"],
+        ["tvOS", "armv8.3", None, "aarch64-apple-darwin"]
+    ])
+    def get_gnu_triplet_test(self, os, arch, compiler, expected_triplet):
+        triplet = tools.get_gnu_triplet(os, arch, compiler)
+        self.assertEqual(triplet, expected_triplet,
+                          "triplet did not match for ('%s', '%s', '%s')" % (os, arch, compiler))
+
+    def get_gnu_triplet_on_windows_without_compiler_test(self):
         with self.assertRaises(ConanException):
             tools.get_gnu_triplet("Windows", "x86")