我的Xcode项目使用两个目标构建到同一产品的变体。两者之间的区别仅在于使用了哪个版本的库。对于.c源文件,使用目标复选框可以很容易地将正确的版本分配给正确的目标。但是,包括头文件始终包含相同的头文件。这对一个目标是正确的,但对另一个目标则是错误的。
有没有办法控制每个目标包含哪个头文件?
这是我的项目文件层次结构(在Xcode中复制):
MyProject
TheirOldLib
theirLib.h
theirLib.cpp
TheirNewLib
theirLib.h
theirLib.cpp
myCode.cpp
和myCode.cpp做的事情如下:
#include "theirLib.h"
…
somecode()
{
#if OLDVERSION
theirOldLibCall(…);
#else
theirNewLibCall(…);
#endif
}
当然,我为一个目标定义OLDVERSION
而不为另一个目标定义。
注意#include
必须如图所示。以下两个都失败,找不到文件错误:
#include "TheirOldLib/theirLib.h"
#include "TheirNewLib/theirLib.h"
那么有没有办法告诉Xcode哪个theirLib.h
包含每个目标?
约束:
- 两个头文件具有相同的名称。作为最后的手段,我可以重命名其中一个,但我宁愿避免这样做,因为这将导致其他平台上的主要头发拉动。
- 必须更改#include
以添加对封闭文件夹的引用也是我宁愿避免的,因为我需要使用条件编译指令执行两次。
- 我可以自由地调整我的项目,因为我认为合适
感谢您的帮助。
答案 0 :(得分:22)
答案的关键部分是在评论中使用Chris建议的USE_HEADERMAP = NO。以下是详细信息。
简短配方(在Xcode 3.2.2中检查):
为每个相关目标添加USE_HEADERMAP = NO的自定义构建设置。方法如下:
1.1。在“构建”窗格中打开目标的信息面板
1.2。下拉窗口左下角的操作弹出菜单,选择“添加用户自定义设置”
1.3。在新添加的行中,将第一列(“设置”)设置为USE_HEADERMAP
,将第二列(“值”)设置为NO
。
为每个目标添加正确的包含路径(目标构建设置“标题搜索路径”)。在我的例子中将是:
2.1。为“旧”目标添加TheirOldLib
2.2。为“新”目标添加TheirNewLib
步骤1 禁用Xcode的自动标题映射功能,通过该功能可以通过其名称直接访问项目中包含的任何头文件,无论其实际路径如何。当两个标题具有相同的名称时,此功能会导致无法解决的歧义。
第2步允许#include "theirLib.h"
无法限定头文件实际路径名。
这两个步骤共同实现了我的两个约束。
据我所知,最后,USE_HEADERMAP
不由Apple记录。我将填写一份错误报告,因为这个设置在许多情况下都是至关重要的,因为谷歌搜索显示。报告为rdar:// 7840694。同样在开放式雷达上http://openradar.appspot.com/radar?id=253401
答案 1 :(得分:7)
USE_HEADERMAP = NO对某些项目来说是过度杀伤力。仅使用HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT = NO就足够了。这里的文档:https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW159
答案 2 :(得分:1)
Xcode通过创建标题映射文件来加快构建速度。
除了向编译器提供目录列表以搜索标头外,您还可以向其提供标头映射文件。标头映射文件就像一个哈希表,查找键是include
参数,值是标头的路径。
以下是此类地图文件的示例:
(注意: 这不是标题映射文件的实际语法,只是人类可读的表示形式)
Foo.h -> /usr/include/Foo.h
Bar.h -> /home/user/Documents/ProjectA/src/include/Bar.h
foo/bar/foobar.h -> /home/user/Documents/ProjectB/inc/foo/bar/foobar.h
这三个条目匹配
#include "Foo.h"
#include "Bar.h"
#include "foo/bar/foobar.h"
现在Xcode具有三个控制标题映射文件生成的设置。
HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT
如果为YES
(默认),则将属于正在构建的目标的所有头文件添加到头映射文件中,并可以使用include "header.h"
将其包括在内。请注意,标头只能属于框架/库/捆绑包目标,而不能属于应用程序/程序目标。
HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES
如果为YES
(默认),则将所有其他目标的标头添加到标头映射文件中,并可以使用include <TargetName/header.h>
将其包括在内。请注意,对于非框架目标也是如此。
HEADERMAP_INCLUDES_PROJECT_HEADERS
如果为YES
(默认),则构建目标所属的项目文件中存在的所有其他标头也将添加到标头映射文件中,并可以使用include "header.h"
来包含。
此外,还有一般设置USE_HEADERMAP
,用于控制是否应生成头文件映射文件。仅当YES
(默认)时,Xcode才会生成头文件映射文件,并将其作为参数传递给编译器。
如果标头映射文件中未列出标头或未使用标头映射,则编译器将使用以下两种搜索策略之一来搜索标头:
如果标头是用<...>
导入的,它将在用-I
选项(HEADER_SEARCH_PATHS
)指定的所有目录中搜索,用-isystem
选项指定的所有目录(在Xcode中为SYSTEM_HEADER_SEARCH_PATHS
)和stanadrd系统标头目录(所选SDK的/usr/include
以及属于已安装的开发人员工具的其他目录)中;完全按照该顺序,并按照给定的顺序在每个类别中。
如果标头是使用"..."
导入的,则它将在与{c1.c}正在构建的.c / .m文件相同的目录中搜索,该目录在所有使用-iquote
选项指定的目录中({{1 }}(在Xcode中),并在相同的目录中搜索USER_HEADER_SEARCH_PATHS
;完全按照该顺序,并按照给定的顺序在每个类别中。
答案 3 :(得分:0)
为什么不能在每个目标中使用不同的包含路径?
答案 4 :(得分:-1)
使用USE_HEADERMAP = NO,然后在“用户标题搜索路径”中首先包含您的自定义目录,然后递归地包含项目目录:$ {PROJECT_DIR} / TheirNewLib $ {PROJECT_DIR} / **