You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/05/30 22:36:23 UTC

[lucy-commits] [05/26] git commit: refs/heads/separate-clownfish-wip2 - Improve support for multiple parcels

Improve support for multiple parcels

* Generate separate parcel.h and parcel.c files for every parcel.
* Support multiple parcels in a single binary.
* Use intra-parcel dependency information for includes and
  bootstrapping.


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/32fe546c
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/32fe546c
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/32fe546c

Branch: refs/heads/separate-clownfish-wip2
Commit: 32fe546c08429a9ed7cf6f9e92d19f155186d764
Parents: cbda25e
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Tue May 21 00:50:05 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Thu May 30 22:30:17 2013 +0200

----------------------------------------------------------------------
 c/install.sh                                       |    1 +
 clownfish/compiler/perl/lib/Clownfish/CFC.pm       |    5 +-
 clownfish/compiler/perl/lib/Clownfish/CFC.xs       |    7 +-
 .../compiler/perl/lib/Clownfish/CFC/Perl/Build.pm  |    7 +-
 clownfish/compiler/src/CFCBindAliases.c            |    1 -
 clownfish/compiler/src/CFCBindClass.c              |   13 +-
 clownfish/compiler/src/CFCBindCore.c               |  226 +++++++++------
 clownfish/compiler/src/CFCParcel.c                 |   16 +
 clownfish/compiler/src/CFCParcel.h                 |    5 +
 clownfish/compiler/src/CFCPerl.c                   |   98 +++----
 clownfish/compiler/src/CFCPerl.h                   |   11 +-
 common/charmonizer.c                               |    9 +
 common/charmonizer.main                            |    9 +
 core/Clownfish.c                                   |   27 ++
 core/Lucy.c                                        |    7 -
 perl/Build.PL                                      |    2 +-
 perl/buildlib/Lucy/Build/Binding/Misc.pm           |    2 +-
 17 files changed, 265 insertions(+), 181 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/c/install.sh
----------------------------------------------------------------------
diff --git a/c/install.sh b/c/install.sh
index 7a8495e..f0c9446 100755
--- a/c/install.sh
+++ b/c/install.sh
@@ -67,6 +67,7 @@ esac
 
 mkdir -p $prefix/include
 cp autogen/include/cfish_hostdefs.h $prefix/include
+cp autogen/include/cfish_parcel.h $prefix/include
 cp autogen/include/lucy_parcel.h $prefix/include
 cp -R autogen/include/Clownfish $prefix/include
 cp -R autogen/include/Lucy $prefix/include

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/perl/lib/Clownfish/CFC.pm
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/lib/Clownfish/CFC.pm b/clownfish/compiler/perl/lib/Clownfish/CFC.pm
index 6635096..cbd28ee 100644
--- a/clownfish/compiler/perl/lib/Clownfish/CFC.pm
+++ b/clownfish/compiler/perl/lib/Clownfish/CFC.pm
@@ -698,7 +698,6 @@ BEGIN { XSLoader::load( 'Clownfish::CFC', '0.01' ) }
     use Clownfish::CFC::Util qw( verify_args a_isa_b );
 
     our %new_PARAMS = (
-        parcel     => undef,
         hierarchy  => undef,
         lib_dir    => undef,
         boot_class => undef,
@@ -709,10 +708,8 @@ BEGIN { XSLoader::load( 'Clownfish::CFC', '0.01' ) }
     sub new {
         my ( $either, %args ) = @_;
         verify_args( \%new_PARAMS, %args ) or confess $@;
-        $args{parcel}
-            = Clownfish::CFC::Model::Parcel->acquire( $args{parcel} );
         return _new(
-            @args{qw( parcel hierarchy lib_dir boot_class header footer )} );
+            @args{qw( hierarchy lib_dir boot_class header footer )} );
     }
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/perl/lib/Clownfish/CFC.xs
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/lib/Clownfish/CFC.xs b/clownfish/compiler/perl/lib/Clownfish/CFC.xs
index 6d3f4f2..308c453 100644
--- a/clownfish/compiler/perl/lib/Clownfish/CFC.xs
+++ b/clownfish/compiler/perl/lib/Clownfish/CFC.xs
@@ -1876,16 +1876,15 @@ PPCODE:
 MODULE = Clownfish   PACKAGE = Clownfish::CFC::Binding::Perl
 
 SV*
-_new(parcel, hierarchy, lib_dir, boot_class, header, footer)
-    CFCParcel *parcel;
+_new(hierarchy, lib_dir, boot_class, header, footer)
     CFCHierarchy *hierarchy;
     const char *lib_dir;
     const char *boot_class;
     const char *header;
     const char *footer;
 CODE:
-    CFCPerl *self = CFCPerl_new(parcel, hierarchy, lib_dir, boot_class,
-                                header, footer);
+    CFCPerl *self = CFCPerl_new(hierarchy, lib_dir, boot_class, header,
+                                footer);
     RETVAL = S_cfcbase_to_perlref(self);
     CFCBase_decref((CFCBase*)self);
 OUTPUT: RETVAL

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm b/clownfish/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
index b816f1c..0243aad 100644
--- a/clownfish/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
+++ b/clownfish/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
@@ -243,15 +243,10 @@ sub _compile_clownfish {
         $package_name->bind_all;
     }
 
