User:Itawswati
Swig And Objective C
[edit]Introduction
[edit]This chapter describes the Swig support for Objective C. Objective C is general pupose,high-level,object oriented language that adds small-talk Style messaging to C programming language. It is the main programming language used by Apple for the OS X and i OS operating systems and their respective APIs,Cocoa and Cocoa Touch. The support for Objective C as a target language, in essence, is similar to the existing Java and C# support. For every possible C++ construct in the SWIG interface, the corresponding interface header and proxy code would be generated. While, the interface header contains an equivalent Objective C representation of every given C++ construct, the proxy (Objective C++) provides the glue code for necessary type conversions i.e for primitive types, pointers, references and custom types. Objective C is an object oriented extension to C which means that other than constructs for creating and manipulating objects, all valid C constructs are valid constructs in Objective C. Hence they appear as is in the Objective C interface. Specifically, there will be a support to generate Objective C constructs and proxies for all C++ and C constructs such as: classes, callbacks, enums, constants, function ,pointers, global functions, variables and C++ templates.
Preliminaries
[edit]Running SWIG
[edit]Let us consider you have defined the swig module as following:
/* File:example.i */ %module example %{ #include “example.h” %} int gcd(int x,int y);
To build Objective C module,run SWIG with -objc option
swig -objc example.i
If the source file is C++ ,then -c++ option is used
swig -c++ -objc example.i
The above command creates two different files. A C/C++ source file generates example_wrap.h , example_wrap.mm and the numerous Objective C files. The generated files contains the Objective C++ wrapper code that needs to be compiled and linked with the rest of the C/C++ program. The name of the input file is derived from the name of module. For eg. If the name of the input file is example.i then the name of the wrapper file is example_wrap.mm.To change this, you can use the -o option. It is also possible to change the output directory that the Objective C files are generated into using -outdir.
Commandline options
[edit]There are certain command line options that are used with Objective C module. There is another way to look to these command line option
swig -objc -help -noproxy Do not generate proxy files (Only C wrappers would be generated)
Compiling a Dynamic Module
[edit]The next step is to build a dynamically loadable module, which we can link to our application. This can be done easily, for example using the gcc compiler:
$ swig -objc example.i $ gcc -objc example_wrap.mm example_proxy.mm $ gcc -shared example_wrap.o example_proxy.o -lobjc -lgnustep-base -o libexample.so
Or, for C++ input:
$ swig -c++ -objc example.i $ gcc -c example_wrap.mm example_proxy.mm $ gcc -shared example_wrap.o example_proxy.o -lobjc -lgnustep-base -o libexample.so
Now the shared library module is ready to use. Note that the name of the generated module is important: it should be prefixed with lib on Unix,dylib on Mac and have the specific extension, like .dll for Windows or .so for Unix systems.
To be able to compile this dynamic module on Mac is an easy step which requires no installations.
But to be able to run Objective C module on Unix ,GNUstep must be installed on a Linux like systems.
In order to have the Objective C support on Swig together with Cocoa/open source environment
on Linux, It is necessary to install gcc, the gcc Objective C support package and GNUstep
environment in the following order:
a.) To install GNUstep on Ubuntu, first open the Terminal window and enter the following command
sudo apt-get install gnustep
After gathering the list of packages that is required for GNUstep run time installation ,apt-get utility will ask for confirmation. After confirmation, packages will be downloaded and installed.
b.) The next step is GNUstep development package installation. For this following command needs to be entered on the Terminal
sudo apt-get install gnustep-devel
The installation of above packages also installs the important packages i.e. GNUstep-common and GNUstep-make that is required.
c.) After installation of above packages. You are ready to build Swig having Objective C support on Linux by specifying following commands: cd swig ./autogen.sh ./configure make make install
d.)Now run Objective C with Swig on Linux. If no error comes during compilation,everything is ok and if you get error message like: gcc: error trying to exec 'cc1obj': execvp: No such file or directory You need to install gobjc++ package by typing following command on Terminal window
sudo apt-get install gobjc++
And then compile the examples
A tour to basic C/C++ wrapping
[edit]Globals
[edit]For the functions and variables which are declared with the extern specifier in the interface file for eg.
%inline %{ extern int gcd(int x, int y); extern double Foo; %}
Following wrapper code is generated for functions
int _wrap_gcd(int arg1, int arg2) { int imresult = 0 ; int result; result = (int)gcd(arg1,arg2); imresult = result; return imresult; }
And for the variables ,following get and set functions are generated to access as well modify the value of a variable.
void _wrap_Foo_set(double imarg1) { double arg1 ; arg1 = (double)imarg1; Foo = arg1; }
double _wrap_Foo_get() { double imresult = 0 ; double result; result = (double)Foo; imresult = result; return imresult; }
And if the proxy flag is true ,the proxy files will contain the functions with the same name as in source code and their definition contains the implicit call to the wrapper functions as shown below
int ObjcGcd(int x, int y) { return _wrap_gcd(x, y); }
void setFoo(double value) { _wrap_Foo_set(value); }
Constants
[edit]C/C++ constants created via #define or the %constant directive become Objective C constants, declared with a extern or const declaration. Also the string constant would have @ appended at the beginning of the constant value. For eg. If the interface file has following code
#define PI 3.14159 #define VERSION "1.0" %constant int FOO = 42;
Then the code generated in proxy.h file would be
extern double PI; extern NSString * VERSION; extern int FOO;
And the code generated in proxy.mm file would be
double PI= 3.14159; NSString * const VERSION= @"1.0"; int Foo= 42;
C constants can be directly accessed by Objective C so there is no need of wrapper in case if the interface file contains the C constants.
Enums
[edit]C/C++ enumeration types will cause SWIG to define an integer type with the name of the enumeration . The values of the enumeration will become variables in Objective C. Enums can be inside the class scope or outside The enums outside ,would be C enums and can be accessed as it is.
But for enums inside the class as shown below
class Foo { public: Foo() { } enum speed { IMPULSE=10, WARP=20, LUDICROUS=30 }; };
Following proxy code is generated
enum Foo_speed { Foo_IMPULSE = 10, Foo_WARP = 20, Foo_LUDICROUS = 30 };
Classes
[edit]The Objective C module has the support to wrap C++ classes. For example if we have following class
class Circle { public: double radius; Circle(double r) : radius(r) { }; double area(void); };
What we need to do is to create an object of the class, manipulate it, and finally, destroy it. SWIG generates C functions for this purpose each time a class declaration is encountered in the interface file. The first two generated functions are used to create and destroy instances of class The generated functions make calls to class' constructors and destructors, respectively. They also do all the necessary things required by the SWIG. The above code can be accessed in Objective C as follows
Circle *circle = [[Circle alloc]initWithR:5]; circle.area(); And the objects which are allocated can be released by [circle release];
Also the wrapping of the class member functions would have -sign prefix and the static member function or variables would have + sign prefixed in proxy code as shown below
@implementation Circle -(double)area { return _wrap_Circle_area([self getCptr]); } @end
And if this would be static function in a C++.The code generated is follows
@implementation Circle +(double)area { return _wrap_Circle_area([self getCptr]); } @end
C++ Inheritance
[edit]Simple C++ inheritance is handled in Objective C as follows.For eg. If we have following interface file
class Shape { public: virtual double area(void) = 0; virtual double perimeter(void) ; }; class Circle : public Shape { public: virtual double area(void); }; class Square : public Shape { public: virtual double area(void); };
The corresponding code is generated in proxy header files
@interface Shape : NSObject { void *swigCPtr; BOOL swigCMemOwn; } -(void*)getCptr; -(id)initWithCptr: (void*)cptr swigOwnCObject: (BOOL)ownCObject; -(double)area; -(double)perimeter; -(void)dealloc; @end @interface Circle : Shape -(double)area; -(void)dealloc; @end @interface Square : Shape -(double)area; -(void)dealloc; @end
Now the shape and the circle Class inherit the features of the base class shape.And to access the base class perimeter function we have use the following code.
Circle *circle =[[Circle alloc]init]; [circle perimeter];
Note that Objective C does not support multiple inheritance so any multiple inheritance in the C++ code is not going to work. A warning is given when multiple inheritance is detected and only the first base class is used.
Pointer and References
[edit]C/C++ pointers are fully supported by SWIG. Furthermore, Objective C has support for it. Here is a rather simple interface
Here is simple interface file
%module example %{ #ifdef __cplusplus extern "C" { #endif extern void add(int *, int *, int *); #ifdef __cplusplus } #endif %}
This when wrapped ,you will able to use the functions in a natural way from Objective C
int* a = ObjcNew_intp(); int* b = ObjcNew_intp(); int* c = ObjcNew_intp(); ObjcAdd(a,b,c);
The first three statements are used to create and assign the pointers to the pointer variables and then making use of ObjcAdd function to add the value pointed to by these pointer variables and getting the result in c.
References are treated as pointers in Objective C
Templates
[edit]C++ templates don't present a huge problem for SWIG. However, in order to create wrappers, you have to tell SWIG to create wrappers for a particular template instantiation. To do this, you use the %template directive. For example:Consider the following interface file module example
%{ #include "example.h" %} %include "example.h" /* Now instantiate some specific template declarations */ %template(maxint) max<int>; %template(maxdouble) max<double>; %}
In Objective C :
NSLog(@"The value returned by maxint is %i",ObjcMaxint(3,7)); NSLog(@"The value returned by maxdouble is %g",ObjcMaxdouble(3.14,2.18)) ;
obviously, there is more to template wrapping than shown in this example. More details can be found in the SWIG and C++ chapter.
Pointer to functions
[edit]Occasionally, a C library may include functions that expect to receive pointers to functions--possibly to serve as callbacks. Objective C provides support for function pointers provided that the callback functions are defined in C. For example, consider a function like this:
extern int do_op(int a, int b, int (*op)(int, int));
/* Now install a bunch of "ops" as constants */ %constant int (*ADD)(int,int) = add; %constant int (*SUB)(int,int) = sub; %constant int (*MUL)(int,int) = mul; extern int (*funcvar)(int,int);
The above function is wrapped as follows
int ObjcDo_op(int a, int b, SWIGTYPE_p_f_int_int__int* op) { return _wrap_do_op(a, b, [op getCptr]); }
And will be called from the client code as below:
ObjcDo_op(a,b,ADD);
Exceptions
[edit]The SWIG Objective C module has support for exceptions thrown from C or C++ code to be caught in scheme. See Exception handling with %exception for more information about declaring exceptions in the interface file. Objective C supports both the SWIG_exception(int code, const char *msg) interface as well as a SWIG_ObjcThrowException(C_word val) function for throwing exceptions from inside the %exception blocks. SWIG_exception will throw a list consisting of the code (as an integer) and the message. Both of these will throw an exception , which can be handled by (handle-exceptions).
Typemaps
[edit]A typemap is really just a special processing rule that is applied to a particular datatype. Each typemap relies on two essential attributes--a datatype and a name (which is optional). When trying to match parameters, target language looks at both attributes. Thus, special processing applied to a parameter of “double *result” will not be applied to “double *input”. On the other hand, special processing defined for a datatype of “double *” could be applied to both (since it is more general). This section describes how you can modify SWIG's default wrapping behavior for various C/C++ data types using the %typemap directive. You are advised to be familiar with the material in the " Typemaps" chapter. The following special variables are available.
$result Result object returned to target language. $symname Name of function/method being wrapped $1...n Argument being wrapped $1_name Name of the argument (if provided) $1_type The actual C datatype matched by the typemap. $1_ltype The assignable version of the C datatype matched by the typemap.
What is a typemap?
[edit]A typemap is nothing more than a code generation rule that is attached to a specific C datatype. For example, to convert integers from Objective C to C, you might define a typemap like this:
%module example %typemap(in) int { $1 = $input; printf("Received an integer : %d\n", $1); } %inline %{ extern int fact(int nonnegative); %}
Typemaps are always associated with some specific aspect of code generation. In this case, the "in" method refers to the conversion of input arguments to C/C++. The datatype int is the datatype to which the typemap will be applied. The supplied C code is used to convert values. In this code a number of special variables prefaced by a $ are used. The $1 variable is a placeholder for a local variable of type int. The $input variable contains the Objective C data
This will be compiled in Objective C as follows. NSLog(@”The factorial of a number is: %d”,fact(6));
Typemaps for mapping C/C++ types to Objective C types There are number of typemaps that are required to use SWIG with Objective C. The following typemaps are used in obj.swg file 'in' typemap are used if we want to make conversions from Objective C to C/C++ code and out typemaps are used to specify the return value from C/C++ to Objective C code If you already know the SWIG C# module, you might find the following name comparison table useful:
imtype ↔ imtype in ↔ in out ↔ out objctype ↔ cstype objcin ↔ csin objcout ↔ csout
imtype ,objctype
[edit]The imtype specifies the types used in the intermediatory code corresponding to the C++ type.And the objctype represents the Objective C(proxy) type corresponding to each Objective C++ type in the intermediate(wrapper) layer.
in,out typemap.
[edit]These typemaps are used to convert the types between C/C++ and Objective C when generating the wrapper code.
The code from the in typemap is used to convert arguments to the Objective C++ wrapper function to the type used in the wrapped code (imtype ->original C++ type), the out typemap is utilized to convert values from the wrapped code to wrapper function return types (original C++ type->imtype).
So,in typemap are used if we want to make conversions from Objective C++ to C/C++ code and out typemaps are used to specify the return value from C/C++ to Objective C++ code
objcin,objcout
[edit]objcin typemaps are used for "in" arguments type conversions from Objective C(proxy) layer to Objective C++(wrapper) layer. And objcout typemaps are used for return-type type conversions from Objective C++(wrapper) to Objective C(proxy)
If the C++ function is gcd(int x,double y).If this function is called from Objective C . Following conversions take place
objctype->imtype->c/c++
i.e.
int(objctype)->int(imtype)->int(c/c++type)
However if there is some object as the second argument say Test *t then the conversion takes place as
Test *t(objctype)->(void *)imtype->(Test * t)c/c++
For return value conversion takes place in opposite direction
c++ type->imtype->objctype
Special Macros
[edit]When generating the Objective C wrappers,a few additional macros are used.
$objcbase
[edit]Currently for internal use only, it contains the Objective C name of the C++ base class (if any) inside proxy classes.
These following typemaps are used for generating the skeleton of proxy classes for C++ types.
By overriding objcprotocols or objcprotocols_derived, the inheritance chain of the generated proxy class for a type can be modified. Objcconstructor,objcdestructor are used to generate the class constructor and destructor respectively.
This is how the typemap for Objective C constructor and destructor looks like
%typemap(objcconstructor) SWIGTYPE %{ if((self = [super init])) { void* cptr = $imcall; swigCPtr = cptr; swigCMemOwn = YES; } return self; %}
%typemap(objcdestructor, methodname="dealloc", methodmodifiers="public") SWIGTYPE %{ if (swigCPtr != NULL) { if (swigCMemOwn) { $imcall; swigCMemOwn = NO; } swigCPtr = NULL; } [super dealloc]; %}
The typemaps containing Objective C code when generating Objective C proxy classes are:
$objcinterfacemodifier is replaced by @interface $objcimplementationmodifier is replaced by @implememnattion $objcclassclose is replaced by @end
$objcinterfacecode,$objcimplementationcode
[edit]These typemaps are used for generating the skeleton for the proxy classes for the C++ class which donot have base class.
$objcinterfacecode_derived,$objcimplementationcode_derived
[edit]These typemaps are used for generating the skeleton for the proxy classes for the C++ class which do have base class.
$objcinput
[edit]This variable is used in objcin typemap and is replaced by the expression which is passed by C/C++. For example,
%typemap(objcin) SomeClass * "[$objcinput getcptr]"
$imcall
[edit]Used in out typemap and contains the call to the intermediatory which provides the value to be used.
Throws typemap
[edit]The "throws” typemap is then used when SWIG encounters an exception specification. The default generic "throws" typemap looks like this:
%typemap(throws) SWIGTYPE, SWIGTYPE &, SWIGTYPE *, SWIGTYPE [ANY] %{ SWIG_ObjcThrowException(SWIG_ObjcRuntimeException,"C++ $1_type exception thrown"); return $null; %}
Basically SWIG will generate a C++ try catch block and the body of the "throws" typemap constitutes the catch block. The above typemap calls a SWIG supplied method which throws a ObjcRuntimeException. This exception class is a runtime exception and therefore not a checked exception.
Work In Progress
[edit]There are number of other features that can be added in near future.The goal is to take this implementation further so that developers of iOS (Cocoa Touch) use swig as much as Android developers are using it (for Android NDK).