[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Chicken and SWIG

From: John Lenz
Subject: Re: [Chicken-users] Chicken and SWIG
Date: Mon, 03 May 2004 19:11:24 -0500

On 2004.05.03 00:17, Felix Winkelmann wrote:
John Lenz wrote:
Just to keep everyone updated, today I checked the changes to the chicken module into the swig cvs. Swig now uses the new type Felix added, so c++ multiple inheritance works as well as proper type checking.

Because of this, future versions of SWIG will now require chicken version 1.40 or above.

Brilliant! I'm looking forward to try it out. I would also be
delighted, if you had any ideas how to integrate SWIG into
Chicken. So far my approaches appear clumsy. For example:

#>(swig) ... code <#

and then "csc myfile.scm -swig" would generate temporary files for
the embedded code tagged (swig) and automatically invoke SWIG and
compile the generated files.

Any suggestions for something cleaner are welcome.

Well, this email is pretty long, so I don't know if this is cleaner :)

Currently, we run swig, and it produces a .c or a .cxx file that needs to be compiled, and it produces a couple of .scm files, which then also need to be compiled by chicken.

For example, we produce a file called modname.scm that has
(cond-expand ((or chicken-compile-shared shared)) (else (declare (unit modname))))

   (hide swig-init)
(foreign-declare "C_extern void modname_swig_init(int,C_word, C_word) C_noret;"))
(define swig-init (##core#primitive "modname_swig_init"))

And in code which we want to use the wrapped library, we have a
(uses modname).

What would be cool is for the chicken compiler to automaticly generate this call to modname_swig_init, and include it in the current module. That way we would not need to generate the above file in SWIG (chicken would pass an argument flag like -nounit or something telling SWIG not to generate this file). Thus we would not need an extra run of chicken to compile the above trivial code.

So what would happen is that swig would run and produce a modname_wrap. cxx file. This would include a function called modname_swig_init which would need to get called. modname_swig_init just does some basic setup and then registers all the wrapped functions. The chicken compiler would automaticly generate this call in the top level environment, and thus the rest of that chicken source file would be able to make calls to the wrapped functions. Secondly, if a user wanted to create a unit, they could just declare the unit in the file that includes the #>(swig) <# stuff.

The only problem is the modname. SWIG gets the modname from the "% module modname" directive in the input. Should the user select it or should chicken just randomly generate it? The problem is, the module name is by default prepended to all symbols. functions will be called "modname:func1" if the function was called func1. This can be overridden by the "-prefix <name>" argument to swig, or by passing the -noprefix option.

SWIG will generate a file called modname_wrap.c or modname_wrap.cxx depending on if SWIG was called with the -c++ command line argument. This can also be changed by the "-o filename" flag to SWIG. (Note I just thought of this, but you will also need some way to pick between c and c++... something like #>(swig-c)...<# and #>(swig-c++) .. #< perhaps?)

Ok, now a little more complicated :)
SWIG also by default generates a modname-clos.scm file (unless the - noclos flag is passed), which includes a bunch of (define-class ..) and (define-method ..) and whatnot. Right now, we would just run chicken again on this file.

But what would be cool is for chicken to read this file after running SWIG. So then these definitions would also be included directly into the "scope" of the chicken input file.

Thirdly, SWIG generates a modname-generic.scm which includes code
(define -set-a!- (make-generic "set-a!")) ;; class <modname:Foo>
SWIG does not generate this file if -nogeneric is passed.
Ok, I have an idea now... kinda forget everything I said above :)

Ok, how about this? When SWIG is called with say a -chicken -usestdio flag, SWIG accepts the .i file on standard input, produces the modname_wrap.cxx file, and then writes all the .scm files to standard output? chicken wouldn't even need to worry about calling the modname_swig_init function, because the (foreign-declare ..) and such would be right at the top of the standard output from SWIG. chicken would then compile whatever comes from swig standard out. (which would include the call to modname_swig_init)

SWIG would remove the first line involving (declare unit) when exporting to stdout, but otherwise we would just write the .scm files to stdout. This way we don't generate any temporary files. The only file SWIG generates will be the c or c++ file. Chicken should probably pass the -o name option, and name the output file the same name as the file chicken is generating, with say "_swig_wrap" appended or something.

Ok, for options, I think chicken should allow the user to select the following 1) choose between c and c++ (this coorisponds to the -c++ flag to SWIG. No -c++ option means c).
2) optinally allow the user to select the -prefix or -noprefix
3) Allow the user to select -noclos or -nogeneric. Possibly invert the defaults... i.e have chicken default to -noclos and -nogeneric, and optionally turn those on.

So maybe something like this?
#>(swig,c,clos,coolprefix) ... #<
would mean swig in c mode, with only the -nogeneric option, and a - prefix coolprefix option.

#>(swig,c++) ... #< would mean pass -c++ -nogeneric -noclos -noprefix

