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

Conversation

plicease
Copy link
Member

@plicease plicease commented Aug 13, 2019

TODO:

  • document FFI::Platypus::Constant
  • document initialization and de-initialization code for bundles.

@plicease
Copy link
Member Author

init example as rendered in full:

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.

  • ffi_pl_bundle_init

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

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

  • ffi_pl_bundle_constant

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

    Called immediately after 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 ffi_platypus_constant_t instance,
    see FFI::Platypus::Constant.

  • ffi_pl_bundle_fini

      void ffi_pl_bundle_fini(const char *package);
    

    Called when the dynamic library is unloaded. package is the Perl
    package that called bundle from Perl space when the library was
    loaded. 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.

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

ffi/init.c:

#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!");
}

lib/Init.pm:

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;

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

undef $ffi;
undef $say;

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

If 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.

@plicease
Copy link
Member Author

plicease commented Aug 14, 2019

The constant documentation rendered in full:

NAME

FFI::Platypus::Constant - Define constants in C space for Perl

VERSION

version 0.95_07

SYNOPSIS

#include <ffi_platypus_bundle.h>

void
ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c)
{
  c->set_str("FOO", "BAR");       /* sets $package::FOO to "BAR" */
  c->set_str("ABC::DEF", "GHI");  /* sets ABC::DEF to GHI        */
}

DESCRIPTION

The Platypus bundle interface (see FFI::Platypus::Bundle) has an entry point
ffi_pl_bundle_constant that lets you define constants in Perl space from C.

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

The first argument package is the name of the Perl package. The second argument
c is a struct with function pointers that lets you define constants of different
types. The first argument for each function is the name of the constant and the
second is the value. If :: is included in the constant name then it will be
defined in that package space. If it isn't then the constant will be defined in
whichever package called bundle.

  • set_str

      c->set_str(name, value);
    

    Sets a string constant.

  • set_sint

      c->set_sint(name, value);
    

    Sets a 64-bit signed integer constant.

  • set_uint

      c->set_uint(name, value);
    

    Sets a 64-bit unsigned integer constant.

  • set_double

      c->set_double(name, value);
    

    Sets a double precision floating point constant.

Example

Suppose you have a header file myheader.h:

#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

You can define these constants from C:

#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);
}

Your Perl code doesn't have to do anything when calling bundle:

package Const;

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

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

1;

@plicease plicease merged commit 3790ddd into master Aug 14, 2019
@plicease plicease deleted the graham/document-constant branch August 14, 2019 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant