home *** CD-ROM | disk | FTP | other *** search
- Path: usage.csd.unsw.oz.au!metro!munnari.oz.au!spool.mu.edu!olivea!apple!veritas!amdcad!sono!waldman
- From: waldman@sono.uucp (Waldman Micah)
- Newsgroups: comp.lang.perl
- Subject: Connecting C functions to Perl
- Message-ID: <1991Jul17.042046.16096@sono.uucp>
- Date: 17 Jul 91 04:20:46 GMT
- Distribution: comp
- Organization: Acuson; Mountain View, California
- Lines: 604
-
-
-
- Recently I had to connect a package of C functions to Perl. After doing so I
- wrote a document describing the procedure in detail (somewhat more than the
- README file in the usub directory ...) for maintenance purposes. I'm
- posting it here in the hope that it will make connecting C to Perl easier, so
- that more people will do it, so that more people will use Perl.
-
- One request though: I would very much appreciate it if someone (Larry?
- Randal? Tom?) will go over it to make sure that the descriptions are correct
- and that the stated reasons for things being as they are match reality and
- the intentions of the designers (str_2mortal would be a good case).
-
- I'm relocating at the end of the week and won't have access to the group for
- about 3 months (they don't have workstations in the Rockies). If someone
- wants to pick up the responsibility for correcting and updating the
- document, that would be great. Also it probably should be added to a FAQ
- which should be created (unless it exists and I don't know about it).
-
- Enough talk. Enjoy connecting C to Perl.
-
- Micah (Michael is fine) Waldman
- Now in California, soon back in Israel.
-
-
-
- Connecting C Functions to Perl
- ==============================
-
-
- Introduction
- ------------
-
- This document describes how to connect C functions to Perl. It contains the
- following sections:
-
- - Overview.
- Lists the major steps in connecting C functions to Perl.
-
- - Initialization Function.
- How to register functions and variables with Perl.
-
- - Subroutines Interface Function.
- The interface between the Perl subroutines and the C functions.
-
- - Passing Arguments.
- The mechanisms for passing arguments and the tools for analyzing them.
-
- - Variables Interface Functions.
- Sharing variables between the Perl program and the C functions.
-
- - Compiling and Linking.
- Putting it all together.
-
- You should also look at the README file in the usub directory of Perl's
- source and at the examples provided there.
-
- Warning: This document is written based on my experience and on browsing
- over Perl's source. It should be treated as containing guidelines and not as
- the official documentation.
-
-
- Overview
- --------
-
- In the process of building Perl a file named uperl.o is created. This object
- file is then linked with your C code to create your own version of Perl.
- The items which are added to uperl.o are:
-
- - An initialization function which registers with Perl all the C
- functions which will be called from a Perl program and all the
- variables which will be shared by the C functions and the Perl
- program.
-
- - For each C function that will be called from Perl there is an
- "interface" which translates arguments from the Perl representation to
- the C representation, calls the C function and then performs the
- translation in the opposite direction. Each C function interface can be
- in a separate function, or several interfaces may be grouped together.
- In the latter case each interface (which corresponds to a specific
- C function) within a group is identified by a number (an index) which
- was specified when the function was registered in the initialization
- function.
-
- - The C functions themselves and any libraries they need.
-
- - For each variable which will be shared between the Perl program and
- the C functions there is an interface which translates between C and
- Perl representations. The interface is divided into two parts: C to
- Perl, and Perl to C. Again, each interface can reside alone (in a pair
- of separate functions) or several interfaces can be grouped together
- into two functions that identify the variable within the group by an
- index.
-
-
- Initialization Function
- -----------------------
-
- The Perl source file usersub.c contains a function called userinit.
- You should add to it a call to your initialization function. (You can
- actually do all of your initialization inside userinit but if there are
- several C packages linked to Perl it is probably best for each to call
- its separate initialization function.) Your initialization function
- description follows.
-
- Arguments:
- None.
-
- Returns:
- Nothing.
-
- Structure:
- DECLARE SUBROUTINE.
- (Specify its name in Perl, its index number, the C function which
- contains its interface, and the file name in which it resides.)
- DECLARE SUBROUTINE.
- DECLARE SUBROUTINE.
- ... (As many as needed)
-
- DECLARE VARIABLE.
- (Specify its name in Perl, its index number, the "set" function
- which handles the Perl-TO-C translation, and the "get" function
- which handles the C-TO-Perl translation.)
- DECLARE VARIABLE.
- DECLARE VARIABLE.
- ... (As many as needed)
-
- Description:
- - DECLARE SUBROUTINE:
- To declare a subroutine you call make_usub which is declared as:
-
- SUBR *
- make_usub(name, ix, subaddr, filename)
- char *name;
- int ix;
- int (*subaddr)();
- char *filename;
-
- The function's return value is not used.
- name - The name of the subroutine as used in a Perl program.
- ix - The index number of the subroutine.
- subaddr - The address of the C function that handles the interfacing
- between Perl and C for the subroutine.
- filename - Name of file where the C function resides (or maybe where
- the interface resides - I'm not sure).
-
- The index values are usually generated using an enumerated
- declaration:
-
- static enum usersubs
- {
- US_first_func,
- US_second_func,
- US_many_more_funcs,
- };
-
- Then a typical call to make_usub would be:
-
- make_usub("first_func", US_first_func, sub_handler, "thisfile");
-
- (Of course you may want to use more meaningful names ...)
-
- - DECLARE VARIABLE:
- To declare a variable you call magicname which is declared as:
-
- void
- magicname(sym,name,namelen)
- char *sym;
- char *name;
- int namelen;
-
- sym - The name of the variable as used in a Perl program.
- name - The address of a structure which holds the variables
- interface functions' addresses and its index number.
- The structure is declared as:
-
- struct ufuncs
- {
- int (*uf_val)();
- int (*uf_set)();
- int uf_index;
- };
-
- uf_val - The address of the C function that handles
- the C-TO-Perl translation.
- uf_set - The address of the C function that handles
- the Perl-TO-C translation.
- uf_index - The index number of the variable.
-
- This structure should be set each time before calling
- magicname. A macro can be used (check the examples
- that come with the source).
- namelen - The size of the ufuncs structure.
-
-
- Subroutines Interface Function
- ------------------------------
-
- This document will only describe grouping all the interfaces into one
- functions. The other way of putting them each in a separate function
- uses the same principles.
-
- Arguments:
- The function is declared as follows:
-
- static int
- sub_handler (sub_index, stack_ptr, n_args)
- int sub_index;
- register int stack_ptr;
- register int n_args;
-
- - sub_index
- Index number of the called subroutine (as specified in the
- initialization function when the subroutine was registered).
- - stack_ptr
- Stack pointer for getting arguments passed to the called
- subroutine. Will be explained in the 'Passing Arguments'
- section below.
- - n_args
- Number of arguments passed to called subroutine.
-
- Returns:
- - Stack pointer for returning results from the called subroutine.
- Will be explained in the 'Passing Arguments' section below.
-
- Structure:
- INITIALIZATIONS.
- SWITCH BY INDEX:
- CASE INDEX 1:
- CHECK NUMBER OF ARGUMENTS PASSED TO CALLED SUBROUTINE.
- TRANSLATE ARGUMENTS FROM PERL TO C REPRESENTATION.
- CALL ACTUAL C FUNCTION.
- TRANSLATE RESULTS FROM C TO PERL REPRESENTATION.
- RETURN WITH STACK.
- CASE INDEX 2:
- CHECK NUMBER OF ARGUMENTS PASSED TO CALLED SUBROUTINE.
- TRANSLATE ARGUMENTS FROM PERL TO C REPRESENTATION.
- CALL ACTUAL C FUNCTION.
- TRANSLATE RESULTS FROM C TO PERL REPRESENTATION.
- RETURN WITH STACK.
- ... (As many as needed)
- DEFAULT:
- ERROR - UNIMPLEMENTED SUBROUTINE.
- RETURN WITH STACK.
-
- Description:
- - INITIALIZATIONS:
- The following variables should be declared:
-
- STR **st = stack->ary_array + sp;
- register STR *Str;
-
- The first (st) will be used to access the arguments on the stack
- (which will be explained in the 'Passing Arguments' section below).
- The second (Str) is used by some Perl macros (e.g. str_get,
- str_gnum).
-
- - CHECK NUMBER OF ARGUMENTS PASSED TO CALLED SUBROUTINE.
- Use n_args to verify that the correct number of arguments were
- passed to the function. If not use the fatal() function to produce
- a usage error message. for example:
-
- if ( n_args != 0 )
- fatal ("Usage: &call_me()");
-
- - TRANSLATE ARGUMENTS FROM PERL TO C REPRESENTATION.
- Will be explained in the 'Passing Arguments' section below.
-
- - TRANSLATE RESULTS FROM C TO PERL REPRESENTATION.
- Will be explained in the 'Passing Arguments' section below.
-
- - RETURN WITH STACK.
- Return the stack pointer (which usually was not changed):
-
- return stack_ptr;
-
- - ERROR - UNIMPLEMENTED SUBROUTINE.
- The only cause for executing the default case is if a subroutine
- was registered with Perl by the initialization function but is not
- implemented yet (i.e. no 'case' for it). Therefore we must issue
- an error message:
-
- fatal("Unimplemented user-defined subroutine");
-
-
- Passing Arguments
- -----------------
-
- The stack:
-
- Perl passes arguments back and forth by placing them on the stack.
- The stack (as everything else in Perl) is a STR which is a structure
- that can hold anything - number, string, array, assoc. array, etc.
- In the case of the stack the STR holds an array for the values of
- the stack. Each item in this array (and so each item in the stack)
- is also a STR. So, anything can be put on the stack - a number or a
- string (I really don't know about putting an array in one item of
- the stack. There is a way to return an array from a subroutine - see
- later in this section). The only thing you need to remember is that
- since STR is a Perl defined structure you cannot assign to it
- directly (or rather, you don't want to). Instead, you use functions
- supplied by Perl that do the necessary conversions from a number or
- string to a STR. (The STR related definitions are in str.c and
- str.h, the array related definitions are in array.c and array.h.)
- The argument stack_ptr passed to the Subroutines Interface Function
- is an index to the place on the stack where the called subroutine's
- arguments begin. For convenience, we defined 'st' at the initialization
- to point directly to that place and we'll use it from there on.
- The first item on the stack (st[0]) is the return value from the
- subroutine. It should be set before returning. The following items
- (st[1], st[2], ...) are the arguments of the subroutine. Each
- argument may serve for input, output, or both.
-
- Getting arguments from the stack:
-
- The following functions can be used to get input arguments from the
- stack:
-
- - str_get
- Used to get a null terminated string, as in:
-
- char* name = (char*) str_get(st[1]);
-
- The first subroutine argument will be assigned as a string to
- the pointer name.
-
- - str_2ptr
- Used to get a non-null terminated string, as in:
-
- char* buffer = (char*) str_2ptr(st[1]);
-
- The first subroutine argument will be assigned as a non-null
- terminated string to the pointer buffer.
-
- - str_gnum
- Used to get a number, as in:
-
- int num = (int) str_gnum(st[2]);
-
- The second subroutine argument will be assigned as a number to
- the variable num.
-
- - str_true
- Used to get a boolean, as in:
-
- int cleanup = (int) str_true(st[3]);
-
- True or false will be assigned to the variable cleanup according
- to the value of the third argument (see the Perl manual for a
- definition of true and false values).
-
- Putting arguments on the stack:
-
- The following functions can be used to put output arguments on the
- stack:
-
- - str_set
- Used to set a null terminated string, as in:
-
- str_set(st[0], (char *) result);
-
- The value of the string pointed to by result will become the
- return value of the subroutine (assuming it was called as a
- function).
-
- - str_nset
- Used to set a non-null terminated string, as in:
-
- str_nset (st[4], (char *) result, result_length);
-
- The value of the result_length bytes pointed to by result will
- be assigned to the fourth argument of the subroutine.
-
- - str_numset
- Used to set a number, as in:
-
- str_numset (st[0], (double) retval);
-
- The value of the integer retval will become the return value
- of the subroutine (assuming it was called as a function). Notice
- the casting to (double).
-
- The following values can be put on the stack:
-
- - str_undef
- Used to return an undefined value, as in:
-
- st[0] = &str_undef;
-
- The return value of the subroutine will be undefined.
-
- - str_yes
- Used to return a yes (true) value, as in:
-
- st[0] = &str_yes;
-
- The return value of the subroutine will be yes.
-
- - str_no
- Used to return a no (false) value, as in:
-
- st[0] = &str_no;
-
- The return value of the subroutine will be no.
-
- Returning an array:
-
- Saying, above, that the first argument on the stack (st[0]) is the
- return value of the subroutine is a simplification. If the
- subroutine is called in a scalar context then st[0] will be its
- return value. If, however, the subroutine is called in an array
- context the return value is the list which begins in st[0] and ends
- where the stack pointer returned from the sub_handler points to.
- For example, if stack_ptr was 80 on entry, and is 85 on exit, A list
- containing 6 elements (st[0] .. st[5]) will be returned from the
- subroutine. If you want your subroutine to return different values
- according to the context it was called from, you need to check the
- context inside the sub_handler (explanation below) and put values
- on the stack accordingly.
- In case you want to return an array the first thing is to make sure
- that the stack is large enough to hold the entire array. Use the
- function astore() to do that. If 'array_size' is the size of the
- array you want to put on the stack, call astore like this:
-
- astore (stack, stack_ptr + array_size, Nullstr);
-
- By doing that the stack may be reallocated in a new memory location.
- Therefore, you must update st (the pointer directly to the arguments
- on the stack) like this:
-
- st = stack->ary_array + stack_ptr;
-
- Now you can put your array on the stack. Since you are creating new
- STR's that will be on the stack (not just updating an output
- argument) different functions should be used instead of str_set,
- str_nset, and str_numset. The following are the equivalent
- functions:
-
- - str_make
- Used to create a STR from a string, as in:
-
- str_make (result, result_length);
-
- The value of the result_length bytes pointed to by result will
- be assigned to a STR. A pointer will be returned to that STR.
- If the length passed is 0 strlen() will be used to determine the
- length of the string.
-
- - str_numset
- Used to create a STR from a number, as in:
-
- str_nmake ((double) retval);
-
- The value of the integer retval will be assigned to a STR. A
- pointer will be returned to that STR. Notice the casting to
- (double).
-
- Since the array created on the stack is only temporary and not
- needed after the whole expression was evaluated, the pointer
- returned from str_make and str_nmake should be passed to
- str_2mortal(), and its output should be assigned to the stack item.
- The whole thing looks like this:
-
- for (item = 0 ; item < array_size; item++)
- {
- st[item] = str_2mortal (str_nmake ((double) array[item]));
- }
-
- (Assuming an array of numbers is returned.)
- As mentioned above the stack pointer returned should point to the
- last array item. Therefore, continuing the example from above the
- function should end with:
-
- return stack_ptr + array_size - 1;
-
- Checking the calling context:
-
- The context of the current subroutine being evaluated is held in
- curcsv->wantarray. curcsv holds the current call-save information
- (all kinds of information about the called subroutine). One of the
- fields (wantarray) is a flag for the context:
- - G_ARRAY : An array context.
- - G_SCALAR: A scalar context.
- curcsv is defined in perl.h so all you need to do is say:
-
- if ( curcsv-wantarray != G_ARRAY )
- {
- /* Scalar context */
- str_numset (st[0], (double) array_size); /* or anything else */
- return stack_ptr;
- }
- else
- {
- /* Array context */
- astore (stack, stack_ptr + array_size, Nullstr);
- st = stack->ary_array + stack_ptr;
-
- for (item = 0 ; item < array_size; item++)
- {
- st[item] = str_2mortal (str_nmake ((double) array[item]));
- }
-
- return stack_ptr + array_size - 1;
- }
-
-
- Variables Interface Functions
- -----------------------------
-
- This document will only describe grouping all the interfaces into a pair
- of functions. The other way of putting them each in a separate pair of
- functions uses the same principles. As explained above, there are tow
- variables interface functions:
- - var_set translates from Perl to C.
- - var_get translates from C to Perl.
-
- Arguments:
- Both functions are declared as follows:
-
- static int
- var_get/var_set (var_index, str)
- int var_index;
- STR *str;
-
- - var_index
- Index number of the variable to be handled (as specified in
- the initialization function when the variable was registered).
- - str
- A STR to which the value of the variable should be assigned
- (var_get) or from which the variable's value should be
- updated (var_set)..
-
- Returns:
- - 0. I don't know what the meaning of it is.
-
- Structure:
- INITIALIZATIONS.
- SWITCH BY INDEX:
- CASE INDEX 1:
- PUT VALUE OF VARIABLE IN STR. or
- PUT VALUE OF STR IN VARIABLE.
- CASE INDEX 2:
- PUT VALUE OF VARIABLE IN STR. or
- PUT VALUE OF STR IN VARIABLE.
- ... (As many as needed)
- DEFAULT:
- ERROR - UNIMPLEMENTED VARIABLE.
-
- Description:
- - INITIALIZATIONS:
- The following variable should be declared in var_set:
-
- register STR *Str;
-
- It is used by some Perl macros (e.g. str_get, str_gnum).
-
- - PUT VALUE OF VARIABLE IN STR.
- Use the functions described above to set a STR (str_set, str_nset,
- str_numset).
-
- - PUT VALUE OF STR IN VARIABLE.
- Use the functions described above to get a STR (str_get, str_gnum,
- str_2ptr).
-
- - ERROR - UNIMPLEMENTED VARIABLE.
- The only cause for executing the default case is if a variable
- was registered with Perl by the initialization function but is not
- implemented yet (i.e. no 'case' for it). Therefore we must issue
- an error message:
-
- fatal("Unimplemented user-defined variable");
-
-
- Compiling and Linking
- ---------------------
-
- Assuming you already have uperl.o (from compiling Perl) a simple make
- file might look like this:
-
- INC = /usr/src/perl # or where you put your Perl source
-
- # assuming you want to connect the package 'pack' which has a library by
- # that name.
-
- userperl: uperl.o usersub.o interface.o
- cc uperl.o usersub.o interface.o -lm -lpack -o userperl
-
- # the C sources include some Perl files so we need INC.
-
- usersub.o: usersub.c
- cc -c -I$(INC) -g usersub.c
-
- interface.o: interface.c
- cc -c -I$(INC) -g interface.c
-
-
- After that, instead of calling perl you call userperl. As in:
-
- #! /usr/local/bin/userperl
-
- print "Just another Perl and C hacker\n";
-
-
-
- Micah Waldman
-