├── Screenshots
├── Screenshot1.png
├── Screenshot2.png
├── DisableBitcode.png
├── ObjCBridgeHeader.png
├── Screenshot_Real_iPhone1.png
└── Screenshot_Real_iPhone2.png
├── Sample
├── Assets.xcassets
│ ├── Contents.json
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── SampleApp.swift
├── Sample.entitlements
├── LLVMBridge.h
├── Info.plist
├── LLVMBridge.mm
├── ContentView.swift
└── Interpreter.cpp
├── .gitignore
├── LICENSE
├── .github
└── workflows
│ └── main.yml
├── README.md
└── Sample.xcodeproj
└── project.pbxproj
/Screenshots/Screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/light-tech/LLVM-On-iOS/HEAD/Screenshots/Screenshot1.png
--------------------------------------------------------------------------------
/Screenshots/Screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/light-tech/LLVM-On-iOS/HEAD/Screenshots/Screenshot2.png
--------------------------------------------------------------------------------
/Screenshots/DisableBitcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/light-tech/LLVM-On-iOS/HEAD/Screenshots/DisableBitcode.png
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Screenshots/ObjCBridgeHeader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/light-tech/LLVM-On-iOS/HEAD/Screenshots/ObjCBridgeHeader.png
--------------------------------------------------------------------------------
/Screenshots/Screenshot_Real_iPhone1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/light-tech/LLVM-On-iOS/HEAD/Screenshots/Screenshot_Real_iPhone1.png
--------------------------------------------------------------------------------
/Screenshots/Screenshot_Real_iPhone2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/light-tech/LLVM-On-iOS/HEAD/Screenshots/Screenshot_Real_iPhone2.png
--------------------------------------------------------------------------------
/Sample/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Sample/SampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SampleApp.swift
3 | // Sample
4 | //
5 | // Created by Lightech on 10/24/2048.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct SampleApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Sample/Sample.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Finder
2 | .DS_Store
3 |
4 | # Xcode - User files
5 | xcuserdata/
6 |
7 | **/*.xcodeproj/project.xcworkspace/*
8 | !**/*.xcodeproj/project.xcworkspace/xcshareddata
9 |
10 | **/*.xcodeproj/project.xcworkspace/xcshareddata/*
11 | !**/*.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
12 |
13 | **/*.playground/playground.xcworkspace/*
14 | !**/*.playground/playground.xcworkspace/xcshareddata
15 |
16 | **/*.playground/playground.xcworkspace/xcshareddata/*
17 | !**/*.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
18 |
19 | llvm-project/
20 | libffi/
21 | tools/
22 | LLVM**.xcframework/
23 |
24 |
--------------------------------------------------------------------------------
/Sample/LLVMBridge.h:
--------------------------------------------------------------------------------
1 | //
2 | // LLVMBridge.h
3 | // Declaration of Objective-C class LLVMBridge to expose C++ services of LLVM to Swift
4 | // For simplicity, this file is also used as Swift-ObjC bridging header in this sample project
5 | //
6 | // Created by Lightech on 10/24/2048.
7 | //
8 |
9 | #ifndef LLVMBridge_h
10 | #define LLVMBridge_h
11 |
12 | #import
13 |
14 |
15 | /// Class to encapsulate the interpreter's output
16 | @interface LLVMInterpreterOutput : NSObject
17 |
18 | @property NSString* _Nullable compilationOutput;
19 | @property NSString* _Nullable programOutput;
20 |
21 | @end
22 |
23 |
24 | /// Class (intended to be single-instanced) to provide LLVM C++ service to Swift front-end
25 | @interface LLVMBridge : NSObject
26 |
27 | // Interpret the C++ source code file
28 | - (nonnull LLVMInterpreterOutput*)interpretProgram:(nonnull NSData*)fileName;
29 |
30 | @end
31 |
32 | #endif /* LLVMBridge_h */
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 light-tech
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Sample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 |
28 | UIApplicationSupportsIndirectInputEvents
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Sample/LLVMBridge.mm:
--------------------------------------------------------------------------------
1 | //
2 | // LLVMBridge.mm
3 | // LLVMBridge Implementation, pretty much just forwarding calls to C++
4 | //
5 | // Created by Lightech on 10/24/2048.
6 | //
7 |
8 | #include
9 | #include
10 | #include
11 | #include "llvm/Support/raw_ostream.h"
12 |
13 | #import "LLVMBridge.h"
14 |
15 | // Declaration for clangInterpret method, implemented in Interpreter.cpp
16 | // TODO Might want to extract a header
17 | int clangInterpret(int argc, const char **argv, llvm::raw_ostream &errorOutputStream);
18 |
19 | // Let's hope that this method is exported in the app's binary
20 | // Need extern "C" to avoid name mangling so that interpreter can find it
21 | std::string programOutputString;
22 | llvm::raw_string_ostream programOutputStream(programOutputString);
23 | extern "C" void AppConsolePrint(const char *str) {
24 | programOutputStream << str;
25 | }
26 |
27 | // Helper function to construct NSString from a null-terminated C string (presumably UTF-8 encoded)
28 | NSString* NSStringFromCString(const char *text) {
29 | return [NSString stringWithUTF8String:text];
30 | }
31 |
32 | /// Implementation of LLVMInterpreterOutput
33 | @implementation LLVMInterpreterOutput
34 | {
35 | }
36 | @end /* implementation LLVMInterpreterOutput */
37 |
38 | /// Implementation of LLVMBridge
39 | @implementation LLVMBridge
40 | {
41 | }
42 |
43 | - (nonnull LLVMInterpreterOutput*)interpretProgram:(nonnull NSData*)fileName
44 | {
45 | // Prepare null terminate string from fileName buffer
46 | char input_file_path[1024];
47 | memcpy(input_file_path, fileName.bytes, fileName.length);
48 | input_file_path[fileName.length] = '\0';
49 |
50 | // Print out the program for inspection.
51 | printf("\n\n<<>>\n<<<%s>>>\n\n", input_file_path);
52 | auto file = fopen(input_file_path, "rb");
53 | if (file != NULL) {
54 | char c;
55 | while ((c = fgetc(file)) != EOF) printf("%c", c);
56 | fclose(file);
57 | }
58 | printf("\n\n<<>>\n\n");
59 |
60 | // Invoke the interpreter
61 | const char* argv[] = { "clang", input_file_path };
62 | std::string errorString;
63 | programOutputString = ""; // reset program output
64 | llvm::raw_string_ostream errorOutputStream(errorString);
65 | clangInterpret(2, argv, errorOutputStream);
66 |
67 | // Return compilation and program ouput
68 | LLVMInterpreterOutput *result = [[LLVMInterpreterOutput alloc] init];
69 | errorString = errorOutputStream.str(); // Needed to flush the output
70 | programOutputString = programOutputStream.str();
71 | printf("\n\nCompilation output: %s\n", errorString.c_str());
72 | result.compilationOutput = NSStringFromCString(errorString.c_str());
73 | result.programOutput = NSStringFromCString(programOutputString.c_str());
74 |
75 | return result;
76 | }
77 |
78 | @end /* implementation LLVMBridge */
79 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build LLVM XCFrameworks for Release
2 | on: [push]
3 | jobs:
4 | prepare-build-tools:
5 | runs-on: macos-11
6 | if: ${{ false }}
7 | steps:
8 | - uses: actions/checkout@v3
9 | - run: ./build-tools.sh
10 | - run: |
11 | curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
12 | unzip ninja-mac.zip
13 | mv ninja tools/bin
14 | - run: tar -cJf tools.tar.xz tools/
15 | - uses: actions/upload-artifact@v3
16 | with:
17 | name: tools
18 | path: tools.tar.xz
19 |
20 | build-libffi:
21 | runs-on: macos-11
22 | strategy:
23 | matrix:
24 | platformArch: [iphoneos, iphonesimulator, iphonesimulator-arm64, maccatalyst, maccatalyst-arm64]
25 | steps:
26 | - uses: actions/checkout@v3
27 | - name: Build libffi for ${{ matrix.platformArch }}
28 | run: source build-llvm.sh && build_libffi ${{ matrix.platformArch }}
29 | - run: tar -cJf libffi-${{ matrix.platformArch }}.tar.xz libffi-${{ matrix.platformArch }}/
30 | - uses: actions/upload-artifact@v3
31 | with:
32 | name: libffi-${{ matrix.platformArch }}
33 | path: libffi-${{ matrix.platformArch }}.tar.xz
34 |
35 | build-llvm:
36 | needs: build-libffi # prepare-build-tools
37 | runs-on: macos-12
38 | strategy:
39 | matrix:
40 | platformArch: [iphoneos, iphonesimulator, iphonesimulator-arm64, maccatalyst, maccatalyst-arm64]
41 | timeout-minutes: 1200
42 | steps:
43 | - uses: actions/checkout@v3
44 | - uses: actions/download-artifact@v3
45 | - name: Extract artifacts
46 | run: find . -name "*.tar.xz" -exec tar xzf {} \;
47 | - run: brew install ninja
48 | - name: Build LLVM for ${{ matrix.platformArch }}
49 | run: source build-llvm.sh && build_llvm ${{ matrix.platformArch }}
50 | - run: tar -cJf LLVM-${{ matrix.platformArch }}.tar.xz LLVM-${{ matrix.platformArch }}/
51 | - uses: actions/upload-artifact@v3
52 | with:
53 | name: LLVM-${{ matrix.platformArch }}
54 | path: LLVM-${{ matrix.platformArch }}.tar.xz
55 |
56 | create-xcframework:
57 | needs: build-llvm
58 | runs-on: macos-12
59 | steps:
60 | - uses: actions/checkout@v3
61 | - uses: actions/download-artifact@v3
62 | - name: Extract artifacts
63 | run: find . -name "*.tar.xz" -exec tar xzf {} \;
64 |
65 | - name: Create XCFramework for Intel Macs
66 | run: source build-llvm.sh && create_xcframework iphoneos iphonesimulator maccatalyst
67 | - run: tar -cJf LLVM_Intel.xcframework.tar.xz LLVM.xcframework
68 | - uses: actions/upload-artifact@v3
69 | with:
70 | name: LLVM_Intel
71 | path: LLVM_Intel.xcframework.tar.xz
72 |
73 | - uses: actions/upload-artifact@v3
74 | with:
75 | name: libclang
76 | path: libclang.tar.xz
77 |
78 | - name: Create XCFramework for M1 Macs
79 | run: source build-llvm.sh && rm -rf LLVM.xcframework && create_xcframework iphoneos iphonesimulator-arm64 maccatalyst-arm64
80 | - run: tar -cJf LLVM_M1.xcframework.tar.xz LLVM.xcframework
81 | - uses: actions/upload-artifact@v3
82 | with:
83 | name: LLVM_M1
84 | path: LLVM_M1.xcframework.tar.xz
85 |
--------------------------------------------------------------------------------
/Sample/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Sample
4 | //
5 | // Created by Lightech on 10/24/2048.
6 | //
7 |
8 | import SwiftUI
9 |
10 | // Path to the app's ApplicationSupport directory where we will put a.k.a. hide our source code
11 | let applicationSupportURL = try! FileManager.default.url(for: .applicationSupportDirectory,
12 | in: .userDomainMask,
13 | appropriateFor: nil,
14 | create: true)
15 |
16 | // Global instance of LLVMBridge
17 | let llvm: LLVMBridge = LLVMBridge()
18 |
19 | struct ContentView: View {
20 | @Environment(\.horizontalSizeClass) var sizeClass
21 |
22 | @State var program: String = """
23 | extern "C" void printf(const char* fmt, ...);
24 |
25 | extern "C" void AppConsolePrint(const char *str);
26 |
27 | int main() {
28 | printf("Hello world!");
29 | AppConsolePrint("Hello world!");
30 | return 0;
31 | }
32 | """
33 |
34 | @State var compilationOutput: String = ""
35 | @State var programOutput: String = ""
36 |
37 | var body: some View {
38 | if (sizeClass == .compact) {
39 | TabView {
40 | VStack {
41 | Button("Interpret Sample Program", action: interpretSampleProgram)
42 | TextEditor(text: $program)
43 | .disableAutocorrection(true)
44 | .font(.body.monospaced())
45 | }.tabItem {
46 | Image(systemName: "doc.plaintext")
47 | Text("Source code")
48 | }
49 |
50 | VStack {
51 | Text(compilationOutput)
52 | Divider()
53 | Text(programOutput)
54 | }.tabItem {
55 | Image(systemName: "greaterthan.square")
56 | Text("Output")
57 | }
58 | }
59 | } else {
60 | VStack {
61 | Button("Interpret Sample Program", action: interpretSampleProgram)
62 | .padding()
63 | HStack {
64 | TextEditor(text: $program)
65 | .disableAutocorrection(true)
66 | .font(.body.monospaced())
67 | Divider()
68 | VStack {
69 | Text(compilationOutput)
70 | Divider()
71 | Text(programOutput)
72 | }
73 | }
74 | }
75 | }
76 | }
77 |
78 | func interpretSampleProgram() {
79 | // Prepare a sample C++ source code file hello.cpp
80 | let filePath = applicationSupportURL.appendingPathComponent("hello.cpp")
81 |
82 | FileManager.default.createFile(atPath: filePath.path,
83 | contents: program.data(using: .utf8)!,
84 | attributes: nil)
85 |
86 | // Compile and interpret the program
87 | print("Interpret sample program at ", filePath)
88 | let output = llvm.interpretProgram(filePath.path.data(using: .utf8)!)
89 | compilationOutput = output.compilationOutput!
90 | programOutput = output.programOutput!
91 | }
92 | }
93 |
94 | // Disable smart quote (replacing ' and " with Unicode characters) as this prevents compilation
95 | // https://stackoverflow.com/questions/66432017/disable-auto-replacement-of-punctuation-in-swiftui-texteditor
96 | // This does not work on Mac Catalyst: change in System preferences > Keyboard > Text > for Double/Single Quotes, choose the last quote style (amongst the 8 possible types).
97 | // https://developer.apple.com/forums/thread/124410
98 | // Note that simply uncheck "Use smart quotes and dashes" does not work either.
99 | extension UITextView {
100 | open override var frame: CGRect {
101 | didSet {
102 | self.smartQuotesType = UITextSmartQuotesType.no
103 | }
104 | }
105 | }
106 |
107 | struct ContentView_Previews: PreviewProvider {
108 | static var previews: some View {
109 | ContentView()
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Sample/Interpreter.cpp:
--------------------------------------------------------------------------------
1 | //===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===//
2 | //
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 | // See https://llvm.org/LICENSE.txt for license information.
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 | //
7 | //===----------------------------------------------------------------------===//
8 |
9 | #include
10 |
11 | #include "clang/Basic/DiagnosticOptions.h"
12 | #include "clang/CodeGen/CodeGenAction.h"
13 | #include "clang/Driver/Compilation.h"
14 | #include "clang/Driver/Driver.h"
15 | #include "clang/Driver/Tool.h"
16 | #include "clang/Frontend/CompilerInstance.h"
17 | #include "clang/Frontend/CompilerInvocation.h"
18 | #include "clang/Frontend/FrontendDiagnostic.h"
19 | #include "clang/Frontend/TextDiagnosticPrinter.h"
20 | #include "llvm/ADT/SmallString.h"
21 | #include "llvm/ExecutionEngine/ExecutionEngine.h"
22 | #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
23 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
24 | #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
25 | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
26 | #include "llvm/ExecutionEngine/SectionMemoryManager.h"
27 | #include "llvm/IR/DataLayout.h"
28 | #include "llvm/IR/Mangler.h"
29 | #include "llvm/IR/Module.h"
30 | #include "llvm/Support/FileSystem.h"
31 | #include "llvm/Support/Host.h"
32 | #include "llvm/Support/ManagedStatic.h"
33 | #include "llvm/Support/Path.h"
34 | #include "llvm/Support/TargetSelect.h"
35 | #include "llvm/Support/raw_ostream.h"
36 | #include "llvm/Target/TargetMachine.h"
37 |
38 | using namespace clang;
39 | using namespace clang::driver;
40 |
41 | // This function isn't referenced outside its translation unit, but it
42 | // can't use the "static" keyword because its address is used for
43 | // GetMainExecutable (since some platforms don't support taking the
44 | // address of main, and some platforms can't implement GetMainExecutable
45 | // without being given the address of a function in the main executable).
46 | std::string GetExecutablePath(const char *Argv0, void *MainAddr) {
47 | return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
48 | }
49 |
50 | namespace llvm {
51 | namespace orc {
52 |
53 | class SimpleJIT {
54 | private:
55 | ExecutionSession ES { std::move(*SelfExecutorProcessControl::Create()) };
56 | std::unique_ptr TM;
57 | const DataLayout DL;
58 | MangleAndInterner Mangle{ES, DL};
59 | JITDylib &MainJD{ES.createBareJITDylib("")};
60 | RTDyldObjectLinkingLayer ObjectLayer{ES, createMemMgr};
61 | IRCompileLayer CompileLayer{ES, ObjectLayer,
62 | std::make_unique(*TM)};
63 |
64 | static std::unique_ptr createMemMgr() {
65 | return std::make_unique();
66 | }
67 |
68 | SimpleJIT(
69 | std::unique_ptr TM, DataLayout DL,
70 | std::unique_ptr ProcessSymbolsGenerator)
71 | : TM(std::move(TM)), DL(std::move(DL)) {
72 | llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
73 | MainJD.addGenerator(std::move(ProcessSymbolsGenerator));
74 | }
75 |
76 | public:
77 | static Expected> Create() {
78 | #ifdef __aarch64__
79 | auto JTMB = new JITTargetMachineBuilder(Triple("arm64-apple-darwin")); // FIXME: Memory leaks here
80 | #else
81 | auto JTMB = JITTargetMachineBuilder::detectHost();
82 | if (!JTMB)
83 | return JTMB.takeError();
84 | #endif
85 |
86 | auto TM = JTMB->createTargetMachine();
87 | if (!TM)
88 | return TM.takeError();
89 |
90 | auto DL = (*TM)->createDataLayout();
91 |
92 | auto ProcessSymbolsGenerator =
93 | DynamicLibrarySearchGenerator::GetForCurrentProcess(
94 | DL.getGlobalPrefix());
95 |
96 | if (!ProcessSymbolsGenerator)
97 | return ProcessSymbolsGenerator.takeError();
98 |
99 | return std::unique_ptr(new SimpleJIT(
100 | std::move(*TM), std::move(DL), std::move(*ProcessSymbolsGenerator)));
101 | }
102 |
103 | const TargetMachine &getTargetMachine() const { return *TM; }
104 |
105 | Error addModule(ThreadSafeModule M) {
106 | return CompileLayer.add(MainJD, std::move(M));
107 | }
108 |
109 | Expected findSymbol(const StringRef &Name) {
110 | return ES.lookup({&MainJD}, Mangle(Name));
111 | }
112 |
113 | Expected getSymbolAddress(const StringRef &Name) {
114 | auto Sym = findSymbol(Name);
115 | if (!Sym)
116 | return Sym.takeError();
117 | return Sym->getAddress();
118 | }
119 | };
120 |
121 | } // end namespace orc
122 | } // end namespace llvm
123 |
124 | llvm::ExitOnError ExitOnErr;
125 |
126 | int clangInterpret(int argc, const char **argv, llvm::raw_ostream &errorOutputStream) {
127 | // This just needs to be some symbol in the binary; C++ doesn't
128 | // allow taking the address of ::main however.
129 | void *MainAddr = (void*) (intptr_t) GetExecutablePath;
130 | std::string Path = GetExecutablePath(argv[0], MainAddr);
131 | IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions();
132 | TextDiagnosticPrinter *DiagClient =
133 | new TextDiagnosticPrinter(errorOutputStream, &*DiagOpts);
134 |
135 | IntrusiveRefCntPtr DiagID(new DiagnosticIDs());
136 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
137 |
138 | #ifdef __aarch64__
139 | const std::string TripleStr = "arm64-apple-darwin";
140 | #else
141 | const std::string TripleStr = llvm::sys::getProcessTriple();
142 | #endif
143 |
144 | llvm::Triple T(TripleStr);
145 |
146 | // Use ELF on Windows-32 and MingW for now.
147 | #ifndef CLANG_INTERPRETER_COFF_FORMAT
148 | if (T.isOSBinFormatCOFF())
149 | T.setObjectFormat(llvm::Triple::ELF);
150 | #endif
151 |
152 | ExitOnErr.setBanner("clang interpreter");
153 |
154 | Driver TheDriver(Path, T.str(), Diags);
155 | TheDriver.setTitle("clang interpreter");
156 | TheDriver.setCheckInputsExist(false);
157 |
158 | // FIXME: This is a hack to try to force the driver to do something we can
159 | // recognize. We need to extend the driver library to support this use model
160 | // (basically, exactly one input, and the operation mode is hard wired).
161 | SmallVector Args(argv, argv + argc);
162 | Args.push_back("-fsyntax-only");
163 | std::unique_ptr C(TheDriver.BuildCompilation(Args));
164 | if (!C)
165 | return 0;
166 |
167 | // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate.
168 |
169 | // We expect to get back exactly one command job, if we didn't something
170 | // failed. Extract that job from the compilation.
171 | const driver::JobList &Jobs = C->getJobs();
172 | if (Jobs.size() != 1 || !isa(*Jobs.begin())) {
173 | SmallString<256> Msg;
174 | llvm::raw_svector_ostream OS(Msg);
175 | Jobs.Print(OS, "; ", true);
176 | Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
177 | return 1;
178 | }
179 |
180 | const driver::Command &Cmd = cast(*Jobs.begin());
181 | if (llvm::StringRef(Cmd.getCreator().getName()) != "clang") {
182 | Diags.Report(diag::err_fe_expected_clang_command);
183 | return 1;
184 | }
185 |
186 | // Initialize a compiler invocation object from the clang (-cc1) arguments.
187 | const llvm::opt::ArgStringList &CCArgs = Cmd.getArguments();
188 | std::unique_ptr CI(new CompilerInvocation);
189 | CompilerInvocation::CreateFromArgs(*CI, CCArgs, Diags);
190 |
191 | // Show the invocation, with -v.
192 | if (CI->getHeaderSearchOpts().Verbose) {
193 | errorOutputStream << "clang invocation:\n";
194 | Jobs.Print(errorOutputStream, "\n", true);
195 | errorOutputStream << "\n";
196 | }
197 |
198 | // FIXME: This is copied from cc1_main.cpp; simplify and eliminate.
199 |
200 | // Create a compiler instance to handle the actual work.
201 | CompilerInstance Clang;
202 | Clang.setInvocation(std::move(CI));
203 |
204 | // Create the compilers actual diagnostics engine.
205 | Clang.createDiagnostics(DiagClient, false);
206 | if (!Clang.hasDiagnostics())
207 | return 1;
208 |
209 | // Infer the builtin include path if unspecified.
210 | if (Clang.getHeaderSearchOpts().UseBuiltinIncludes &&
211 | Clang.getHeaderSearchOpts().ResourceDir.empty())
212 | Clang.getHeaderSearchOpts().ResourceDir =
213 | CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
214 |
215 | // Create and execute the frontend to generate an LLVM bitcode module.
216 | std::unique_ptr Act(new EmitLLVMOnlyAction());
217 | if (!Clang.ExecuteAction(*Act))
218 | return 1;
219 |
220 | llvm::InitializeNativeTarget();
221 | llvm::InitializeNativeTargetAsmPrinter();
222 |
223 | int Res = 255;
224 | std::unique_ptr Ctx(Act->takeLLVMContext());
225 | std::unique_ptr Module = Act->takeModule();
226 |
227 | if (Module) {
228 | auto J = ExitOnErr(llvm::orc::SimpleJIT::Create());
229 |
230 | ExitOnErr(J->addModule(
231 | llvm::orc::ThreadSafeModule(std::move(Module), std::move(Ctx))));
232 | auto Main = (int (*)(...))ExitOnErr(J->getSymbolAddress("main"));
233 | Res = Main();
234 | }
235 |
236 | // Shutdown.
237 | // llvm::llvm_shutdown();
238 |
239 | return Res;
240 | }
241 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LLVM on iOS
2 |
3 | The goal of this project is to illustrate how to use LLVM + Clang to provide an iOS app with some scripting capability.
4 |
5 | 
6 | 
7 |
8 | For the eager reader, we provide a sample iOS app project which has **NO license attached** so feel free to do whatever you want with it.
9 | In this app, we use Clang's C interpreter example located in `examples/clang-interpreter/main.cpp` of Clang source code to _interpret a simple C++ program_ and _print out the output on the iOS app's user interface_.
10 | (The file was renamed to `Interpreter.cpp` to fit in with iOS development style. Also note that the example was removed from LLVM 14 but it should be available prior.)
11 | The code is pretty much copied verbatim except for some minor modifications, namely:
12 |
13 | 1. We change the `main` function name to `clangInterpret` since iOS app already has `main` function.
14 |
15 | 2. We comment out the last line
16 | ```c++
17 | // llvm::llvm_shutdown();
18 | ```
19 | so that you can _call `clangInterpret` again_ in the app.
20 | This line only makes sense in the original program because it was a one-shot command line program.
21 |
22 | 3. We add a third parameter
23 | ```c++
24 | llvm::raw_ostream &errorOutputStream
25 | ```
26 | 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.
27 |
28 | 4. **For real iOS device**: The implementation of [`llvm::sys::getProcessTriple()`](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/Host.cpp) is currently bogus according to the implementation of [`JITTargetMachineBuilder::detectHost()`](https://github.com/llvm/llvm-project/blob/main/llvm/lib/ExecutionEngine/Orc/JITTargetMachineBuilder.cpp).
29 | So we need to add the appropriate conditional compilation directive `#ifdef __aarch64__ ... #else ... #endif` to give it the correct triple.
30 |
31 | In the latest version, you should be able to edit the program, interpret it and see the output in the app UI.
32 |
33 | ### Preparations
34 |
35 | Before building the project, you need to either
36 | 1. compile LLVM (see instructions down below); or
37 | 2. download our prebuilt XCFramework (the file named `LLVM.xcframework.tar.xz`) from our [releases](https://github.com/light-tech/LLVM-On-iOS/releases),
38 | then `cd` to the repo folder and do
39 | ```shell
40 | tar -xzf PATH_TO_DOWNLOADED_TAR_XZ # e.g. ~/Downloads/LLVM.xcframework.tar.xz
41 | ```
42 |
43 | ### Known Limitations
44 |
45 | For simulator, can only build **Debug** version only!
46 |
47 | You can run the app on the Mac (thank to Mac Catalyst) and iOS simulator. Do NOT expect the app to work on real iPhone due to iOS security preventing [Just-In-Time (JIT) Execution](https://saagarjha.com/blog/2020/02/23/jailed-just-in-time-compilation-on-ios/) that the interpreter example was doing.
48 | By pulling out the device crash logs, the reason turns out to be the fact the [code generated in-memory by LLVM/Clang wasn't signed](http://iphonedevwiki.net/index.php/Code_Signing) and so the app was terminated with SIGTERM CODESIGN.
49 |
50 | If there is compilation error, the error message was printed out instead of crashing as expected:
51 |
52 | 
53 | 
54 |
55 | **Note**: It does work if one [launches the app from Xcode](https://9to5mac.com/2020/11/06/ios-14-2-brings-jit-compilation-support-which-enables-emulation-apps-at-full-performance/) though.
56 |
57 | To make the app work on real iPhone _untethered from Xcode_, one possibility is to use compilation into binary, somehow sign it and use [system()](https://stackoverflow.com/questions/32439095/how-to-execute-a-command-line-in-iphone).
58 | Another possibility would be to use the slower LLVM bytecode interpreter instead of ORC JIT that the example was doing, as many [existing terminal apps](https://opensource.com/article/20/9/run-linux-ios) illustrated.
59 | Also, check out [L* C++](https://apps.apple.com/us/app/l-c/id1562808282) on the App Store.
60 | I recommend reading [LLVM Programmer's Manual](https://llvm.org/docs/ProgrammersManual.html) before using LLVM API.
61 |
62 | ## Build LLVM for iOS
63 |
64 | ### The tools we needs
65 |
66 | * [Xcode](https://developer.apple.com/xcode/): Download from app store.
67 | - Note that we need the Xcode command line tools as well.
68 | * [CMake](https://cmake.org/download/): See [installation instruction](https://tudat.tudelft.nl/installation/setupDevMacOs.html) to add to `$PATH`.
69 | * [Ninja](https://ninja-build.org/): Download the [binary](https://github.com/ninja-build/ninja/releases) and add it to `$PATH`.
70 |
71 | Except for Xcode, the other items can be easily installed with Homebrew:
72 | ```shell
73 | brew install cmake ninja
74 | ```
75 |
76 | _WARNING_: It has come to our attention that LLVM's CMake Build configuration have some dependency discovery that might be interfered by Homebrew. For example, LLVM depends on `libz` that is both supplied by Xcode and Homebrew. Since we are building for iOS, we really want the Xcode version of the library. But CMake can discover the Homebrew version and uses it instead! So you might want to build on a pristine machine. Don't get yourself **Homescrewed**TM!
77 |
78 | ### Build LLVM and co.
79 |
80 | Apple has introduced [XCFramework](https://developer.apple.com/videos/play/wwdc2019/416/) to allow packaging a library for multiple-platforms (iOS, Simulator, watchOS, macOS) and CPU architectures (x86_64, arm64) that could be easily added to a project so that we do not have to switch out the libraries when we build the app for different targets (e.g. testing the app on real iPhone arm64 vs on the simulator x86_64).
81 |
82 | Our script [build-llvm.sh](build-llvm.sh) provides functions to build LLVM and libffi dependency for several iOS platforms.
83 | It also has a function `create_xcframework` to produce an XCFramework from them.
84 | The script assumes the various tools aforementioned are installed and asccessible in `$PATH`.
85 |
86 | At this repo root:
87 | ```shell
88 | source build-llvm.sh
89 | build_libffi iphoneos
90 | build_llvm iphoneos # iphonesimulator maccatalyst iphonesimulator-arm64 maccatalyst-arm64
91 | create-xcframework iphoneos # iphonesimulator maccatalyst
92 | ```
93 | (If you are building for use in your own development machine, you can skip some platforms that you do not need. For example, an M1 Macs can skip on `iphonesimulator maccatalyst` as those are meant for Intel Macs.)
94 |
95 | Our prebuilt release are built with [GitHub Actions](https://github.com/light-tech/LLVM-On-iOS/actions).
96 |
97 | ## Behind the Scene
98 |
99 | These days, you probably want to write your app in _Swift_ whereas LLVM library is written in _C++_ so we need to create a _bridge_ to expose LLVM backend to your app Swift frontend. This could be accomplished via Objective-C as an intermediate language:
100 | ```
101 | Swift <-> Objective-C <-> C++
102 | ```
103 | So to understand how our Sample project works, you need to know
104 | 1. how language interoperability works; and
105 | 2. how to configure your Xcode project to use it.
106 |
107 | ### Swift-C++ interoperability
108 |
109 | To start, you might want to start with _Anthony Nguyen_'s
110 | [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)
111 | for a quick intro on how to make use of C++ in Objective-C.
112 | (Note that both C++ and Objective-C are extensions of C and reduces to C.)
113 | An easy read on Objective-C and Swift interoperability could be found in
114 | [Understanding Objective-C and Swift interoperability](https://rderik.com/blog/understanding-objective-c-and-swift-interoperability/#expose-swift-code-to-objective-c)
115 | by _RDerik_.
116 | Combining these two articles is the basis for our Sample app.
117 |
118 | A typical approach to allow C++ in Swift-based iOS app will be using
119 | * _Swift_ : Anything iOS-related (UI, file system access, Internet, ...)
120 | * _Objective-C_ : Simple classes (like [`LLVMBridge`](Sample/LLVMBridge.h) in our Sample app) to expose service written in C++.
121 | The main role is to convert data types between C++ and Swift.
122 | For example: Swift's `Data` to Objective-C's `NSData` to C++'s buffer `char*` (and length).
123 | * _C++_ : Actual implementation of processing functionality.
124 |
125 | **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.
126 |
127 | _Apple_'s [Programming with Objective-C](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011210)
128 | is fairly useful in helping us write the Objective-C bridging class `LLVMBridge`: Once we pass to C++, we are in our home turf.
129 |
130 | ### Configure iOS App Xcode Project
131 |
132 | 1. Create a new iOS app project in Xcode and copy `LLVM.xcframework` to the project folder.
133 |
134 | 2. In Xcode, add `LLVM.xcframework` to the project's Framework and Libraries. Choose **Do not embed** so that the static library is linked into the app and the entire framework is NOT copied to the app bundle.
135 |
136 | 3. To create the Objective-C bridge between Swift and C++ mentioned at the beginning, add to your project a new header file, say `LLVMBridge.h` and an implementation file, say `LLVMBridge.mm` (here, we use the `.mm` extension for Objective-C++ since we do need C++ to implement our `LLVMBridge` class) and then change the Objective-C bridging header setting in the project file to tell Xcode that the Objective-C class defined in `LLVMBridge.h` should be exposed to Swift.
137 | Again, go to **Build settings** your project and search for `bridg` and you should find **Objective-C Bridging Header** under **Swift Compiler - General**.
138 | 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`).
139 |
140 | **Note**: Only Objective-C classes in *Objective-C Bridging Header* are visible to Swift!
141 |
142 | 
143 |
144 | At this point, we should be able to run the project on iOS simulator.
145 | **To build the app for real iOS devices, an extra step is needed.**
146 |
147 | 4. 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`.
148 |
149 | 
150 |
151 | Now you are ready to make use of LLVM glory.
152 |
--------------------------------------------------------------------------------
/Sample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B7FA402325EE383900563EDC /* LLVM.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7FA402225EE383900563EDC /* LLVM.xcframework */; };
11 | C639E815254517EF004DB533 /* SampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C639E814254517EF004DB533 /* SampleApp.swift */; };
12 | C639E817254517EF004DB533 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C639E816254517EF004DB533 /* ContentView.swift */; };
13 | C639E819254517F0004DB533 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C639E818254517F0004DB533 /* Assets.xcassets */; };
14 | C639E81C254517F0004DB533 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C639E81B254517F0004DB533 /* Preview Assets.xcassets */; };
15 | C639E84525451C0A004DB533 /* Interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C639E84225451C0A004DB533 /* Interpreter.cpp */; };
16 | C639E84625451C0A004DB533 /* LLVMBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = C639E84325451C0A004DB533 /* LLVMBridge.mm */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | B76E87CD27C887770092565F /* build-tools.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-tools.sh"; sourceTree = SOURCE_ROOT; };
21 | B76E87CE27C887770092565F /* build-llvm.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-llvm.sh"; sourceTree = SOURCE_ROOT; };
22 | B76E87CF27C887770092565F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };
23 | B7923BE027FAA1CE003DE86D /* main.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; name = main.yml; path = .github/workflows/main.yml; sourceTree = SOURCE_ROOT; };
24 | B7FA401A25EE377D00563EDC /* Sample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Sample.entitlements; sourceTree = ""; };
25 | B7FA402225EE383900563EDC /* LLVM.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = LLVM.xcframework; sourceTree = ""; };
26 | C639E811254517EF004DB533 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
27 | C639E814254517EF004DB533 /* SampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleApp.swift; sourceTree = ""; };
28 | C639E816254517EF004DB533 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
29 | C639E818254517F0004DB533 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
30 | C639E81B254517F0004DB533 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
31 | C639E81D254517F0004DB533 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | C639E84225451C0A004DB533 /* Interpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Interpreter.cpp; sourceTree = ""; };
33 | C639E84325451C0A004DB533 /* LLVMBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LLVMBridge.mm; sourceTree = ""; };
34 | C639E84425451C0A004DB533 /* LLVMBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLVMBridge.h; sourceTree = ""; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXFrameworksBuildPhase section */
38 | C639E80E254517EF004DB533 /* Frameworks */ = {
39 | isa = PBXFrameworksBuildPhase;
40 | buildActionMask = 2147483647;
41 | files = (
42 | B7FA402325EE383900563EDC /* LLVM.xcframework in Frameworks */,
43 | );
44 | runOnlyForDeploymentPostprocessing = 0;
45 | };
46 | /* End PBXFrameworksBuildPhase section */
47 |
48 | /* Begin PBXGroup section */
49 | B76E87CB27C887560092565F /* Scripts */ = {
50 | isa = PBXGroup;
51 | children = (
52 | B7923BE027FAA1CE003DE86D /* main.yml */,
53 | B76E87CE27C887770092565F /* build-llvm.sh */,
54 | B76E87CD27C887770092565F /* build-tools.sh */,
55 | B76E87CF27C887770092565F /* README.md */,
56 | );
57 | name = Scripts;
58 | sourceTree = "";
59 | };
60 | B7FA402125EE383800563EDC /* Frameworks */ = {
61 | isa = PBXGroup;
62 | children = (
63 | B7FA402225EE383900563EDC /* LLVM.xcframework */,
64 | );
65 | name = Frameworks;
66 | sourceTree = "";
67 | };
68 | C639E808254517EF004DB533 = {
69 | isa = PBXGroup;
70 | children = (
71 | C639E813254517EF004DB533 /* Sample */,
72 | C639E812254517EF004DB533 /* Products */,
73 | B7FA402125EE383800563EDC /* Frameworks */,
74 | );
75 | sourceTree = "";
76 | };
77 | C639E812254517EF004DB533 /* Products */ = {
78 | isa = PBXGroup;
79 | children = (
80 | C639E811254517EF004DB533 /* Sample.app */,
81 | );
82 | name = Products;
83 | sourceTree = "";
84 | };
85 | C639E813254517EF004DB533 /* Sample */ = {
86 | isa = PBXGroup;
87 | children = (
88 | B76E87CB27C887560092565F /* Scripts */,
89 | B7FA401A25EE377D00563EDC /* Sample.entitlements */,
90 | C639E84225451C0A004DB533 /* Interpreter.cpp */,
91 | C639E84425451C0A004DB533 /* LLVMBridge.h */,
92 | C639E84325451C0A004DB533 /* LLVMBridge.mm */,
93 | C639E814254517EF004DB533 /* SampleApp.swift */,
94 | C639E816254517EF004DB533 /* ContentView.swift */,
95 | C639E818254517F0004DB533 /* Assets.xcassets */,
96 | C639E81D254517F0004DB533 /* Info.plist */,
97 | C639E81A254517F0004DB533 /* Preview Content */,
98 | );
99 | path = Sample;
100 | sourceTree = "";
101 | };
102 | C639E81A254517F0004DB533 /* Preview Content */ = {
103 | isa = PBXGroup;
104 | children = (
105 | C639E81B254517F0004DB533 /* Preview Assets.xcassets */,
106 | );
107 | path = "Preview Content";
108 | sourceTree = "";
109 | };
110 | /* End PBXGroup section */
111 |
112 | /* Begin PBXNativeTarget section */
113 | C639E810254517EF004DB533 /* Sample */ = {
114 | isa = PBXNativeTarget;
115 | buildConfigurationList = C639E836254517F1004DB533 /* Build configuration list for PBXNativeTarget "Sample" */;
116 | buildPhases = (
117 | C639E80D254517EF004DB533 /* Sources */,
118 | C639E80E254517EF004DB533 /* Frameworks */,
119 | C639E80F254517EF004DB533 /* Resources */,
120 | );
121 | buildRules = (
122 | );
123 | dependencies = (
124 | );
125 | name = Sample;
126 | productName = Sample;
127 | productReference = C639E811254517EF004DB533 /* Sample.app */;
128 | productType = "com.apple.product-type.application";
129 | };
130 | /* End PBXNativeTarget section */
131 |
132 | /* Begin PBXProject section */
133 | C639E809254517EF004DB533 /* Project object */ = {
134 | isa = PBXProject;
135 | attributes = {
136 | LastSwiftUpdateCheck = 1210;
137 | LastUpgradeCheck = 1210;
138 | TargetAttributes = {
139 | C639E810254517EF004DB533 = {
140 | CreatedOnToolsVersion = 12.1;
141 | LastSwiftMigration = 1210;
142 | };
143 | };
144 | };
145 | buildConfigurationList = C639E80C254517EF004DB533 /* Build configuration list for PBXProject "Sample" */;
146 | compatibilityVersion = "Xcode 9.3";
147 | developmentRegion = en;
148 | hasScannedForEncodings = 0;
149 | knownRegions = (
150 | en,
151 | Base,
152 | );
153 | mainGroup = C639E808254517EF004DB533;
154 | productRefGroup = C639E812254517EF004DB533 /* Products */;
155 | projectDirPath = "";
156 | projectRoot = "";
157 | targets = (
158 | C639E810254517EF004DB533 /* Sample */,
159 | );
160 | };
161 | /* End PBXProject section */
162 |
163 | /* Begin PBXResourcesBuildPhase section */
164 | C639E80F254517EF004DB533 /* Resources */ = {
165 | isa = PBXResourcesBuildPhase;
166 | buildActionMask = 2147483647;
167 | files = (
168 | C639E81C254517F0004DB533 /* Preview Assets.xcassets in Resources */,
169 | C639E819254517F0004DB533 /* Assets.xcassets in Resources */,
170 | );
171 | runOnlyForDeploymentPostprocessing = 0;
172 | };
173 | /* End PBXResourcesBuildPhase section */
174 |
175 | /* Begin PBXSourcesBuildPhase section */
176 | C639E80D254517EF004DB533 /* Sources */ = {
177 | isa = PBXSourcesBuildPhase;
178 | buildActionMask = 2147483647;
179 | files = (
180 | C639E817254517EF004DB533 /* ContentView.swift in Sources */,
181 | C639E84625451C0A004DB533 /* LLVMBridge.mm in Sources */,
182 | C639E815254517EF004DB533 /* SampleApp.swift in Sources */,
183 | C639E84525451C0A004DB533 /* Interpreter.cpp in Sources */,
184 | );
185 | runOnlyForDeploymentPostprocessing = 0;
186 | };
187 | /* End PBXSourcesBuildPhase section */
188 |
189 | /* Begin XCBuildConfiguration section */
190 | C639E834254517F1004DB533 /* Debug */ = {
191 | isa = XCBuildConfiguration;
192 | buildSettings = {
193 | ALWAYS_SEARCH_USER_PATHS = NO;
194 | CLANG_ANALYZER_NONNULL = YES;
195 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
196 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
197 | CLANG_CXX_LIBRARY = "libc++";
198 | CLANG_ENABLE_MODULES = YES;
199 | CLANG_ENABLE_OBJC_ARC = YES;
200 | CLANG_ENABLE_OBJC_WEAK = YES;
201 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
202 | CLANG_WARN_BOOL_CONVERSION = YES;
203 | CLANG_WARN_COMMA = YES;
204 | CLANG_WARN_CONSTANT_CONVERSION = YES;
205 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
206 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
207 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
208 | CLANG_WARN_EMPTY_BODY = YES;
209 | CLANG_WARN_ENUM_CONVERSION = YES;
210 | CLANG_WARN_INFINITE_RECURSION = YES;
211 | CLANG_WARN_INT_CONVERSION = YES;
212 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
213 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
214 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
216 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
217 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
218 | CLANG_WARN_STRICT_PROTOTYPES = YES;
219 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
220 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
221 | CLANG_WARN_UNREACHABLE_CODE = YES;
222 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
223 | COPY_PHASE_STRIP = NO;
224 | DEBUG_INFORMATION_FORMAT = dwarf;
225 | ENABLE_STRICT_OBJC_MSGSEND = YES;
226 | ENABLE_TESTABILITY = YES;
227 | GCC_C_LANGUAGE_STANDARD = gnu11;
228 | GCC_DYNAMIC_NO_PIC = NO;
229 | GCC_NO_COMMON_BLOCKS = YES;
230 | GCC_OPTIMIZATION_LEVEL = 0;
231 | GCC_PREPROCESSOR_DEFINITIONS = (
232 | "DEBUG=1",
233 | "$(inherited)",
234 | );
235 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
236 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
237 | GCC_WARN_UNDECLARED_SELECTOR = YES;
238 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
239 | GCC_WARN_UNUSED_FUNCTION = YES;
240 | GCC_WARN_UNUSED_VARIABLE = YES;
241 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
242 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
243 | MTL_FAST_MATH = YES;
244 | ONLY_ACTIVE_ARCH = YES;
245 | SDKROOT = iphoneos;
246 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
247 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
248 | };
249 | name = Debug;
250 | };
251 | C639E835254517F1004DB533 /* Release */ = {
252 | isa = XCBuildConfiguration;
253 | buildSettings = {
254 | ALWAYS_SEARCH_USER_PATHS = NO;
255 | CLANG_ANALYZER_NONNULL = YES;
256 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
258 | CLANG_CXX_LIBRARY = "libc++";
259 | CLANG_ENABLE_MODULES = YES;
260 | CLANG_ENABLE_OBJC_ARC = YES;
261 | CLANG_ENABLE_OBJC_WEAK = YES;
262 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
263 | CLANG_WARN_BOOL_CONVERSION = YES;
264 | CLANG_WARN_COMMA = YES;
265 | CLANG_WARN_CONSTANT_CONVERSION = YES;
266 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
267 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
268 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
269 | CLANG_WARN_EMPTY_BODY = YES;
270 | CLANG_WARN_ENUM_CONVERSION = YES;
271 | CLANG_WARN_INFINITE_RECURSION = YES;
272 | CLANG_WARN_INT_CONVERSION = YES;
273 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
274 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
275 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
276 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
277 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
279 | CLANG_WARN_STRICT_PROTOTYPES = YES;
280 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
281 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
282 | CLANG_WARN_UNREACHABLE_CODE = YES;
283 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
284 | COPY_PHASE_STRIP = NO;
285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
286 | ENABLE_NS_ASSERTIONS = NO;
287 | ENABLE_STRICT_OBJC_MSGSEND = YES;
288 | GCC_C_LANGUAGE_STANDARD = gnu11;
289 | GCC_NO_COMMON_BLOCKS = YES;
290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
292 | GCC_WARN_UNDECLARED_SELECTOR = YES;
293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
294 | GCC_WARN_UNUSED_FUNCTION = YES;
295 | GCC_WARN_UNUSED_VARIABLE = YES;
296 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
297 | MTL_ENABLE_DEBUG_INFO = NO;
298 | MTL_FAST_MATH = YES;
299 | SDKROOT = iphoneos;
300 | SWIFT_COMPILATION_MODE = wholemodule;
301 | SWIFT_OPTIMIZATION_LEVEL = "-O";
302 | VALIDATE_PRODUCT = YES;
303 | };
304 | name = Release;
305 | };
306 | C639E837254517F1004DB533 /* Debug */ = {
307 | isa = XCBuildConfiguration;
308 | buildSettings = {
309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
310 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
311 | CLANG_ENABLE_MODULES = YES;
312 | CODE_SIGN_ENTITLEMENTS = Sample/Sample.entitlements;
313 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
314 | CODE_SIGN_STYLE = Automatic;
315 | DEVELOPMENT_ASSET_PATHS = "\"Sample/Preview Content\"";
316 | ENABLE_BITCODE = NO;
317 | ENABLE_PREVIEWS = YES;
318 | HEADER_SEARCH_PATHS = "";
319 | INFOPLIST_FILE = Sample/Info.plist;
320 | IPHONEOS_DEPLOYMENT_TARGET = 15.5;
321 | "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 15.0;
322 | LD_RUNPATH_SEARCH_PATHS = (
323 | "$(inherited)",
324 | "@executable_path/Frameworks",
325 | );
326 | LIBRARY_SEARCH_PATHS = "$(inherited)";
327 | PRODUCT_BUNDLE_IDENTIFIER = com.lightech.Sample;
328 | PRODUCT_NAME = "$(TARGET_NAME)";
329 | SUPPORTS_MACCATALYST = YES;
330 | SWIFT_OBJC_BRIDGING_HEADER = Sample/LLVMBridge.h;
331 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
332 | SWIFT_VERSION = 5.0;
333 | TARGETED_DEVICE_FAMILY = "1,2,6";
334 | };
335 | name = Debug;
336 | };
337 | C639E838254517F1004DB533 /* Release */ = {
338 | isa = XCBuildConfiguration;
339 | buildSettings = {
340 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
341 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
342 | CLANG_ENABLE_MODULES = YES;
343 | CODE_SIGN_ENTITLEMENTS = Sample/Sample.entitlements;
344 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
345 | CODE_SIGN_STYLE = Automatic;
346 | DEVELOPMENT_ASSET_PATHS = "\"Sample/Preview Content\"";
347 | ENABLE_BITCODE = NO;
348 | ENABLE_PREVIEWS = YES;
349 | HEADER_SEARCH_PATHS = "";
350 | INFOPLIST_FILE = Sample/Info.plist;
351 | IPHONEOS_DEPLOYMENT_TARGET = 15.5;
352 | "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 15.0;
353 | LD_RUNPATH_SEARCH_PATHS = (
354 | "$(inherited)",
355 | "@executable_path/Frameworks",
356 | );
357 | LIBRARY_SEARCH_PATHS = "$(inherited)";
358 | PRODUCT_BUNDLE_IDENTIFIER = com.lightech.Sample;
359 | PRODUCT_NAME = "$(TARGET_NAME)";
360 | SUPPORTS_MACCATALYST = YES;
361 | SWIFT_OBJC_BRIDGING_HEADER = Sample/LLVMBridge.h;
362 | SWIFT_VERSION = 5.0;
363 | TARGETED_DEVICE_FAMILY = "1,2,6";
364 | };
365 | name = Release;
366 | };
367 | /* End XCBuildConfiguration section */
368 |
369 | /* Begin XCConfigurationList section */
370 | C639E80C254517EF004DB533 /* Build configuration list for PBXProject "Sample" */ = {
371 | isa = XCConfigurationList;
372 | buildConfigurations = (
373 | C639E834254517F1004DB533 /* Debug */,
374 | C639E835254517F1004DB533 /* Release */,
375 | );
376 | defaultConfigurationIsVisible = 0;
377 | defaultConfigurationName = Release;
378 | };
379 | C639E836254517F1004DB533 /* Build configuration list for PBXNativeTarget "Sample" */ = {
380 | isa = XCConfigurationList;
381 | buildConfigurations = (
382 | C639E837254517F1004DB533 /* Debug */,
383 | C639E838254517F1004DB533 /* Release */,
384 | );
385 | defaultConfigurationIsVisible = 0;
386 | defaultConfigurationName = Release;
387 | };
388 | /* End XCConfigurationList section */
389 | };
390 | rootObject = C639E809254517EF004DB533 /* Project object */;
391 | }
392 |
--------------------------------------------------------------------------------