Home → Developer Docs → Convert Swig |
---|
The purpose of convert_swig is to create SWIG interface files for the given C/C++ header file (usually S_source.hh) and each of the header files that it (recursively) includes. SWIG (Simplified Wrapper and Interface Generator) is an interface compiler that connects programs written in C and C++ with scripting languagues such as Perl and Python.
In Trick the list of header files to be processed is usually produced by the script make_swig_makefile.pm, as it's creating Makefile_swig. This list is stored in the file ".S_library_swig". So, if .S_library_swig exists, we can just open and read it.
Otherwise we need to process S_source.hh to produce the list of header files.
Specifically, we want to generate SWIG interfaces for those header files that are:
The header files that are actually included are the dependencies we care about. Keep in mind that the preprocessor and the current ENVIRONMENT may cause some headers to be conditionally included or excluded. We only want to generate SWIG interfaces for headers that are ACTUALLY included.
Whereas the preprocessor can (using the gcc -MM option) generate a list of dependencies that satisfy 1) (above), it can't handle that ICG exclusions. And, whereas the function get_headers() can generate a list of dependences which are flagged if they contain ICG_NO, it doesn't handle conditional includes.
So, the strategy that we employ is to generate and then find the intersection of both lists. Then we eliminate those that are in 1) $TRICK_HOME/trick_source, or 2) flagged as containing ICG_NO or 3) are in ICG_EXCLUDE'd directories.
First, create a list headers using the GCC with the -MM option. GCC will handle conditional inclusion.
Second, create a list where the files are flagged if they contain ICG_NO.
Then we generate the intersection of the two lists and then eliminate the dependencies that:
to create the final list of header dependencies that we need to convert into SWIG interfaces.
Next we need to determine which of the files do not have up-to-date SWIG files. For each header file in final dependency list, if the corresponding SWIG (.i) file doesn't exist or the header file is newer than the existing SWIG file, then record that a new SWIG file needs needs to be created. The global hash %out_of_date represents a list of header files whose corresponding .i files need to be regenerated.
Finally, call process_file() to create SWIG interface files for each of the out_of_date headers.
This subroutine processes S_source.h and each of it's requisite header files to generate the corresponding SWIG interfaces files.
sim_ref Is this parameter ever used?
in_file The name of input file, invariably "S_source.hh".
This function first reads the contents of <in_file> and each of the header files that it (recursively) includes into a hash (%file_contents), keyed by the corresponding filenames. It then converts the contents of the each header whose corresponding SWIG interface file is out of date into a SWIG interface file.
To create the file_contents hash, we first run the input file through the
C/C++ preprocessor with the -dI option. This creates one file containing
the contents of all of the included header files delimited by "line markers".
The line markers indicate which header file each of content came from.
Preprocessor line markers are of the form: '#'
For each line in the ONE big file, check whether it's a linemarker or not. if it's a linemarker ( telling us where the following content is from) extract the header filename. This will be our current filecontents hash key. If it's not a linemarker, then it must be content. So, append it to the string, whose key is the current file name ($curr_name).
The global hash %out_of_date represents the list of header files whose corresponding SWIG interface files are out of date. It is generated in the main part of the convert_swig program.
For each of these out of date header files, we generate a SWIG interface file from the contents stored in the %file_contents hash.
First we remove the friend init_attr functions from the headers content. They don't need to be wrapped.
Then, for each of the #includes in the out_of_date header file create a corresponding %import directive.
Next, we generate a module name and path for the SWIG interface file. The module name is generated from an md5 hash of the header file's full name.
Finally we open the SWIG interface file, and in it we:
Process header file contents for use in the corresponding SWIG interface file.
contents_ref (IN) reference to header file contents that are to be converted to a SWIG interface.
new_contents_ref (OUT) SWIG interface code, derived from the header file contents.
curr_namespace (IN) current namespace.
class_names_ref (OUT) reference to an array of class and/or struct names encountered when processing the header file contents.
template_typedefs_ref (OUT) Series of SWIG %template directives. %template directives create a type in the target language that corresponds to a C++ template instance.
While there's header file content remaining to be processed, repeatedly make the best match with the following available patterns:
Case of :
typedef existing-type-name new-type-name ';'
Concatenate the matched text to the SWIG interface text.
Case of :
typedef enum optional-name '{' bracketed-content '}' enum-name';'
Concatenate the matched text to the SWIG interface text.
Case of :
typedef ( struct | union ) name '{'
Call process_typedef_struct() to process the matched text and the bracketed
content of the struct that follows in the header file contents and update the
SWIG interface text accordingly.
Case of :
template '<' template-parameters '>' class class-name
then just concatenate the matched text to the SWIG interface text.
Case of:
namespace name
then call process_namespace() to process the matched text and the
bracketed content that follows in the header file contents and update the the
SWIG interface text accordingly.
Case of:
( class | struct ) class-name ( '{' | ':' )
Call process_class() to process the matched text and the bracketed
that follows in the header file contents and update the the SWIG interface text.
Default: Match anything that doesn't match the other patterns and concatenate it to the to the SWIG interface text. Note that (in Perl) ? in the regular expression (.?) is a non-greedy quantifier, so it gobbles up text only until another match can be made.
Process namespaces found in a header file for use in the corresponding SWIG interface file.
namespace_string (IN) This is a string of the form: namespace name, that was extracted from the header file contents. In the contents there should remain the bracketed content to which this namespace applies.
contents_ref (IN) This is a reference to the remainder of the header file (following the above string) to be processed.
new_contents_ref (OUT) The SWIG code generated so far.
curr_namespace (IN) current namespace.
class_names_ref (OUT) reference to an array of class and/or struct names encountered when processing the header file contents.
template_typedefs_ref (OUT) Series of SWIG %template directives. %template directives create a type in the target language that corresponds to a C++ template instance.
Extract the name from the namespace_string and append it to the current namespace's name.
Add the namespace_string to the SWIG interface text.
Call extract_bracketed() to extract the contents of the namespace from the header text.
Call process_contents() to convert the extracted namespace contents to a SWIG interface.
Append whatever wasn't matched in process contents to the SWIG interface text.
Process classes declarations found in a header file for use in the corresponding SWIG interface file.
class_string
(IN) This is a string of the form:
( class | struct ) class-name ( '{' | ':' )
contents_ref (IN) This is a reference to the remainder of the header file (following the class_string) to be processed.
new_contents_ref (OUT) The SWIG code generated so far.
curr_namespace (IN) current namespace.
class_names_ref (OUT) reference to an array of class and/or struct names encountered when processing the header file contents.
template_typedefs_ref (OUT) Series of SWIG %template directives. %template directives create a type in the target language that corresponds to a C++ template instance.
process_class() processes class declarations with the following steps:
Extract the class_name from the class_string. Add the class_string to the SWIG interface text.
Call extract_bracketed() to extract the class contents between '{' and '}'.
While there's class content text remaining to be processed, repeatedly search for data members that match : template_name '<' template-params '>' name ; For each match, create a SWIG %template directive to create an instantiation of the specific templated type used by the data member. Due to changes in SWIG 4, template directives must be specified before their respective data members. As such, the template directives are inserted immediately prior to the class definition. SWIG does not resolve namespaces in these directives the same as C++ does (it will only check local scope, not global). To account for this, if the directive specifies a template outside the local namespace, convert_swig will escape the current namespace in the format : } template_directive namespace name {
Process a type definition of a struct or union to make it suitable as SWIG interface code. Extract the struct (or union) name and bracketed contents from the header file text (typedef_struct_string and contents_ref) . Record the extracted names in the list referenced by class_names_ref, and then reconsistute the type definition, via the new_contents_ref.
typedef_struct_string
(IN) This is a string of the form:
1. <b>typedef struct</b> [ <i>optional-name</i> ] <b>"{"</b> OR<br>
1. <b>typedef union</b> [ <i>optional-name</i> ] <b>"{"</b><br>
contents_ref (IN) This is a reference to the remainder of the header file (following the above string) to be processed.
new_contents_ref (OUT) The SWIG interface code generated so far.
class_names_ref (OUT) reference to an array of class and/or struct names encountered when processing the header file contents.
process_typedef_struct() processes a type definition of a struct or union with the following steps:
Append the typedef_struct_string to the SWIG interface text (via new_contents_ref).
Extract the optional-name from the typedef_struct_string.
Call extract_bracketed() to extract the struct contents from the header text (via contents_ref), including the right bracket.
Extract the one or more typedef'ed names followed by a semi-colon, that should still be in the header text.
Push the optional-name and the typedef'ed names into the class_names list (via class_names_ref).
Append the bracketed struct contents and the one or more typedef'ed names and the semi-colon that we just extracted to the SWIG interface text.