Tiny C Compiler for FFI
use FFI::TinyCC;
use FFI::Platypus::Declare qw( int );
my $tcc = FFI::TinyCC->new;
$tcc->compile_string(q{
int
find_square(int value)
{
return value*value;
}
});
my $address = $tcc->get_symbol('find_square');
attach [$address => 'find_square'] => [int] => int;
print find_square(4), "\n"; # prints 16
This module provides an interface to a very small C compiler known as
TinyCC. It does almost no optimizations, so gcc
or clang
will
probably generate faster code, but it is very small and is very fast and
thus may be useful for some Just In Time (JIT) or Foreign Function
Interface (FFI) situations.
For a simpler, but less powerful interface see FFI::TinyCC::Inline.
my $tcc = FFI::TinyCC->new;
Create a new TinyCC instance.
Methods will generally throw an exception on failure.
$tcc->set_options($options);
Set compiler and linker options, as you would on the command line, for example:
$tcc->set_options('-I/foo/include -L/foo/lib -DFOO=22');
$tcc->add_file('foo.c');
$tcc->add_file('foo.o');
$tcc->add_file('foo.so'); # or dll on windows
Add a file, DLL, shared object or object file.
On windows adding a DLL is not supported via this interface.
$tcc->compile_string($c_code);
Compile a string containing C source code.
$tcc->add_symbol($name, $callback);
$tcc->add_symbol($name, $pointer);
Add the given given symbol name / callback or pointer combination. See example below for how to use this to call Perl from Tiny C code.
It will accept a FFI::Raw::Callback at a performance penalty. If possible pass in the pointer to the C entry point instead.
If you are using FFI::Platypus you can use FFI::Platypus#cast or FFI::Platypus::Declare#cast to get a pointer to a closure:
use FFI::Platypus::Declare;
my $clousre = closure { return $_[0]+1 };
my $pointer = cast '(int)->int' => 'opaque', $closure;
$tcc->add_symbol('foo' => $pointer);
$tcc->add_include_path($path);
Add the given path to the list of paths used to search for include files.
$tcc->add_sysinclude_path($path);
Add the given path to the list of paths used to search for system include files.
$tcc->set_lib_path($path);
Set the lib path
$tcc->define_symbol($name => $value);
$tcc->define_symbol($name);
Define the given symbol, optionally with the specified value.
$tcc->undefine_symbol($name);
Undefine the given symbol.
$tcc->set_output_type('memory');
$tcc->set_output_type('exe');
$tcc->set_output_type('dll');
$tcc->set_output_type('obj');
Set the output type. This must be called before any compilation.
Output formats may not be supported on your platform. exe
is
NOT supported on *BSD or OS X.
As a basic baseline at least memory
should be supported.
$tcc->add_library($libname);
Add the given library when linking. Example:
$tcc->add_library('m'); # equivalent to -lm (math library)
$tcc->add_library_path($pathname);
Add the given directory to the search path used to find libraries.
my $exit_value = $tcc->run(@arguments);
my $pointer = $tcc->get_symbol($symbol_name);
Return symbol address or undef if not found. This can be passed into the FFI::Platypus#function method, FFI::Platypus#attach method, FFI::Platypus::Declare#function function or similar interface that takes a pointer to a C function.
$tcc->output_file($filename);
Output the generated code (either executable, object or DLL) to the given filename. The type of output is specified by the set_output_type method.
DEPRECATED
my $ffi = $tcc->get_ffi_raw($symbol_name, $return_type, @argument_types);
Given the name of a function, return an FFI::Raw instance that will allow you to call it from Perl.
This method is deprecated, and will be removed from a future version of FFI::TinyCC, but not before January 31, 2017. It will issue a warning if you try to use it. Instead of this:
my $function = $ffi->get_ffi_raw($name, FFI::void);
$function->();
Do this:
use FFI::Raw;
my $function = FFI::Raw->new_from_ptr($ffi->get_symbol($name), FFI::void);
$function->();
Or better yet, use FFI::Platypus instead:
use FFI::Platypus::Declare;
attach [$ffi->get_symbol($name) => 'function'] => [] => 'void';
function();
use FFI::TinyCC;
my $tcc = FFI::TinyCC->new;
$tcc->compile_string(<<EOF);
int
main(int argc, char *argv[])
{
puts("hello world");
}
EOF
my $r = $tcc->run;
exit $r;
use FFI::TinyCC;
use FFI::Platypus::Declare qw( opaque );
my $say = closure { print $_[0], "\n" };
my $ptr = cast '(string)->void' => opaque => $say;
my $tcc = FFI::TinyCC->new;
$tcc->add_symbol(say => $ptr);
$tcc->compile_string(<<EOF);
extern void say(const char *);
int
main(int argc, char *argv[])
{
int i;
for(i=0; i<argc; i++)
{
say(argv[i]);
}
}
EOF
my $r = $tcc->run($0, @ARGV);
exit $r;
use FFI::TinyCC;
use FFI::Platypus::Declare qw( int );
my $tcc = FFI::TinyCC->new;
$tcc->compile_string(q{
int
calculate_square(int value)
{
return value*value;
}
});
my $value = shift @ARGV;
$value = 4 unless defined $value;
my $address = $tcc->get_symbol('calculate_square');
attach [$address => 'square'] => [int] => int;
print square($value), "\n";
Tiny C is only supported on platforms with ARM or Intel processors. All features may not be fully supported on all operating systems.
Tiny C is no longer supported by its original author, though various forks seem to have varying levels of support. We use the fork that comes with Alien::TinyCC.
- FFI::TinyCC::Inline
- Tiny C
- Tiny C Compiler Reference Documentation
- FFI::Platypus
- Alien::TinyCC
- C::TinyCompiler
This package also comes with a parser that was shamelessly stolen from XS::TCC, which I strongly suspect was itself shamelessly "borrowed" from Inline::C::Parser::RegExp
The license details for the parser are:
Copyright 2002 Brian Ingerson Copyright 2008, 2010-2012 Sisyphus Copyright 2013 Steffen Muellero
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Graham Ollis plicease@cpan.org
This software is copyright (c) 2015 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.