Creating .sip files

The easiest way to understand the creation of the .sip input files is to look at an example. The process begins with the original header file from the library source code distribution (in this case, qmultilinedit.h) which is used as the starting point in creating the .sip file. It is a bit of a drudgery, since transforming a header file into an input file for sip is mostly handwork.

Shown is a fragment of the qmultilinedit.sip file created from qmultilinedit.h. If you look at the original file in the PyQt sources, you will find at the top of the complete qmultilinedit.sip some code for generating documentation, which is omitted here.

class QMultiLineEdit : QTableView
{
%HeaderCode
#include <qmultilinedit.h>
%End

public:
  QMultiLineEdit(QWidget * /TransferThis/ = 0,const char * = 0);

  int numLines() const;
  virtual void removeLine(int);

  void cursorPosition(int *,int *) const;
%MemberCode
  // The Python interface returns a tuple.

  QMultiLineEdit *ptr;

  if (sipParseArgs(&sipArgsParsed,sipArgs,
                   "m",
                   sipThisObj,sipClass_QMultiLineEdit,
                   &ptr))
  {
    int line, col;

    ptr -> QMultiLineEdit::cursorPosition(&line,&col);

    return Py_BuildValue("(ii)",line,col);
  }
%End
    

Most of the process of creating a .sip file is deleting all of the things SIP doesn't need or can't use. Typically all comments are stripped from the .h file in creating the .sip file, since they aren't necessary for SIP and are still available in the original .h file. For PyQt, SIP only uses methods and variables from specific parts of each class:

Table C-1. C++ access specifiers and sip

C++ accessUse in .sip file
publicmethods and variables
protectedmethods only
privatemethods only

All private variables are deleted from the C++ header (.h) file, as are all protected variables. Public methods and variables are retained.

Normally all private methods are also deleted, but there are one or two cases where they are useful. For example, declaring a private copy constructor prevents SIP from automatically generating a public copy constructor.

Next, all parameter names are deleted. For instance:

  ...
  void cursorPosition( int *line, int *col ) const;
  ...
    

becomes

  ...
  void cursorPosition(int *,int *) const;
  ...
    

sip does not ‘understand' (or need) method parameter names, and in fact any parameter names left in the .sip file will cause a sip syntax error when sip is run on the file. Note also that the ‘public' directive is removed from the class declaration line, as is any Q_OBJECT declaration or any friend class declarations when these are present. Any inline C++ code is also removed.

In the QMultiLineEdit constructor, the ‘parent' parameter name has been replaced with a /TransferThis/ directive. This directive tells sip that if the parameter is not None then ownership of the QMultiLineEdit object is transferred from PyQt to Qt. Therefore Qt is responsible for deleting this QMultiLineEdit object at the appropriate time. Failure to include this directive where needed would result in a segmentation fault, usually when the program terminates and Python tries to destroy the object which Qt has already destroyed. A /Transfer/ directive is also available to serve a similar purpose for an an object passed as a parameter to an ordinary function or method.

Directly following the class declaration is a %Headercode declaration that references the .h file that this .sip file was derived from. The %Headercode declaration goes inside the class definition because sip generates a .h/.cpp file for every class. If there were multiple classes defined in qmultilinedit.h, each class would require a %Headercode declaration. Sip itself doesn't use the .h file, but the sip generated code needs the .h file so it can know about the Qt classes and methods being wrapped.