Xcode 4无法从静态库依赖项中找到公共头文件


91

备用标题以帮助搜索

  • Xcode找不到标题
  • Xcode中缺少.h
  • 找不到Xcode .h文件
  • 找不到词汇或预处理程序问题文件

我正在研究一个来自Xcode 3的iOS应用程序项目。我现在已移至Xcode 4,我的项目构建了许多静态库。

这些静态库还声明了公共头,这些头由应用程序代码使用。在Xcode 3.x中,将标头复制(作为构建阶段)到public headers directory,然后在应用程序项目中将标头public headers directory添加到中headers search list

在Xcode 4下,构建目录移至~/Library/Developer/Xcode/DerivedData/my-project

问题是如何在标题搜索设置中引用此新位置?看起来:

  • public headers directory是相对于DerivedData目录的,但是
  • headers search 目录相对于其他目录(可能是项目位置)

我应该如何在Xcode 4中为iOS开发设置静态库目标,以确保在尝试作为依赖项进行编译时,头文件可用于使用静态库的客户端?


可能与路径名相关。请检查这篇文章。[在Xcode 4静态库] [1] [1]:stackoverflow.com/questions/6074576/static-libraries-in-xcode-4/...
迭Marafetti

Answers:


124

我所见过的解决此问题的每一个解决方案要么看起来都很笨拙(将标头复制到应用程序的项目中),要么过于简化,以至于它们仅适用于琐碎的情况。

简短的答案

将以下路径添加到用户标题搜索路径

“ $(BUILD_ROOT)/../ IntermediateBuildFilesPath / UninstalledProducts”

为什么这样做?

首先,我们需要了解问题。在正常情况下,也就是说,当您运行,测试,分析或分析时,Xcode会构建您的项目,并将输出放在Build / Products / Configuration / Products目录中,该目录可通过$ BUILT_PRODUCTS_DIR宏获得。

有关静态库的大多数指南建议将“ 公共头文件夹”路径设置为$ TARGET_NAME,这意味着您的lib文件将变成$ BUILT_PRODUCTS_DIR /libTargetName.a,并且您的头会放入$ BUILT_PRODUCTS_DIR / TargetName中。只要您的应用程序的搜索路径中包含$ BUILT_PRODUCTS_DIR,导入就可以在上述4种情况下进行。但是,当您尝试存档时,这将不起作用。

存档的工作方式略有不同

存档项目时,Xcode使用另一个名为ArchiveIntermediates的文件夹。在该文件夹中,您将找到/ YourAppName / BuildProductsPath / Release-iphoneos /。这是您进行归档时$ BUILT_PRODUCTS_DIR指向的文件夹。如果您在其中查看,您会看到一个指向已构建的静态库文件的符号链接,但是缺少带有标题的文件夹。

要找到标题(和lib文件),您需要转到IntermediateBuildFilesPath / UninstalledProducts /。还记得有人告诉您静态库的“ 跳过安装 ” 设置为“是”吗?好的,这就是设置存档时产生的效果。

旁注:如果您未将其设置为跳过安装,则标题将放置在另一个位置,并且lib文件将被复制到存档中,从而阻止您导出可提交到App Store的.ipa文件。 。

经过大量搜索后,我找不到与UninstalledProducts文件夹完全对应的任何宏,因此需要使用“ $(BUILD_ROOT)/../ IntermediateBuildFilesPath / UninstalledProducts”构造路径

摘要

对于您的静态库,请确保跳过安装过程,并将公共标头放置在$ TARGET_NAME中。

对于您的应用程序,将用户标头搜索路径设置为“ $(BUILT_PRODUCTS_DIR)”(适用于常规版本)和“ $(BUILD_ROOT)/../ IntermediateBuildFilesPath / UninstalledProducts”(适用于归档版本)。


这与DerivedData文件夹有何关系?
理查德·斯特林

常规构建转到:DerivedData / WorkspaceName-hash / Build / Products / Debug-iphoneos / TargetName.app ---存档构建转到:DerivedData / WorkspaceName-hash / Build / Intermediates / ArchiveIntermediates / TargetName / BuildProductsPath / Release-iphoneos / TargetName.app
Colin

3
对我而言,将“ $(BUILD_ROOT)/../ IntermediateBuildFilesPath / UninstalledProducts”与递归复选框一起使用不起作用。一旦我使用了没有递归标志的“ $(BUILD_ROOT)/../ IntermediateBuildFilesPath / UninstalledProducts / <nameOfStaticLibrary>”,它就对我有用。
TPoschel

