包括/排除目标中的整个组

时间:2014-08-28 21:49:33

标签: xcode xcode5

我的项目有一个包含几百个文件的组(组织成两个级别的几十个子组)。该组中的文件本身经常被合理地更改。我希望这些文件包含在某些目标中,而不是其他目标。

在Xcode 3.x中,每次更改组后,我只会获取组本身的信息,转到“目标”选项卡,然后(重新)选择我想要的目标。 (事实上​​,这是2010年几乎完全相同的问题的答案,Xcode — groups and targets。)

在Xcode 5中,如果您选择了一个组,则等效的“文件检查器”面板没有“目标成员”部分(即使选择一个组与选择其所有文件相同,也会禁用“目标成员”复选框)如果您选择多个文件)。

那么,这个功能是否仍然存在,但隐藏在我无法找到的地方?

如果没有,显然还有其他方法可以做我想要的 - 脚本Xcode,解析.pbxproj文件,或者将组抽象到子项目或构建静态库等的完全独立的项目中。但是我'我希望能够在这里使用Xcode,就像我在3.x中所做的那样,而不是必须与之对抗。


实际上,编写Xcode脚本似乎不起作用。任何获取构建阶段的构建文件的尝试都会失败,并出现通用的-10000错误。例如:

tell application "Xcode"
    set theproject to project "SampleProject"
    set thetarget to target "SampleTarget" of theproject
    set thephase to build phase "Compile Sources" of thetarget
    build files of phase
end tell

...在最后一行失败:

error "Xcode got an error: AppleEvent handler failed." number -10000

1 个答案:

答案 0 :(得分:1)

这是我最终使用的黑客 - 我显然仍然欣赏更好的解决方案。

#!/usr/bin/env python3

import os
import plistlib
import sys

pbxproj = os.path.join(sys.argv[1], 'project.pbxproj')
groupname = sys.argv[2]
extensions = 'm mm c cc cpp'.split()

with open(pbxproj, 'rb') as f:
    p = plistlib.load(f)

objs = p['objects']

groupid, group = next((k, v) for k, v in objs.items()
                      if v.get('path') == groupname)

def descendants(id):
    obj = objs[id]
    if obj['isa'] == 'PBXFileReference':
        yield (id, obj)
    for child in obj.get('children', []):
        yield from descendants(child)

mdict = {id: obj for id, obj in descendants(group_id)
         if os.path.splitext(obj['path'])[-1] in extensions}

proj_id, proj = next((k, v) for k, v in objs.items()
                     if v['isa'] == 'PBXProject')

for target_id in proj['targets']:
    target = objs[target_id]
    phase_ids = target['buildPhases']
    phases = [(phase_id, objs[phase_id]) for phase_id in phase_ids]
    phase_id, phase = next((phase_id, phase)
                           for phase_id, phase in phases
                           if phase['isa'] == 'PBXSourcesBuildPhase')
    fileref_ids = [i
                   for i, buildfile_id in enumerate(phase['files'])
                   if objs[buildfile_id]['fileRef'] in mdict]
    fileref_ids.sort(reverse=True)
    for i in fileref_ids:
        del phase['files'][i]

with open(pbxproj + '.new', 'wb') as f:
    plistlib.dump(p, f)
os.rename(pbxproj, pbxproj + '.bak')
os.rename(pbxproj + '.new', pbxproj)