├── 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 | ![Edit the program screenshot](Screenshots/Screenshot1.png) 6 | ![Interpret the program screenshot](Screenshots/Screenshot2.png) 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 | ![Add #include non-existing header](Screenshots/Screenshot_Real_iPhone1.png) 53 | ![Compilation error was printed out](Screenshots/Screenshot_Real_iPhone2.png) 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 | ![Objective-C Bridging Header Setting](Screenshots/ObjCBridgeHeader.png) 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 | ![Bitcode Setting](Screenshots/DisableBitcode.png) 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 | --------------------------------------------------------------------------------