This way, chicken should just add a "%module whatever" to swig stdin. Because chicken would always pass the -prefix or -noprefix option, the module name will never appear anywhere visable to the user. It will only appear in the _wrap.cxx file. The modname is prepended to generated functions, so that we don't clutter up the global symbol table.

Note this way we can allow multiple #>(swig) .. <# blocks per file... each one would get a different module name, but as long as the module names are different, SWIG will be run twice, and if the prefixes are different, the generated symbol names won't clash...

Lastly, and even more complicated, SWIG allows type dependence between modules. That is, if I say wrap a class Foo in one module (mod1), and then derive a class Bar : public Foo in another module (mod2). I need to include the "%import mod1.i" directive in mod2. SWIG will then look in the mod1.i for types and such, and then swig will know that Bar is a derived class of Foo.

What happens at runtime is that swig stores a bunch of information about types, which includes stuff like which classes are derived from which other classes. In order for type dependence between modules to work, the two modules that get loaded must merge together the two type trees. (since the type info for Foo will be in mod1 and the type info for Bar will be in mod2)

By default, every module does all the type stuff by itself. Thus each module keeps the type information seperate and everthing is fine and dandy. But if the "-noruntime" option is passed to SWIG, SWIG does not include this runtime type managing code. Instead, the runtime code is expected to be available during linking. Thus, say module 1 will include the runtime code AND make it globaly visible (i.e. the functions will not be declared "static") by passing the "-runtime" option. module 2 will be passed the "-noruntime" option, and during the linking phase, the module2 type functions will be linked to the functions in module 1. Thus the two type trees will be merged together and typing works between modules. (NOTE: if neither -runtime or - noruntime is passed, the type functions are included and declared static so that other modules can not link to them).

How does this impact chicken? Well, it would be nice to support this as well from the chicken called swig. Thus we might want to add another option that the user can select.
#>(swig,c,clos,coolprefix1,runtime) ... <#
#>(swig,c,clos,coolprefix2,noruntime) ... <#
and chicken would just pass -runtime or -noruntime to swig. (If neither is given, not pass either).

The problem is, SWIG needs the %import directive, because it needs to know about the base classes. Since the code that normally would be in the file %import would read, and that code is from some other chicken file, the file we would import wouldn't exist. To solve this, chicken would also have to have a similar %import directive. All this would do would be to parse the chicken file looking for the #<(swig...) <# directive, (add the SAME %module <modname> that would be added when parsing that file normally), and pass that code to swig somehow. That code would either need to be written to a temporary file, or included in the swig input file in say a
%import %{
code here
NOTE: we can't just include the code directly in the file, because SWIG needs to know if it should be generating wrapper functions for it or not. When we import a file, we don't generate any code, just use it for type purposes. Thus SWIG knows that code in the %import %{ it should just be reading for type purposes.

#>(swig,c,coolmod,noruntime,import=mod1.scm,import=mod3.scm)... #<

Note as well, if we allow multiple #>(swig,...) ... <# in the same chicken file, and the user wants to have type dependence between them, chicken would need some way to do that inclusion as well... This implies that we would need to optionally name each swig block, so that the second swig block can reference the first one.
somethine like
#>(swig,...,importblock=otherBlock) <#.
In this case, chicken would do the same thing.. it would include the code from then otherBlock in an %import %{ ... %} when calling SWIG for this block. I was thinking we could use the prefix for this naming of the blocks, but we run into trouble if no prefix is given i.e. - noprefix. Also would need a way to determine which #>(swig) <# block in the included file. Although, it seems kinda wierd to have multiple #>(swig..) blocks in the same file... probably just restrict it to one per file!

One last problem with this :)
In the mod1-clos.scm file, it will include the (define-class <mod1:Foo> ...)
depending on the status of -prefix and -noprefix. i.e. if -noprefix is passed, it would export a (define-class <Foo> ...). The problem is in mod2-clos.scm. mod2-clos.scm will include something like
(define-class <coolmod2:Bar> (<mod1:Foo>) ())
Note the use of mod1: If say when compiling mod1 we passed a -prefix coolmod1 option, then mod1-clos.scm will have a definiton <coolmod1: Foo> instead of a <mod1:Foo>. Currently it is a limitation of SWIG that there is no way to change this prefix in imported files!!! i.e. currently swig will always append the module name of the imported file (from the %module directive in the imported file) to the class symbols. Note the -prefix option replaces the mod2: with something else, so that won't work.

What I think would need to happen is that swig would accept a
%chickenprefix "prefix" directive. This would have the same effect as the -prefix command line argument. Thus when chicken is generating the code to be passed to swig, when it is parsing an import=mod1.scm thing, it would add the directive %chickenprefix coolmod1 to the code inside
%import %{
%chickenprefix "coolmod1"
SWIG would then know enough to use the variable <coolmod1:Foo>.
This way again, the actual module name is never seen by the user and chicken can pick whatever it wants.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]