Using the Xcode 8.3 beta incarnation of swiftc, how do you generate an Arm7 or Arm64 binary?
I've tried the obvious argument -target-cpu arm64 which gives me a linker message <unknown>:0: warning: argument unused during compilation: '-mcpu=arm64'
ld: library not found for -lobjc and it plows ahead trying to build an x64 target.
Actual command:
swiftc -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/ -L /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib -F /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/ -swift-version 3 -target-cpu arm64 somefile.swift
you can use the sdk and target option to do this. Here is an example:
/Projects/Test $ cat main.swift
print("Hello world!");
Compiling for x86_64
/Projects/Test $ swiftc main.swift
/Projects/Test $ lipo -info main
Non-fat file: main is architecture: x86_64
/Projects/Test $ ./main
Hello world!
Compiling for armv7
/Projects/Test $ swiftc main.swift -sdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.2.sdk -target armv7-apple-ios8.1
/Projects/Test $ lipo -info main
Non-fat file: main is architecture: armv7
Compiling for arm64
/Projects/Test $ swiftc main.swift -sdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.2.sdk -target arm64-apple-ios8.1
/Projects/Test $ lipo -info main
Non-fat file: main is architecture: arm64
I wrote a script build.sh so that its easier to use:
#!/bin/sh
TARGET_MAC_VERSION=10.11
TARGET_IOS_VERSION=8.1
if [ "$#" -ne 2 ]; then
echo "Usage $0: <armv7/arm64/x86_64> <file>"
exit
fi
if [ "$1" != 'armv7' ] && [ "$1" != 'arm64' ] && [ "$1" != 'x86_64' ]; then
echo "Usage $0: <armv7/arm64/x86_64>"
exit
fi
if [ "$1" == 'x86_64' ]; then
SDK=macosx
TARGET="x86_64-macosx$TARGET_MAC_VERSION"
else
SDK=iphoneos
TARGET="$1-apple-ios$TARGET_IOS_VERSION"
fi
echo "xcrun -sdk $SDK swiftc $2 -target $TARGET"
xcrun -sdk $SDK swiftc $2 -target $TARGET
Output
$ ./build.sh armv7 main.swift
xcrun -sdk iphoneos swiftc main.swift -target armv7-apple-ios8.1
$ lipo -info main
Non-fat file: main is architecture: armv7
$ ./build.sh arm64 main.swift
xcrun -sdk iphoneos swiftc main.swift -target arm64-apple-ios8.1
$ lipo -info main
Non-fat file: main is architecture: arm64
$ ./build.sh x86_64 main.swift
xcrun -sdk macosx swiftc main.swift -target x86_64-macosx10.11
$ lipo -info main
Non-fat file: main is architecture: x86_64
Edit Note: Optimized the script based on the input from #jens. See the comments for more information.
Related
We can easily compile a Swift script with:
$ swiftc /path/to/script.swift -o /path/to/binary
However, that only compiles for the current architecture.
$ lipo -archs /path/to/binary
arm64
I found some commands to build for multiple architectures, but they seem to require setting up a new project. I don’t want or need to do that yet, for now I just want to compile a single script file easily, hence swiftc. Is there a way to do this?
As a bonus, does Rosetta 2 need to be installed to generate universal binaries, or is it possible to make them without it?
You would need to build the binary two times, for example, for a project that's targeting macOS, you would compile once with -target x86_64-apple-macos10.15 and the other one with -target arm64-apple-macos10.15.
After that, you would use lipo -create to stitch those together into a single file like this lipo -create <path/to/arm64-slice> <path/to/x86_64-slice> -output <path/to/universal/binary>.
This is how I did it:
➜ UniversalBinaryTest swiftc source.swift -target x86_64-apple-macos10.15 -o binary_x86-64
➜ UniversalBinaryTest lipo -archs binary_x86-64
x86_64
➜ UniversalBinaryTest swiftc source.swift -target arm64-apple-macos10.15 -o binary_arm64
➜ UniversalBinaryTest lipo -archs binary_arm64
arm64
➜ UniversalBinaryTest lipo -create binary_x86-64 binary_arm64 -output binary_universal
➜ UniversalBinaryTest lipo -archs binary_universal
x86_64 arm64
After all of that, you would probably want to re-sign the new binary.
Edit: Actually, it looks like lipo handles signing for you if both slices are signed:
➜ UniversalBinaryTest codesign -s - binary_x86-64
➜ UniversalBinaryTest codesign -vvv binary_x86-64
binary_x86-64: valid on disk
binary_x86-64: satisfies its Designated Requirement
➜ UniversalBinaryTest codesign -vvvvv binary_x86-64
binary_x86-64: valid on disk
binary_x86-64: satisfies its Designated Requirement
➜ UniversalBinaryTest codesign -s - binary_arm64
➜ UniversalBinaryTest lipo -create binary_x86-64 binary_arm64 -output binary_universal
➜ UniversalBinaryTest codesign -vvv binary_universal
binary_universal: valid on disk
binary_universal: satisfies its Designated Requirement
I want to set under Mac OSX the runtime path of an executable (for the linker) at compile time, such that shared libraries at non-standard locations are found by the dynamic linker at program start.
Under Linux this is possible with -Xlinker -rpath -Xlinker /path/to (or using -Wl,-rpath,/path/to) and under Solaris you can add -R/path/to to the compiler command line.
I found some information that Mac OS X gcc has -rpath support since 10.5, i.e. since ~ 2008.
I tried to get it working with a minimal example - without success:
$ cat blah.c
int blah(int b)
{
return b+1;
}
And:
$ cat main.c
#include <stdio.h>
int blah(int);
int main ()
{
printf("%d\n", blah(22));
return 0;
}
Compiled it like this:
$ gcc -c blah.c
$ gcc -dynamiclib blah.o -o libblah.dylib
$ gcc main.c -lblah -L`pwd` -Xlinker -rpath -Xlinker `pwd`/t
Now the test:
$ mkdir t
$ mv libblah.dylib t
$ ./a.out
dyld: Library not loaded: libblah.dylib
Referenced from: /Users/max/test/./a.out
Reason: image not found
Trace/BPT trap
Thus the question: How to I set the runtime path for the linker under Mac OSX?
Btw, setting DYLD_LIBRARY_PATH works - but I don't want to use this hack.
Edit: Regarding otool -L:
$ otool -L a.out
a.out:
libblah.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.1)
It seems that otool -L only prints the library names (and probable the locations at link time) the executable was linked against and no runtime path information.
Found by experimentation, and inspecting the command lines generated by Xcode for a reference rpath demo project by Dave Driblin:
otool -L shows you the install name of the linked libraries. To get #rpath to work, you need to change the install name of the library:
$ gcc -dynamiclib blah.o -install_name #rpath/t/libblah.dylib -o libblah.dylib
$ mkdir t ; mv libblah.dylib t/
$ gcc main.c -lblah -L`pwd`/t -Xlinker -rpath -Xlinker `pwd`
I'm running a script to build a static library for the device and the simulator to later be merged using lipo.
To build both versions I'm using the following commands:
xcodebuild -target ${L_NAME} -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target ${L_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
The problem is that no iphonesimulator version is created. Inside the Products folder only a Debug-iphoneos version exists.
I eventually found out the problem, I didn't have i386 as a valid architecture
I'm new to ios development, and I want to use the mp4v2 library. I have successfully compiled for iphone simulator, i386, but am having trouble compiling for the iphone architecture. Configuring/Make-ing for i386 was easy:
./configure --disable-gch --enable-ub=i386
However, using armv6/7 as a tag didn't work
./configure --disable-gch --enable-ub=armv6,armv7
While configuring worked, the make command led to the error below:
/bin/sh ./libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -arch i386 -arch armv6 -arch armv7 -I./include -I./include -I. -I. -Wall -Wformat -g -O2 -fvisibility=hidden -c -o src/3gp.lo src/3gp.cpp
libtool: compile: g++ -DHAVE_CONFIG_H -arch i386 -arch armv6 -arch armv7 -I./include -I./include -I. -I. -Wall -Wformat -g -O2 -fvisibility=hidden -c src/3gp.cpp -fno-common -DPIC -o src/.libs/3gp.o
llvm-g++-4.2: error trying to exec '/usr/bin/../llvm-gcc-4.2/bin/arm-apple-darwin11-llvm-g++-4.2': execvp: No such file or directory
llvm-g++-4.2: error trying to exec '/usr/bin/../llvm-gcc-4.2/bin/arm-apple-darwin11-llvm-g++-4.2': execvp: No such file or directory
lipo: can't figure out the architecture type of: /var/folders/b6/vmqqncd55k79nb1nc4x30nwr0000gn/T//cctU2lnr.out
make: *** [src/3gp.lo] Error 1
How do I compile for iphone?
I guess that this error is caused by trying to find cross compiler from system root path /usr/bin/../llvm-gcc-4.2/bin/arm-apple-darwin11-llvm-g++-4.2 instead of from Developer document.
A little stupid solution is create a symbolic link llvm-gcc-4.2 in system root path /usr, pointing to the real path.
I beleive you may need to verify your xcode-select(1) value so your path includes the new xcode release tree. The tools should have been found under /Applications/xcode with the latest release.
I was wondering if anyone knew how to configure FreeType in XCode for the iPhone SDK. I have been trying with no success.
Ideally you'll want to build using the latest tools, and as of the release of iOS 6.0 SDK, with a minimum SDK version of 4.3 and with builds for armv7 and armv7s.
Here is the methid I used to build freetype 2.4.10 for iOS. From the root of the freetype 2.4.10 source, do:
mkdir build-armv7
./configure --prefix=./build-armv7 --host=arm-apple-darwin --enable-static=yes --enable-shared=no \
CPPFLAGS="-arch armv7 -fpascal-strings -Os -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=4.3 -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/usr/include/libxml2 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk" \
CC=`xcrun -sdk iphoneos -find clang` \
CFLAGS="-arch armv7 -fpascal-strings -Os -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=4.3 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk" \
LD=`xcrun -sdk iphoneos -find ld` \
LDFLAGS="-arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk -miphoneos-version-min=4.3" \
AR=`xcrun -sdk iphoneos -find ar`
make
make install
Next, clean the build directory, and build again for armv7s:
make clean
mkdir build-armv7s
./configure --prefix=./build-armv7s --host=arm-apple-darwin --enable-static=yes --enable-shared=no \
CPPFLAGS="-arch armv7s -fpascal-strings -Os -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=4.3 -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/usr/include/libxml2 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk" \
CC=`xcrun -sdk iphoneos -find clang` \
CFLAGS="-arch armv7s -fpascal-strings -Os -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=4.3 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk" \
LD=`xcrun -sdk iphoneos -find ld` \
LDFLAGS="-arch armv7s -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk -miphoneos-version-min=4.3" \
AR=`xcrun -sdk iphoneos -find ar`
make
make install
Finally, combine the architectures into a single binary, and remove the unnecessary extra headers etc. for the second architecture (which are identical to the first architecture).
xcrun -sdk iphoneos lipo -create -arch armv7 build-armv7/lib/libfreetype.a -arch armv7s build-armv7s/lib/libfreetype.a -output libfreetype_universal.a
rm -rf build-armv7s
mv -f libfreetype_universal.a build-armv7/lib/libfreetype.a
mv build-armv7 build
I have; this blog post helped immensely:
http://robertcarlsen.net/2009/03/25/openframeworks-iphone-libs-593
(Plus, there are lots of examples lying around google that do similar things.
Use the configure script supplied with Freetype.
mkdir install_dir
If you are compiling for the simulator:
export CFLAGS = "-arch i386 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk"
./configure --prefix=install_dir
if you are compiling for a device:
export CFLAGS = "-arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk"
./configure --prefix=install_dir --host=arm-apple-darwin
and then
make
make install
You will now find the headers and lib in 'install_dir'.
the 'make install' step is important, as configure will setup the headers correctly. You can't just copy or use them directly from the source tree.
You can build for each platform (simulator and device) and then combine the libs into one multi-architechture lib using the 'lipo' tool.