Re: [Pyobjc-dev] execing /usr/bin/python
Brought to you by:
ronaldoussoren
From: <bb...@ma...> - 2002-11-01 02:53:29
|
On Thursday, October 31, 2002, at 04:42 PM, Ronald Oussoren wrote: > On Thursday, Oct 31, 2002, at 14:20 Europe/Amsterdam, bb...@ma... > wrote: >>> 2. If not, how could this be implemented? >> >> It is is implemented by: > - The python sources are copied to the Resources directory of > the application > > Do we have any control over this? I'd like to be able to convert the > sources to bytecode (slightly faster startup, and this makes it harder > to change the code). Sure. - Add a new shell script build phase to your project - check off the 'Run only when installing' checkbox - set the script to the command necessary to compile the python code [see the PBX docs for what variables are available, etc...] The alternative is to do a new target of type legacy makefile, then create another target named packaging and add both the app target and the legacy target to packaging. The legacy target could be used to compile all py files upon installation. This is how the Web Services Tool project works -- if you 'pbxbuild install -target Packaging', it uses a legacy makefile target to copy the readme and license to the destination directory. With the addition of a script written by Mike Trent and I, the whole thing can be automatically shoved onto a Disk Image automatically. >> - using a series of copy file phases to copy the PyObjC module >> into the 'pyobjc' subdirectory of the Resources directory of the >> application when the 'install' target is used ('pbxbuild install' >> from the command line). >> >> - the main.m uses execve() to transfer control to /usr/bin/python >> and exec Main.py in a fashion where OS X thinks that /usr/bin/python >> is the executable within the app wrapper (otherwise, mainBundle >> breaks). Unfortunately, this is what breaks gdb. Fortunately, this >> will go away when Apple ships a new build of Python that includes a >> library for embedding. > In a conversation about an 'addon-for-Apple-python' version of > MacPython I mentioned this technique to Jack Jansen (the MacPython > maintainer). He intends to use a slightly different technique: The > wrapper does not use execve() /usr/bin/python, but a python binary(*) > in the Contents/MacOS directory of the .app with and argv[0] that > actually points to this python binary. The reason for this variation > is that this would make 'sys.executable' point to a python interpreter > and appearantly some existing code expects this (including the Python > testsuite). We didn't know if the APIs that require a full path to the > application in argv[0] would mind that argv[0] is not the name of the > binary mentioned in the Info.plist. That'll work though the current use of execve() has a distinct advantage (and, in reality, calling execve to transfer control to the python interpreter adds very little overhead). The advantage to the current method is that the binary contained in the app wrapper can be linked against all the frameworks that should be loaded into the python interpreter environment; including any frameworks specifically built for the project. The main that is in Web Services Tool and-- now-- the Project Template passes the set of frameworks linked into the app wrapper's executable into the execution of the python binary as an argument. This argument is picked up by Main.py and it automatically dynamically loads all of the frameworks and executes an Init.py in each, if present. In other words, the app wrapper automatically bootstraps the python environment with all of the frameworks that would normally be linked directly into the application -- the developer doesn't have to do anything to cause these frameworks to be loaded. In the production app that I'm working on that uses PyObjC, the automatic linking of the frameworks has proved to be a huge time saver. "It just works". In particular, it means that PBX's indexing features and everything about the build process work exactly like a normal Cocoa app save for the funky main file. Debugging only requires one extra step; an 'attach PID' command issued to a gdb session against /usr/bin/python -- there is a default you can set [found in main.m] that causes the app to actually print the gdb command needed to debug the app. In any case, argv[0] *must* be the path to the executable within the app wrapper or else the NSBundle/CFBundle environment will not be correctly initialized. --- Keep in mind that all of this is nothing but a workaround needed if using Apple's python. When using the Fink or framework builds, it is possible to simply embed the interpreter directly into the executable found within the app wrapper, thereby completely obviating the need to do any of this goofy execve() or sym linking or providing the python executable garbage that we are doing now. With an embedded interpreter, the launch times drop to normal, custom classes are linked directly into the executable, and debugging works exactly as it does with any other Cocoa application. With some serious trickery, we can actually support both execution models from the same executable as long as all of the custom classes are pushed into frameworks... at least, I'm pretty damned sure we can... it'll require some low level hacquery for which I have neither the need or whiskey to tackle right now. Have a look at the "other" main.m that is provided in the Web Services Tool example; it was the original version that I wrote for use with an embedded interpreter. In particular, it programmatically sets sys.executable as a part of the interpreter initialization. It is a far better solution than anything involving execve() or symlinks to python interpreters. b.bum |