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

Reply via email to