繁体   English   中英

如何链接和使用 Objective-C Xcode 项目中的 LLVM 库?

[英]How do I link and use LLVM libraries from an Objective-C Xcode project?

我想在我自己的 Objective-C 应用程序中使用 LLVM 项目中的几个类。 具体来说,我想使用在BitstreamReader.hBitstreamWriter.h中声明的类。 不幸的是,我没有太多链接 C++ 库的经验,所以我真的不知道从哪里开始。 我首先通过 Homebrew 使用brew install llvm@14 然后,在我的 Xcode 项目中,我尝试链接/opt/homebrew/opt/llvm@14/lib中的库,并将/opt/homebrew/opt/llvm@14/include/**添加到我的HEADER_SEARCH_PATHS中。

现在我完全卡住了。 我在 Xcode 中有一堆构建错误,例如:

  • “参考未解决的使用声明”
  • “全局命名空间中没有名为‘ldiv’的成员”
  • “使用未声明的标识符‘wcspbrk’”
  • ...

任何帮助都将不胜感激。 谢谢!

在 C++ 世界中,有很多方法可以将依赖项合并到您的项目中,我将概述其中的一些,但会尝试详细描述我认为最适合您的场景的一种:

1. 在系统/用户范围内安装库

这是最经典的方法,当您为特定平台预编译和预安装库时,它们可以在默认库搜索路径下使用。 类似于 iOS 中系统框架的使用方式——你只在项目中添加 linker 命令,而框架(库)独立存在(或不存在,导致 linker 错误)。 这种方法的问题是,您不能真正将库用于受限系统,其中“默认”库是不可更改的(iOS、tvOS、iPadOS)

2.嵌入static库

另一种方法是将您需要的所有库预编译到所有平台的档案库中,这些库应该被使用,然后只将其中一个所需的库版本嵌入到您的最终应用程序二进制文件中。 这种方法有些麻烦且不可移植,因为每次需要更改库的某些部分或支持新平台时,它都需要您手动编译库并重新嵌入它。

3.嵌入一个xcframework

这种方法与前一种方法非常相似,有一些好处,您可以将所有平台的二进制文件打包在一个 package 下,甚至可以在 SPM 中发布。

4.使用CMake构建系统

C++ 中的许多项目(LLVM 也不例外)都是使用所谓的 CMake 工具制作的。 它被广泛采用的多平台构建系统,您可以使用的好处之一是您可以轻松地将任何其他项目作为您自己的一部分。 同时 CMake 在移动开发领域并不普遍,因此您可能很难找到这些平台的相关信息。

5.使用Xcode个工作空间

这是我想更详细地描述的解决方案。 简而言之,该方法包括 6 个步骤:

  • 下载 LLVM 项目仓库;
  • 使用 CMake 为所需的 LLVM 库生成 Xcode 项目;
  • 制作一个 Xcode 工作空间,将新生成的项目添加到其中;
  • 将您自己的项目添加到同一工作区;
  • 将 LLVM 项目所需的依赖项添加到您自己的项目中;
  • 调整项目设置以使其与依赖项兼容。

这种方法的好处是它提供了最一致的体验(生成项目后,所有部分都可以从 Xcode 进行配置)、管理源代码的自由(LLVM 项目文件可以根据需要进行更改),以及内置的豪华 -在依赖图中(构建目标所需的所有库都在 Xcode 设置下给出)。


下载 LLVM 项目

您可以从此处克隆该项目。 请注意,这必须位于您未来工作区所在的同一文件夹中,因此您最好提前做好准备:

% mkdir MyWorkspace && cd MyWorkspace
% git clone git@github.com:llvm/llvm-project.git

生成 LLVM Xcode 项目

首先,确保您已安装 CMake(它不是随 macOS 开箱即用的)。 您可以使用brew或从官方网站下载应用程序。 之后,在llvm-project repo 文件夹旁边为未来的 Xcode 项目创建一个新文件夹,并在 LLVM 工具包项目上运行cmake

% mkdir LLVM && cd LLVM
% cmake -GXCode ../llvm-project/llvm

创建 Xcode 工作区

这里没什么特别的,只需打开 Xcode 并导航到File/New/Workspace菜单( Ctrl+Cmd+N快捷键)。 确保您的工作区是在MyWorkspace文件夹中创建的。 你可以从 Xcode 开始: 在此处输入图像描述

然后,添加在上一步中创建的 LLVM 项目。 打开File/Add Files to "MyWorkspace"...菜单( Option+Cmd+A )和 select Xcode 项目文件: 在此处输入图像描述

如果 Xcode 建议自动创建方案,我建议您接受此建议,这样您以后就不必自己处理了。

添加自己的项目

此步骤模仿前一个步骤,但您将自己的项目添加到工作区。 我没有现有的项目,所以我只是在工作区目录中创建了一个新项目(在我的例子中是 macOS 命令行应用程序)。 如果您这样做,请确保项目已添加到“MyWorkspace”并且文件夹正确: 在此处输入图像描述

最终你的工作区“Project Navigator”应该看起来像这样: 在此处输入图像描述

简而言之,目录树如下所示:

% 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

将依赖项添加到您的项目

从现在开始,您只需输入 Xcode 即可完成这项工作。 首先,让我们将您需要的库链接到项目并从Bitstream存档开始。 打开项目的目标“常规”选项卡设置,然后在“框架”和“库”下单击+号,这会将您带到包含当前可用的所有本地依赖项的屏幕。 LLVM 项目 + 本机 Apple 库中的工具列表相当长,因此您可能希望根据需要对其进行过滤以找到所需的 position:

在此处输入图像描述

现在是棘手的部分。 您可能实际上不需要这样做,但如果LLVMBitstreamReader目标本身依赖于其他库的符号(并通过显式使用库符号公开这种依赖性)项目链接将失败,所以为了安全起见 go 到LLVMBitstreamReader构建设置并在目标依赖项部分检查它依赖于什么:

在此处输入图像描述

现在也将这些依赖项添加到您的项目中。 最终您的框架和库部分应该如下所示:

在此处输入图像描述

调整项目设置

  • CMake 生成 Xcode 项目具有特殊性。 在我们的例子中,LLVM 项目目标的构建文件夹位于项目目录下,名称与所选配置匹配( Debug / Release / MinSizeRel / RelWithDebInfo )。 为了让您自己的项目的目标找到使用给定配置构建的库,您必须调整 LLVM 项目/目标设置,我不推荐这样做,因为它需要大量手动工作,或者只需将自定义库搜索路径添加到你的项目。 对于后者 go 在上一步中添加依赖项的目标的构建设置,找到Library Search Path项并添加$(SRCROOT)/../LLVM/$(CONFIGURATION)/lib作为新项:

在此处输入图像描述

  • 另一个棘手的部分是,如果依赖项的目标具有不兼容的构建设置,则依赖目标将不会生成依赖项来构建。 不兼容在这里是一个模糊的术语,但通常意味着匹配架构部分。 幸运的是,在我们的例子中,它仅意味着进行发布配置以仅构建活动架构(调试根本不需要任何更改):

在此处输入图像描述

  • 最后但并非最不重要的一点是库的标题。 生成 LLVM Xcode 项目后,它提供的标头并未(完全)随项目一起提供,实际上位于存储库文件夹中。 您可以直接将标头复制到您自己的项目中,但我建议在系统标头搜索路径中添加 repo 目录以与 LLVM Xcode 项目设置保持一致(您可以自己检查标头搜索路径在LLVMBitstreamReader Build 下的位置设置)。 与lib搜索路径类似,我建议使用设置变量的帮助并灵活地添加此路径:
$(SRCROOT)/../llvm-project/llvm/include
$(SRCROOT)/../LLVM/include

在此处输入图像描述

压轴

此时,您应该可以很好地使用 LLVMBitstreamReader 库和其中定义的类。 我将main.m重命名为main.mm ,因此 clang 知道我将在我的代码中使用 C++,这是我的示例代码:

//
//  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;
}

如果一切正常,现在应该可以正常编译了。


PS我多次关注特定目录层次结构是有原因的 - 当通过 CMake 生成 XCode 项目时,它通常使用绝对路径,而不是相对路径,如果将项目移动到另一个目录,则必须调整构建中的路径所需目标/项目的设置或重复生成 LLVM Xcode 项目的步骤。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM