Opened 17 months ago

Last modified 17 months ago

#66302 new defect

gcc12 universal variant has no effect

Reported by: JanWielemaker (Jan Wielemaker) Owned by:
Priority: Normal Milestone:
Component: ports Version: 2.8.0
Keywords: universal arm64 x68_64 Cc: cjones051073 (Chris Jones)
Port: gcc12

Description

Wondering about universal binaries created using gcc, I saw that the gcc12 port provides a universal variant and according to the Portfile, this should allow for x86_64 arm64 when compiled on arm (M1).

sudo port install gcc12 +universal works fine, but after that gcc-mp-12 -arch x86_64 still claims the architecture is not supported. Running port variants gcc12 says this, which also suggests the variant was not applied. I uninstalled all gcc12 ports and reinstalled the universal variant to no avail.

gcc12 has the variants:
[+]stdlib_flag: Enable stdlib command line flag to select c++ runtime
   universal: Build for multiple architectures

Would be great if this works because the performance for the swi-prolog port is a lot better with gcc, notably on x68_64.

Platform: MacOS 12.4 on Macbook Air M1

Change History (7)

comment:1 Changed 17 months ago by jmroot (Joshua Root)

There is no way to build a GCC that can target both x86_64 and arm64. You can get one that targets both i386 and x86_64 using multilib, which is what the fake "universal" variant does (it doesn't actually install a universal GCC on any platform.) It might be possible to build separate x86_64 and arm64 GCCs, one configured as a native compiler and one as a cross-compiler, depending on your hardware, and combine them somehow, but I suspect it wouldn't be as simple as a standard muniversal build. And you still wouldn't have a GCC that can target multiple architectures with a flag, you would have two different GCCs glued together, so the target arch would depend on which arch you run the binary as.

Getting this to work the way everyone wants would have to involve an updated version of the driver-driver that Apple used to ship to enable ppc and i386 universal builds with gcc-4.x.

comment:2 Changed 17 months ago by JanWielemaker (Jan Wielemaker)

Thanks. The fragment of the Portfile below caused me to hope for something better :(

if { ${os.platform} eq "darwin" && ${os.major} >= 20 } {
    platform i386 {
        configure.universal_archs x86_64 arm64
    }
    platform arm {
        configure.universal_archs x86_64 arm64
    }

A cross-compiler would be good enough for me. There are quite a few cross-compilers in Macports, but this one seems to be lacking and creating it doesn't look trivial ...

comment:3 Changed 17 months ago by jmroot (Joshua Root)

Cc: cjones051073 added

Hm, well maybe Chris (who added that fragment) knows something I don't.

comment:4 Changed 17 months ago by kencu (Ken)

the gcc10-bootstrap port is as close to a real cross compiler as we have for this, but still has a number of faults, and is not really a cross-compiler.

It should be able to build a universal binary arm64-x86/64 if running on an M1 system, though, using rosetta.

It lacks several important features, primary amongst them is a distinct universal driver ("driverdriver.c") and the different archs it can build currently have to run in the actual arch it is building for, so not exactly a cross-compiler, but again, on an M1, should probably work using rosetta.

With some minor tweaking it could become a cross compiler (where the compilers run in the machine's host arch rather than the target arch) but that would need more work.

https://github.com/macports/macports-ports/blob/master/lang/gcc10-bootstrap/Portfile

comment:5 in reply to:  description Changed 17 months ago by ryandesign (Ryan Carsten Schmidt)

Replying to JanWielemaker:

[...] Running port variants gcc12 says this, which also suggests the variant was not applied. [...]

gcc12 has the variants:
[+]stdlib_flag: Enable stdlib command line flag to select c++ runtime
   universal: Build for multiple architectures

This output is correct and normal. The annotations shown in e.g. port variants gcc12 (such as [+]) tell you what variants would be selected by default. They do not reflect the variants with which you have installed the port. To see the latter, run port installed gcc12.

comment:6 in reply to:  4 ; Changed 17 months ago by JanWielemaker (Jan Wielemaker)

Replying to kencu:

the gcc10-bootstrap port is as close to a real cross compiler as we have for this, but still has a number of faults, and is not really a cross-compiler.

Thanks. Is this simply a X86_64 gcc, i.e., running as x86_64 under Rosetta and producing x86_64 binaries? Even the same as I would get if I copy a gcc installation from an Intel Mac to the M1?

comment:7 in reply to:  6 Changed 17 months ago by kencu (Ken)

Replying to JanWielemaker:

Replying to kencu:

the gcc10-bootstrap port is as close to a real cross compiler as we have for this, but still has a number of faults, and is not really a cross-compiler.

Thanks. Is this simply a X86_64 gcc, i.e., running as x86_64 under Rosetta and producing x86_64 binaries? Even the same as I would get if I copy a gcc installation from an Intel Mac to the M1?

No, it closer to what you want. It is two compilers combined together:

$ file ./opt/local/libexec/gcc10-bootstrap/bin/gcc
./opt/local/libexec/gcc10-bootstrap/bin/gcc: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64]
./opt/local/libexec/gcc10-bootstrap/bin/gcc (for architecture x86_64):	Mach-O 64-bit executable x86_64
./opt/local/libexec/gcc10-bootstrap/bin/gcc (for architecture arm64):	Mach-O 64-bit executable arm64

$ file ./opt/local/libexec/gcc10-bootstrap/bin/x86_64-apple-darwin20-gcc
./opt/local/libexec/gcc10-bootstrap/bin/x86_64-apple-darwin20-gcc: Mach-O 64-bit executable x86_64

$ file ./opt/local/libexec/gcc10-bootstrap/bin/aarch64-apple-darwin20-gcc
./opt/local/libexec/gcc10-bootstrap/bin/aarch64-apple-darwin20-gcc: Mach-O 64-bit executable arm64

$ file ./opt/local/libexec/gcc10-bootstrap/lib/libstdc++.6.dylib
./opt/local/libexec/gcc10-bootstrap/lib/libstdc++.6.dylib: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit dynamically linked shared library x86_64] [arm64]
./opt/local/libexec/gcc10-bootstrap/lib/libstdc++.6.dylib (for architecture x86_64):	Mach-O 64-bit dynamically linked shared library x86_64
./opt/local/libexec/gcc10-bootstrap/lib/libstdc++.6.dylib (for architecture arm64):	Mach-O 64-bit dynamically linked shared library arm64

and you can use it somewhat clumsily with the muniversal portgroup to make fat binary:

$ port notes gcc10-bootstrap
--->  gcc10-bootstrap has the following notes:
  To use this bootstrap version of gcc instead of the default compiler, add the following lines to the Portfile:
  
  depends_lib-append      port:gcc10-bootstrap
  
  configure.cc            ${prefix}/libexec/gcc10-bootstrap/bin/gcc
  configure.cxx           ${prefix}/libexec/gcc10-bootstrap/bin/g++
  
  If you would like to build universal port with this compiler, you must use per target compiler. The easy way is using muniversal PG:
  
  PortGroup               muniversal 1.0
  
  if {${universal_possible} && [variant_isset universal]} {
      configure.cc        {}
      configure.cxx       {}
  
      foreach arch ${universal_archs_supported} {
          lappend merger_configure_env(${arch})  "CC=arch -arch ${arch} ${prefix}/libexec/gcc10-bootstrap/bin/gcc"
          lappend merger_configure_env(${arch})  "CXX=arch -arch ${arch} ${prefix}/libexec/gcc10-bootstrap/bin/g++"
      }
  } else {
      configure.cc        ${prefix}/libexec/gcc10-bootstrap/bin/gcc
      configure.cxx       ${prefix}/libexec/gcc10-bootstrap/bin/g++
  }

but the arm64 compiler is an arm64 and the x86_64 compiler is an x86_64 binary, so it will only work to build a fat binary on an arm64 mac.

That could be fixed, as above, so the whole compiler is written in one arch but can output two different arches, but even so, it is very clumsy to use, so I haven't bothered pushing this idea until somebody updates driverdriver.c to make it work right.

If someone wanted to push ahead on that idea it would be a bit convoluted to sort out the arch naming, so we'd probably need to add a "host" or "build" variant into the port to make it work. Just too messy, so I"m not doing it.

But for TODAY, it most likely CAN build a fat binary on an M1 Mac.

Note: See TracTickets for help on using tickets.