Difference between revisions of "Polyglot"
Line 20: | Line 20: | ||
</pre> | </pre> | ||
− | = | + | = Making a Fortran wrapped C parcel = |
− | In the first example we'll call a Fortran | + | In the first example we'll call a C function from a Fortran program: |
<pre> | <pre> | ||
Line 37: | Line 37: | ||
<pre> | <pre> | ||
− | + | call_c.exe | |
</pre> | </pre> | ||
− | Tada! We've mixed our languages into a single executable and it works! Cool. Very cool. OK, so much for the magic, let's take a look inside the files. Open up ''' | + | Tada! We've mixed our languages into a single executable and it works! Cool. Very cool. OK, so much for the magic, let's take a look inside the files. Open up '''call_c.f90'''. In this simple program, we have a character string that we pass to the C function--called '''cfunc'''--which in turn modifies the string and we can print the result. For those familiar with Fotran90, the main program is trivial enough. So, let's turn to the C code in '''func.c'''. Again this is a simple function and the syntax will be familiar to those who know some C. An interesting detail, however, is the name of the function. Note that we have called it '''cfunc_''', i.e. with a trailing underscore. Why on earth have we done that? Well, we are anticipating the 'decoration' or '''name mangling''' that the compiler will apply. |
− | + | We can look inside the object files using a utility called '''nm'''. First let's look inside '''call_c.o'''. On my machine I get: | |
− | + | ||
− | + | <pre> | |
− | + | > nm call_c.o | |
− | + | 00000000 T MAIN__ | |
− | + | U _gfortran_set_std | |
+ | U _gfortran_st_write | ||
+ | U _gfortran_st_write_done | ||
+ | U _gfortran_transfer_character | ||
+ | U cfunc_ | ||
+ | </pre> | ||
+ | |||
+ | These are the '''symbols''' created by the compiler in the object file. Now let's look inside '''func.o''': | ||
+ | |||
+ | <pre> | ||
+ | > nm func.o | ||
+ | 00000000 T cfunc_ | ||
+ | </pre> | ||
+ | |||
+ | Note the two '''cfunc_'''s? '''They match!''' If we had not pre-decorated the name of the function in '''func.c''', we would not have got a match and we would have got a link-time error. However, we were smart and got ourselves a working executable--hurrah! | ||
+ | |||
+ | A word of caution, however. Different compilers 'mangle' subroutine and function names differently, i.e. dependening upon the mix of compilers, we can't always rely on a single trailing underscore decoration. You will need to use '''nm''' to determine the exact decoration your Fortran compiler expects and to design your code so that any changes are easily accomodated. One way to do this is to include a '''define''' preprocessor macro in you C code, such as: | ||
+ | |||
+ | <pre> | ||
+ | #define CFUNC cfunc_ | ||
+ | ... | ||
+ | void CFUNC(int* string_size, char* string) | ||
+ | </pre> | ||
+ | |||
+ | In that way, a change of decoration can be easily, and consistently made across the whole file/library. | ||
= Turning the Parcel Inside-Out = | = Turning the Parcel Inside-Out = | ||
− | Now let's work the other way 'round and call some | + | Now let's work the other way 'round and call some Fortran from a C program: |
<pre> | <pre> | ||
cd ../example2 | cd ../example2 | ||
</pre> | </pre> | ||
+ | |||
+ | Things to get right: | ||
+ | * use 'nm' or a similar program to investigate the name mangling used by your Fortran compiler, so that you can match the name in your C program. | ||
+ | * matching the sizes of variables | ||
+ | * pass by reference, pass by value | ||
+ | * fortran indexes arrays from 1, by defualt; C from 0. | ||
+ | * The rows/columns are reversed for 2-dimensional arrays in Fortran to C. Arrays in C are 'row-major' and arrays in Fortran are 'column major'. | ||
= The cfortran Header File Project = | = The cfortran Header File Project = |
Revision as of 10:05, 28 May 2008
Mixed Language Programming: Mix up a quick and useful cocktail today!
Introduction
One of the ey underling themes in this series of pragrmatic programming workshops is getting things done, with a minimum of fuss and wasted effort, and this workshop on mixed language programming is no exception.
When we sit down to a keyboard, we do so with a particular goal in mind. We have a task, idea or experiment and the computer is our workbench. The languages we write programes with, along with the text editors, compilers, debuggers etc. are our tools. Now some tools are better than others (e.g. Subversion is an improvment upon CVS). Some we just may have a preference for (e.g. emacs vs. vi for editing files). None are perfect, however, and all have their pros and cons.
What's all this got to do with mixed language programming? you ask. Well, imagine a scenario:
You sit down to your workbench. You have your goal and you ask yourself whether somebody else has written some code which will do at least part of what you want. Perhaps they've bundled it up into a nice open-source library that you can use? That way you'll save truck-loads of time. A couple of web searches later, and bingo! You've found an ideal library for the job. There's only one snag. You like programming in Fortran, and the library is written in C. Scuppered! Well, perhaps not..
What are your options? You could use something not so suitable because it happens to be written in Fortran. Hmm, that doesn't sound so good. You could translate the library from C to Fortran. Hmm, that sounds like tedious and time-consuming work. Plus you'd need to understand the C, and perhaps a direct translation can't be made anyhow? This is looking like a dead-end too. It would be far better to leave the library as it is and to call the routines from your favoured language. Is that possible? Sure it is! Read on and find out how..
In this workshop, we'll look at ways in which we can mix languages and in the process create a useful end product which plays to the strengths of it's components and gets you to where you want to be, without any laborious re-writes. In the first two examples we'll look at calling C code from Fortran and then calling Fortran from C. To get the code for examples, log into your preferred Linux machine and cut and paste the following into your terminal.
svn export http://source.ggy.bris.ac.uk/subversion-open/polyglot/trunk ./polyglot
Making a Fortran wrapped C parcel
In the first example we'll call a C function from a Fortran program:
cd examples/example1
To compile the example, type:
make
and to run it, type:
call_c.exe
Tada! We've mixed our languages into a single executable and it works! Cool. Very cool. OK, so much for the magic, let's take a look inside the files. Open up call_c.f90. In this simple program, we have a character string that we pass to the C function--called cfunc--which in turn modifies the string and we can print the result. For those familiar with Fotran90, the main program is trivial enough. So, let's turn to the C code in func.c. Again this is a simple function and the syntax will be familiar to those who know some C. An interesting detail, however, is the name of the function. Note that we have called it cfunc_, i.e. with a trailing underscore. Why on earth have we done that? Well, we are anticipating the 'decoration' or name mangling that the compiler will apply.
We can look inside the object files using a utility called nm. First let's look inside call_c.o. On my machine I get:
> nm call_c.o 00000000 T MAIN__ U _gfortran_set_std U _gfortran_st_write U _gfortran_st_write_done U _gfortran_transfer_character U cfunc_
These are the symbols created by the compiler in the object file. Now let's look inside func.o:
> nm func.o 00000000 T cfunc_
Note the two cfunc_s? They match! If we had not pre-decorated the name of the function in func.c, we would not have got a match and we would have got a link-time error. However, we were smart and got ourselves a working executable--hurrah!
A word of caution, however. Different compilers 'mangle' subroutine and function names differently, i.e. dependening upon the mix of compilers, we can't always rely on a single trailing underscore decoration. You will need to use nm to determine the exact decoration your Fortran compiler expects and to design your code so that any changes are easily accomodated. One way to do this is to include a define preprocessor macro in you C code, such as:
#define CFUNC cfunc_ ... void CFUNC(int* string_size, char* string)
In that way, a change of decoration can be easily, and consistently made across the whole file/library.
Turning the Parcel Inside-Out
Now let's work the other way 'round and call some Fortran from a C program:
cd ../example2
Things to get right:
- use 'nm' or a similar program to investigate the name mangling used by your Fortran compiler, so that you can match the name in your C program.
- matching the sizes of variables
- pass by reference, pass by value
- fortran indexes arrays from 1, by defualt; C from 0.
- The rows/columns are reversed for 2-dimensional arrays in Fortran to C. Arrays in C are 'row-major' and arrays in Fortran are 'column major'.
The cfortran Header File Project
Calling C from Python using SWIG
NB You will need swig
installed on your machine for this example. swig
is instaled on dylan
Currently as per:
Here we move from 'mixing', to more of an API arrangement.