On 28/07/01 19:12 -0700, Mark D. Anderson wrote:
> I've now spent several hours reading and playing around Inline::* .
> Here are several questions I had as I went along, whose answers I could not easily
>find.
> Here the questions are, with draft answers i made up after perusing the code.
Mark,
Thanks for banging so hard on Inline. I would almost go so far as to say that
you've looked more critically at Inline, than anyone to date. I not only
welcome this, but am very excited to address the issues. Many of the
shortcomings you've found exist because nobody has brought them to light
previously. I prefer not to implement things until people ask for them. So
now that you have, let's start to address them...
> WARNING-- there is some sarcasm below. No hard feelings;
> this is to prompt a proper replacement answer and for entertainment value.
> Also, i'm sure some of these answers are wrong, and probably many
> of them will be wrong in the future as Inline improves.
I would ask you to drop the sarcasm though. It's not that it offends me but
rather that it confuses your point in some cases.
>
> Feel free to incorporate this contribution in whatever permanent faq you like.
>
> -mda
>
> Q: What is this "C => Config => Name => 'Foobar'" idiom?
>
> A: It looks odd, but this is acceptable perl. It just makes a flat list. The
> only difference between "=>" and "," is that the token on the left is automatically
> quoted, which is convenient here. You don't have to have an even number of
> elements, as in "Config => TYPEMAPS => 'typemap'". See "perldoc perldata".
You can have general config:
use Inline Config => [key/value pairs];
You can have language specific config:
use Inline Cobol => Config => [key/value pairs];
You can have object specific config:
use Inline Cobol => DATA => [key/value pairs];
>
> Q: How does Inline deal with =pod or #ifdef or other complicated C cruft?
> Will it expand macros or typedefs? Will it follow #includes?
>
> A: First off, you should understand that your Inline'd C code is used twice:
> in the "parse" phase, when Inline is trying to automatically find functions for which
> to make XS glue, and in the "compile" phase, when it is creating a .dll/.so.
> For C, it uses a simple C grammar for the parse phase, while for the compile phase,
> it of course uses a real C compiler.
> (For languages more introspective than C and C++, it can use the real compiler for
>both
> phases.)
This is important. Inline differs from other extension facilities in that
your source code doubles as your glue code.
> You can see the C grammar at Inline/C/grammar.pm; it looks roughly like this:
>
> code: part*
> part: comment | function_definition | function_declaration | anything_else
> comment: cxx_comment | c_comment
> cxx_comment: m{\s* // [^\n]* \n }x
> c_comment: m{\s* /\* (?:[^*]+|\*(?!/))* \*/ ([ \t]*)? }x
> function_definition: rtype IDENTIFIER '(' <leftop: arg ',' arg>(s?) ')' '{'
> function_declaration: rtype IDENTIFIER '(' <leftop: arg_decl ',' arg_decl>(s?) ')'
>';'
> rtype: TYPE star* | modifier* TYPE star*
> arg: type IDENTIFIER | '...'
> arg_decl: type IDENTIFIER* | '...'
> type: TYPE star*
> modifier: 'unsigned' | 'long' | 'extern'
> star: '*'
> IDENTIFIER: /\w+/
> TYPE: /\w+/
> anything_else: /.*/
>
> Note that the grammar does not understand comments inside a function_declaration.
> Note also the simplistic grammar for rtype, which is why static functions are not
>matched.
Inline::C can use any C code as "source code", but can only understand a
subset of C as "glue code". If Inline::C's grammar cannot understand your
code it will ignore it. The code may still compile, but Inline may not bind
to the functions you expected.
You can always find out what the parser thought you meant by using the INFO
shortcut.
perl -MInline=INFO script.pl
Inline will understand 'static' in the next release. It will mean "don't bind
to this function". But then I can warn you if a non-static function didn't
bind.
>
> The grammar for C++ in Inline/CPP/grammar.pm is completely independent
> of that for C. For example, it currently matches both declarations and
> definitions regardless of AUTOWRAP. Also, Inline::CPP is smarter about
> structs than Inline::C. Maybe eventually someone will capitalize on
> the fact that C and C++ are related.
Admittedly, Neil has done a lot more work on C++ than I have on C. Most of
this is because C++ is much more involved. I'll work with Neil to integrate
the overlapping bits for the next release.
On the other hand, Inline::CPP inherits most of its methods from Inline::C.
>
> By default, Inline will just match the grammar against the literal
> text you provide (either directly or in the contents of the file whose
> name you specify). This means:
>
> it will not expand #includes it will not obey #ifdef's or =pod but
> will look at every line outside of C or C++ comments it will not
> expand #define macros it will not try to understand typedefs
>
> Of course, the compile phase will act like a real compiler.
>
> Q: But maybe I want my C code to be processed before parsing?
>
> A: The above default behavior might work fine if you are writing your
> own code from scratch, or hand writing your perl-C interface code, but it is
> often not so useful if you are attempting to use already existing C code.
Inline has always be optimized for the first two, and not so much for the
third. Dumping existing code into your Perl may work, but that's not my
style. If you have existing code, you probably should compile it separately
and write nice new interface code inline. Good C interfaces generally make
lousy Perl interfaces. But TMTOWTDI.
>
> You can provide a list of FILTERS to apply before the parse phase is done:
>
> use Inline C => $code, FILTERS => ['Strip_POD', \&MyFilter, 'Preprocess' ];
>
> If a filter is a string such as 'foobar', then there has to be a function
>Inline::Filters::foobar.
> Otherwise you can provide a CODE ref. If you supply a CODE ref, it should take a
>single argument
> of $code, and return a modified version of it. (Functions in Inline::Filters are
>objects which
> take a filter($ilsm,$code) method, but that is hidden from you.)
>
> Filters are run in order, chained to each other (output of one becomes input to the
>next).
>
> Note that the filter result is used *both* in the parse phase and in the compile
>phase.
> This is generally a good thing, for example you would want to remove pod
>documentation your C code
> for both phases. It does mean that if you run the C preprocessor as a filter, then it
> will get run again in the compile phase.
>
> Note also that the 'Preprocess' filter uses this command:
>
> $Config{cpprun},
> $Config{cppflags},
> "-I$Config{archlibexp}/CORE",
> @{$ilsm->{ILSM}{MAKEFILE}{INC}||[]}
>
> which excludes CCFLAGS and OPTIMIZE (not to mention ignoring CC). So the result
> may not match what the compiler does in the compile phase.
>
> Q: But even with preprocessing, Inline won't deal with typedefs will it?
>
> A: Not unless you provide a filter which does that. Inline uses a string match
> on whatever type name is given in the function declaration, and looks that up
> in the typemap file. Sometimes, most of the time this is a good thing, because
> you often don't want to treat all char* typedefs the same way, for example.
> (Note that SWIG has support for a typedef declaration.)
I don't understand the third sentence.
>
> Q: Why isn't the Inline::Filters module part of the base Inline distribution?
>
> A: Because Brian Ingerson and Neil Watkiss are different people, and
> it isn't like they work for the same company, so that coordination would be easy.
I can't be sure how high the sarcasm level is here. Neil and I talk several
times a day usually. We did work at the same company until recently. We will
continue to support Inline together for the forseeable future.
Inline::Filters is a fairly young hack. It may eventually be distributed with
Inline. But Neil would have to give the code to me, and I'd rather have _him_
working on it for now.
>
> Q: What does AUTOWRAP do?
>
> A: No, this option does not wrap long lines. Rather, it makes the builtin C parser
> look for function *declarations*, in addition to function *definitions*.
> The same grammar is used; it is just that more is taken from it.
> Oh, and currently Inline::CPP always takes declarations, regardless of AUTOWRAP.
You need to take people's real life situations into mind when you implement
something. Binding to declarations may not be what you want, so you need an
option to turn it off. Thus AUTOWRAP. You could make it the default, but that
might break existing code. If you are going to break code, do it on a major
release. AUTOWRAP will probably happen by default in release 0.50. (The next
major release) Inline::CPP has more flexible options because far less people
use it.
>
> Q: Why is the C++ module called Inline::CPP instead of Inline::CXX or Inline::CC?
>
> A: People who have spent too much time with Microsoft development tools tend
> to think of CPP as a file suffix, not as the C preprocessor. Not that this is
> any kind of an excuse.
The module is called Inline::CPP. The usage syntax can be:
use Inline 'CPP';
use Inline 'C++';
use Inline 'CPlusPlus';
If you ask Neil nicely, I'm sure he'll add CXX. ;)
>
> Q: How do I get my #define's, const variables, and enum's automatically converted
> to perl constants?
>
> A: You don't, at least not with Inline. You could try SWIG.
You obviously know a lot more about SWIG than I. If you'd like to work with
me, I'll be glad to see which things make good sense to Inline.
This particular issue is something I'd like to add sometime soon. The XS
people have also brought it up.
BTW, Although I haven't used SWIG much I have met Dave Beazley. Nice guy :)
Also, I'm thinking of someday having Inline emit SWIG as well as XS. XS was
much better for the first implementation, because it is ubiquitous in Perl.
> Q: How does Inline interpret foobar(int* x)? As an array of int? An output parameter?
> What about baz(Something* x)? Is this treated as an output returning Something, or
> an input pointer to a Something struct? What is char** argv?
>
> A: Inline just uses the typemap (Perl's builtin one, plus any you provide).
> (Note that Perl's typemap defines "char **"; it is the only double star type, which
> is why it is treated differently.)
> Inline doesn't do anything at all about input vs. output,
> or const argument declarations. (For example, there is nothing like SWIG's
> mechanisms for noting INPUT, OUTPUT, or BOTH parameters.)
> You can manually create wrapper functions if you like. Isn't that fun?
I agree that Inline is lacking in output parameter facilities. In general I
disfavor output parameters. They produce bad Perl interfaces. Perl
programmers expect list returns.
If you really want to modify by reference, you should pass in by SV* and do
it yourself.
I've always stood behind the philosophy of taking time to handcraft great
interfaces, rather than autogenerate shoddy ones. In general, most of your
Inline code should be *interface* code.
>
> Q: Are Inline's typemaps anything like SWIG's typemaps?
> A: No, Inline uses typemap files formatted like Perl's. SWIG has a different
> (cross-language) syntax.
Inline has no TYPEMAP files of its own. It just allows you to pass
extra XS typemap files to XS. It uses the standard Perl typemap file
for defaults.
>
> Q: What sort of protection is there against passing the wrong number
> of arguments, or the wrong type of arguments, or undef, to some C
> function?
>
> A: XS will verify that the number of arguments is correct (unless
> ellipses are used). XS will also verify that the type of arguments
> is correct. Of course, your C program can still crash, by making
> assumptions about the value within the range of the type, or doing
> bad things with free or malloc, etc. The Inline module does not
> support constraint declarations, like SWIG.
This seems interesting. One problem Inline has to overcome is how to specify
extra semantics in the C code. Since the C code *is* the glue code, all
semantics need to be valid C. Some have suggested comment based hints.
>
> Q: Is there an easy way to map C++ exceptions to perl exceptions?
>
> A: You mean like in SWIG? No, nothing right now.
>
> Q: Is there an easy way to map C return codes to perl exceptions?
>
> A: You could do this by a typemap for a typedef'd return type. I think.
>
> Q: Is there a way to get Inline to automatically generate tracing code whenever
> I cross a language boundary?
>
> A: That would be nice, wouldn't it?
After 0.50 goes out, one of the next big pushes will be better debugging
support. This wil include things like tracing. It will also include an
extension to the Perl debugger which hooks to the GNU debugger.
>
> Q: Can I specify string contents or a hash data structure instead of a filename for
>TYPEMAPS?
>
> A: No. It has to be a filename. Of course internally it is parsed into a data
> structure (see Inline::C::get_types()).
>
> Q: Why is "TYPEMAPS" plural?
>
> A: The value has to be a scalar filename value, not an array ref.
> However, you can repeat the option, in which case it adds it to a list of typemaps
> (that is, it is internally stored as an array ref).
> Ultimately these are added as -typemap arguments to xsubpp.
> Note that the "typemap" file in your perl distribution is always used
> regardless of what you do.
The reason TYPEMAPS is plural is because it is a proxy for the
ExtUtils::MakeMaker option "TYPEMAPS". This is true of many Inline::C
options.
>
> Q: If I specify a relative path for the filename value of C or TYPEMAPS,
> what is it relative to?
>
> A: It is relative to the current working directory; this might *not*
> the directory your perl module is in, unless you arrange for it to be.
This is being addressed for all the relative PATH issues. When everthing is
fixed, the paths should be relative to your source directory, even if you are
not cd'd to it. I use FindBin.pm for this.
>
> Q: Is using AUTO_INCLUDE the same as if I put an "#include" in my C code?
>
> A: Yes, right after the builtin includes for perl and Inline. So the
> AUTO_INCLUDE option is really only useful if you have multiple uses of Inline
> sharing a single configuration.
It is also useful if you need to replace or rearrange your default headers.
Sometimes you need to put headers above the default ones.
---
I'll add many of these entries to the Inline-FAQ. Thanks again.
Cheers, Brian