7
请注意,您的$(BUILD_ROOT)/../ IntermediateBuildFilesPath / UninstalledProducts实际上是$(TARGET_BUILD_DIR)。即使在存档时。;)
Pascal

1
在Xcode 5中对我来说:$(BUILD_ROOT)/../ IntermediateBuildFilesPath / UninstalledProducts / include / LIBRARY的名称我没有设置为YES:始终搜索用户路径。
xarly 2014年

84

在开发自己的静态库时,我也遇到了同样的问题,尽管Colin的回答非常有帮助,但为了在Xcode 4下使用Workspace运行和归档项目时始终如一地工作,我不得不对其进行一些修改。

我的方法的不同之处在于,您可以对所有构建配置使用单个用户标头路径。

我的方法如下:

创建工作区

  1. 在Xcode 4下,转到“文件”,“新建”,“工作区”。
  2. 然后,您可以从Finder中拖入.xcodeproj项目,以获取要使用的静态库以及正在使用该库构建的新应用程序。有关设置工作区的更多信息,请参阅Apple Docs:https : //developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Workspace.html

静态库项目设置

  1. 确保所有静态库的标头都设置为复制到“公共”。这是在静态库目标>构建阶段的设置下完成的。在“复制标题”阶段,确保所有标题都在“公共”部分中。
  2. 接下来转到“构建设置”,找到“公共标题文件夹路径”,然后输入您的库的路径。我选择使用此:

包含/库名

我从RestKit的使用中采纳了这一点,并发现它与我的所有静态库一起使用效果最佳。这是告诉Xcode将在步骤1中移至“公共”标头部分的所有标头复制到此处指定的文件夹中,该文件在构建时位于“派生数据”文件夹中。与RestKit一样,我喜欢使用一个“ include”文件夹包含我在项目中使用的每个静态库。

我也不喜欢在这里使用宏,因为当我们使用静态库配置项目时,它将允许我们稍后使用单个用户标头搜索路径。

  1. 找到“跳过安装”,并确保将其设置为“是”。

使用静态库的项目设置

  1. 在“构建阶段”>“使用库链接二进制文件”下将静态库添加为框架,并为要使用的任何静态库添加libLibraryName.a文件。
  2. 接下来,确保将项目设置为搜索“用户搜索路径”。这是在“构建设置”>“始终搜索用户路径”下完成的,并确保将其设置为“是”。
  3. 在同一区域中找到“用户标题搜索路径”并添加:

    “ $(PROJECT_TEMP_DIR)/../ UninstalledProducts / include”

这告诉Xcode在Xcode在构建过程中创建的中间构建文件夹中寻找静态库。在这里,我们拥有用于步骤2中为静态库项目设置设置的静态库位置的“ include”文件夹。这是使Xcode正确找到静态库的最重要步骤。

配置工作区

在这里,我们要配置工作区,以便在构建应用程序时可以构建静态库。这是通过编辑用于我们应用的方案来完成的。

  1. 确保已选择将创建应用程序的方案。
  2. 从方案下拉列表中,选择“编辑方案”。
  3. 选择左侧列表顶部的“生成”。通过按中间窗格上的+添加新目标。
  4. 您应该看到要尝试链接的库显示静态库。选择iOS静态库。
  5. 单击运行和存档。这告诉方案在您构建应用程序时为静态库编译库。
  6. 将静态库拖到应用程序目标上方。这使静态库在您的应用程序目标之前进行编译。

开始使用图书馆

现在,您应该可以使用以下命令导入静态库

import <LibraryName/LibraryName.h>

此方法避免了必须为不同的配置使用不同的用户标头路径的麻烦,因此,对于存档进行编译应该没有问题。

为什么这样做?

一切都取决于以下路径:

"$(PROJECT_TEMP_DIR)/../UninstalledProducts/include"

因为我们将静态库配置为使用“跳过安装”,所以已编译的文件将移至临时构建目录中的“ UninstalledProjects”文件夹。我们这里的路径也解析为我们为静态库设置的“ include”文件夹,并用于我们的用户标题搜索路径。两者一起使Xcode知道在编译过程中在哪里可以找到我们的库。由于此临时构建目录同时存在于Debug和Release配置中,因此您只需一个路径即可让Xcode搜索静态库。


3
你真棒,伙计!这确实很有帮助,并且按您描述的那样工作。
neevek 2012年

1
太棒了 我应该在哪里送花:)
拉梅什(Ramesh)

1
进行此设置后,您中的某些人可能会遇到“ ...]无法识别的选择器,该选择器已发送到类0x ... ”。如果您愿意,请尝试将其添加到项目的“目标”- >“项目”->“构建设置”->“链接”
MkVal 2013年

