[英]How do I compile + link C++ code in Xcode in an Objective-C project?
[英]How do I link and use LLVM libraries from an Objective-C Xcode project?
我想在我自己的 Objective-C 应用程序中使用 LLVM 项目中的几个类。 具体来说,我想使用在BitstreamReader.h和BitstreamWriter.h中声明的类。 不幸的是,我没有太多链接 C++ 库的经验,所以我真的不知道从哪里开始。 我首先通过 Homebrew 使用brew install llvm@14
。 然后,在我的 Xcode 项目中,我尝试链接/opt/homebrew/opt/llvm@14/lib
中的库,并将/opt/homebrew/opt/llvm@14/include/**
添加到我的HEADER_SEARCH_PATHS
中。
现在我完全卡住了。 我在 Xcode 中有一堆构建错误,例如:
任何帮助都将不胜感激。 谢谢!
在 C++ 世界中,有很多方法可以将依赖项合并到您的项目中,我将概述其中的一些,但会尝试详细描述我认为最适合您的场景的一种:
这是最经典的方法,当您为特定平台预编译和预安装库时,它们可以在默认库搜索路径下使用。 类似于 iOS 中系统框架的使用方式——你只在项目中添加 linker 命令,而框架(库)独立存在(或不存在,导致 linker 错误)。 这种方法的问题是,您不能真正将库用于受限系统,其中“默认”库是不可更改的(iOS、tvOS、iPadOS)
另一种方法是将您需要的所有库预编译到所有平台的档案库中,这些库应该被使用,然后只将其中一个所需的库版本嵌入到您的最终应用程序二进制文件中。 这种方法有些麻烦且不可移植,因为每次需要更改库的某些部分或支持新平台时,它都需要您手动编译库并重新嵌入它。
xcframework
这种方法与前一种方法非常相似,有一些好处,您可以将所有平台的二进制文件打包在一个 package 下,甚至可以在 SPM 中发布。
C++ 中的许多项目(LLVM 也不例外)都是使用所谓的 CMake 工具制作的。 它被广泛采用的多平台构建系统,您可以使用的好处之一是您可以轻松地将任何其他项目作为您自己的一部分。 同时 CMake 在移动开发领域并不普遍,因此您可能很难找到这些平台的相关信息。
这是我想更详细地描述的解决方案。 简而言之,该方法包括 6 个步骤:
这种方法的好处是它提供了最一致的体验(生成项目后,所有部分都可以从 Xcode 进行配置)、管理源代码的自由(LLVM 项目文件可以根据需要进行更改),以及内置的豪华 -在依赖图中(构建目标所需的所有库都在 Xcode 设置下给出)。
您可以从此处克隆该项目。 请注意,这必须位于您未来工作区所在的同一文件夹中,因此您最好提前做好准备:
% mkdir MyWorkspace && cd MyWorkspace
% git clone git@github.com:llvm/llvm-project.git
首先,确保您已安装 CMake(它不是随 macOS 开箱即用的)。 您可以使用brew
或从官方网站下载应用程序。 之后,在llvm-project
repo 文件夹旁边为未来的 Xcode 项目创建一个新文件夹,并在 LLVM 工具包项目上运行cmake
:
% mkdir LLVM && cd LLVM
% cmake -GXCode ../llvm-project/llvm
这里没什么特别的,只需打开 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构建设置并在目标依赖项部分检查它依赖于什么:
现在也将这些依赖项添加到您的项目中。 最终您的框架和库部分应该如下所示:
Debug
/ Release
/ MinSizeRel
/ RelWithDebInfo
)。 为了让您自己的项目的目标找到使用给定配置构建的库,您必须调整 LLVM 项目/目标设置,我不推荐这样做,因为它需要大量手动工作,或者只需将自定义库搜索路径添加到你的项目。 对于后者 go 在上一步中添加依赖项的目标的构建设置,找到Library Search Path项并添加$(SRCROOT)/../LLVM/$(CONFIGURATION)/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.