diff options
Diffstat (limited to 'Mac/Demo/plugins.html')
-rw-r--r-- | Mac/Demo/plugins.html | 324 |
1 files changed, 0 insertions, 324 deletions
diff --git a/Mac/Demo/plugins.html b/Mac/Demo/plugins.html deleted file mode 100644 index a49da68..0000000 --- a/Mac/Demo/plugins.html +++ /dev/null @@ -1,324 +0,0 @@ -<HTML><HEAD><TITLE>Creating a C extension module on the Macintosh</TITLE></HEAD> -<BODY> -<H1>Creating a C extension module on the Macintosh</H1> -<HR> - -This document gives a step-by-step example of how to create a new C -extension module on the mac. For this example, we will create a module -to interface to the programmers' API of InterSLIP, a package that -allows you to use MacTCP (and, hence, all internet services) over a -modem connection. The actual example does not work anymore, as both -MacTCP and Interslip died long ago, but the text is still mostly -correct.<p> - -<H2>Prerequisites</H2> - -There are a few things you need to pull this off. First and foremost, -you need a C development environment. Actually, you need a specific -development environment, CodeWarrior by <A -HREF="http://www.metrowerks.com/">MetroWerks</A>. You will -need Version 7 or later. You may be able to get by with an older -version of CodeWarrior or with another development environment (Up to -about 1994 python was developed with THINK C, and in the dim past it -was compiled with MPW C) assuming you have managed to get Python to -compile under your development environment, but the step-by-step -character of this document will be lost. <p> - -Next, you need to install the Developer option in the MacPython installer. -You may also find that Guido's <A -HREF="http://www.python.org/doc/ext/ext.html">Extending and embedding -the Python interpreter</A> is a very handy piece of documentation. I -will skip lots of details that are handled there, like complete -descriptions of <CODE>Py_ParseTuple</CODE> and such utility routines, or -the general structure of extension modules. <p> - -<H2>InterSLIP and the C API to it</H2> - -InterSLIP, the utility to which we are going to create a python -interface, is a system extension that does all the work of connecting -to the internet over a modem connection. InterSLIP is provided -free-of-charge by <A -HREF="http://www.intercon.com/">InterCon</A>. First it connects to -your modem, then it goes through the whole process of dialling, -logging in and possibly starting the SLIP software on the remote -computer and finally it starts with the real work: packing up IP -packets handed to it by MacTCP and sending them to the remote side -(and, of course, the reverse action of receiving incoming packets, -unpacking them and handing them to MacTCP). InterSLIP is a device -driver, and you control it using a application supplied with it, -InterSLIP Setup. The API that InterSLIP Setup uses to talk to the -device driver is published in the documentation and, hence, also -useable by other applications. <p> - -I happened to have a C interface to the API, which is all ugly -low-level device-driver calls by itself. The C interface is in <A -HREF="interslip/InterslipLib.c">InterslipLib.c</A> and <A -HREF="interslip/InterslipLib.h">InterslipLib.h</A>, we'll -concentrate here on how to build the Python wrapper module around -it. Note that this is the "normal" situation when you are writing a -Python extension module: you have some sort of functionality available -to C programmers and want to make a Python interface to it. <p> - -<H2>Using Modulator</H2> - -The method we describe in this document, using Modulator, is the best -method for small interfaces. For large interfaces there is another -tool, Bgen, which actually generates the complete module without you -lifting a single finger. Bgen, however, has the disadvantage of having -a very steep learning curve, so an example using it will have to wait -until another document, when I have more time. <p> - -First, let us look at the <A -HREF="interslip/InterslipLib.h">InterslipLib.h</A> header file, -and see that the whole interface consists of six routines: -<CODE>is_open</CODE>, <CODE>is_connect</CODE>, -<CODE>is_disconnect</CODE>, <CODE>is_status</CODE>, -<CODE>is_getconfig</CODE> and <CODE>is_setconfig</CODE>. Our first -step will be to create a skeleton file <A -HREF="interslip/@interslipmodule.c">@interslipmodule.c</A>, a -dummy module that will contain all the glue code that python expects -of an extension module. Creating this glue code is a breeze with -modulator, a tool that we only have to tell that we want to create a -module with methods of the six names above and that will create the -complete skeleton C code for us. <p> - -Why call this dummy module <CODE>@interslipmodule.c</CODE> and not -<CODE>interslipmodule.c</CODE>? Self-preservation: if ever you happen -to repeat the whole process after you have actually turned the -skeleton module into a real module you would overwrite your -hand-written code. By calling the dummy module a different name you -have to make <EM>two</EM> mistakes in a row before you do this. <p> - -If you installed Tk support when you installed Python this is extremely -simple. You start modulator and are provided with a form in which you -fill out the details of the module you are creating. <p> - -<IMG SRC="html.icons/modulator.gif" ALIGN=CENTER><p> - -You'll need to supply a module name (<CODE>interslip</CODE>, in our -case), a module abbreviation (<CODE>pyis</CODE>, which is used as a -prefix to all the routines and data structures modulator will create -for you) and you enter the names of all the methods your module will -export (the list above, with <CODE>is_</CODE> stripped off). Note that -we use <CODE>pyis</CODE> as the prefix instead of the more logical -<CODE>is</CODE>, since the latter would cause our routine names to -collide with those in the API we are interfacing to! The method names -are the names as seen by the python program, and the C routine names -will have the prefix and an underscore prepended. Modulator can do -much more, like generating code for objects and such, but that is a -topic for a later example. <p> - -Once you have told modulator all about the module you want to create -you press "check", which checks that you haven't omitted any -information and "Generate code". This will prompt you for a C output -file and generate your module for you. <p> - -<H2>Using Modulator without Tk</H2> - - -Modulator actually uses a two-stage process to create your code: first -the information you provided is turned into a number of python -statements and then these statements are executed to generate your -code. This is done so that you can even use modulator if you don't -have Tk support in Python: you'll just have to write the modulator -python statements by hand (about 10 lines, in our example) and -modulator will generate the C code (about 150 lines, in our -example). Here is the Python code you'll want to execute to generate -our skeleton module: <p> - -<CODE><PRE> - import addpack - addpack.addpack('Tools') - addpack.addpack('modulator') - import genmodule - - m = genmodule.module() - m.name = 'interslip' - m.abbrev = 'pyis' - m.methodlist = ['open', 'connect', 'disconnect', 'status', \ - 'getconfig', 'setconfig'] - m.objects = [] - - fp = open('@interslipmodule.c', 'w') - genmodule.write(fp, m) -</PRE></CODE> - -Drop this program on the python interpreter and out will come your -skeleton module. <p> - -Now, rename the file to interslipmodule.c and you're all set to start -developing. The module is complete in the sense that it should -compile, and that if you import it in a python program you will see -all the methods. It is, of course, not yet complete in a functional -way... <p> - -<H2>Creating a plugin module</H2> - -The easiest way to build a plugin module is to use the distutils package, -this works fine on MacOS with CodeWarrior. See the distutils documentation -for details. Keep in mind that even though you are on the Mac you specify -filenames with Unix syntax: they are actually URLs, not filenames. - <p> - -Alternatively you can build the project file by hand. -Go to the ":Mac:Build" folder and copy the files xx.carbon.mcp, -and xx.carbon.mcp.exp to interslipmodule.carbon.mcp and -interslipmodule.carbon.mcp.exp, respectively. Edit -interslipmodule.carbon.mcp.exp and change the name of the exported routine -"initxx" to "initinterslip". Open interslipmodule.carbon.mcp with CodeWarrior, -remove the file xxmodule.c and add interslipmodule.c and make a number -of adjustments to the preferences: -<UL> -<LI> in PPC target, set the output file name to "interslipmodule.carbon.slb", -<LI> if you are working without a source distribution (i.e. with a normal -binary distribution plus a development distribution) you will not have -a file <code>PythonCoreCarbon</code>. The installation process has deposited this -file in the System <code>Extensions</code> folder under the name -<code>PythonCoreCarbon <i>version</i></code>. Add that file to the project, replacing -<code>PythonCoreCarbon</code>. -<LI> you must either download and build GUSI (if your extension module uses sockets -or other Unix I/O constructs) or remove GUSI references from the Access Paths -settings. See the <a href="building.html">Building</a> document for where to get GUSI -and how to build it. -</UL> -Next, compile and link your module, fire up python and test it. <p> - -<H2>Getting the module to do real work</H2> - -So far, so good. In half an hour or so we have created a complete new -extension module for Python. The downside, however, is that the module -does not do anything useful. So, in the next half hour we will turn -our beautiful skeleton module into something that is at least as -beautiful but also gets some serious work done. For this once, -<EM>I</EM> have spent that half hour for you, and you can see the -results in <A -HREF="interslip/interslipmodule.c">interslipmodule.c</A>. <p> - -We add -<CODE><PRE> - #include "InterslipLib.h" - #include "macglue.h" -</PRE></CODE> -to the top of the file, and work our way through each of the methods -to add the functionality needed. Starting with open, we fill in the -template docstring, the value accessible from Python by looking at -<CODE>interslip.open.__doc__</CODE>. There are not many tools using -this information at the moment, but as soon as class browsers for -python become available having this minimal documentation available is -a good idea. We put "Load the interslip driver" as the comment -here. <p> - -Next, we tackle the body of <CODE>pyis_open()</CODE>. Since it has no -arguments and no return value we don't need to mess with that, we just -have to add a call to <CODE>is_open()</CODE> and check the return for -an error code, in which case we raise an error: -<CODE><PRE> - err = is_open(); - if ( err ) { - PyErr_Mac(ErrorObject, err); - return NULL; - } -</PRE></CODE> -The routine <CODE><A NAME="PyErr_Mac">PyErr_Mac()</A></CODE> is a -useful routine that raises the exception passed as its first -argument. The data passed with the exception is based on the standard -MacOS error code given, and PyErr_Mac() attempts to locate a textual -description of the error code (which sure beats the "error -14021" -messages that so many macintosh applications tell their poor -users). <p> - -We will skip pyis_connect and pyis_disconnect here, which are pretty -much identical to pyis_open: no arguments, no return value, just a -call and an error check. With pyis_status() things get interesting -again: this call still takes 3 arguments, and all happen to be values -returned (a numeric connection status indicator, a message sequence -number and a pointer to the message itself, in MacOS pascal-style -string form). We declare variables to receive the returned values, do -the call, check the error and format the return value. <p> - -Building the return value is done using <CODE><A -NAME="Py_BuildValue">Py_BuildValue</A></CODE>: -<CODE><PRE> - return Py_BuildValue("iiO&", (int)status, (int)seqnum, PyMac_BuildStr255, message); -</PRE></CODE> -Py_BuildValue() is a very handy routine that builds tuples according -to a format string, somewhat similar to the way <CODE>printf()</CODE> -works. The format string specifies the arguments expected after the -string, and turns them from C objects into python objects. The -resulting objects are put in a python tuple object and returned. The -"i" format specifier signifies an "int" (hence the cast: status and -seqnum are declared as "long", which is what the is_status() routine -wants, and even though we use a 4-byte project there is really no -reason not to put the cast here). Py_BuildValue and its counterpart -Py_ParseTuple have format codes for all the common C types like ints, -shorts, C-strings, floats, etc. Also, there is a nifty escape -mechanism to format values about which is does not know. This is -invoked by the "O&" format: it expects two arguments, a routine -pointer and an int-sized data object. The routine is called with the -object as a parameter and it should return a python objects -representing the data. <CODE>Macglue.h</CODE> declares a number of -such formatting routines for common MacOS objects like Str255, FSSpec, -OSType, Rect, etc. See the comments in the include file for -details. <p> - -<CODE>Pyis_getconfig()</CODE> is again similar to pyis_getstatus, only -two minor points are worth noting here. First, the C API return the -input and output baudrate squashed together into a single 4-byte -long. We separate them out before returning the result to -python. Second, whereas the status call returned us a pointer to a -<CODE>Str255</CODE> it kept we are responsible for allocating the -<CODE>Str255</CODE> for getconfig. This is something that would have -been easy to get wrong had we not used prototypes everywhere. Morale: -always try to include the header files for interfaces to libraries and -other stuff, so that the compiler can catch any mistakes you make. <p> - -<CODE>Pyis_setconfig()</CODE> finally shows off -<CODE>Py_ParseTuple</CODE>, the companion function to -<CODE>Py_BuildValue</CODE>. You pass it the argument tuple "args" -that your method gets as its second argument, a format string and -pointers to where you want the arguments stored. Again, standard C -types such as strings and integers Py_ParseTuple knows all about and -through the "O&" format you can extend the functionality. For each -"O&" you pass a function pointer and a pointer to a data area. The -function will be called with a PyObject pointer and your data pointer -and it should convert the python object to the correct C type. It -should return 1 on success and 0 on failure. Again, a number of -converters for standard MacOS types are provided, and declared in -<CODE>macglue.h</CODE>. <p> - -Next in our source file comes the method table for our module, which -has been generated by modulator (and it did a good job too!), but -which is worth looking at for a moment. Entries are of the form -<CODE><PRE> - {"open", pyis_open, 1, pyis_open__doc__}, -</PRE></CODE> -where the entries are python method name, C routine pointer, flags and -docstring pointer. The value to note is the 1 for the flags: this -signifies that you want to use "new-style" Py_ParseTuple behaviour. If -you are writing a new module always use this, but if you are modifying -old code which calls something like <CODE>getargs(args, "(ii)", -...)</CODE> you will have to put zero here. See "extending and -embedding" or possibly the getargs.c source file for details if you -need them. <p> - -Finally, we add some code to the init module, to put some symbolic -constants (codes that can by returned by the status method) in the -module dictionary, so the python program can use "interslip.RUN" -instead of the cryptic "4" when it wants to check that the interslip -driver is in RUN state. Modulator has already generated code to get at -the module dictionary using PyModule_GetDict() to store the exception -object, so we simply call -<CODE><PRE> - PyDict_SetItemString(d, "IDLE", PyInt_FromLong(IS_IDLE)); -</PRE></CODE> -for each of our items. Since the last bit of code in our init routine -checks for previous errors with <CODE>PyErr_Occurred()</CODE> and -since <CODE>PyDict_SetItemString()</CODE> gracefully handles the case -of <CODE>NULL</CODE> parameters (if <CODE>PyInt_FromLong()</CODE> -failed, for instance) we don't have to do error checking here. In some -other cases you may have to do error checking yourself. <p> - -This concludes our crash-course on writing Python extensions in C on -the Macintosh. If you are not done reading yet I suggest you look -back at the <A HREF="index.html">MacPython Crashcourse index</A> to -find another topic to study. <p> |