Building ARM code on OS X - ios

I am targeting the Cortex-A7 (ARMv7-A)
As a test:
bootstrap.s
.globl _start
_start:
mov sp,#0x00010000
bl main
hang: b hang
main.c
int main(void) { return 0; }
Trying:
$ as -arch armv7 -march=armv7-a -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 bootstrap.s -o bootstrap.o
$ file bootstrap.o
bootstrap.o: Mach-O object arm
$ clang -c -arch armv7 -march=armv7-a -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 main.c -o main.o
$ file main.o
notmain.o: Mach-O object arm
Confirms the compilation of Mach-O arm object files (also verified using hexdump, otool, gobjdump)
But now we try to link them together:
$ ld -e _start -arch armv7 bootstrap.o main.o -o foo
ld: warning: -ios_version_min not specified, assuming 6.0
ld: building for iOS, but linking in object file built for OSX, file 'bootstrap.o' for architecture armv7
And we have some issues. Not sure what's going on here. I haven't asked to link-in any iOS-related stuff. Using the -t linker flag confirms that no other objects are being linked in. Not sure why it thinks bootstrap.o is built for OS X when it clearly is a Mach-O arm file. Not sure if I'm passing the right flags to the assembler (pretty much all of them are undocumented?) or the linker
Note that this is for a bare-metal mini-project running on RPi2. I'm going to gobjcopy the linked executable object to a flat binary anyways. I'm just working with Mach-O since that's the only object type the system linker on OS X is capable of working with (and fat Mach-O). If I built a separate cross-compiler, I would be doing the exact same thing, instead I'd be linking ELF files before converting them to flat binary (I can output ELF32 files using clang/llvm anyways, I just cant link them). Seems silly to build a separate cross-compiler when clang/llvm is a perfectly suitable cross-compiler that's able to target my microarchitecture

Related

How to compile C into a universal library that works with iOS architectures