如果用户标题搜索路径中有空格,请确保它们用引号引起来。
尊重TheCode 2013年

Xcode 4.6.2没有为我写任何东西到“ $(PROJECT_TEMP_DIR)/../ UninstalledProducts / include”。知道我缺少什么吗?还是Xcode行为再次改变了?
罗尔德

16

Xcode 4项目无法编译静态库

相关问题:Xcode 4中“找不到词法或预处理器问题文件”

错误可能包括;缺少头文件,“词汇或预处理器问题”

解决方案:

  1. 检查“用户头路径”是否正确
  2. 将“始终搜索用户路径”设置为“是”
  3. 在您的项目中创建一个名为“索引标头”的组,并将标头拖动到该组中,在出现提示时请勿添加到任何目标。

11
另一个容易忽略但极其重要的步骤:确保搜索路径用双引号引起来,以避开任何空格。我总是忘记这样做。
布拉德(Brad)

谢谢@布拉德,这确实是一个非常重要和有益的评论。
朱利安·D。

15

这是一个非常有用的线程。在研究自己的情况时,我发现Apple有一份12页的文档,日期为2012年9月,标题为“在iOS中使用静态库”。这是pdf链接:http : //developer.apple.com/library/ios/technotes/iOSStaticLibraries/iOSStaticLibraries.pdf

它比大多数Internet讨论要简单得多,并且通过一些小的mod来说明我正在使用的外部库的配置方式,因此对我来说效果很好。最重要的部分可能是:

如果您的库目标具有“复制标题”构建阶段,则应将其删除;否则,请删除它。在Xcode中执行“存档”操作时,复制标头构建阶段无法与静态库目标一起正常使用。

使用Xcode 4.4或更高版本创建的新静态库目标将带有适当配置的用于标题的“复制文件”阶段,因此在创建一个静态库目标之前,应检查一下是否已有一个。如果不这样做,请按目标编辑器底部的“添加构建阶段”,然后选择“添加复制文件”。披露新的“复制文件”构建阶段,并将“目标”设置为“产品目录”。将子路径设置为包括/ $ {PRODUCT_NAME}。这会将文件复制到以您的库命名的文件夹中(取自PRODUCT_NAME构建设置),位于构建的产品目录中一个名为include的文件夹中。构建产品目录中的include文件夹位于应用程序的默认标题搜索路径中,因此这是放置标题文件的适当位置。

我确信,在许多现有情况下,Apple的方法可能还不够。我将其张贴在这里,供刚刚开始在静态图书馆花园小径上旅行的任何人使用-这可能是简单案例的最佳起点。


对于上面的链接后面的那些..当心:在创建库项目时要求您删除虚拟模板文件的步骤..不要删除* .pch文件..它最终将困扰您+以上建议不适用于类别..尽管有一个解决方案(在某处看到)
大约

感谢您提供指向Apple官方方法以建立静态库的链接。我首先使用这种方法构建了静态库,但无法进行存档。@abbood-删除生成的pch文件有什么问题?
奥古斯托·卡列哈斯2013年

如果您删除.pch文件..该项目将完全无法编译..(出于存档目的或其他目的)..
13年

它对我不起作用。当我尝试使用“”导入语句时,我需要<>。在归档时也找不到标题。有什么想法吗?
user1010819 2014年

4

http://developer.apple.com/library/ios/#technotes/iOSStaticLibraries/Articles/creating.html

根据Apple记录:

您的库将具有一个或多个该库的客户端需要导入的头文件。要配置将哪些标头导出到客户端,请选择您的库项目以打开项目编辑器,选择库目标以打开目标编辑器,然后选择构建阶段选项卡。如果您的库目标具有“复制标题”构建阶段,则应将其删除;否则,请删除它。在Xcode中执行“存档”操作时,复制标头构建阶段无法与静态库目标一起正常使用。



2

$(OBJROOT)/ UninstalledProducts / exactPathToHeaders添加标题搜索路径。

由于某种原因,递归复选框对我不起作用,我不得不将其余路径添加到标头所在的位置。

在Xcode中的Log Navigator(断点导航器右侧的选项卡)下,您可以查看构建历史记录。如果选择实际的构建失败,则可以展开其详细信息以查看setenv PATH并检查以确保头文件的路径在那里。


关于递归复选框的注意事项,此处相同。
Codezy 2012年

是的,我还必须指定一个特定的子文件夹,检查递归不起作用。
奥利弗·皮尔曼

但是,我最终使用了该路径(仅仅是因为它较短)“ $(PROJECT_TEMP_DIR)/../ UninstalledProducts / SubProjectHeaders”
Oliver Pearmain 2014年