-    my $module_name  = $self->module_name;
-    my @module_parts = split( '::', $module_name );
-    my $parcel       = $module_parts[-1];
-
     my $binding = Clownfish::CFC::Binding::Perl->new(
-        parcel     => $parcel,
         hierarchy  => $hierarchy,
         lib_dir    => $LIB_DIR,
-        boot_class => $module_name,
+        boot_class => $self->module_name,
         header     => $self->clownfish_params('autogen_header'),
         footer     => '',
     );

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/src/CFCBindAliases.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindAliases.c b/clownfish/compiler/src/CFCBindAliases.c
index 12890ad..91da364 100644
--- a/clownfish/compiler/src/CFCBindAliases.c
+++ b/clownfish/compiler/src/CFCBindAliases.c
@@ -24,7 +24,6 @@ struct alias {
 };
 
 struct alias aliases[] = {
-    {"CFISH_VISIBLE", "LUCY_VISIBLE"},
     {NULL, NULL}
 };
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/src/CFCBindClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindClass.c b/clownfish/compiler/src/CFCBindClass.c
index 9c4548a..9c15345 100644
--- a/clownfish/compiler/src/CFCBindClass.c
+++ b/clownfish/compiler/src/CFCBindClass.c
@@ -119,8 +119,7 @@ CFCBindClass_to_c_header(CFCBindClass *self) {
 
 static char*
 S_to_c_header_inert(CFCBindClass *self) {
-    //const char *prefix    = CFCClass_get_prefix(self->client);
-    const char *prefix    = "lucy_";
+    const char *prefix    = CFCClass_get_prefix(self->client);
     char *inert_func_decs = S_sub_declarations(self);
     char *inert_var_defs  = S_inert_var_declarations(self);
     char *short_names     = S_short_names(self);
@@ -156,10 +155,8 @@ static char*
 S_to_c_header_dynamic(CFCBindClass *self) {
     const char *privacy_symbol  = CFCClass_privacy_symbol(self->client);
     const char *vt_var          = CFCClass_full_vtable_var(self->client);
-    //const char *prefix          = CFCClass_get_prefix(self->client);
-    //const char *PREFIX          = CFCClass_get_PREFIX(self->client);
-    const char *prefix          = "lucy_";
-    const char *PREFIX          = "LUCY_";
+    const char *prefix          = CFCClass_get_prefix(self->client);
+    const char *PREFIX          = CFCClass_get_PREFIX(self->client);
     char *struct_def            = S_struct_definition(self);
     char *parent_include        = S_parent_include(self);
     char *sub_declarations      = S_sub_declarations(self);
@@ -168,8 +165,12 @@ S_to_c_header_dynamic(CFCBindClass *self) {
     char *method_defs           = S_method_defs(self);
     char *short_names           = S_short_names(self);
 
+    // We must include lucy_parcel.h for the Serialize/Deserialize methods.
+    // This should be removed when InStream and OutStream are moved to the
+    // Clownfish parcel or serialization is reworked.
     char pattern[] =
         "#include \"%sparcel.h\"\n"
+        "#include \"lucy_parcel.h\"\n" // For serialize/deserialize
         "\n"
         "/* Include the header for this class's parent. \n"
         " */\n"

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindCore.c b/clownfish/compiler/src/CFCBindCore.c
index ec36cab..c1f200e 100644
--- a/clownfish/compiler/src/CFCBindCore.c
+++ b/clownfish/compiler/src/CFCBindCore.c
@@ -22,7 +22,6 @@
 #define CFC_NEED_BASE_STRUCT_DEF
 #include "CFCBase.h"
 #include "CFCBindCore.h"
-#include "CFCBindAliases.h"
 #include "CFCBindClass.h"
 #include "CFCBindFile.h"
 #include "CFCClass.h"
@@ -45,12 +44,12 @@ struct CFCBindCore {
  * all classes, plus typedefs for all class structs.
  */
 static void
-S_write_parcel_h(CFCBindCore *self);
+S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel);
 
 /* Write the "parcel.c" file containing autogenerated implementation code.
  */
 static void
-S_write_parcel_c(CFCBindCore *self);
+S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel);
 
 static char*
 S_charmony_defines();
@@ -116,8 +115,13 @@ CFCBindCore_write_all_modified(CFCBindCore *self, int modified) {
     // If any class definition has changed, rewrite the parcel.h and parcel.c
     // files.
     if (modified) {
-        S_write_parcel_h(self);
-        S_write_parcel_c(self);
+        CFCParcel **parcels = CFCParcel_source_parcels();
+        for (size_t i = 0; parcels[i]; ++i) {
+            CFCParcel *parcel = parcels[i];
+            S_write_parcel_h(self, parcel);
+            S_write_parcel_c(self, parcel);
+        }
+        FREEMEM(parcels);
     }
 
     return modified;
@@ -127,69 +131,41 @@ CFCBindCore_write_all_modified(CFCBindCore *self, int modified) {
  * all classes, plus typedefs for all class structs.
  */
 static void
-S_write_parcel_h(CFCBindCore *self) {
-    CFCHierarchy *hierarchy = self->hierarchy;
-    CFCParcel    *parcel    = NULL;
+S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
+    CFCHierarchy *hierarchy   = self->hierarchy;
+    const char   *prefix      = CFCParcel_get_prefix(parcel);
+    const char   *PREFIX      = CFCParcel_get_PREFIX(parcel);
+    const char   *privacy_sym = CFCParcel_get_privacy_sym(parcel);
 
     char *charmony_defines = S_charmony_defines();
 
     // Declare object structs for all instantiable classes.
-    // Obtain parcel prefix for use in bootstrap function name.
     char *typedefs = CFCUtil_strdup("");
     CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy);
     for (int i = 0; ordered[i] != NULL; i++) {
         CFCClass *klass = ordered[i];
+        const char *class_prefix = CFCClass_get_prefix(klass);
+        if (strcmp(class_prefix, prefix) != 0) { continue; }
+
         if (!CFCClass_inert(klass)) {
             const char *full_struct = CFCClass_full_struct_sym(klass);
             typedefs = CFCUtil_cat(typedefs, "typedef struct ", full_struct,
                                    " ", full_struct, ";\n", NULL);
         }
-        if (!CFCClass_included(klass)) {
-            if (parcel && CFCClass_get_parcel(klass) != parcel) {
-                //CFCUtil_die("Multiple parcels not yet supported.");
-            }
-            parcel = CFCClass_get_parcel(klass);
-        }
     }
     FREEMEM(ordered);
 
-    if (!parcel) {
-        CFCUtil_die("No source classes found.");
-    }
-    //const char *prefix = CFCParcel_get_prefix(parcel);
-    //const char *PREFIX = CFCParcel_get_PREFIX(parcel);
-    const char *prefix = "lucy_";
-    const char *PREFIX = "LUCY_";
-
-    // Create Clownfish aliases if necessary.
-    char *aliases = CFCBindAliases_c_aliases();
-
-    const char pattern[] =
-        "%s\n"
-        "#ifndef CFCPARCEL_H\n"
-        "#define CFCPARCEL_H 1\n"
-        "\n"
-        "#ifdef __cplusplus\n"
-        "extern \"C\" {\n"
-        "#endif\n"
-        "\n"
+    // Special includes for Clownfish parcel.
+    const char *cfish_includes_pattern =
         "#include <stdarg.h>\n"
         "#include <stddef.h>\n"
         "\n"
         "%s"
         "\n"
-        "#include \"cfish_hostdefs.h\"\n"
-        "\n"
-        "#ifdef CFP_LUCY\n"
-        "  #include \"charmony.h\"\n"
-        "  #define LUCY_VISIBLE CFISH_EXPORT\n"
-        "#else\n"
-        "  #define LUCY_VISIBLE CFISH_IMPORT\n"
-        "#endif\n"
-        "\n"
-        "%s\n"
-        "%s\n"
-        "\n"
+        "#include \"cfish_hostdefs.h\"\n";
+
+    // Special definitions for Clownfish parcel.
+    const char *cfish_defs =
         "/* Generic method pointer.\n"
         " */\n"
         "typedef void\n"
@@ -269,6 +245,52 @@ S_write_parcel_h(CFCBindCore *self) {
         "  #define MethodSpec               cfish_MethodSpec\n"
         "  #define VTableSpec               cfish_VTableSpec\n"
         "#endif\n"
+        "\n";
+
+    const char *extra_defs;
+    char *extra_includes;
+    if (strcmp(prefix, "cfish_") == 0) {
+        extra_defs = cfish_defs;
+        extra_includes = CFCUtil_sprintf(cfish_includes_pattern,
+                                         charmony_defines);
+    }
+    else {
+        extra_defs = "";
+        extra_includes = CFCUtil_strdup("");
+
+        // Include parcel.h of dependent parcels.
+        CFCParcel **dep_parcels = CFCParcel_dependent_parcels(parcel);
+        for (size_t i = 0; dep_parcels[i]; ++i) {
+            const char *dep_prefix = CFCParcel_get_prefix(dep_parcels[i]);
+            extra_includes = CFCUtil_cat(extra_includes, "#include <",
+                                         dep_prefix, "parcel.h>\n", NULL);
+        }
+        FREEMEM(dep_parcels);
+    }
+
+    const char pattern[] =
+        "%s\n"
+        "#ifndef CFISH_%sPARCEL_H\n"
+        "#define CFISH_%sPARCEL_H 1\n"
+        "\n"
+        "#ifdef __cplusplus\n"
+        "extern \"C\" {\n"
+        "#endif\n"
+        "\n"
+        "%s" // Extra includes.
+        "\n"
+        "#ifdef %s\n"
+        "  #include \"charmony.h\"\n"
+        "  #define %sVISIBLE CFISH_EXPORT\n"
+        "#else\n"
+        "  #define %sVISIBLE CFISH_IMPORT\n"
+        "#endif\n"
+        "\n"
+        "%s" // Typedefs.
+        "\n"
+        "%s" // Extra definitions.
+        "%sVISIBLE void\n"
+        "%sbootstrap_inheritance();\n"
         "\n"
         "%sVISIBLE void\n"
         "%sbootstrap_parcel();\n"
@@ -280,13 +302,15 @@ S_write_parcel_h(CFCBindCore *self) {
         "}\n"
         "#endif\n"
         "\n"
-        "#endif /* CFCPARCEL_H */\n"
+        "#endif /* CFISH_%sPARCEL_H */\n"
         "\n"
         "%s\n"
         "\n";
     char *file_content
-        = CFCUtil_sprintf(pattern, self->header, charmony_defines, aliases,
-                          typedefs, PREFIX, prefix, prefix, self->footer);
+        = CFCUtil_sprintf(pattern, self->header, PREFIX, PREFIX,
+                          extra_includes, privacy_sym, PREFIX, PREFIX,
+                          typedefs, extra_defs, PREFIX, prefix, PREFIX, prefix,
+                          prefix, PREFIX, self->footer);
 
     // Unlink then write file.
     const char *inc_dest = CFCHierarchy_get_include_dest(hierarchy);
@@ -297,18 +321,17 @@ S_write_parcel_h(CFCBindCore *self) {
     FREEMEM(filepath);
 
     FREEMEM(charmony_defines);
-    FREEMEM(aliases);
     FREEMEM(typedefs);
+    FREEMEM(extra_includes);
     FREEMEM(file_content);
 }
 
 static void
-S_write_parcel_c(CFCBindCore *self) {
+S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
     CFCHierarchy *hierarchy = self->hierarchy;
-    CFCParcel    *parcel    = NULL;
+    const char   *prefix    = CFCParcel_get_prefix(parcel);
 
-    // Aggregate C code from all files.
-    // Obtain parcel prefix for use in bootstrap function name.
+    // Aggregate C code for the parcel.
     char *privacy_syms = CFCUtil_strdup("");
     char *includes     = CFCUtil_strdup("");
     char *c_data       = CFCUtil_strdup("");
@@ -318,13 +341,13 @@ S_write_parcel_c(CFCBindCore *self) {
     CFCClass **ordered  = CFCHierarchy_ordered_classes(hierarchy);
     for (int i = 0; ordered[i] != NULL; i++) {
         CFCClass *klass = ordered[i];
+        const char *class_prefix = CFCClass_get_prefix(klass);
+        if (strcmp(class_prefix, prefix) != 0) { continue; }
 
         const char *include_h = CFCClass_include_h(klass);
         includes = CFCUtil_cat(includes, "#include \"", include_h,
                                "\"\n", NULL);
 
-        if (CFCClass_included(klass)) { continue; }
-
         CFCBindClass *class_binding = CFCBindClass_new(klass);
         char *class_c_data = CFCBindClass_to_c_data(class_binding);
         c_data = CFCUtil_cat(c_data, class_c_data, "\n", NULL);
@@ -342,28 +365,51 @@ S_write_parcel_c(CFCBindCore *self) {
         const char *privacy_sym = CFCClass_privacy_symbol(klass);
         privacy_syms = CFCUtil_cat(privacy_syms, "#define ",
                                    privacy_sym, "\n", NULL);
-        if (parcel && CFCClass_get_parcel(klass) != parcel) {
-            //CFCUtil_die("Multiple parcels not yet supported.");
-        }
-        parcel = CFCClass_get_parcel(klass);
     }
     vt_specs = CFCUtil_cat(vt_specs, "\n};\n", NULL);
     FREEMEM(ordered);
 
-    if (!parcel) {
-        CFCUtil_die("No source classes found.");
+    // Bootstrapping code for dependent parcels.
+    //
+    // bootstrap_inheritance() first calls bootstrap_inheritance() for all
+    // parcels from which classes are inherited. Then the VTables of the parcel
+    // are initialized. It aborts on recursive invocation.
+    //
+    // bootstrap_parcel() first calls bootstrap_inheritance() of its own
+    // parcel. Then it calls bootstrap_parcel() for all dependent parcels.
+    // Finally, it calls init_parcel(). Recursive invocation is allowed.
+
+    char *inh_bootstrap = CFCUtil_strdup("");
+    char *dep_bootstrap = CFCUtil_strdup("");
+    CFCParcel **inh_parcels = CFCParcel_inherited_parcels(parcel);
+    for (size_t i = 0; inh_parcels[i]; ++i) {
+        const char *inh_prefix = CFCParcel_get_prefix(inh_parcels[i]);
+        inh_bootstrap = CFCUtil_cat(inh_bootstrap, "    ", inh_prefix,
+                                    "bootstrap_inheritance();\n", NULL);
     }
-    //const char *prefix = CFCParcel_get_prefix(parcel);
-    const char *prefix = "lucy_";
+    FREEMEM(inh_parcels);
+    CFCParcel **dep_parcels = CFCParcel_dependent_parcels(parcel);
+    for (size_t i = 0; dep_parcels[i]; ++i) {
+        const char *dep_prefix = CFCParcel_get_prefix(dep_parcels[i]);
+        dep_bootstrap = CFCUtil_cat(dep_bootstrap, "    ", dep_prefix,
+                                    "bootstrap_parcel();\n", NULL);
+    }
+    FREEMEM(dep_parcels);
 
     char pattern[] =
         "%s\n"
         "\n"
-        "#define C_CFISH_VTABLE\n"
+        "#define C_CFISH_VTABLE\n"          // Needed for method_ptrs offset.
+        "#include <stdio.h>\n"
+        "#include <stdlib.h>\n"
         "%s\n"
         "#include \"%sparcel.h\"\n"
         "#include \"callbacks.h\"\n"
-        "#include \"Clownfish/VTable.h\"\n"
+        "#include \"Clownfish/CharBuf.h\"\n" // Needed for dump/load.
+        "#include \"Clownfish/Err.h\"\n"     // Needed for dump/load.
+        "#include \"Clownfish/Num.h\"\n"     // Needed for dump/load.
+        "#include \"Clownfish/VArray.h\"\n"  // Needed for dump/load.
+        "#include \"Clownfish/VTable.h\"\n"  // Needed for method_ptrs offset.
         "%s\n"
         "\n"
         "%s\n"
@@ -372,20 +418,37 @@ S_write_parcel_c(CFCBindCore *self) {
         " */\n"
         "%s\n"
         "\n"
+        "static int bootstrap_state = 0;\n"
+        "\n"
         "void\n"
-        "%sbootstrap_parcel() {\n"
-        "    static bool bootstrapped = false;\n"
-        "    if (bootstrapped) { return; }\n"
+        "%sbootstrap_inheritance() {\n"
+        "    if (bootstrap_state == 1) {\n"
+        "        fprintf(stderr, \"Cycle in class inheritance between\"\n"
+        "                        \" parcels detected.\\n\");\n"
+        "        abort();\n"
+        "    }\n"
+        "    if (bootstrap_state >= 2) { return; }\n"
+        "    bootstrap_state = 1;\n"
+        "%s" // Bootstrap inherited parcels.
         "    cfish_VTable_bootstrap(vtable_specs, %d);\n"
+        "    bootstrap_state = 2;\n"
+        "}\n"
+        "\n"
+        "void\n"
+        "%sbootstrap_parcel() {\n"
+        "    if (bootstrap_state >= 3) { return; }\n"
+        "    %sbootstrap_inheritance();\n"
+        "    bootstrap_state = 3;\n"
+        "%s" // Finish bootstrapping of all dependent parcels.
         "    %sinit_parcel();\n"
-        "    bootstrapped = true;\n"
         "}\n"
         "\n"
         "%s\n";
     char *file_content
         = CFCUtil_sprintf(pattern, self->header, privacy_syms, prefix,
-                          includes, c_data, vt_specs, prefix, num_specs,
-                          prefix, self->footer);
+                          includes, c_data, vt_specs, prefix, inh_bootstrap,
+                          num_specs, prefix, prefix, dep_bootstrap, prefix,
+                          self->footer);
 
     // Unlink then open file.
     const char *src_dest = CFCHierarchy_get_source_dest(hierarchy);
@@ -399,6 +462,8 @@ S_write_parcel_c(CFCBindCore *self) {
     FREEMEM(includes);
     FREEMEM(c_data);
     FREEMEM(vt_specs);
+    FREEMEM(inh_bootstrap);
+    FREEMEM(dep_bootstrap);
     FREEMEM(file_content);
 }
 
@@ -409,7 +474,6 @@ void
 CFCBindCore_write_callbacks_h(CFCBindCore *self) {
     CFCHierarchy  *hierarchy   = self->hierarchy;
     CFCClass     **ordered     = CFCHierarchy_ordered_classes(hierarchy);
-    CFCParcel     *parcel      = NULL;
     char          *includes    = CFCUtil_strdup("");
     char          *all_cb_decs = CFCUtil_strdup("");
 
@@ -426,22 +490,11 @@ CFCBindCore_write_callbacks_h(CFCBindCore *self) {
             all_cb_decs = CFCUtil_cat(all_cb_decs, cb_decs, NULL);
             FREEMEM(cb_decs);
             CFCBase_decref((CFCBase*)class_binding);
-
-            if (parcel && CFCClass_get_parcel(klass) != parcel) {
-                //CFCUtil_die("Multiple parcels not yet supported.");
-            }
-            parcel = CFCClass_get_parcel(klass);
         }
     }
 
     FREEMEM(ordered);
 
-    if (!parcel) {
-        CFCUtil_die("No source classes found.");
-    }
-    //const char *prefix = CFCParcel_get_prefix(parcel);
-    const char *prefix = "lucy_";
-
     const char pattern[] =
         "%s\n"
         "#ifndef CFCCALLBACKS_H\n"
@@ -451,7 +504,6 @@ CFCBindCore_write_callbacks_h(CFCBindCore *self) {
         "extern \"C\" {\n"
         "#endif\n"
         "\n"
-        "#include \"%sparcel.h\"\n"
         "%s"
         "\n"
         "%s"
@@ -465,7 +517,7 @@ CFCBindCore_write_callbacks_h(CFCBindCore *self) {
         "%s\n"
         "\n";
     char *file_content
-        = CFCUtil_sprintf(pattern, self->header, prefix, includes, all_cb_decs,
+        = CFCUtil_sprintf(pattern, self->header, includes, all_cb_decs,
                           self->footer);
 
     // Unlink then write file.

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/src/CFCParcel.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParcel.c b/clownfish/compiler/src/CFCParcel.c
index de2c3bc..fe4f27a 100644
--- a/clownfish/compiler/src/CFCParcel.c
+++ b/clownfish/compiler/src/CFCParcel.c
@@ -37,6 +37,7 @@ struct CFCParcel {
     char *prefix;
     char *Prefix;
     char *PREFIX;
+    char *privacy_sym;
     int is_included;
     char **dependent_parcels;
     size_t num_dependent_parcels;
@@ -217,6 +218,15 @@ CFCParcel_init(CFCParcel *self, const char *name, const char *cnick,
     self->Prefix[prefix_len] = '\0';
     self->PREFIX[prefix_len] = '\0';
 
+    // Derive privacy symbol.
+    size_t privacy_sym_len = cnick_len + 4;
+    self->privacy_sym = (char*)MALLOCATE(privacy_sym_len + 1);
+    memcpy(self->privacy_sym, "CFP_", 4);
+    for (size_t i = 0; i < cnick_len; i++) {
+        self->privacy_sym[i+4] = toupper(self->cnick[i]);
+    }
+    self->privacy_sym[privacy_sym_len] = '\0';
+
     // Set is_included.
     self->is_included = is_included;
 
@@ -314,6 +324,7 @@ CFCParcel_destroy(CFCParcel *self) {
     FREEMEM(self->prefix);
     FREEMEM(self->Prefix);
     FREEMEM(self->PREFIX);
+    FREEMEM(self->privacy_sym);
     for (size_t i = 0; self->dependent_parcels[i]; ++i) {
         FREEMEM(self->dependent_parcels[i]);
     }
@@ -374,6 +385,11 @@ CFCParcel_get_PREFIX(CFCParcel *self) {
     return self->PREFIX;
 }
 
+const char*
+CFCParcel_get_privacy_sym(CFCParcel *self) {
+    return self->privacy_sym;
+}
+
 int
 CFCParcel_included(CFCParcel *self) {
     return self->is_included;

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/src/CFCParcel.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParcel.h b/clownfish/compiler/src/CFCParcel.h
index c269fe0..d937297 100644
--- a/clownfish/compiler/src/CFCParcel.h
+++ b/clownfish/compiler/src/CFCParcel.h
@@ -110,6 +110,11 @@ CFCParcel_get_Prefix(CFCParcel *self);
 const char*
 CFCParcel_get_PREFIX(CFCParcel *self);
 
+/* Return the Parcel's privacy symbol.
+ */
+const char*
+CFCParcel_get_privacy_sym(CFCParcel *self);
+
 /** Return true if the parcel is from an include directory.
  */
 int

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/src/CFCPerl.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCPerl.c b/clownfish/compiler/src/CFCPerl.c
index 7263632..37f8b19 100644
--- a/clownfish/compiler/src/CFCPerl.c
+++ b/clownfish/compiler/src/CFCPerl.c
@@ -36,19 +36,13 @@
 
 struct CFCPerl {
     CFCBase base;
-    CFCParcel *parcel;
     CFCHierarchy *hierarchy;
     char *lib_dir;
     char *boot_class;
     char *header;
     char *footer;
     char *xs_path;
-    char *boot_h_file;
-    char *boot_c_file;
-    char *boot_h_path;
-    char *boot_c_path;
     char *boot_func;
-    char *parcel_h_file;
 };
 
 // Modify a string in place, swapping out "::" for the supplied character.
@@ -65,24 +59,20 @@ static const CFCMeta CFCPERL_META = {
 };
 
 CFCPerl*
-CFCPerl_new(CFCParcel *parcel, CFCHierarchy *hierarchy, const char *lib_dir,
+CFCPerl_new(CFCHierarchy *hierarchy, const char *lib_dir,
             const char *boot_class, const char *header, const char *footer) {
     CFCPerl *self = (CFCPerl*)CFCBase_allocate(&CFCPERL_META);
-    return CFCPerl_init(self, parcel, hierarchy, lib_dir, boot_class, header,
-                        footer);
+    return CFCPerl_init(self, hierarchy, lib_dir, boot_class, header, footer);
 }
 
 CFCPerl*
-CFCPerl_init(CFCPerl *self, CFCParcel *parcel, CFCHierarchy *hierarchy,
-             const char *lib_dir, const char *boot_class, const char *header,
-             const char *footer) {
-    CFCUTIL_NULL_CHECK(parcel);
+CFCPerl_init(CFCPerl *self, CFCHierarchy *hierarchy, const char *lib_dir,
+             const char *boot_class, 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->parcel     = (CFCParcel*)CFCBase_incref((CFCBase*)parcel);
     self->hierarchy  = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy);
     self->lib_dir    = CFCUtil_strdup(lib_dir);
     self->boot_class = CFCUtil_strdup(boot_class);
@@ -94,47 +84,26 @@ CFCPerl_init(CFCPerl *self, CFCParcel *parcel, CFCHierarchy *hierarchy,
                                     boot_class);
     S_replace_double_colons(self->xs_path, CHY_DIR_SEP_CHAR);
 
-    // Derive the name of the files containing bootstrapping code.
-    const char *prefix   = CFCParcel_get_prefix(parcel);
-    const char *inc_dest = CFCHierarchy_get_include_dest(hierarchy);
-    const char *src_dest = CFCHierarchy_get_source_dest(hierarchy);
-    self->boot_h_file = CFCUtil_sprintf("%sboot.h", prefix);
-    self->boot_c_file = CFCUtil_sprintf("%sboot.c", prefix);
-    self->boot_h_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s", inc_dest,
-                                        self->boot_h_file);
-    self->boot_c_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s", src_dest,
-                                        self->boot_c_file);
-
     // Derive the name of the bootstrap function.
-    self->boot_func = CFCUtil_sprintf("%s%s_bootstrap", prefix, boot_class);
+    self->boot_func = CFCUtil_sprintf("cfish_%s_bootstrap", boot_class);
     for (int i = 0; self->boot_func[i] != 0; i++) {
         if (!isalnum(self->boot_func[i])) {
             self->boot_func[i] = '_';
         }
     }
 
-    // Derive the name of the "parcel.h" file.
-    //self->parcel_h_file = CFCUtil_sprintf("%sparcel.h", prefix);
-    self->parcel_h_file = CFCUtil_sprintf("%sparcel.h", "lucy_");
-
     return self;
 }
 
 void
 CFCPerl_destroy(CFCPerl *self) {
-    CFCBase_decref((CFCBase*)self->parcel);
     CFCBase_decref((CFCBase*)self->hierarchy);
     FREEMEM(self->lib_dir);
     FREEMEM(self->boot_class);
     FREEMEM(self->header);
     FREEMEM(self->footer);
     FREEMEM(self->xs_path);
-    FREEMEM(self->boot_h_file);
-    FREEMEM(self->boot_c_file);
-    FREEMEM(self->boot_h_path);
-    FREEMEM(self->boot_c_path);
     FREEMEM(self->boot_func);
-    FREEMEM(self->parcel_h_file);
     CFCBase_destroy((CFCBase*)self);
 }
 
@@ -221,7 +190,11 @@ S_write_boot_h(CFCPerl *self) {
     char *content
         = CFCUtil_sprintf(pattern, self->header, guard, guard, self->boot_func,
                           guard, self->footer);
-    CFCUtil_write_file(self->boot_h_path, content, strlen(content));
+
+    const char *inc_dest = CFCHierarchy_get_include_dest(self->hierarchy);
+    char *boot_h_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "boot.h", inc_dest);
+    CFCUtil_write_file(boot_h_path, content, strlen(content));
+    FREEMEM(boot_h_path);
 
     FREEMEM(content);
     FREEMEM(guard);
@@ -229,11 +202,18 @@ S_write_boot_h(CFCPerl *self) {
 
 static void
 S_write_boot_c(CFCPerl *self) {
-    CFCClass **ordered   = CFCHierarchy_ordered_classes(self->hierarchy);
-    char *pound_includes = CFCUtil_strdup("");
-    char *alias_adds     = CFCUtil_strdup("");
-    char *isa_pushes     = CFCUtil_strdup("");
-    const char *prefix   = CFCParcel_get_prefix(self->parcel);
+    CFCClass  **ordered   = CFCHierarchy_ordered_classes(self->hierarchy);
+    CFCParcel **parcels   = CFCParcel_source_parcels();
+    char *pound_includes  = CFCUtil_strdup("");
+    char *bootstrap_code  = CFCUtil_strdup("");
+    char *alias_adds      = CFCUtil_strdup("");
+    char *isa_pushes      = CFCUtil_strdup("");
+
+    for (size_t i = 0; parcels[i]; ++i) {
+        const char *prefix = CFCParcel_get_prefix(parcels[i]);
+        bootstrap_code = CFCUtil_cat(bootstrap_code, "    ", prefix,
+                                     "bootstrap_parcel();\n", NULL);
+    }
 
     for (size_t i = 0; ordered[i] != NULL; i++) {
         CFCClass *klass = ordered[i];
@@ -284,18 +264,18 @@ S_write_boot_c(CFCPerl *self) {
     const char pattern[] =
         "%s\n"
         "\n"
-        "#include \"%s\"\n"
+        "#include \"cfish_parcel.h\"\n"
         "#include \"EXTERN.h\"\n"
         "#include \"perl.h\"\n"
         "#include \"XSUB.h\"\n"
-        "#include \"%s\"\n"
+        "#include \"boot.h\"\n"
         "#include \"Clownfish/CharBuf.h\"\n"
         "#include \"Clownfish/VTable.h\"\n"
         "%s\n"
         "\n"
         "void\n"
         "%s() {\n"
-        "    %sbootstrap_parcel();\n"
+        "%s"
         "\n"
         "    cfish_ZombieCharBuf *alias = CFISH_ZCB_WRAP_STR(\"\", 0);\n"
         "%s"
@@ -307,15 +287,21 @@ S_write_boot_c(CFCPerl *self) {
         "%s\n"
         "\n";
     char *content
-        = CFCUtil_sprintf(pattern, self->header, self->parcel_h_file,
-                          self->boot_h_file, pound_includes, self->boot_func,
-                          prefix, alias_adds, isa_pushes, self->footer);
-    CFCUtil_write_file(self->boot_c_path, content, strlen(content));
+        = CFCUtil_sprintf(pattern, self->header, pound_includes,
+                          self->boot_func, bootstrap_code, alias_adds,
+                          isa_pushes, self->footer);
+
+    const char *src_dest = CFCHierarchy_get_source_dest(self->hierarchy);
+    char *boot_c_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "boot.c", src_dest);
+    CFCUtil_write_file(boot_c_path, content, strlen(content));
+    FREEMEM(boot_c_path);
 
     FREEMEM(content);
     FREEMEM(isa_pushes);
     FREEMEM(alias_adds);
+    FREEMEM(bootstrap_code);
     FREEMEM(pound_includes);
+    FREEMEM(parcels);
     FREEMEM(ordered);
 }
 
@@ -366,8 +352,7 @@ S_xs_file_contents(CFCPerl *self, const char *generated_xs,
         "%s"
         "\n"
         "#include \"XSBind.h\"\n"
-        "#include \"%s\"\n"
-        "#include \"%s\"\n"
+        "#include \"boot.h\"\n"
         "\n"
         "#include \"Clownfish/Util/Memory.h\"\n"
         "#include \"Clownfish/Util/StringHelper.h\"\n"
@@ -389,10 +374,9 @@ S_xs_file_contents(CFCPerl *self, const char *generated_xs,
         "\n"
         "%s";
     char *contents
-        = CFCUtil_sprintf(pattern, self->header, self->parcel_h_file,
-                          self->boot_h_file, generated_xs, self->boot_class,
-                          self->boot_class, xs_init, hand_rolled_xs,
-                          self->footer);
+        = CFCUtil_sprintf(pattern, self->header, generated_xs,
+                          self->boot_class, self->boot_class, xs_init,
+                          hand_rolled_xs, self->footer);
 
     return contents;
 }
@@ -504,7 +488,6 @@ S_write_callbacks_c(CFCPerl *self) {
         "\n"
         "#include \"XSBind.h\"\n"
         "#include \"callbacks.h\"\n"
-        "#include \"%s\"\n"
         "\n"
         "static void\n"
         "S_finish_callback_void(const char *meth_name) {\n"
@@ -577,8 +560,7 @@ S_write_callbacks_c(CFCPerl *self) {
         "    return retval;\n"
         "}\n"
         "\n";
-    char *content
-        = CFCUtil_sprintf(pattern, self->header, self->parcel_h_file);
+    char *content = CFCUtil_sprintf(pattern, self->header);
 
     for (size_t i = 0; ordered[i] != NULL; i++) {
         CFCClass *klass = ordered[i];

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/clownfish/compiler/src/CFCPerl.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCPerl.h b/clownfish/compiler/src/CFCPerl.h
index 04f0c53..eef10ac 100644
--- a/clownfish/compiler/src/CFCPerl.h
+++ b/clownfish/compiler/src/CFCPerl.h
@@ -67,14 +67,13 @@ struct CFCHierarchy;
  * typically copyright information.
  */
 CFCPerl*
-CFCPerl_new(struct CFCParcel *parcel, struct CFCHierarchy *hierarchy,
-            const char *lib_dir, const char *boot_class, const char *header,
-            const char *footer);
+CFCPerl_new(struct CFCHierarchy *hierarchy, const char *lib_dir,
+            const char *boot_class, const char *header, const char *footer);
 
 CFCPerl*
-CFCPerl_init(CFCPerl *self, struct CFCParcel *parcel,
-             struct CFCHierarchy *hierarchy, const char *lib_dir,
-             const char *boot_class, const char *header, const char *footer);
+CFCPerl_init(CFCPerl *self, struct CFCHierarchy *hierarchy,
+             const char *lib_dir, const char *boot_class, const char *header,
+             const char *footer);
 
 void
 CFCPerl_destroy(CFCPerl *self);

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/common/charmonizer.c b/common/charmonizer.c
index eda0a12..267e1a5 100644
--- a/common/charmonizer.c
+++ b/common/charmonizer.c
@@ -6832,6 +6832,7 @@ S_add_compiler_flags(struct chaz_CLIArgs *args) {
         chaz_CFlags_add_define(extra_cflags, "HAS_BOOL", NULL);
     }
 
+    chaz_CFlags_add_define(extra_cflags, "CFP_CFISH", NULL);
     chaz_CFlags_add_define(extra_cflags, "CFP_LUCY", NULL);
 }
 
@@ -6984,6 +6985,10 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     free(scratch);
 
     scratch = chaz_Util_join("", "autogen", dir_sep, "source", dir_sep,
+                             "cfish_parcel", obj_ext, NULL);
+    chaz_MakeVar_append(var, scratch);
+    free(scratch);
+    scratch = chaz_Util_join("", "autogen", dir_sep, "source", dir_sep,
                              "lucy_parcel", obj_ext, NULL);
     chaz_MakeVar_append(var, scratch);
     free(scratch);
@@ -7023,6 +7028,10 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     free(scratch);
 
     /* Needed for parallel builds. */
+    scratch = chaz_Util_join(dir_sep, "autogen", "source", "cfish_parcel.c",
+                             NULL);
+    rule = chaz_MakeFile_add_rule(makefile, scratch, "autogen");
+    free(scratch);
     scratch = chaz_Util_join(dir_sep, "autogen", "source", "lucy_parcel.c",
                              NULL);
     rule = chaz_MakeFile_add_rule(makefile, scratch, "autogen");

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/common/charmonizer.main
----------------------------------------------------------------------
diff --git a/common/charmonizer.main b/common/charmonizer.main
index 99a28c3..d7236fb 100644
--- a/common/charmonizer.main
+++ b/common/charmonizer.main
@@ -90,6 +90,7 @@ S_add_compiler_flags(struct chaz_CLIArgs *args) {
         chaz_CFlags_add_define(extra_cflags, "HAS_BOOL", NULL);
     }
 
+    chaz_CFlags_add_define(extra_cflags, "CFP_CFISH", NULL);
     chaz_CFlags_add_define(extra_cflags, "CFP_LUCY", NULL);
 }
 
@@ -242,6 +243,10 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     free(scratch);
 
     scratch = chaz_Util_join("", "autogen", dir_sep, "source", dir_sep,
+                             "cfish_parcel", obj_ext, NULL);
+    chaz_MakeVar_append(var, scratch);
+    free(scratch);
+    scratch = chaz_Util_join("", "autogen", dir_sep, "source", dir_sep,
                              "lucy_parcel", obj_ext, NULL);
     chaz_MakeVar_append(var, scratch);
     free(scratch);
@@ -281,6 +286,10 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     free(scratch);
 
     /* Needed for parallel builds. */
+    scratch = chaz_Util_join(dir_sep, "autogen", "source", "cfish_parcel.c",
+                             NULL);
+    rule = chaz_MakeFile_add_rule(makefile, scratch, "autogen");
+    free(scratch);
     scratch = chaz_Util_join(dir_sep, "autogen", "source", "lucy_parcel.c",
                              NULL);
     rule = chaz_MakeFile_add_rule(makefile, scratch, "autogen");

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/core/Clownfish.c
----------------------------------------------------------------------
diff --git a/core/Clownfish.c b/core/Clownfish.c
new file mode 100644
index 0000000..130b87a
--- /dev/null
+++ b/core/Clownfish.c
@@ -0,0 +1,27 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Clownfish/Num.h"
+#include "Clownfish/Hash.h"
+#include "Clownfish/Err.h"
+
+void
+cfish_init_parcel() {
+    cfish_Bool_init_class();
+    cfish_Hash_init_class();
+    cfish_Err_init_class();
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/core/Lucy.c
----------------------------------------------------------------------
diff --git a/core/Lucy.c b/core/Lucy.c
index ebd0c0b..4bbfad5 100644
--- a/core/Lucy.c
+++ b/core/Lucy.c
@@ -14,14 +14,7 @@
  * limitations under the License.
  */
 
-#include "Clownfish/Num.h"
-#include "Clownfish/Hash.h"
-#include "Clownfish/Err.h"
-
 void
 lucy_init_parcel() {
-    cfish_Bool_init_class();
-    cfish_Hash_init_class();
-    cfish_Err_init_class();
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/perl/Build.PL
----------------------------------------------------------------------
diff --git a/perl/Build.PL b/perl/Build.PL
index db8a3d9..ce003dc 100644
--- a/perl/Build.PL
+++ b/perl/Build.PL
@@ -68,7 +68,7 @@ my $builder = Lucy::Build->new(
             $UTF8PROC_SRC_DIR,
         ],
     },
-    extra_compiler_flags => '-DCFP_LUCY',
+    extra_compiler_flags => '-DCFP_CFISH -DCFP_LUCY',
     add_to_cleanup => [
         qw(
             Lucy-*

http://git-wip-us.apache.org/repos/asf/lucy/blob/32fe546c/perl/buildlib/Lucy/Build/Binding/Misc.pm
----------------------------------------------------------------------
diff --git a/perl/buildlib/Lucy/Build/Binding/Misc.pm b/perl/buildlib/Lucy/Build/Binding/Misc.pm
index 0e25807..c1377e0 100644
--- a/perl/buildlib/Lucy/Build/Binding/Misc.pm
+++ b/perl/buildlib/Lucy/Build/Binding/Misc.pm
@@ -32,7 +32,7 @@ sub bind_lucy {
 MODULE = Lucy    PACKAGE = Lucy
 
 BOOT:
-    lucy_Lucy_bootstrap();
+    cfish_Lucy_bootstrap();
 
 IV
 _dummy_function()