I'm trying to compile a very small amount of C source into a library that I can use in XCode for an iOS application.
The files are a single .c file and three header files. I'm very new to C, and no matter what I try I can't seem to get them to compile into a library that supports iOS architectures.
The files depend on the openssl library, and I've got that installed and working fine.
I just need to know the process of compiling these four files into a single library. I've found a plethora of information on the subject online, but I can't decipher which parts are necessary for what I'm trying to do.
I've tried the following:
gcc -fPIC -c main.c
gcc -shared -o mylib.so main.o -lcrypto -lssl
which seems to compile it for x86_64, (I've not tested the resulting file, just checked it's arch).
I've also tried
./configure --disable-shared --enable-utf8 --host=arm-apple-darwin CFLAGS="-arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk" CXXFLAGS="-arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk" LDFLAGS="-L." CC="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc" CXX="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++"
which only gives me errors
checking for arm-apple-darwin-gcc... no
checking for gcc... gcc
checking whether the C compiler works... no
configure: error: in `/Users/nathanf/compilec':
configure: error: C compiler cannot create executables
I've been scouring the internet for the last few days trying to figure this out, but it's so convoluted to cross compile just a few files and I'm frustrated so I came here for some input.
Any help would be greatly appreciated.

Error: ld: warning: ignoring file libfile01.a, file was built for archive which is not the architecture being linked (armv7): libfile01.a

I'm trying to compile a project developed in C language for iOS devices. It uses custom library file, libcurl, libcrypto, libssl and libpthread. I have successfully compiled it for Mac OS X, but having issues compiling it for iOS. Also, any help I try to find online is more of Xcode GUI help, and I need command line help for it. Need to compile it through commands instead of Xcode GUI.
First it needs to compile couple of C files, then make a static library file out of these compiled files, which further used when compiling a native binary.
This is how I generated iOS arm ouptut files from c files inside file01:
Store the iphoneos sdk path in environemnt variable:
CC="$(xcrun --sdk iphoneos9.2 --find clang) -isysroot $(xcrun --sdk iphoneos9.2 --show-sdk-path) -arch armv7 -arch armv7s -arch arm64 -arch armv6 -arch arm64"
Compile the c files in file01 with command:
$CC -c -O2 *.c
To check which architect these files are compiled for can be checked with this lipo command. Example:
$ lipo -info example_file01.o
Architectures in the fat file: example_file01.o are: armv7 armv7s armv6 arm64
To make a static library file I can get iOS ar file path using command:
$ xcrun --sdk iphoneos9.2 --find ar /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar
I could store the path in an environment variable, but it was not working throwing error not recognising ar command arguments rcu. So, used the ar path instead to create the library file with this command:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar rcu ../output/libfile01.a *.o
If checking which architectures this lib file supports it gives this output:
$ lipo -info ../output/libfile01.a
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: archive with no architecture specification: ../output/libfile01.a (can't determine architecture for it)
But, it should have given output similar to this one:
$ lipo -info ../ios/lib/libcurl.a
Architectures in the fat file: ../ios/lib/libcurl.a are: i386 armv7 armv7s x86_64 arm64
This is causing error when trying compiling files in using the generated static lib file with command:
$CC -o ../output/FinalProjectFile -O2 *.c ../output/libfile01.a ../ios/lib/libcurl.a ../ios/lib/libssl.a ../ios/lib/libcrypto.a -lpthread -lm
Error: ​ld: warning: ignoring file ../output/libfile01.a, file was built for archive which is not the architecture being linked (armv7): ../output/libfile01.a​
Thanks for help
I finally solved the issue by using different argument for ar.
Instead of using
$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar rcu ../output/libfile01.a *.o
used
$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar -rcs ../output/libfile01.a *.o
The only difference was it's -rcs instead of rcu.
When checking the info of this libfile it shows the output like this:
$ lipo -info ../output/libfile01.a
Architectures in the fat file: ../output/libfile01.a are: armv7 armv7s armv6 arm64

Method to determine whether a binary contains Bitcode no longer seems to work

In my search for a method to determine if a iOS binary was build with Bitcode, I found the following post:
How to check if a framework is BITCODE supported for Xcode7
Here, the following method was suggested to determine if bitcode is present in a binary:
$ otool -l libName.o | grep __LLVM
However, I have tried this on several binaries with no success. One of them is a library I know has bitcode since after I changed the flag on its project a build error went away. Another one of them is a binary for a file extension, build using Archive. And another is for apple watch.
I believe all of the above binaries should have Bitcode, and yet I always get no results from the above command.
Does anyone know any other method that works with the latest binaries?
I'm using XCode 7.2 and 10.10.5 in case it matters.
UPDATE: Here is an example of a file which is supposed to have bitcode but the above command doesn't return anything. It is a binary from a test File Provider. I generated it via Archive and Deploy as Ad Hoc, and made sure the setting for bitcode was on for the target.
https://www.dropbox.com/s/eyuzs5j1t7nsq6t/CustomDocumentProviderFileProvider?dl=0
If you have a fat binary, then you need to run otool -l on a specific slice. For instance, in the following example I chose arm64:
otool -arch arm64 -l MyFramework.framework/MyFramework | grep -a4 __LLVM
In the output you should check:
if there is at least one section named __LLVM
if the size is greater than zero
This seems to be a problem with otool as reported here. Use file to get a list of architectures and then supply the architecture to otool. Given a fat binary with Bitcode for armv7, arm64, i386 and x86_64:
$ file lib.a
lib.a: Mach-O universal binary with 4 architectures
lib.a (for architecture armv7): current ar archive random library
lib.a (for architecture i386): current ar archive random library
lib.a (for architecture x86_64): current ar archive random library
lib.a (for architecture arm64): current ar archive random library
$ otool -arch armv7 -l lib.a | grep bitcode
sectname __bitcode
According to this question, otool does not report Bitcode for x86_64 and i368.
CustomDocumentProviderFileProvider does not seem to contain Bitcode:
$ file CustomDocumentProviderFileProvider
CustomDocumentProviderFileProvider: Mach-O universal binary with 2 architectures
CustomDocumentProviderFileProvider (for architecture armv7): Mach-O executable arm
CustomDocumentProviderFileProvider (for architecture arm64): Mach-O 64-bit executable
$ otool -arch armv7 -l CustomDocumentProviderFileProvider | grep bit
$
Disclaimer: I'm the author of LibEBC.
You can use ebcutil to determine whether bitcode is present in any binary (Mach-O, ELF) or library (.a/.dylib/.so).
https://github.com/JDevlieghere/LibEBC
As of today, the technique which works for me is the one mentioned in this answer from another SO thread. Specifically, for a (dynamic) framework named MyLib and containing those two device architectures:
otool -arch armv7 MyLib.framework/MyLib | grep LLVM
otool -arch arm64 MyLib.framework/MyLib | grep LLVM

Cross compiling with a makefile on Mac

I've been writing a makefile which will need to compile for multiple platforms. Right now I only need to compile for iOS, but as I already know that I'll need to support Mac OS X in a near future I've also been looking on how to compile for that as well. Notice that I'm not using Xcode. That's not an option as the project will also have to support other platforms.
I already have a makefile compiling for iPhone. It's working (tested on the simulator, even) but I still have a few doubts.
Specifically I've read about many tools and right now I'm a bit confused about some of them:
xcodebuild and clang I get clang, it's a compiler, but what about xcodebuild? Does it just use clang for compiling and also runs some tests? Are there upsides to using? Downsides?
libtool vs ar pretty much the same thing. How do these differ? I've read that ar should be followed by a call to ran lib (although it's not clear on the why), so there must be downsides, but which? Edit: forgot to include lipo in the discussion
Finally, and I hope I'm not getting off topic, I'm generating fat files for iphoneos and iphonesimulator. Here's how; first I compile for each platform:
ifeq ($(ARCH), iphoneos)
ARCHFLAGS = -arch armv7 -arch armv7s -arch arm64
else
ARCHFLAGS = -arch i386 -arch x86_64
endif
ifeq ($(ARCH), iphoneos)
VERFLAGS = -miphoneos-version-min=7.0
else
VERFLAGS = -mios-simulator-version-min=7.0
endif
CC = $(shell xcrun --sdk $(ARCH) --find clang)
CFLAGS := -isysroot $(shell xcrun --sdk $(ARCH) --show-sdk-path)
CFLAGS += $(ARCHFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) $(CFLAGS) -c $< -o $#
Some flags, variables, and rules are omitted. This generates two sets of .o files. I then use ar (should it be libtool?):
AR = ar
ARFLAGS = crv
$(BINARY): $(OBJECTS) # This rule depends on the previous one
$(AR) $(ARFLAGS) $(BINARY) $(OBJECTS)
By now I have a static library (.a) file for each platform. I proceed to generate the fat file:
$(LIBTOOL) $(LIBTOOLFLAGS) -o $(call libfile,iphone,debug) $(call libfile,iphoneos,debug) $(call libfile,iphonesimulator,debug)
Note: libfile is a function which returns the file name for the given configuration.
Two questions now:
Could I just skip the generation of the two separate .a files and jump to the the fat file by specifying ARCHFLAGS = -arch armv7 -arch armv7s -arch arm64 -arch i386 -arch x86_64? That is, all platforms in a single call. Is it the same thing?
This was the closest I got to listing supported architectures (not a good option, I'd say). Could I just list all (or a subset) of them, generate an "obese" (lol) file and expect the compiler to optimize the file's size when linked against an actual implementation? Or are fat files shipped with the final product?
Thank you for reading so far.
Best.

Error compiling freetype2 library for arm7 with OSX gcc: `limits.h: No such file or directory

