package FFI::Platypus::Lang::Go; use strict; use warnings; use 5.008001; use File::ShareDir::Dist 0.07 qw( dist_config ); # ABSTRACT: Documentation and tools for using Platypus with Go our $VERSION = '0.02'; # VERSION my $config; sub _config { unless($config) { $config = dist_config 'FFI-Platypus-Lang-Go'; # running out of an unbuilt git, probe for types on the fly if(!%$config && -f 'inc/mymm-build.pl') { my $clean = 0; if(!-f 'blib') { require Capture::Tiny; my($out, $exit) = Capture::Tiny::capture_merged(sub { my @cmd = ($^X, 'inc/mymm-build.pl'); print "+@cmd\n"; system @cmd; }); if($exit) { require File::Path; File::Path::rmtree('blib',0,0); print STDERR $out; die "probe of go types failed"; } else { $clean = 1; } } $config = do './blib/lib/auto/share/dist/FFI-Platypus-Lang-Go/config.pl'; if($clean) { require File::Path; File::Path::rmtree('blib',0,0); } } } $config; } sub native_type_map { _config->{go_types}; } sub load_custom_types { my(undef, $ffi) = @_; $ffi->load_custom_type('::GoString' => 'gostring'); } 1; __END__ =pod =encoding UTF-8 =head1 NAME FFI::Platypus::Lang::Go - Documentation and tools for using Platypus with Go =head1 VERSION version 0.02 =head1 SYNOPSIS Go code: package main import "C" //export add func add(x, y int) int { return x + y } func main() {} Perl code: use FFI::Platypus 2.00; use FFI::CheckLib qw( find_lib_or_die ); use File::Basename qw( dirname ); my $ffi = FFI::Platypus->new( api => 2, lib => './add.so', lang => 'Go', ); $ffi->attach( add => ['goint', 'goint'] => 'goint' ); print add(1,2), "\n"; # prints 3 =head1 DESCRIPTION This distribution is the Go language plugin for Platypus. It provides the definition for native Go types, like C and C. It also provides a L interface for building Perl extensions written in Go (see L for details). =head1 EXAMPLES The examples in this discussion are bundled with this distribution and can be found in the C directory. =head2 Passing and Returning Integers =head3 Go package main import "C" //export add func add(x, y int) int { return x + y } func main() {} =head3 Perl use FFI::Platypus 2.00; use FFI::CheckLib qw( find_lib_or_die ); use File::Basename qw( dirname ); my $ffi = FFI::Platypus->new( api => 2, lib => './add.so', lang => 'Go', ); $ffi->attach( add => ['goint', 'goint'] => 'goint' ); print add(1,2), "\n"; # prints 3 =head3 Execute $ go build -o add.so -buildmode=c-shared add.go $ perl add.pl 3 =head3 Discussion The Go code has to: =over 4 =item 1 Import the pseudo package C<"C"> =item 2 Mark any exported function with the command C =item 3 Include a C
function, even if you do not use it. =back From the Perl side, the Go types have a C prefix, so C in Go is C in Perl. Aside from that passing basic types like integers and floats is trivial with FFI. =head2 Module =head3 Go /* * borrowed from * https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf */ package main import "C" import ( "fmt" "math" "sort" "sync" ) var count int var mtx sync.Mutex //export Add func Add(a, b int) int { return a + b } //export Cosine func Cosine(x float64) float64 { return math.Cos(x) } //export Sort func Sort(vals []int) { sort.Ints(vals) } //export Log func Log(msg string) int { mtx.Lock() defer mtx.Unlock() fmt.Println(msg) count++ return count } func main() {} =head3 Perl Module: package Awesome::FFI; use strict; use warnings; use FFI::Platypus; use FFI::Go::String; use base qw( Exporter ); our @EXPORT_OK = qw( Add Cosine Log ); my $ffi = FFI::Platypus->new( api => 1, lang => 'Go' ); # See FFI::Platypus::Bundle for the how and why # bundle works. $ffi->bundle; $ffi->attach( Add => ['goint','goint'] => 'goint' ); $ffi->attach( Cosine => ['gofloat64' ] => 'gofloat64' ); $ffi->attach( Log => ['gostring' ] => 'goint' ); 1; Test: use Test2::V0 -no_srand => 1; use Awesome::FFI qw( Add Cosine Log ); use Capture::Tiny qw( capture ); use FFI::Go::String; is( Add(1,2), 3 ); is( Cosine(0), 1.0 ); is( [capture { Log("Hello Perl!") }], ["Hello Perl!\n", '', 1] ); done_testing; =head3 Execute $ prove -lvm t/awesome_ffi.t t/awesome_ffi.t .. ok 1 ok 2 ok 3 1..3 ok All tests successful. Files=1, Tests=3, 1 wallclock secs ( 0.01 usr 0.00 sys + 1.28 cusr 0.48 csys = 1.77 CPU) Result: PASS =head3 Discussion This is a full working example of a Perl distribution / module included in the C directory. =head1 SEE ALSO =over 4 =item L More about FFI and Platypus itself. =item L Type plugin for the go string type. =item L Low level interface to the go string type. =item L L class for handling Go modules. =item L =back =head1 AUTHOR Graham Ollis =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018-2022 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. =cut