Home > database >  How do I link and use LLVM libraries from an Objective-C Xcode project?
How do I link and use LLVM libraries from an Objective-C Xcode project?

Time:12-15

I'd like to use a few classes from the LLVM project in my own Objective-C app. Specifically, I want to use the classes declared in enter image description here

Then, add the LLVM project created on the previous step. Open File/Add Files to "MyWorkspace"... menu (Option Cmd A) and select the Xcode project file: enter image description here

If Xcode suggests to auto-create schemes I recommend accepting this suggestion so you don't have to deal with it yourself later on.

Adding your own project

This step mimics the previous one with exception that you add your own project to the workspace. I didn't have an existing project for that, so I just created a new one (in my case macOS command-line app) in the workspace directory. If you do the same, ensure that the project is added to "MyWorkspace" and the folder is correct: enter image description here

Eventually your workspace "Project Navigator" should look something like this: enter image description here

And here is how the directory tree looks like in a nutshell:

% tree -L 2
.
|-- LLVM
|   |-- $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|   |-- CMakeCache.txt
|   |-- CMakeFiles
|   |-- CMakeScripts
|   |-- CPackConfig.cmake
|   |-- CPackSourceConfig.cmake
|   |-- Debug
|   |-- LLVM.xcodeproj
|   |-- MinSizeRel
|   |-- RelWithDebInfo
|   |-- Release
|   |-- benchmarks
|   |-- build
|   |-- cmake
|   |-- cmake_install.cmake
|   |-- docs
|   |-- examples
|   |-- include
|   |-- lib
|   |-- llvm.spec
|   |-- projects
|   |-- runtimes
|   |-- test
|   |-- third-party
|   |-- tools
|   |-- unittests
|   `-- utils
|-- MyProject
|   |-- MyProject
|   `-- MyProject.xcodeproj
|-- MyWorkspace.xcworkspace
|   |-- contents.xcworkspacedata
|   |-- xcshareddata
|   `-- xcuserdata
`-- llvm-project
    |-- CONTRIBUTING.md
    |-- LICENSE.TXT
    |-- README.md
    |-- SECURITY.md
    |-- bolt
    |-- clang
    |-- clang-tools-extra
    |-- cmake
    |-- compiler-rt
    |-- cross-project-tests
    |-- flang
    |-- libc
    |-- libclc
    |-- libcxx
    |-- libcxxabi
    |-- libunwind
    |-- lld
    |-- lldb
    |-- llvm
    |-- llvm-libgcc
    |-- mlir
    |-- openmp
    |-- polly
    |-- pstl
    |-- runtimes
    |-- third-party
    `-- utils

Adding dependencies to your project

From this point forward you'll only need Xcode to finish the job. First, let's link the libraries you need to the project and start from the Bitstream archive. Open your project's target General tab settings and under Framework and Libraries click the sign which should take you to the screen with all local dependencies currently available. It's quite a long list of tools from the LLVM project native Apple libs, so you may want to filter it as needed to find the required position:

enter image description here

Now the tricky part. You might not actually be required to do that, but if the LLVMBitstreamReader target itself relies on symbols of other libraries (and exposes such a dependency with explicit use of the libraries symbols) the project linking will fail, so to be safe go to the LLVMBitstreamReader build settings and check what it depends on under Target Dependencies section:

enter image description here

Now add these dependencies to your project as well. Eventually your Frameworks and Libraries section should look like this:

enter image description here

Adjusting project settings

  • CMake generated Xcode projects come with peculiarities. In our case the build folders for the LLVM project targets are located under the project directory with the name matching selected configuration (Debug/Release/MinSizeRel/RelWithDebInfo). In order for your own project's targets to find the libraries built with the given configuration you either have to adjust the LLVM project/targets settings, which I don't recommend because it's a lot of manual work, or just add custom library search path to your project. For the latter go the Build Settings of the target where you added the dependencies at the previous step, find Library Search Path item and add $(SRCROOT)/../LLVM/$(CONFIGURATION)/lib as a new item:

enter image description here

  • Another tricky part is that dependent targets won't make dependencies to build if the dependencies' targets have incompatible build settings. Incompatible is a vague term here, but commonly it means matching the Architectures section. Luckily in our case it merely means making Release configuration to build active architecture only (the Debug shouldn't require any changes at all):

enter image description here

  • Last, but not least, the headers of the library. After generating the LLVM Xcode project, the headers it offers don't (completely) come with the project and are actually located in the repository folder. You may just copy the headers right into your own project, but I suggest adding the repo directory in the System Headers Search paths to stay consistent with the LLVM Xcode Project settings (you can yourself check where the headers search paths are under the the LLVMBitstreamReader Build Settings). Similarly to lib search path, I suggest use help of settings variables and add this path flexibly:
$(SRCROOT)/../llvm-project/llvm/include
$(SRCROOT)/../LLVM/include

enter image description here

Finale

At this point you should be good to use the LLVMBitstreamReader library and classes defined there. I renamed my main.m to main.mm so clang knows i'm going to use C in my code, and here is my sample code:

//
//  main.mm
//  MyProject
//
//  Created by Aleksandr Medvedev on 14.12.2022.
//

#import <Foundation/Foundation.h>
#import <llvm/Bitstream/BitstreamReader.h>
#import <iostream>

int main(int argc, const char * argv[]) {
    llvm::BitstreamBlockInfo::BlockInfo info;
    info.Name = "Hello, LLVM!";
    std::cout << info.Name << std::endl;
    
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
    }
    return 0;
}

If everything is done right, it should compile without any errors now.


P.S. I many times focused on specific directory hierarchy for a reason - when an XCode project is generated through CMake it often uses absolute paths, not relative and if you move your project to another directory, you will have to either adjust the paths in the build settings of required targets/projects or repeat the step with generating the LLVM Xcode project again.

  • Related