Support multiple XS files
write_bindings now takes the name of the boot class and an array of
parcels. CFC::Perl::Build takes a list of modules like
modules => [
{
name => 'Clownfish',
parcels => [ 'Clownfish', 'TestClownfish' ],
make_target => 'core_objects',
c_source_dirs => [ $XS_SOURCE_DIR ],
},
],
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/db8df155
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/db8df155
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/db8df155
Branch: refs/heads/master
Commit: db8df1553ef1d4bacdec865b0151b0c605ca92eb
Parents: 0c09e83
Author: Nick Wellnhofer <[email protected]>
Authored: Tue Jun 14 17:53:37 2016 +0200
Committer: Nick Wellnhofer <[email protected]>
Committed: Mon Jun 20 14:44:15 2016 +0200
----------------------------------------------------------------------
compiler/perl/lib/Clownfish/CFC.pm | 11 ++-
compiler/perl/lib/Clownfish/CFC.xs | 35 +++++++--
compiler/perl/lib/Clownfish/CFC/Perl/Build.pm | 83 ++++++++++++++------
.../lib/Clownfish/CFC/Perl/Build/Charmonic.pm | 8 +-
compiler/src/CFCPerl.c | 72 +++++++++++------
compiler/src/CFCPerl.h | 19 ++---
runtime/perl/buildlib/Clownfish/Build.pm | 11 ++-
7 files changed, 169 insertions(+), 70 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/db8df155/compiler/perl/lib/Clownfish/CFC.pm
----------------------------------------------------------------------
diff --git a/compiler/perl/lib/Clownfish/CFC.pm
b/compiler/perl/lib/Clownfish/CFC.pm
index 8896925..eec76bd 100644
--- a/compiler/perl/lib/Clownfish/CFC.pm
+++ b/compiler/perl/lib/Clownfish/CFC.pm
@@ -720,7 +720,6 @@ BEGIN { XSLoader::load( 'Clownfish::CFC', '0.5.0' ) }
our %new_PARAMS = (
hierarchy => undef,
lib_dir => undef,
- boot_class => undef,
header => undef,
footer => undef,
);
@@ -729,7 +728,15 @@ BEGIN { XSLoader::load( 'Clownfish::CFC', '0.5.0' ) }
my ( $either, %args ) = @_;
verify_args( \%new_PARAMS, %args ) or confess $@;
return _new(
- @args{qw( hierarchy lib_dir boot_class header footer )} );
+ @args{qw( hierarchy lib_dir header footer )} );
+ }
+
+ sub write_bindings {
+ my ( $self, %args ) = @_;
+ $args{parcels} = [ map {
+ Clownfish::CFC::Model::Parcel->acquire($_);
+ } @{ $args{parcels} } ];
+ return $self->_write_bindings( @args{qw( boot_class parcels )} );
}
}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/db8df155/compiler/perl/lib/Clownfish/CFC.xs
----------------------------------------------------------------------
diff --git a/compiler/perl/lib/Clownfish/CFC.xs
b/compiler/perl/lib/Clownfish/CFC.xs
index 49c4187..c79ee34 100644
--- a/compiler/perl/lib/Clownfish/CFC.xs
+++ b/compiler/perl/lib/Clownfish/CFC.xs
@@ -84,6 +84,26 @@ S_array_of_cfcbase_to_av(CFCBase **things) {
return retval;
}
+// Transform a Perl arrayref into a NULL-terminated array of CFCBase*.
+static CFCBase**
+S_av_to_array_of_cfcbase(SV *ref, const char *class_name) {
+ if (!SvROK(ref)) { croak("Not an arrayref"); }
+ SV *sv = SvRV(ref);
+ if (SvTYPE(sv) != SVt_PVAV) { croak("Not an arrayref"); }
+ AV *av = (AV*)sv;
+ size_t size = av_len(av) + 1;
+ CFCBase **retval = (CFCBase**)CALLOCATE(size + 1, sizeof(CFCBase*));
+ for (size_t i = 0; i < size; i++) {
+ SV **elem = av_fetch(av, i, 0);
+ if (!elem || !sv_derived_from(*elem, class_name)) {
+ croak("Array element not of type %s", class_name);
+ }
+ IV objint = SvIV((SV*)SvRV(*elem));
+ retval[i] = INT2PTR(CFCBase*, objint);
+ }
+ return retval;
+}
+
static SV*
S_sv_eat_c_string(char *string) {
if (string) {
@@ -1945,15 +1965,13 @@ PPCODE:
MODULE = Clownfish PACKAGE = Clownfish::CFC::Binding::Perl
SV*
-_new(hierarchy, lib_dir, boot_class, header, footer)
+_new(hierarchy, lib_dir, header, footer)
CFCHierarchy *hierarchy;
const char *lib_dir;
- const char *boot_class;
const char *header;
const char *footer;
CODE:
- CFCPerl *self = CFCPerl_new(hierarchy, lib_dir, boot_class, header,
- footer);
+ CFCPerl *self = CFCPerl_new(hierarchy, lib_dir, header, footer);
RETVAL = S_cfcbase_to_perlref(self);
CFCBase_decref((CFCBase*)self);
OUTPUT: RETVAL
@@ -1985,10 +2003,15 @@ PPCODE:
CFCPerl_write_hostdefs(self);
void
-write_bindings(self)
+_write_bindings(self, boot_class, sv)
CFCPerl *self;
+ const char *boot_class;
+ SV *sv;
PPCODE:
- CFCPerl_write_bindings(self);
+ CFCParcel **parcels = (CFCParcel**)
+ S_av_to_array_of_cfcbase(sv, "Clownfish::CFC::Model::Parcel");
+ CFCPerl_write_bindings(self, boot_class, parcels);
+ FREEMEM(parcels);
void
write_xs_typemap(self)
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/db8df155/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
----------------------------------------------------------------------
diff --git a/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
b/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
index 6095dc1..804ba87 100644
--- a/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
+++ b/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
@@ -256,7 +256,6 @@ sub _compile_clownfish {
my $binding = Clownfish::CFC::Binding::Perl->new(
hierarchy => $hierarchy,
lib_dir => $LIB_DIR,
- boot_class => $self->module_name,
header => $self->clownfish_params('autogen_header'),
footer => '',
);
@@ -277,9 +276,14 @@ sub ACTION_clownfish {
$self->add_to_cleanup($AUTOGEN_DIR);
- my @module_dir = split( '::', $self->module_name );
- my $class_name = pop(@module_dir);
- my $xs_filepath = catfile( $LIB_DIR, @module_dir, "$class_name.xs" );
+ my $modules = $self->clownfish_params('modules');
+ my @xs_filepaths;
+
+ for my $module (@$modules) {
+ my @module_dir = split( '::', $module->{name} );
+ my $class_name = pop(@module_dir);
+ push @xs_filepaths, catfile( $LIB_DIR, @module_dir, "$class_name.xs" );
+ }
my $buildlib_pm_filepaths = $self->rscan_dir( $BUILDLIB_DIR, qr/\.pm$/ );
my $cfh_filepaths = $self->_cfh_filepaths;
@@ -289,7 +293,7 @@ sub ACTION_clownfish {
return
if $self->up_to_date(
[ @$cfh_filepaths, @$buildlib_pm_filepaths ],
- [ $xs_filepath, $log_filepath, ]
+ [ @xs_filepaths, $log_filepath, ]
);
# Write out all autogenerated files.
@@ -312,14 +316,20 @@ sub ACTION_clownfish {
# Rewrite XS if either any .cfh files or relevant .pm files were modified.
my $buildlib_modified = ! $self->up_to_date(
- \@$buildlib_pm_filepaths, [ $xs_filepath, $log_filepath ]
+ \@$buildlib_pm_filepaths, [ @xs_filepaths, $log_filepath ]
);
if ( $cfh_modified || $buildlib_modified ) {
- $self->add_to_cleanup($xs_filepath);
+ $self->add_to_cleanup(@xs_filepaths);
$perl_binding->write_host_code;
$perl_binding->write_hostdefs;
- $perl_binding->write_bindings;
+
+ for my $module (@$modules) {
+ $perl_binding->write_bindings(
+ boot_class => $module->{name},
+ parcels => $module->{parcels},
+ );
+ }
print "Writing POD...\n";
my $pod_files = $perl_binding->write_pod;
@@ -329,12 +339,14 @@ sub ACTION_clownfish {
# Touch autogenerated files in case the modifications were inconsequential
# and didn't trigger a rewrite, so that we won't have to check them again
# next pass.
- if (!$self->up_to_date(
- [ @$cfh_filepaths, @$buildlib_pm_filepaths ], $xs_filepath
- )
- )
- {
- utime( time, time, $xs_filepath ); # touch
+ for my $xs_filepath (@xs_filepaths) {
+ if (!$self->up_to_date(
+ [ @$cfh_filepaths, @$buildlib_pm_filepaths ], $xs_filepath
+ )
+ )
+ {
+ utime( time, time, $xs_filepath ); # touch
+ }
}
$hierarchy->write_log;
@@ -361,10 +373,22 @@ sub ACTION_compile_custom_xs {
$self->depends_on('ppport');
+ # Make sure all parcels are read and registered.
+ $self->_compile_clownfish();
+
+ my $modules = $self->clownfish_params('modules');
+ for my $module (@$modules) {
+ $self->_compile_custom_xs($module);
+ }
+}
+
+sub _compile_custom_xs {
+ my ( $self, $module ) = @_;
+
require ExtUtils::CBuilder;
require ExtUtils::ParseXS;
- my $module_name = $self->module_name;
+ my $module_name = $module->{name};
my @module_parts = split( '::', $module_name );
my @module_dir = @module_parts;
my $class_name = pop(@module_dir);
@@ -376,23 +400,27 @@ sub ACTION_compile_custom_xs {
my @objects;
# Make core objects.
- if ($self->can('cf_make_core_objects')) {
- my $core_objects = $self->cf_make_core_objects();
+ if ($module->{make_target}) {
+ my $core_objects = $self->cf_make_objects($module->{make_target});
push @objects, @$core_objects;
$self->add_to_cleanup(@$core_objects);
}
# Compile C source files.
my $c_files = [];
- my $source_dirs = $self->clownfish_params('c_source');
+ my $source_dirs = $module->{c_source_dirs} || [];
for my $source_dir (@$source_dirs) {
push @$c_files, @{ $self->rscan_dir( $source_dir, qr/\.c$/ ) };
}
my $autogen_src_dir = catdir( $AUTOGEN_DIR, 'source' );
- my $autogen_regex = ( grep { /^$autogen_src_dir/ } @objects )
- ? qr/_perl\.c$/ # Only compile *_perl.c files.
- : qr/\.c$/;
- push @$c_files, @{ $self->rscan_dir( $autogen_src_dir, $autogen_regex ) };
+ for my $parcel ( @{ $module->{parcels} } ) {
+ $parcel = Clownfish::CFC::Model::Parcel->acquire($parcel);
+ my $prefix = $parcel->get_prefix;
+ # Assume *_parcel.c is built with make.
+ push @$c_files, catfile( $autogen_src_dir, "${prefix}parcel.c" )
+ if !$module->{make_target};
+ push @$c_files, catfile( $autogen_src_dir, "${prefix}perl.c" );
+ }
my $extra_cflags = $self->clownfish_params('cflags');
for my $c_file (@$c_files) {
my $o_file = $c_file;
@@ -599,6 +627,17 @@ the Perl bindings for Clownfish modules.
extra_linker_flags => [ @cf_linker_flags ],
clownfish_params => {
source => [ catdir( @cf_base_path, 'core' ) ],
+ modules => [
+ {
+ name => 'My::Module',
+ c_source_dirs => 'xs',
+ parcels => [ 'MyModule' ],
+ },
+ {
+ name => 'My::Module::Test',
+ parcels => [ 'TestMyModule' ],
+ },
+ ],
},
requires => {
'Other::Module' => '0.3.0',
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/db8df155/compiler/perl/lib/Clownfish/CFC/Perl/Build/Charmonic.pm
----------------------------------------------------------------------
diff --git a/compiler/perl/lib/Clownfish/CFC/Perl/Build/Charmonic.pm
b/compiler/perl/lib/Clownfish/CFC/Perl/Build/Charmonic.pm
index 03b48f5..97cc0b7 100644
--- a/compiler/perl/lib/Clownfish/CFC/Perl/Build/Charmonic.pm
+++ b/compiler/perl/lib/Clownfish/CFC/Perl/Build/Charmonic.pm
@@ -140,8 +140,8 @@ sub charmony {
return;
}
-sub cf_make_core_objects {
- my $self = shift;
+sub cf_make_objects {
+ my ( $self, $target ) = @_;
return [] unless $self->charmonizer_params('create_makefile');
@@ -149,12 +149,12 @@ sub cf_make_core_objects {
my @command = (
$self->config('make'),
$self->split_like_shell($make_options),
- 'core_objects',
+ lc($target),
);
print join(' ', @command), "\n";
system @command and die($self->config('make') . " failed");
- return [ split( /\s+/, $self->charmony('CORE_OBJECTS') ) ];
+ return [ split( /\s+/, $self->charmony(uc($target)) ) ];
}
1;
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/db8df155/compiler/src/CFCPerl.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerl.c b/compiler/src/CFCPerl.c
index 6a15d43..c58d30c 100644
--- a/compiler/src/CFCPerl.c
+++ b/compiler/src/CFCPerl.c
@@ -19,6 +19,11 @@
#include <string.h>
#include <stdio.h>
+#ifndef true
+ #define true 1
+ #define false 0
+#endif
+
#define CFC_NEED_BASE_STRUCT_DEF
#include "CFCBase.h"
#include "CFCPerl.h"
@@ -45,14 +50,12 @@ struct CFCPerl {
CFCBase base;
CFCHierarchy *hierarchy;
char *lib_dir;
- char *boot_class;
char *header;
char *footer;
char *c_header;
char *c_footer;
char *pod_header;
char *pod_footer;
- char *xs_path;
};
// Modify a string in place, swapping out "::" for the supplied character.
@@ -72,23 +75,21 @@ static const CFCMeta CFCPERL_META = {
};
CFCPerl*
-CFCPerl_new(CFCHierarchy *hierarchy, const char *lib_dir,
- const char *boot_class, const char *header, const char *footer) {
+CFCPerl_new(CFCHierarchy *hierarchy, const char *lib_dir, const char *header,
+ const char *footer) {
CFCPerl *self = (CFCPerl*)CFCBase_allocate(&CFCPERL_META);
- return CFCPerl_init(self, hierarchy, lib_dir, boot_class, header, footer);
+ return CFCPerl_init(self, hierarchy, lib_dir, header, footer);
}
CFCPerl*
CFCPerl_init(CFCPerl *self, CFCHierarchy *hierarchy, const char *lib_dir,
- const char *boot_class, const char *header, const char *footer) {
+ const char *header, const char *footer) {
CFCUTIL_NULL_CHECK(hierarchy);
CFCUTIL_NULL_CHECK(lib_dir);
- CFCUTIL_NULL_CHECK(boot_class);
CFCUTIL_NULL_CHECK(header);
CFCUTIL_NULL_CHECK(footer);
self->hierarchy = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy);
self->lib_dir = CFCUtil_strdup(lib_dir);
- self->boot_class = CFCUtil_strdup(boot_class);
self->header = CFCUtil_strdup(header);
self->footer = CFCUtil_strdup(footer);
self->c_header = CFCUtil_make_c_comment(header);
@@ -96,11 +97,6 @@ CFCPerl_init(CFCPerl *self, CFCHierarchy *hierarchy, const
char *lib_dir,
self->pod_header = CFCUtil_make_perl_comment(header);
self->pod_footer = CFCUtil_make_perl_comment(footer);
- // Derive path to generated .xs file.
- self->xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", lib_dir,
- boot_class);
- S_replace_double_colons(self->xs_path, CHY_DIR_SEP_CHAR);
-
return self;
}
@@ -108,14 +104,12 @@ void
CFCPerl_destroy(CFCPerl *self) {
CFCBase_decref((CFCBase*)self->hierarchy);
FREEMEM(self->lib_dir);
- FREEMEM(self->boot_class);
FREEMEM(self->header);
FREEMEM(self->footer);
FREEMEM(self->c_header);
FREEMEM(self->c_footer);
FREEMEM(self->pod_header);
FREEMEM(self->pod_footer);
- FREEMEM(self->xs_path);
CFCBase_destroy((CFCBase*)self);
}
@@ -536,8 +530,11 @@ S_add_xsub_spec(char *xsub_specs, CFCPerlSub *xsub) {
}
void
-CFCPerl_write_bindings(CFCPerl *self) {
- CFCParcel **parcels = CFCParcel_all_parcels();
+CFCPerl_write_bindings(CFCPerl *self, const char *boot_class,
+ CFCParcel **parcels) {
+ CFCUTIL_NULL_CHECK(boot_class);
+ CFCUTIL_NULL_CHECK(parcels);
+
CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy);
CFCPerlClass **registry = CFCPerlClass_registry();
char *privacy_syms = CFCUtil_strdup("");
@@ -549,8 +546,6 @@ CFCPerl_write_bindings(CFCPerl *self) {
char *hand_rolled_xs = CFCUtil_strdup("");
for (size_t i = 0; parcels[i]; ++i) {
- if (CFCParcel_included(parcels[i])) { continue; }
-
// Bake the parcel privacy defines into the XS, so it can be compiled
// without any extra compiler flags.
const char *privacy_sym = CFCParcel_get_privacy_sym(parcels[i]);
@@ -567,7 +562,16 @@ CFCPerl_write_bindings(CFCPerl *self) {
for (size_t i = 0; ordered[i] != NULL; i++) {
CFCClass *klass = ordered[i];
- if (CFCClass_included(klass)) { continue; }
+
+ CFCParcel *parcel = CFCClass_get_parcel(klass);
+ int found = false;
+ for (size_t j = 0; parcels[j]; j++) {
+ if (parcel == parcels[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) { continue; }
// Pound-includes for generated headers.
const char *include_h = CFCClass_include_h(klass);
@@ -638,7 +642,19 @@ CFCPerl_write_bindings(CFCPerl *self) {
// Hand-rolled XS.
for (size_t i = 0; registry[i] != NULL; i++) {
- const char *xs = CFCPerlClass_get_xs_code(registry[i]);
+ CFCPerlClass *perl_class = registry[i];
+
+ CFCParcel *parcel = CFCPerlClass_get_parcel(perl_class);
+ int found = false;
+ for (size_t j = 0; parcels[j]; j++) {
+ if (parcel == parcels[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) { continue; }
+
+ const char *xs = CFCPerlClass_get_xs_code(perl_class);
hand_rolled_xs = CFCUtil_cat(hand_rolled_xs, xs, "\n", NULL);
}
@@ -681,13 +697,19 @@ CFCPerl_write_bindings(CFCPerl *self) {
"%s"; // Footer
char *contents
= CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes,
- generated_xs, self->boot_class, self->boot_class,
- class_specs, xsub_specs, bootstrap_calls,
- hand_rolled_xs, self->c_footer);
+ generated_xs, boot_class, boot_class, class_specs,
+ xsub_specs, bootstrap_calls, hand_rolled_xs,
+ self->c_footer);
+
+ // Derive path to generated .xs file.
+ char *xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", self->lib_dir,
+ boot_class);
+ S_replace_double_colons(xs_path, CHY_DIR_SEP_CHAR);
// Write out if there have been any changes.
- CFCUtil_write_if_changed(self->xs_path, contents, strlen(contents));
+ CFCUtil_write_if_changed(xs_path, contents, strlen(contents));
+ FREEMEM(xs_path);
FREEMEM(contents);
FREEMEM(hand_rolled_xs);
FREEMEM(bootstrap_calls);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/db8df155/compiler/src/CFCPerl.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerl.h b/compiler/src/CFCPerl.h
index ea8bf21..45db605 100644
--- a/compiler/src/CFCPerl.h
+++ b/compiler/src/CFCPerl.h
@@ -54,13 +54,9 @@ struct CFCHierarchy;
*/
/**
- * @param parcel The L<Clownfish::CFC::Model::Parcel> to which the
- * C<boot_class> belongs.
* @param hierarchy A Clownfish::CFC::Model::Hierarchy.
* @param lib_dir location of the Perl lib directory to which files will be
* written.
- * @param boot_class The name of the main class, which will own the shared
- * object.
* @param header Text which will be prepended to generated C/XS files --
* typically, an "autogenerated file" warning.
* @param footer Text to be appended to the end of generated C/XS files --
@@ -68,12 +64,11 @@ struct CFCHierarchy;
*/
CFCPerl*
CFCPerl_new(struct CFCHierarchy *hierarchy, const char *lib_dir,
- const char *boot_class, const char *header, const char *footer);
+ const char *header, const char *footer);
CFCPerl*
CFCPerl_init(CFCPerl *self, struct CFCHierarchy *hierarchy,
- const char *lib_dir, const char *boot_class, const char *header,
- const char *footer);
+ const char *lib_dir, const char *header, const char *footer);
void
CFCPerl_destroy(CFCPerl *self);
@@ -92,10 +87,16 @@ CFCPerl_write_pod(CFCPerl *self);
void
CFCPerl_write_host_code(CFCPerl *self);
-/** Generate the XS bindings for all classes in the hierarchy.
+/** Generate the XS bindings for all classes in the given parcels.
+ *
+ * @param boot_class The name of the main class, which will own the shared
+ * object.
+ * @param parcels NULL-terminated list of parcels to include in the shared
+ * object.
*/
void
-CFCPerl_write_bindings(CFCPerl *self);
+CFCPerl_write_bindings(CFCPerl *self, const char *boot_class,
+ struct CFCParcel **parcels);
/** Generate hostdefs file.
*/
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/db8df155/runtime/perl/buildlib/Clownfish/Build.pm
----------------------------------------------------------------------
diff --git a/runtime/perl/buildlib/Clownfish/Build.pm
b/runtime/perl/buildlib/Clownfish/Build.pm
index 8ae957f..3d1b8c3 100644
--- a/runtime/perl/buildlib/Clownfish/Build.pm
+++ b/runtime/perl/buildlib/Clownfish/Build.pm
@@ -68,8 +68,15 @@ sub new {
$args{clownfish_params} = {
autogen_header => _autogen_header(),
include => [], # Don't use default includes.
- source => [ $CORE_SOURCE_DIR ],
- c_source => [ $XS_SOURCE_DIR ],
+ source => [ $CORE_SOURCE_DIR ],
+ modules => [
+ {
+ name => 'Clownfish',
+ parcels => [ 'Clownfish', 'TestClownfish' ],
+ make_target => 'core_objects',
+ c_source_dirs => [ $XS_SOURCE_DIR ],
+ },
+ ],
};
my $self = $class->SUPER::new( recursive_test_files => 1, %args );