Open fxcoudert opened 3 years ago
there's some old statement about "walking before running" ;-)
There are a number of things we never implemented in GCC because we had no iPhoneOS/iOS/tvOS/watchOS support - e.g. min versions etc. My guess is that those will affect the way in which SDK headers get used. Probably not rocket science to add what's needed (but we'll have to add the validation of xxOS versions in place of that used for macOS).
(conjecture) --disable-multilib
is probably needed because the versioning is all "unexpected" and thus the rules for what to use and what to include are probably wrong (or at least somewhat off).
[when starting on the Arm64 port] I went through an exercise of comparing what the clang driver produced in response to various permutations of --xxxxx-version-min, archxxx, etc. .. and it's somewhat complex ..
it's likely that the code-gen is not too much wrong but the configury and packaging will need working through...
of course, we have no support for Arm iPhoneOS at all (no Mach-O backend stuff for the Arm port) - so you would have to ensure that the configury did not try to do that.
@iains what would be the best way, in your opinion, for GCC to make a difference between iOS and macOS on ARM, both being aarch64-apple-darwin
triplets?
I know “walk before you run”, but to be honest I think for some limited use cases, we're not far from having a Fortran compiler for iOS, which is something people have been asking for a really long time. It would enable things like scipy and other scientific software. The limited use case could be “generating object files and static libraries” to link in a bigger project, for example.
(long[er] term)
That is somewhat confusing - actually, IIRC, clang uses -target xxxxx-apple-darwin == iOS and xxxxx-apple-macos[x]NN.MM == MacOS .. and then some things extra for tvOS and watchOS .. I'd need to run through the exercise again.
It's a plan to get the darwin port to recognise "-target" and try to harmonise at least the user-facing command line options with those of clang.
=== (short[er] term)
I think that if we can let the backend know we're targeting iOS, probably we don't need to do too much heavy lifting.
1) Implement -miphoneos-min-version (or whatever is the most reasonable one for iOS)
2) go through the Darwin specs and add in the ones reflecting the right actions (especially making sure that the assembler and linker are called correctly)
3) See if we need some configure-level change to deal with this (I hope not)
My concern is the the backend is experimental and has known issues; you understand that, I understand that - but once published for end users , be prepared for complaints that "it don't work".
sigh if only all the end users cared enough to fund at least one full-time Darwin engineer .. that would still be hardly enough .. but at least a step in the right direction (the Linux distros have a team of toolchain engineers, after all).
@iains I know I've been trying to figure out ways we could get funding to improve the state of things… don't know good ways, it seems some open source is now funded through foundations (like Gates for some machine learning toolkits, etc)
-target xxxxx-apple-darwin == iOS
In clang, xxxxx-apple-darwin
implies macOS. See for eg: https://github.com/llvm/llvm-project/blob/62ec4ac90738a5f2d209ed28c822223e58aaaeb7/llvm/unittests/ADT/TripleTest.cpp#L1184-L1186
xxxxx-apple-darwin20
is internally xxxxx-apple-macosx11.0
. You need xxxxx-apple-ios
for iphoneOS.
In my experience xxxxx-apple-darwin
for clang
implies both macOS an iOS. That is a bother, as x86_64-apple-darwin
means both MacOS and the iOS simulator, and arm64-apple-darwin
means both MacOS running on the new processor and iOS running on a phone. xxxxx-apple-ios
also works, but it is less often used.
there are two places that count ;
the user-facing command lines - (which go to the driver) which accept a combination of -arch and -mxxxxxx-min-version etc, etc. and produces ....
... an internal target triple which is passed to clang -cc1 / clang -cc1as
GCC also has a driver (that's what you get when you type gcc ...
) and Darwin has driver code to normalise some of these things; In particular, to ensure that cc1
gets sensible options and that __ENVIRONMENT_MACOSX_VERSION_MIN__
gets set to a valid/sensible value. That also means that we can select appropriate values to pass on to the assembler (which for many cases actually calls back to the Xcode as
which, in turn, calls clang -cc1as
) and the linker.
We have not, so far, implemented the equivalent checks and balances for iOS. So I'd say "all bets are probably off" about how the SDK headers are interpreted and values passed to the assembler / linker.
You might be lucky - but I expect that currently we're lying to both the assembler and linker (claiming to be macOS when you really wanted iOS).
An update of progress by myself, I have successfully been able to compile gmp, mpc, mpfr for iOS and made sure they work. I've also done most of the other gcc dependencies including binutils
I am building on linux, so things may be a little different: So far, I've managed to get configure and make to run, but when configuring gcc itself, it fails with the following log as the c compiler is unable to work: https://paste.debian.net/1185250/
What is bizarre is that configure does not respect the host of the initial configuration (which was aarch64-apple-darwin) rather, it sees the host as the build system
Edit: manually going to the Build folder and rerunning make works
I am documenting here my notes on how to use this branch to set up a cross-compiler to aarch64-apple-darwin (ideally iOS, not macOS) from x86_64-apple-darwin. I hope you don't mind Iain :) The goal is actually to produce an iOS cross-compiler.
I managed to get something working with:
../gcc/configure --prefix=/tmp \ --build=x86_64-apple-darwin20 --target=aarch64-apple-darwin20 \ --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl \ --with-native-system-header-dir=/usr/include \ --with-sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk \ AS_FOR_TARGET=/usr/bin/as LD_FOR_TARGET=/usr/bin/ld \ NM_FOR_TARGET=/usr/bin/nm RANLIB_FOR_TARGET=/usr/bin/ranlib \ AR_FOR_TARGET=/usr/bin/ar LIPO_FOR_TARGET=/usr/bin/lipo \ --disable-multilib
Some notes on this:
- it's important to set
build
and nothost
, as GCC otherwise thinks it's setting up a Canadian cross (which fails) on linux, this is not possible as when configure is testing the compiler, it gets an exec format error. Somehow, we need to tell gcc to use --host and --target for ios
@demhademha the procedure discussed here only works for a macOS host machine, because it's using the multi-arch Apple compiler/assembler/linker.
Thank you for the work so far.
How did you get the cross-compiler to actually target iOS after it is compiled?
Since I haven't found an explicit way to target iOS rather than macOS, I get:
clang: warning: using sysroot for 'iPhoneOS' but targeting 'MacOSX' [-Wincompatible-sysroot]
and
ld: building for iOS, but linking in object file built for macOS, file 'cfortran_test.o' for architecture arm64
Is there some flag to specify that I am building for iOS? I am currently just using "-arch arm64", as gfortran does not seem to support "-target".
You need both -arch arm64
and -miphoneos-version-min=14.0
. I've had to edit some files to make sure the compiler inserts -miphoneos-version-min=14.0
instead of -mmacosx-version-min=11.0
. The result is a compiler that can only compile for iOS, which is fine for me but not for distribution.
As @fxcoudert said, the command line to compile is a bit large:
# !!! make sure it's /usr/local/bin/gcc and not /usr/bin/gcc
../gcc_arm/configure --build=x86_64-apple-darwin20 --target=aarch64-apple-darwin20 \
--prefix="/usr/local" \
--disable-multilib \
--disable-libssp \
--disable-libstdcxx \
--enable-languages=c,fortran \
--with-ld="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
AR="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar" \
LD="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
AS="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/as" \
RANLIB="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" \
NM="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/nm" \
AR_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar" \
LD_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
AS_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/as" \
RANLIB_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" \
REAL_LD_FILE_NAME="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
NM_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/nm" \
LIPO="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo" \
LIPO_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo" \
CFLAGS_FOR_TARGET="-miphoneos-version-min=14.0" \
CXXFLAGS_FOR_TARGET="-miphoneos-version-min=14.0"\
LDFLAGS_FOR_TARGET="-miphoneos-version-min=14.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -lSystem"\
--with-native-system-header-dir=/usr/include \
--with-sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
Just a note: There's also iPhone Simulator, Watch Simulator, Apple TV Simulator, Mac Catalyst, DriverKit as well as bridgeOS targets.
From ld(1) on iOS
-platform_version platform min_version sdk_version
This is set to indicate the platform, oldest supported version of that
platform that output is to be used on, and the SDK that the output was
built against. platform is a numeric value as defined in <mach-
o/loader.h>, or it may be one of the following strings:
• macos
• ios
• tvos
• watchos
• bridgeos
• mac-catalyst
• ios-simulator
• tvos-simulator
• watchos-simulator
• driverkit
Specifying a newer min or SDK version enables the linker to assume fea‐
tures of that OS or SDK in the output file. The format of min_version
and sdk_version is a version number such as 10.13 or 10.14
_syslog$DARWIN_EXTSN
was not exist on iOS, but you can find the source from syslog
Note that for the 64-bit version watchOS have 32-bit pointers on a 64-bit CPU (much like x32 in this regard), and is called arm64_32, which is a different ABI.
I'm trying to follow the instructions in the OP on macOS Monterey x86 but it fails at libgcc_s.dylib:
The only difference from OP is that I added --enable-languages=c,fortran
at the end of the configure command line.
Any ideas?
EDIT: pthread_jit_write_protect_np
is not supported on iOS. I simply commented it out in libgcc/config/aarch64/heap-trampoline.c
(blamed commit) but ideally it would use a macro.
I am documenting here my notes on how to use this branch to set up a cross-compiler to aarch64-apple-darwin (ideally iOS, not macOS) from x86_64-apple-darwin. I hope you don't mind Iain :) The goal is actually to produce an iOS cross-compiler.
I managed to get something working with:
Some notes on this:
build
and nothost
, as GCC otherwise thinks it's setting up a Canadian cross (which fails)sysroot
for iOS is theiPhoneOS.sdk
SDK (weird name…)*_FOR_TARGET
are important, as they are not automatically detected by gcc*_FOR_TARGET
need to have an absolute path, otherwise the configure script will discard them (I don't fully understand why, and this cause a lot of pain to figure out)--disable-multilib
would be needed, but without it, GCC tries to build two variants ofaarch64-apple-darwin20
: a normal one and alp64
one. This feels like a bug, really.What is the result? Well, the compiler builds and most of the runtime libraries do, as well.
ld
warning:I'm not sure where in GCC we're creating macOS-specific code, but it may be from passing the linker the
-mmacosx-version-min=
option in various places.libgfortran
fails to build withimplicit declaration of function ‘getentropy’
, because on the iOS SDK,getentropy
exists (thus configure finds it in the system libraries) but it's not declared (and you're not supposed to use it, it's considered a private API). If I bypass this, the build succeeds.libssp
fails (not that I care much) with_2023 edit:
DSYMUTIL_FOR_TARGET=/usr/bin/dsymutil
is also needed now._