I am trying to compile the freetype2 library for arm7, using Xcode's command line tools in OSX. I am using the following parameterisation of the project's configure script:
Compiling FreeType for iPhone?
These errors were produced when running the script:
configure:3426: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc -E conftest.c
In file included from conftest.c:10:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin10/4.2.1/include/limits.h:15:25: error: limits.h: No such file or directory
configure:3426: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc -E -traditional-cpp conftest.c
conftest.c:12: error: assert.h: No such file or directory
configure:3426: /lib/cpp conftest.c
/Volumes/DATA/filestore/development/libs/c/freetype2/extract/2.5.3/builds/unix/configure: line 1600: /lib/cpp: No such file or directory
configure:3465: result: /lib/cpp
configure:3485: /lib/cpp conftest.c
/Volumes/DATA/filestore/development/libs/c/freetype2/extract/2.5.3/builds/unix/configure: line 1600: /lib/cpp: No such file or directory
I can see that the missing files actually do exist in the directories output in the error messages.
CFLAGS and LDFLAGS contain the following parameter, which should allow for the inclusion of system header files:
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/
The other odd thing that I noticed with these error messages, is that the architecture identifier in the directory structures is i686-apple-darwin10. The -arch armv7 compiler flag is being used, so why are i686-apple-darwin10 directories being inspected at all?
* UPDATED *
I also tried parameterising the configure script as per another example:
https://stackoverflow.com/a/12594507/1704014
The following error terminated its execution:
checking for suffix of native executables... ld: library not found for -lcrt1.10.6.o
collect2: ld returned 1 exit status
configure: error: native C compiler is not working
This also indicates that a different target architecture (OSX 10.6) is being built against, not arm7.
Any help much appreciated.
The problem in my OSX build environment was the Xcode command line tools installation. I reinstalled the latest distribution of the tools, and was able to compile successfully from then on.
To build the freetype2 library for arm7 and arm7s architectures, I found the following suggested commands useful:
https://stackoverflow.com/a/12594507/1704014

Resources