Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

document constant interface + more bundle interface nits #169

Merged
merged 9 commits into from Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Changes
@@ -1,6 +1,7 @@
Revision history for {{$dist->name}}

{{$NEXT}}
- Document constant interface (see FFI::Platypus::Constant) (gh#169)

0.95_07 2019-08-13 13:38:30 -0400
- Minor tweak to bundle interface: do not create fbx.json file when
Expand Down
2 changes: 1 addition & 1 deletion Makefile.PL
Expand Up @@ -41,8 +41,8 @@ my %WriteMakefileArgs = (
"lib/FFI/Platypus/API.pm" => "\$(INST_LIB)/FFI/Platypus/API.pm",
"lib/FFI/Platypus/Buffer.pm" => "\$(INST_LIB)/FFI/Platypus/Buffer.pm",
"lib/FFI/Platypus/Bundle.pm" => "\$(INST_LIB)/FFI/Platypus/Bundle.pm",
"lib/FFI/Platypus/Bundle/Constant.pm" => "\$(INST_LIB)/FFI/Platypus/Bundle/Constant.pm",
"lib/FFI/Platypus/Closure.pm" => "\$(INST_LIB)/FFI/Platypus/Closure.pm",
"lib/FFI/Platypus/Constant.pm" => "\$(INST_LIB)/FFI/Platypus/Constant.pm",
"lib/FFI/Platypus/DL.pm" => "\$(INST_LIB)/FFI/Platypus/DL.pm",
"lib/FFI/Platypus/Declare.pm" => "\$(INST_LIB)/FFI/Platypus/Declare.pm",
"lib/FFI/Platypus/Function.pm" => "\$(INST_LIB)/FFI/Platypus/Function.pm",
Expand Down
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -532,12 +532,14 @@ dynamic library that was built when your distribution was installed.

\[version 0.96 api = 1+\]

$ffi->bundle($package, \@args);
$ffi->bundle(\@args);
$ffi->bundle($package);
$ffi->bundle;

This is a new experimental interface for bundling compiled code with your
distribution intended to eventually replace the `package` method documented
above.
above. See [FFI::Platypus::Bundle](https://metacpan.org/pod/FFI::Platypus::Bundle) for details on how this works.

## abis

Expand Down
4 changes: 3 additions & 1 deletion author.yml
Expand Up @@ -120,6 +120,8 @@ pod_spelling_system:
- Anwar
- MANWAR
- api
- deallocating
- deinitialization

pod_coverage:
skip: 0
Expand All @@ -138,7 +140,7 @@ pod_coverage:
- FFI::Platypus::Closure#add_data
- FFI::Probe
- FFI::Platypus::Bundle
- FFI::Platypus::Bundle::Constant
- FFI::Platypus::Constant
- App::fbx#main
- FFI::Build::File::Object#default_suffix
- FFI::Build::File::Library#default_suffix
Expand Down
13 changes: 13 additions & 0 deletions examples/bundle-const/ffi/const.c
@@ -0,0 +1,13 @@
#include <ffi_platypus_bundle.h>
#include "myheader.h"

void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c)
{
c->set_str("MYVERSION_STRING", MYVERSION_STRING);
c->set_uint("MYVERSION_MAJOR", MYVERSION_MAJOR);
c->set_uint("MYVERSION_MINOR", MYVERSION_MINOR);
c->set_uint("MYVERSION_PATCH", MYVERSION_PATCH);
c->set_sint("MYBAD", MYBAD);
c->set_sint("MYOK", MYOK);
c->set_double("MYPI", MYPI);
}
16 changes: 16 additions & 0 deletions examples/bundle-const/ffi/myheader.h
@@ -0,0 +1,16 @@
#ifndef MYHEADER_H
#define MYHEADER_H

#define MYVERSION_STRING "1.2.3"
#define MYVERSION_MAJOR 1
#define MYVERSION_MINOR 2
#define MYVERSION_PATCH 3

enum {
MYBAD = -1,
MYOK = 1
};

#define MYPI 3.14

#endif
12 changes: 12 additions & 0 deletions examples/bundle-const/lib/Const.pm
@@ -0,0 +1,12 @@
package Const;

use strict;
use warnings;
use FFI::Platypus;

{
my $ffi = FFI::Platypus->new( api => 1 );
$ffi->bundle;
}

1;
14 changes: 14 additions & 0 deletions examples/bundle-const/t/const.t
@@ -0,0 +1,14 @@
use strict;
use warnings;
use Test::More;
use Const;

foreach my $name (sort keys %Const::)
{
next unless $name =~ /^MY/;
note "$name=@{[ Const->$name ]}";
}

ok 1;

done_testing;
26 changes: 26 additions & 0 deletions examples/bundle-init/ffi/init.c
@@ -0,0 +1,26 @@
#include <ffi_platypus_bundle.h>

char buffer[512];
const char *version;
void (*say)(const char *);

void
ffi_pl_bundle_init(const char *package, int argc, void *argv[])
{
version = argv[0];
say = argv[1];

say("in init!");

snprintf(buffer, 512, "package = %s, version = %s", package, version);
say(buffer);

snprintf(buffer, 512, "args = %d", argc);
say(buffer);
}

void
ffi_pl_bundle_fini(const char *package)
{
say("in fini!");
}
26 changes: 26 additions & 0 deletions examples/bundle-init/lib/Init.pm
@@ -0,0 +1,26 @@
package Init;

use strict;
use warnings;
use FFI::Platypus;

our $VERSION = '1.00';

{
my $ffi = FFI::Platypus->new( api => 1 );

my $say = $ffi->closure(sub {
my $string = shift;
print "$string\n";
});

$ffi->bundle([
$ffi->cast( 'string' => 'opaque', $VERSION ),
$ffi->cast( '(string)->void' => 'opaque', $say ),
]);

undef $ffi;
undef $say;
}

1;
8 changes: 8 additions & 0 deletions examples/bundle-init/t/init.t
@@ -0,0 +1,8 @@
use strict;
use warnings;
use Test::More;
use Init;

ok 'did not crash';

done_testing;
21 changes: 0 additions & 21 deletions ffi/bundle.c

This file was deleted.

21 changes: 21 additions & 0 deletions ffi/constant.c
@@ -0,0 +1,21 @@
#include <ffi_platypus_bundle.h>

ffi_platypus_constant_t *
ffi_platypus_constant__new(void* set_str,
void* set_sint,
void* set_uint,
void* set_double)
{
ffi_platypus_constant_t *self = malloc(sizeof(ffi_platypus_constant_t));
self->set_str = set_str;
self->set_sint = set_sint;
self->set_uint = set_uint;
self->set_double = set_double;
return self;
}

void
ffi_platypus_constant__DESTROY(ffi_platypus_constant_t *self)
{
free(self);
}
2 changes: 1 addition & 1 deletion inc/mm-build.pl
Expand Up @@ -38,7 +38,7 @@

my $name = basename($lib->basename);

foreach my $dir ( 'FFI/Platypus/Memory','FFI/Platypus/Record/Meta', 'FFI/Platypus/Bundle/Constant' )
foreach my $dir ( 'FFI/Platypus/Memory','FFI/Platypus/Record/Meta', 'FFI/Platypus/Constant' )
{
my($file) = $dir =~ m{/([^/]+)$};
mkpath("blib/arch/auto/$dir", 0, 0755);
Expand Down
17 changes: 6 additions & 11 deletions include/ffi_platypus_bundle.h
Expand Up @@ -13,20 +13,15 @@
#include <stdlib.h>
#endif

typedef void (*set_str_t) (const char *name, const char *value);
typedef void (*set_sint_t) (const char *name, int64_t value );
typedef void (*set_uint_t) (const char *name, uint64_t value );
typedef void (*set_double_t) (const char *name, double value );

typedef struct {
set_str_t set_str;
set_sint_t set_sint;
set_uint_t set_uint;
set_double_t set_double;
} ffi_pl_bundle_constant_t;
void (*set_str) (const char *name, const char *value);
void (*set_sint) (const char *name, int64_t value );
void (*set_uint) (const char *name, uint64_t value );
void (*set_double) (const char *name, double value );
} ffi_platypus_constant_t;

void ffi_pl_bundle_init(const char *, int, void **);
void ffi_pl_bundle_constant(const char *, ffi_pl_bundle_constant_t *);
void ffi_pl_bundle_constant(const char *, ffi_platypus_constant_t *);
void ffi_pl_bundle_fini(const char *);

#endif
4 changes: 3 additions & 1 deletion lib/FFI/Platypus.pm
Expand Up @@ -1006,12 +1006,14 @@ sub package

[version 0.96 api = 1+]

$ffi->bundle($package, \@args);
$ffi->bundle(\@args);
$ffi->bundle($package);
$ffi->bundle;

This is a new experimental interface for bundling compiled code with your
distribution intended to eventually replace the C<package> method documented
above.
above. See L<FFI::Platypus::Bundle> for details on how this works.

=cut

Expand Down
72 changes: 67 additions & 5 deletions lib/FFI/Platypus/Bundle.pm
Expand Up @@ -223,6 +223,70 @@ using L<Dist::Zilla>:
Specifying version 1.04 will ensure that any C<.o> or C<.so> files are pruned
from your build tree and not distributed by mistake.

=head2 Initialization example

The bundle interface also gives you entry points which will be called automatically
when your code is loaded and unloaded if they are found.

=over 4

=item C<ffi_pl_bundle_init>

void ffi_pl_bundle_init(const char *package, int argc, void *argv[]);

Called when the dynamic library is loaded. C<package> is the Perl package
that called C<bundle> from Perl space. C<argc> and C<argv> represents an
array of opaque pointers that can be passed as an array to bundle as the
last argument. (the count C<argc> is a little redundant because C<argv>
is also NULL terminated).

=item C<ffi_pl_bundle_constant>

void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c);

Called immediately after C<ffi_pl_bundle_init>, and is intended to allow
you to set Perl constants from C space. For details on how this works
and what methods you can call on the C<ffi_platypus_constant_t> instance,
see L<FFI::Platypus::Constant>.

=item C<ffi_pl_bundle_fini>

void ffi_pl_bundle_fini(const char *package);

Called when the dynamic library is unloaded. C<package> is the Perl
package that called C<bundle> from Perl space when the library was
loaded. B<CAVEAT>: if you attach any functions then this will
never be called, because attaching functions locks the Platypus
instance into memory along with the libraries which it is using.

=back

Here is an example that passes the version and a callback back into Perl
space that emulates the Perl 5.10 C<say> feature.

C<ffi/init.c>:

# EXAMPLE: examples/bundle-init/ffi/init.c

C<lib/Init.pm>:

# EXAMPLE: examples/bundle-init/lib/Init.pm

The deinitialization order for the C<$say> callback and the C<$ffi>
instance is essential here, so we do it manually with C<undef>:

undef $ffi;
undef $say;

First we deallocate C<$ffi> which calls C<ffi_pl_bundle_fini>,
which calls C<$say>, so we want to make sure the latter is still
allocated. Once C<ffi_pl_bundle_fini> is done, we can safely
deallocate C<$say>.

If C<ffi_pl_bundle_fini> didn't call back into Perl space like
this then we don't have to be as careful about deallocating
things in Perl space.

=cut

package FFI::Platypus;
Expand Down Expand Up @@ -330,13 +394,13 @@ sub _bundle

if(my $init = eval { $self->function( 'ffi_pl_bundle_init' => [ 'string', 'sint32', 'opaque[]' ] => 'void' ) })
{
$init->call($package, scalar(@arg_ptrs)-1, \@arg_ptrs);
$init->call($package, scalar(@arg_ptrs)-1, \@arg_ptrs);
}

if(my $init = eval { $self->function( 'ffi_pl_bundle_constant' => [ 'string', 'opaque' ] => 'void' ) })
{
require FFI::Platypus::Bundle::Constant;
my $api = FFI::Platypus::Bundle::Constant->new($package);
require FFI::Platypus::Constant;
my $api = FFI::Platypus::Constant->new($package);
$init->call($package, $api->ptr);
}

Expand All @@ -349,8 +413,6 @@ sub _bundle
};
}

# TODO: fini

$self;
}

Expand Down