Skip to content

Commit e088647

Browse files
committed
Fix target triple for real iOS device
1 parent 9f06ad1 commit e088647

2 files changed

Lines changed: 49 additions & 19 deletions

File tree

README.md

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,25 @@ Build LLVM for iOS (physical device and simulator)
77
From [the official instructions](https://llvm.org/docs/GettingStarted.html):
88

99
```shell
10-
git clone https://github.com/llvm/llvm-project.git # Alternatively, download and extract the monorepo source code from https://releases.llvm.org/download.html
10+
# Alternative to git clone is to download and extract the monorepo source code from https://releases.llvm.org/download.html
11+
git clone https://github.com/llvm/llvm-project.git
1112
cd llvm-project
1213
mkdir build
1314
cd build
1415
cmake -G <generator> [options] ../llvm
1516
```
1617

17-
Our script [buildllvm-iOS.sh](buildllvm-iOS.sh) and [buildllvm-iOS-Simulator.sh](buildllvm-iOS-Simulator.sh) build LLVM, Clang and LLD for iOS and iOS simulator respectively. We disable various stuffs such as `terminfo` since there is no terminal in iOS; otherwise, there will be problem when linking in Xcode. Needs:
18+
Our script [buildllvm-iOS.sh](buildllvm-iOS.sh) and [buildllvm-iOS-Simulator.sh](buildllvm-iOS-Simulator.sh) build LLVM, Clang, LLD and LibC++ for iOS and iOS simulator respectively.
19+
We disable various stuffs such as `terminfo` since there is no terminal in iOS; otherwise, there will be problem when linking in Xcode.
20+
Needs:
1821
* [Xcode](https://developer.apple.com/xcode/): Download from app store.
1922
* [CMake](https://cmake.org/download/): See [installation instruction](https://tudat.tudelft.nl/installation/setupDevMacOs.html) to add to PATH.
2023
* [Ninja](https://github.com/ninja-build/ninja/releases): Download and extract the ninja executable to `~/Downloads` folder.
2124

2225
Once the tools are ready, run the script in the `llvm-project` top folder (or `llvm-project-VERSION` if you download the source zipped package instead of cloning).
23-
Once the build process is completed, the library and include headers should be available at `~/Download/LLVM-iOS` or `~/Download/LLVM-iOS-Simulator`.
26+
27+
Once the build process is completed, the library and include headers should be installed at `~/Download/LLVM-iOS` or `~/Download/LLVM-iOS-Simulator`.
28+
(We will subsequently refer to these directories as the _LLVM installation dir_.)
2429

2530
Before being able to use in Xcode, in the built folder, we first need to move the `lib/clang/` and `lib/cmake` and `lib/*.dylib` out of `lib/`:
2631
```shell
@@ -31,13 +36,14 @@ mv lib/cmake lib2/
3136
mv lib/*.dylib lib2/
3237
```
3338
Otherwise, iOS will crash when loading dynamic libraries.
34-
Maybe remove the unnecessary stuffs in `bin` as well.
35-
Running our script [prepare-llvm.sh](prepare-llvm.sh) in the LLVM installation folder i.e. `~/Download/LLVM-iOS` or `~/Download/LLVM-iOS-Simulator` will perform the necessary set-up.
39+
Running our script [prepare-llvm.sh](prepare-llvm.sh) in the LLVM installation dir will perform the necessary set-up.
40+
41+
Optionally, you could move the `liblld*` to `lib2` as well and the `bin` since it's unlikely you need binary linkage and the `clang` command line program in iOS app.
3642

3743
Our Sample iOS Project
3844
----------------------
3945

40-
We provide a sample iOS app project in the [Sample/](Sample) folder; no license attached so feel free to do whatever you want with it.
46+
We provide a sample iOS app project in the [Sample/](Sample) folder; _no license attached_ so feel free to do whatever you want with it.
4147
In this project, we use Clang's C interpreter example located in `examples/clang-interpreter/main.cpp` of Clang source code to interpret a simple C++ program.
4248
(The file was renamed to `Interpreter.cpp` to fit in with iOS development style.)
4349
The code is pretty much copied verbatim except for some minor modifications, namely:
@@ -48,18 +54,24 @@ The code is pretty much copied verbatim except for some minor modifications, nam
4854
```c++
4955
// llvm::llvm_shutdown();
5056
```
51-
so that you can call `clangInterpret` again in the app. Originally, the example was a one-shot command line program where this makes sense.
57+
so that you can _call `clangInterpret` again_ in the app.
58+
This line only makes sense in the original program because it was a one-shot command line program.
5259

5360
3. We add a third parameter
5461
```c++
5562
llvm::raw_ostream &errorOutputStream
5663
```
57-
to `clangInterpret` and replace all `llvm::errs()` with `errorOutputStream` so we can capture the compilation output and pass it back to the app front-end to display to users.
64+
to `clangInterpret` and replace all `llvm::errs()` with `errorOutputStream` so we can capture the compilation output and pass it back to the app front-end to display to the user.
65+
66+
4. **For real iOS device**: The implementation of [`llvm::sys::getProcessTriple()`](https://github.com/llvm/llvm-project/blob/master/llvm/lib/Support/Host.cpp) is currently bogus according to the implementation of [`JITTargetMachineBuilder::detectHost()`](https://github.com/llvm/llvm-project/blob/master/llvm/lib/ExecutionEngine/Orc/JITTargetMachineBuilder.cpp): _FIXME: getProcessTriple is bogus. It returns the host LLVM was compiled on, rather than a valid triple for the current process._
67+
So we need to add the appropriate conditional compilation directive `#if TARGET_OS_SIMULATOR ... #else ... #endif` to give it the correct triple. (The platform macro is documented at `<TargetConditionals.h>`.)
68+
69+
In the latest version, you should be able to edit the program, interpret it and see the output in the app UI.
5870

59-
In the latest version, you should be able to edit the program, interpret it and see the output.
6071
Before building the project, you need to copy the LLVM installation folder, say `~/Download/LLVM-iOS-Simulator`, to the root folder of the project like this
6172
```shell
62-
cp ~/Download/LLVM-iOS-Simulator LLVM # Assuming at Sample project folder
73+
# At Sample project folder:
74+
cp ~/Download/LLVM-iOS-Simulator LLVM
6375
```
6476
Here, we copy the `LLVM-iOS-Simulator` to build the app and run it on the simulator.
6577

@@ -68,7 +80,8 @@ Here, we copy the `LLVM-iOS-Simulator` to build the app and run it on the simula
6880

6981
Read on for details on how to create and configure your own project.
7082

71-
**Known Limitation**: For simulator, can only build **Debug** version only! The current app does not work on real device yet!
83+
**Known Limitation**: For simulator, can only build **Debug** version only!
84+
The current app does not work on real device yet (UI is OK but cannot interpret)!
7285

7386
Behind the Scene: Configure iOS App Xcode Project
7487
-------------------------------------------------
@@ -77,12 +90,7 @@ These days, you probably want to write your app in _Swift_ whereas LLVM library
7790
```
7891
Swift <-> Objective-C <-> C++
7992
```
80-
A typical approach will be using
81-
* Swift: anything iOS-related (UI, file system, Internet, ...)
82-
* Objective-C: simple class say `LLVMBridge` to expose service such as compilation; basically to convert data types between C++ and Swift such as Swift's `Data` to Objective-C's `NSData` to C++'s buffer `char*`.
83-
* C++: actual implementation of processing functionality.
84-
85-
Go to [Further Readings](#further-readings) for more details.
93+
Go to [Further Readings](#further-readings) for more details on Swift-C++ interoperability.
8694

8795
1. Create a new iOS app project in Xcode and copy an LLVM installation to the project folder.
8896
Unfortunately, LLVM cannot build fat binary for iOS at the moment so we have to manually switch between the two LLVM installations when we switch testing between real iOS device (ARM) or iOS simulator (x86_64).
@@ -102,10 +110,12 @@ Add a new item `$(PROJECT_DIR)/LLVM/include`.
102110
Again, go to **Build settings** your project and search for `bridg` and you should find **Objective-C Bridging Header** under **Swift Compiler - General**.
103111
Set it to `PROJECT_NAME/LLVMBridge.h` or if you are using more than just LLVM, a header file of your choice (but that header should include `LLVMBridge.h`).
104112

113+
**Note**: Only Objective-C classes in *Objective-C Bridging Header* are visible to Swift!
114+
105115
![Objective-C Bridging Header Setting](ObjCBridgeHeader.png)
106116

107117
At this point, we should be able to run the project on iOS simulator.
108-
**To build the app on real iOS device, an extra step is needed.**
118+
**To build the app for real iOS devices, an extra step is needed.**
109119

110120
5. Since we are using a bunch of precompiled static libraries (and not the actual C++ source code in our app), we need to disable bitcode. Search for `bitcod` and set **Enable Bitcode** setting to `No`.
111121

@@ -116,7 +126,7 @@ Now you are ready to make use of LLVM glory.
116126
Further Readings
117127
----------------
118128

119-
You might want to start with _Anthony Nguyen_'s
129+
To start, you might want to start with _Anthony Nguyen_'s
120130
[Using C++ in Objective-C iOS app: My first walk](https://medium.com/@nguyenminhphuc/using-c-in-objective-c-ios-app-my-first-walk-77319d94a940)
121131
for a quick intro on how to make use of C++ in Objective-C.
122132
(Note that both C++ and Objective-C are extensions of C and reduces to C.)
@@ -125,5 +135,14 @@ An easy read on Objective-C and Swift interoperability could be found in
125135
by _RDerik_.
126136
Combining these two articles is the basis for our Sample app.
127137

138+
A typical approach to allow C++ in Swift-based iOS app will be using
139+
* _Swift_ : Anything iOS-related (UI, file system access, Internet, ...)
140+
* _Objective-C_ : Simple classes (like `LLVMBridge` in our Sample app) to expose service written in C++.
141+
The main role is to convert data types between C++ and Swift.
142+
For example: Swift's `Data` to Objective-C's `NSData` to C++'s buffer `char*` (and length).
143+
* _C++_ : Actual implementation of processing functionality.
144+
145+
**Tip**: When writing bridging classes, you should use `NSData` for arguments instead of `NSString` and leave the `String <-> Data` conversion to Swift since you will want a `char*` in C++ anyway.
146+
128147
_Apple_'s [Programming with Objective-C](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011210)
129148
is fairly useful in helping us write the Objective-C bridging class `LLVMBridge`: Once we pass to C++, we are in our home turf.

Sample/Sample/Interpreter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include <TargetConditionals.h>
10+
911
#include "clang/Basic/DiagnosticOptions.h"
1012
#include "clang/CodeGen/CodeGenAction.h"
1113
#include "clang/Driver/Compilation.h"
@@ -73,9 +75,14 @@ class SimpleJIT {
7375

7476
public:
7577
static Expected<std::unique_ptr<SimpleJIT>> Create() {
78+
#if TARGET_OS_SIMULATOR
7679
auto JTMB = JITTargetMachineBuilder::detectHost();
7780
if (!JTMB)
7881
return JTMB.takeError();
82+
#else
83+
// FIXME: Memory leaks
84+
auto JTMB = new JITTargetMachineBuilder(Triple("arm64-apple-darwin"));
85+
#endif
7986

8087
auto TM = JTMB->createTargetMachine();
8188
if (!TM)
@@ -129,7 +136,11 @@ int clangInterpret(int argc, const char **argv, llvm::raw_ostream &errorOutputSt
129136
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
130137
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
131138

139+
#if TARGET_OS_SIMULATOR
132140
const std::string TripleStr = llvm::sys::getProcessTriple();
141+
#else
142+
const std::string TripleStr = "arm64-apple-darwin";
143+
#endif
133144
llvm::Triple T(TripleStr);
134145

135146
// Use ELF on Windows-32 and MingW for now.

0 commit comments

Comments
 (0)