Commits

Bob Ippolito committed b5c375e

Probably working Xcode 2.1 support (for converted Xcode 2.0 projects)

Comments (0)

Files changed (6)

 <li><a href="#nsset-vs-set" id="id23" name="id23">NSSet vs set</a></li>
 <li><a href="#python-2-4" id="id24" name="id24">Python 2.4</a></li>
 <li><a href="#nslog-stringwithformat" id="id25" name="id25">NSLog, stringWithFormat, ...</a></li>
+<li><a href="#darwin-x86" id="id26" name="id26">Darwin/x86</a></li>
 </ul>
 </li>
 </ul>
 Python and Objective-C code snippets.</li>
 </ul>
 <h3><a href="#id5" name="test-suite">Test suite</a></h3>
-<p>XXX: It might be a good idea to move the unittests to a seperate python
-package (e.g. <code><span>PyObjCTest</span></code>) that is not installed. I'd be surprised if anyone
-ever runs the unittests outside of the build tree.</p>
 <p>The test suite needs to be enhanced.</p>
 <ul>
 <li>Somehow find a way to check code-coverage of the unittests.</li>
-<li>Tests that exercise Key-Value Observing in a way that crashes older versions
-of PyObjC.</li>
+<li>Tests in the AppKit and Foundation packages that test functionality in
+the objc package should be moved to the objc package.</li>
+<li>Enhance KVO/KVC tests</li>
 <li>tests for all functions in <code><span>Modules/*/*Mapping*.m</span></code>
 (including IMPs)</li>
 <li>tests for all non-generated function wrappers (and some for the generated
 <li>Also restructure class-builder.m, this file is way to large.</li>
 <li>Rewrite selectors to work as regular functions with some attributes,
 rather than descriptors, so that they can be used more easily with tools
-such as PyProtocols dispatch.</li>
+such as PyProtocols dispatch.<p>XXX(Ronald): that's only possible for methods with a python implementation,
+and should result in less code as well. A disadvantage is that this would
+probably be a backward-incomptable change, but that should not be a problem.</p>
+</li>
 </ul>
 <h3><a href="#id8" name="support-for-gnustep">Support for GNUstep</a></h3>
 <p>The current SVN version contains some support for GNUstep, this needs to
 <h3><a href="#id25" name="nslog-stringwithformat">NSLog, stringWithFormat, ...</a></h3>
 <p>Functions and methods that use format strings are not properly wrapped. Fix
 that.</p>
+<h3><a href="#id26" name="darwin-x86">Darwin/x86</a></h3>
+<ul>
+<li>mach_inject needs to be ported to intel.</li>
+<li>when that works we need to figure out if and how we can inject code into 
+programs running an other instruction set (e.g. cross-platform inject).</li>
+<li>drop autoconf/automake for libffi, integrate into the normal build machinery.
+This will make it easier to create fat binaries of PyObjC later on.</li>
+</ul>
 </body>
 </html>

Lib/PyObjCTools/XcodeSupport/ArchiveGraph.py

         fn = unicode(fn, 'utf-8')
     return NSDictionary.dictionaryWithContentsOfFile_(fn)
 
+XCODE_20 = 1000
+XCODE_21 = 999
+
+def _xcodeFiles(base):
+    for fn in os.listdir(base):
+        base, ext = os.path.splitext(fn)
+        if ext == '.xcode':
+            yield XCODE_20, os.path.join(base, fn, 'project.pbxproj')
+        elif ext == '.xcodeproj':
+            yield XCODE_21, os.path.join(base, fn, 'project.pbxproj')
+
+def xcodeFiles(base):
+    lst = list(_xcodeFiles(base))
+    lst.sort()
+    return [path for (ver, path) in lst]
+        
 def main():
-    fn = (sys.argv[1:2] or glob.glob('*.xcode/project.pbxproj'))[0]
+    fn = (sys.argv[1:2] or xcodeFiles('.'))[0]
     o = ArchiveGraph.fromPath(fn)
     o.graphreport()
     return o

Lib/PyObjCTools/XcodeSupport/XcodeProj.py

+import os
+from altgraph.compat import *
+
+class Xcode(object):
+    def __init__(self, project, archive, env):
+        self.project = project
+        self.archive = archive
+        self.env = dict(
+            BUILT_PRODUCTS_DIR='build',
+            TARGET_TEMP_DIR=os.path.join('build', project + '.py2app.build'),
+        )
+        self.env.update(env)
+
+    def py2app_argv(self, argv):
+        action = self.env.get('ACTION', '').strip()
+        if not action:
+            return argv
+        if action == 'build':
+            action = 'py2app'
+        rval = [argv[0], action]
+        return rval
+
+    def findGroup(self, groupName):
+        for group in self.archive.root.mainGroup.children:
+            if group.name == groupName:
+                return group
+        raise ValueError("%r group not found" % (groupName,))
+    
+    def findMainScript(self):
+        name = u'Main Script'
+        group = self.findGroup(name)
+        if len(group.children) != 1:
+            raise ValueError("Expecting exactly 1 item in %r group, found %d" % (name, len(group.children),))
+        return unicode(group.children[0].path).encode('utf8')
+
+    def iterNIBFiles(self):
+        name = u'Resources'
+        group = self.findGroup(name)
+        for ref in group.children:
+            if ref.isa == u'PBXFileReference':
+                name, ext = os.path.splitext(ref.path)
+            elif ref.isa == u'PBXVariantGroup':
+                name, ext = os.path.splitext(ref.name)
+            else:
+                continue
+            if ext == u'.nib':
+                yield unicode(os.path.basename(name)).encode('utf8')
+
+    def iterModules(self):
+        name = u'Classes'
+        group = self.findGroup(name)
+        for ref in group.children:
+            if ref.isa != u'PBXFileReference':
+                raise ValueError('Only file references are allowed in Classes')
+            yield os.path.splitext(unicode(ref.path).encode('utf8'))[0]
+
+    def getPlist(self, nibFiles, modules):
+        try:
+            import plistlib
+            plist = plistlib.Plist.fromFile('Info.plist')
+        except IOError:
+            plist = {}
+
+        plist.update(dict(
+            PyObjCXcode=dict(
+                NIBFiles=nibFiles,
+                Modules=modules,
+            ),
+        ))
+
+        return plist
+    
+    def getTarget(self, nibFiles, modules):
+        return dict(
+            script=self.findMainScript(),
+            plist=self.getPlist(nibFiles, modules),
+        )
+
+    def iterResources(self):
+        name = u'Resources'
+        group = self.findGroup(name)
+        refs = iter(group.children)
+        while True:
+            for ref in refs:
+                children = getattr(ref, 'children', None)
+                if children is not None:
+                    refs = chain(ref.children, refs)
+                    break
+                path = ref.path
+                sourceTree = self.env.get(getattr(ref, 'sourceTree', None))
+                dirname = unicode(os.path.dirname(path))
+                if sourceTree:
+                    path = os.path.join(unicode(sourceTree, 'utf-8'), path)
+                yield dirname, [unicode(path).encode('utf8')]
+            else:
+                break
+
+    def py2app_setup_options(self, buildstyle):
+        nibFiles = list(self.iterNIBFiles())
+        modules = list(self.iterModules())
+        py2app = dict(includes=modules)
+        resources = list(self.iterResources())
+        if self.env.get('BUILD_STYLE') == 'Development':
+            py2app['alias'] = True
+        py2app['dist_dir'] = self.env['BUILT_PRODUCTS_DIR']
+        py2app['bdist_base'] = self.env['TARGET_TEMP_DIR']
+        rval = dict(
+            data_files=resources,
+            options=dict(py2app=py2app),
+        )
+        rval[buildstyle] = [self.getTarget(nibFiles, modules)]
+
+        return rval

Lib/PyObjCTools/XcodeSupport/api.py

 def xcodeFromEnvironment(project, env):
     from PyObjCTools.XcodeSupport import ArchiveGraph
     from PyObjCTools.XcodeSupport import Xcode
+    from PyObjCTools.XcodeSupport import XcodeProj
     path = os.path.join(project, 'project.pbxproj')
     if not os.path.exists(path):
-        path = glob.glob('*.xcode/project.pbxproj')[0]
-    return Xcode.Xcode(project, ArchiveGraph.ArchiveGraph.fromPath(path), env)
+        path = ArchiveGraph.xcodeFiles('.')[0]
+    projType = os.path.splitext(os.path.dirname(path))[1]
+    if projType == '.xcodeproj':
+        mod = XcodeProj
+    elif projType == '.xcode':
+        mod = Xcode
+    return mod.Xcode(project, ArchiveGraph.ArchiveGraph.fromPath(path), env)
+
+def main():
+    import sys
+    return xcodeFromEnvironment(sys.argv[1], dict(os.environ))
+
+if __name__ == '__main__':
+    main()
 <p>An overview of the relevant changes in new, and older, releases.</p>
 <h2><a name="version-1-3-7">Version 1.3.7 (????-??-??)</a></h2>
 <ul>
+<li>Probably working Xcode 2.1 support (for converted Xcode 2.0 projects)</li>
 <li>Hide List, Object, and Protocol classes from objc.loadBundle
 to prevent confusion with Python code.  They can still be looked
 up with objc.lookUpClass.</li>
 Version 1.3.7 (????-??-??)
 --------------------------
 
+- Probably working Xcode 2.1 support (for converted Xcode 2.0 projects)
+
 - Hide List, Object, and Protocol classes from objc.loadBundle
   to prevent confusion with Python code.  They can still be looked
   up with objc.lookUpClass.