2

在我的情况下,我的工作区有几个静态库项目,其中一个具有依赖关系,包括头文件。问题在于建造的顺序。在“构建”部分下的“编辑方案”页面中,我取消选择“并行化”选项,并根据依赖关系排列了目标的顺序,从而解决了问题


1

在用户标题搜索路径中添加以下路径:

$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts

这已验证!


1

冒着暴露出我是白痴的危险...我一直在遭受XCode整个下午拒绝找到我的.h文件的困扰。

然后我意识到了。

因为我使用的是“ XCode 4”,所以“智能地”决定将我的所有项目放在一个名为“ XCode 4 projects ” 的文件夹的子文件夹中。

文件夹名称中的空格使XCode混乱了!

将该文件夹重命名为“ XCode_4_Projects ”,使我重新获得了快乐(减少了咒骂)。

再次提醒我,一年?

也许有人可以告诉苹果开发商...


1

这些答案都不对我有用。这是做什么的。将以下内容(复制并粘贴包括双引号)准确地添加到“ 用户标题搜索路径”构建设置中:

"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include/"

请注意,与其他答案相比,增加了“ / include /”子目录。正如其他用户指出的那样,“递归”选项似乎没有任何作用,因此您可以忽略它。

现在,以以下形式导入静态库头文件时,我的项目能够成功存档:

#import "LibraryName/HeaderFile.h"

不会需要启用始终搜索用户路径设置,除非你是包括尖括号(你的静态库头#import <LibraryName/HeaderFile.h>),但你真的不应该这样做无论如何,如果它不是一个系统/框架头。


1

上面的答案都没有在Xcode 7上对我有用,但是它们给了我一个好主意。对于在Xcode 7上苦苦挣扎的家伙,我通过在用户标题搜索路径(包括引号)中添加以下内容来解决此问题

"$(BUILT_PRODUCTS_DIR)/usr/local/include"

usr/local/include根据静态库的“公共标题文件夹路径”设置中的内容更改相对URL部分


0

这是一个相关的问题,导致我提出了这个问题,因此我将严格地为文档添加解决方案,这可以节省大量的精力

找不到DropboxSDK.h文件

经过数天的尝试让VES为iOS编译,我最终遇到了这个问题。在DropboxSDK.h肯定中接触不到的地方search headers我甚至把它添加到framework headers搜索路径,included为.h直接就去各种竭尽全力的尝试并获得DropboxSDK.h发现。

明确DropboxSDK.framework文件拖到Xcode的文件中Project Navigation,并确保Copy Files if needed已选中。还要确保根据需要检查了目标。

警告

在其中设置显式框架位置build phases对我不起作用。我必须 .framework拖到Xcode中,并确保将文件复制到我的项目中。

#mbp2015#xcode7#ios9


0

有多种复杂的方法可以执行此操作,并且在此线程中提出了一些非常智能的解决方案。

所有这些解决方案的主要问题是,它严重降低了库的可移植性。

  • 每次需要使用您的库启动一个新项目并将其存档到iTunes时,这都是一个配置难题。
  • 每次您需要与团队或客户共享项目时,项目可能由于任何原因而中断(上下文,Xcode版本等)。

最后,我的选择是按照Apple的建议(WWDC视频)始终简单地使用框架。

如此简单,最后完成相同的工作!

似乎可行的另一个非常优雅的解决方案是使用专用Cocoapods。Cocoapods完成所有配置工作,标头复制等。

框架摇滚!


1
您在哪里设置?simply use frameworks - always -
尼尔·福克纳

它没有设置任何地方。这只是一个架构选择。框架是“现代库”,它们更易于链接和管理。在收到此消息时,swift仍然不允许建立二进制库。
驼鹿

0

这是为我解决相同问题的方法。

我有一个应用程序目标和一个iMessage扩展目标。然后,我有2个SDK(我自己的),与App Target链接。

问题是:我的iMessage目标也使用了我的2个SDK(单独的项目),但是在构建阶段->用库链接二进制文件中没有与它们进行链接。我必须将2个SDK添加到那里的iMessage目标,以匹配我的App目标,然后将其存档。

因此,故事的寓意是:如果您有多个目标(例如扩展),请确保所有目标都链接到所需的库。它能够构建并部署到模拟器和设备,但不能存档。



-18

避免麻烦,并执行此操作=在Mac上创建新的用户帐户-使用新的用户帐户打开项目-所有问题均消失。节省时间并保持理智。所有这些书呆子的答复都无济于事!

祝好运

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.