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 2016/07/11 11:25:43 UTC

[10/14] lucy-clownfish git commit: Separate test binaries

Separate test binaries

The C bindings build a separate shared library libcfishtest.so.
Building a static library would simplify things a little but would
require another per-parcel macro on Windows (like
CFP_STATIC_TESTCFISH).

The Perl bindings build a separate XS module Clownfish::Test.

For the Go and Python bindings, a separate static library
libtestcfish.a is built.


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

Branch: refs/heads/master
Commit: ef738c212adbed879cc75ab49675deae4f6e8b04
Parents: a80e405
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Fri Jul 8 13:57:30 2016 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Fri Jul 8 14:29:42 2016 +0200

----------------------------------------------------------------------
 runtime/c/.gitignore                            |  21 +--
 runtime/common/charmonizer.c                    | 157 ++++++++++++------
 runtime/common/charmonizer.main                 | 159 +++++++++++++------
 runtime/go/build.go                             |   3 +-
 runtime/perl/.gitignore                         |   2 +
 runtime/perl/buildlib/Clownfish/Build.pm        |   8 +-
 .../perl/buildlib/Clownfish/Build/Binding.pm    |   2 +-
 runtime/perl/lib/Clownfish/Test.pm              |   8 +
 runtime/perl/t/binding/019-obj.t                |   1 +
 runtime/perl/t/binding/023-string.t             |   1 +
 runtime/python/setup.py                         |  11 +-
 11 files changed, 253 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/c/.gitignore
----------------------------------------------------------------------
diff --git a/runtime/c/.gitignore b/runtime/c/.gitignore
index 641de1e..724f367 100644
--- a/runtime/c/.gitignore
+++ b/runtime/c/.gitignore
@@ -1,18 +1,13 @@
+*.dll
+*.dll.a
+*.dylib
+*.exe
+*.exp
+*.lib
+*.so
+*.so.*
 /Makefile
 /autogen/
-/cfish-*.dll
-/cfish-*.exp
-/cfish-*.lib
 /charmonizer
-/charmonizer.exe
 /charmony.h
-/cygcfish-*.dll
-/libcfish-*.dll
-/libcfish.*.dylib
-/libcfish.a
-/libcfish.a.*
-/libcfish.dylib
-/libcfish.so
-/libcfish.so.*
 /t/test_cfish
-/t/test_cfish.exe

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/runtime/common/charmonizer.c b/runtime/common/charmonizer.c
index af37cfd..37cfaf4 100644
--- a/runtime/common/charmonizer.c
+++ b/runtime/common/charmonizer.c
@@ -8589,7 +8589,8 @@ chaz_VariadicMacros_run(void) {
 
 typedef struct cfish_MakeFile {
     chaz_MakeFile   *makefile;
-    chaz_MakeBinary *binary;
+    chaz_MakeBinary *lib;
+    chaz_MakeBinary *test_lib;
     chaz_MakeVar    *cfh_var;
     chaz_CLI        *cli;
 
@@ -8804,7 +8805,8 @@ cfish_MakeFile_new(chaz_CLI *cli) {
     cfish_MakeFile *self = malloc(sizeof(cfish_MakeFile));
 
     self->makefile = chaz_MakeFile_new();
-    self->binary   = NULL;
+    self->lib      = NULL;
+    self->test_lib = NULL;
     self->cfh_var  = NULL;
     self->cli      = cli;
 
@@ -8851,15 +8853,12 @@ cfish_MakeFile_destroy(cfish_MakeFile *self) {
 
 static void
 cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags) {
-    static const char *const autogen_src_files[] = {
-        "cfish_parcel.c",
-        "testcfish_parcel.c",
-        NULL
-    };
-
     const char *dir_sep = chaz_OS_dir_sep();
     const char *host    = chaz_CLI_strval(self->cli, "host");
 
+    const char *lib_objs      = NULL;
+    const char *test_lib_objs = NULL;
+
     chaz_MakeVar  *var;
     chaz_MakeRule *rule;
 
@@ -8868,8 +8867,6 @@ cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags) {
     chaz_CFlags *compile_flags;
     chaz_CFlags *link_flags;
 
-    int i;
-
     printf("Creating Makefile...\n");
 
     /* Directories */
@@ -8903,77 +8900,119 @@ cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags) {
 
     chaz_CFlags_destroy(makefile_cflags);
 
-    /* Binary. */
+    /* Core library. */
 
     if (strcmp(host, "c") == 0 || strcmp(host, "perl") == 0) {
+        /* Shared library for C and Perl. */
+
         chaz_MakeFile_add_rule(self->makefile, "all", "$(CFISH_SHARED_LIB)");
 
-        self->binary
+        self->lib
             = chaz_MakeFile_add_shared_lib(self->makefile, NULL, "cfish",
                                            cfish_version, cfish_major_version);
-        chaz_MakeFile_add_rule(self->makefile, "$(CFISH_SHARED_LIB_OBJS)",
-                               self->autogen_target);
+        lib_objs = "$(CFISH_SHARED_LIB_OBJS)";
+
+        compile_flags = chaz_MakeBinary_get_compile_flags(self->lib);
+        chaz_CFlags_add_define(compile_flags, "CFP_CFISH", NULL);
+
+        link_flags = chaz_MakeBinary_get_link_flags(self->lib);
+        chaz_CFlags_enable_debugging(link_flags);
+        chaz_CFlags_append(link_flags,
+                           chaz_CFlags_get_string(extra_link_flags));
     }
     else {
+        /* Static library for Go and Python. */
+
         chaz_MakeFile_add_rule(self->makefile, "static",
-                               "$(CLOWNFISH_STATIC_LIB)");
+                               "$(CLOWNFISH_STATIC_LIB)"
+                               " $(TESTCFISH_STATIC_LIB)");
 
-        self->binary
+        self->lib
             = chaz_MakeFile_add_static_lib(self->makefile, NULL, "clownfish");
-        chaz_MakeFile_add_rule(self->makefile, "$(CLOWNFISH_STATIC_LIB_OBJS)",
-                               self->autogen_target);
+        lib_objs = "$(CLOWNFISH_STATIC_LIB_OBJS)";
     }
 
     if (self->host_src_dir) {
-        chaz_MakeBinary_add_src_dir(self->binary, self->host_src_dir);
+        chaz_MakeBinary_add_src_dir(self->lib, self->host_src_dir);
     }
-    chaz_MakeBinary_add_src_dir(self->binary, self->core_dir);
-    chaz_MakeBinary_add_src_dir(self->binary, self->test_dir);
+    chaz_MakeBinary_add_src_dir(self->lib, self->core_dir);
+    chaz_MakeBinary_add_src_file(self->lib, self->autogen_src_dir,
+                                 "cfish_parcel.c");
+
+    /* Test library. */
 
-    compile_flags = chaz_MakeBinary_get_compile_flags(self->binary);
-    chaz_CFlags_add_define(compile_flags, "CFP_CFISH", NULL);
-    chaz_CFlags_add_define(compile_flags, "CFP_TESTCFISH", NULL);
+    if (strcmp(host, "c") == 0 || strcmp(host, "perl") == 0) {
+        /* Shared library for C and Perl. */
+
+        self->test_lib
+            = chaz_MakeFile_add_shared_lib(self->makefile, NULL, "testcfish",
+                                           cfish_version, cfish_major_version);
+        test_lib_objs = "$(TESTCFISH_SHARED_LIB_OBJS)";
 
-    link_flags = chaz_MakeBinary_get_link_flags(self->binary);
-    chaz_CFlags_enable_debugging(link_flags);
-    chaz_CFlags_append(link_flags, chaz_CFlags_get_string(extra_link_flags));
+        compile_flags = chaz_MakeBinary_get_compile_flags(self->test_lib);
+        chaz_CFlags_add_define(compile_flags, "CFP_TESTCFISH", NULL);
 
-    for (i = 0; autogen_src_files[i] != NULL; ++i) {
-        chaz_MakeBinary_add_src_file(self->binary, self->autogen_src_dir,
-                                     autogen_src_files[i]);
+        link_flags = chaz_MakeBinary_get_link_flags(self->test_lib);
+        chaz_CFlags_enable_debugging(link_flags);
+        chaz_CFlags_append(link_flags,
+                           chaz_CFlags_get_string(extra_link_flags));
+        chaz_CFlags_add_shared_lib(link_flags, NULL, "cfish",
+                                   cfish_major_version);
+
+        chaz_MakeBinary_add_prereq(self->test_lib, "$(CFISH_SHARED_LIB)");
+    }
+    else {
+        /* Static library for Go and Python. */
+
+        self->test_lib
+            = chaz_MakeFile_add_static_lib(self->makefile, NULL, "testcfish");
+        test_lib_objs = "$(TESTCFISH_STATIC_LIB_OBJS)";
     }
 
+    chaz_MakeBinary_add_src_dir(self->test_lib, self->test_dir);
+    chaz_MakeBinary_add_src_file(self->test_lib, self->autogen_src_dir,
+                                 "testcfish_parcel.c");
+
     /* Additional rules. */
 
+    /* Object files depend on autogenerated headers. */
+    chaz_MakeFile_add_rule(self->makefile, lib_objs, self->autogen_target);
+    chaz_MakeFile_add_rule(self->makefile, test_lib_objs,
+                           self->autogen_target);
+
     if (strcmp(host, "c") == 0) {
         cfish_MakeFile_write_c_cfc_rules(self);
         cfish_MakeFile_write_c_test_rules(self);
     }
 
+    /* Targets to compile object files for Perl. */
     if (strcmp(host, "perl") == 0) {
-        char *core_objects = chaz_MakeBinary_obj_string(self->binary);
+        char *objects;
+
         chaz_MakeFile_add_rule(self->makefile, "core_objects",
                                "$(CFISH_SHARED_LIB_OBJS)");
-        chaz_ConfWriter_add_def("CORE_OBJECTS", core_objects);
-        free(core_objects);
-    }
+        objects = chaz_MakeBinary_obj_string(self->lib);
+        chaz_ConfWriter_add_def("CORE_OBJECTS", objects);
+        free(objects);
 
-    /* Needed for parallel builds. */
-    for (i = 0; autogen_src_files[i] != NULL; ++i) {
-        char *path = chaz_Util_join(dir_sep, self->autogen_src_dir,
-                                    autogen_src_files[i], NULL);
-        chaz_MakeFile_add_rule(self->makefile, path, self->autogen_target);
-        free(path);
+        chaz_MakeFile_add_rule(self->makefile, "test_objects",
+                               "$(TESTCFISH_SHARED_LIB_OBJS)");
+        objects = chaz_MakeBinary_obj_string(self->test_lib);
+        chaz_ConfWriter_add_def("TEST_OBJECTS", objects);
+        free(objects);
     }
 
-    rule = chaz_MakeFile_clean_rule(self->makefile);
-    chaz_MakeRule_add_recursive_rm_command(rule, "autogen");
-
     chaz_MakeFile_write(self->makefile);
 }
 
 static void
 cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
+    static const char *const autogen_src_files[] = {
+        "cfish_parcel.c",
+        "testcfish_parcel.c",
+        NULL
+    };
+
     chaz_MakeRule *rule;
 
     const char *dir_sep  = chaz_OS_dir_sep();
@@ -8983,6 +9022,8 @@ cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
     char *cfc_exe;
     char *cfc_command;
 
+    int i;
+
     cfc_dir = chaz_Util_join(dir_sep, self->base_dir, "..", "compiler", "c",
                              NULL);
     cfc_exe = chaz_Util_join("", cfc_dir, dir_sep, "cfc", exe_ext, NULL);
@@ -8995,14 +9036,24 @@ cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
     chaz_Make_list_files(self->core_dir, "cfh", S_cfh_file_callback, self);
     chaz_Make_list_files(self->test_dir, "cfh", S_cfh_file_callback, self);
 
-    rule = chaz_MakeFile_add_rule(self->makefile, self->autogen_target, cfc_exe);
+    rule = chaz_MakeFile_add_rule(self->makefile, self->autogen_target,
+                                  cfc_exe);
     chaz_MakeRule_add_prereq(rule, "$(CLOWNFISH_HEADERS)");
     cfc_command = chaz_Util_join("", cfc_exe, " --source=", self->core_dir,
                                  " --source=", self->test_dir,
                                  " --dest=autogen --header=cfc_header", NULL);
     chaz_MakeRule_add_command(rule, cfc_command);
 
+    /* Tell make how autogenerated source files are built. */
+    for (i = 0; autogen_src_files[i] != NULL; ++i) {
+        char *path = chaz_Util_join(dir_sep, self->autogen_src_dir,
+                                    autogen_src_files[i], NULL);
+        chaz_MakeFile_add_rule(self->makefile, path, self->autogen_target);
+        free(path);
+    }
+
     rule = chaz_MakeFile_clean_rule(self->makefile);
+    chaz_MakeRule_add_recursive_rm_command(rule, "autogen");
     chaz_MakeRule_add_make_command(rule, cfc_dir, "clean");
 
     rule = chaz_MakeFile_distclean_rule(self->makefile);
@@ -9016,19 +9067,25 @@ cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
 static void
 cfish_MakeFile_write_c_test_rules(cfish_MakeFile *self) {
     chaz_MakeBinary *exe;
-    chaz_CFlags     *link_cflags;
+    chaz_CFlags     *link_flags;
     chaz_MakeRule   *rule;
 
     exe = chaz_MakeFile_add_exe(self->makefile, "t", "test_cfish");
     chaz_MakeBinary_add_src_file(exe, "t", "test_cfish.c");
-    chaz_MakeFile_add_rule(self->makefile, "$(TEST_CFISH_EXE_OBJS)",
-                           self->autogen_target);
-    link_cflags = chaz_MakeBinary_get_link_flags(exe);
-    chaz_CFlags_add_shared_lib(link_cflags, NULL, "cfish",
+
+    link_flags = chaz_MakeBinary_get_link_flags(exe);
+    chaz_CFlags_add_rpath(link_flags, "\"$$PWD\"");
+    chaz_CFlags_add_shared_lib(link_flags, NULL, "testcfish",
                                cfish_major_version);
-    chaz_CFlags_add_rpath(link_cflags, "\"$$PWD\"");
+    chaz_CFlags_add_shared_lib(link_flags, NULL, "cfish",
+                               cfish_major_version);
+
+    chaz_MakeBinary_add_prereq(exe, "$(TESTCFISH_SHARED_LIB)");
     chaz_MakeBinary_add_prereq(exe, "$(CFISH_SHARED_LIB)");
 
+    chaz_MakeFile_add_rule(self->makefile, "$(TEST_CFISH_EXE_OBJS)",
+                           self->autogen_target);
+
     rule = chaz_MakeFile_add_rule(self->makefile, "test", "$(TEST_CFISH_EXE)");
     chaz_MakeRule_add_command(rule, "$(TEST_CFISH_EXE)");
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/common/charmonizer.main
----------------------------------------------------------------------
diff --git a/runtime/common/charmonizer.main b/runtime/common/charmonizer.main
index 7ceb2dd..124541c 100644
--- a/runtime/common/charmonizer.main
+++ b/runtime/common/charmonizer.main
@@ -41,7 +41,8 @@
 
 typedef struct cfish_MakeFile {
     chaz_MakeFile   *makefile;
-    chaz_MakeBinary *binary;
+    chaz_MakeBinary *lib;
+    chaz_MakeBinary *test_lib;
     chaz_MakeVar    *cfh_var;
     chaz_CLI        *cli;
 
@@ -256,7 +257,8 @@ cfish_MakeFile_new(chaz_CLI *cli) {
     cfish_MakeFile *self = malloc(sizeof(cfish_MakeFile));
 
     self->makefile = chaz_MakeFile_new();
-    self->binary   = NULL;
+    self->lib      = NULL;
+    self->test_lib = NULL;
     self->cfh_var  = NULL;
     self->cli      = cli;
 
@@ -303,15 +305,12 @@ cfish_MakeFile_destroy(cfish_MakeFile *self) {
 
 static void
 cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags) {
-    static const char *const autogen_src_files[] = {
-        "cfish_parcel.c",
-        "testcfish_parcel.c",
-        NULL
-    };
-
     const char *dir_sep = chaz_OS_dir_sep();
     const char *host    = chaz_CLI_strval(self->cli, "host");
 
+    const char *lib_objs      = NULL;
+    const char *test_lib_objs = NULL;
+
     chaz_MakeVar  *var;
     chaz_MakeRule *rule;
 
@@ -320,8 +319,6 @@ cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags) {
     chaz_CFlags *compile_flags;
     chaz_CFlags *link_flags;
 
-    int i;
-
     printf("Creating Makefile...\n");
 
     /* Directories */
@@ -355,77 +352,119 @@ cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags) {
 
     chaz_CFlags_destroy(makefile_cflags);
 
-    /* Binary. */
+    /* Core library. */
 
     if (strcmp(host, "c") == 0 || strcmp(host, "perl") == 0) {
+        /* Shared library for C and Perl. */
+
         chaz_MakeFile_add_rule(self->makefile, "all", "$(CFISH_SHARED_LIB)");
 
-        self->binary
+        self->lib
             = chaz_MakeFile_add_shared_lib(self->makefile, NULL, "cfish",
                                            cfish_version, cfish_major_version);
-        chaz_MakeFile_add_rule(self->makefile, "$(CFISH_SHARED_LIB_OBJS)",
-                               self->autogen_target);
+        lib_objs = "$(CFISH_SHARED_LIB_OBJS)";
+
+        compile_flags = chaz_MakeBinary_get_compile_flags(self->lib);
+        chaz_CFlags_add_define(compile_flags, "CFP_CFISH", NULL);
+
+        link_flags = chaz_MakeBinary_get_link_flags(self->lib);
+        chaz_CFlags_enable_debugging(link_flags);
+        chaz_CFlags_append(link_flags,
+                           chaz_CFlags_get_string(extra_link_flags));
     }
     else {
+        /* Static library for Go and Python. */
+
         chaz_MakeFile_add_rule(self->makefile, "static",
-                               "$(CLOWNFISH_STATIC_LIB)");
+                               "$(CLOWNFISH_STATIC_LIB)"
+                               " $(TESTCFISH_STATIC_LIB)");
 
-        self->binary
+        self->lib
             = chaz_MakeFile_add_static_lib(self->makefile, NULL, "clownfish");
-        chaz_MakeFile_add_rule(self->makefile, "$(CLOWNFISH_STATIC_LIB_OBJS)",
-                               self->autogen_target);
+        lib_objs = "$(CLOWNFISH_STATIC_LIB_OBJS)";
     }
 
     if (self->host_src_dir) {
-        chaz_MakeBinary_add_src_dir(self->binary, self->host_src_dir);
+        chaz_MakeBinary_add_src_dir(self->lib, self->host_src_dir);
     }
-    chaz_MakeBinary_add_src_dir(self->binary, self->core_dir);
-    chaz_MakeBinary_add_src_dir(self->binary, self->test_dir);
+    chaz_MakeBinary_add_src_dir(self->lib, self->core_dir);
+    chaz_MakeBinary_add_src_file(self->lib, self->autogen_src_dir,
+                                 "cfish_parcel.c");
 
-    compile_flags = chaz_MakeBinary_get_compile_flags(self->binary);
-    chaz_CFlags_add_define(compile_flags, "CFP_CFISH", NULL);
-    chaz_CFlags_add_define(compile_flags, "CFP_TESTCFISH", NULL);
+    /* Test library. */
 
-    link_flags = chaz_MakeBinary_get_link_flags(self->binary);
-    chaz_CFlags_enable_debugging(link_flags);
-    chaz_CFlags_append(link_flags, chaz_CFlags_get_string(extra_link_flags));
+    if (strcmp(host, "c") == 0 || strcmp(host, "perl") == 0) {
+        /* Shared library for C and Perl. */
 
-    for (i = 0; autogen_src_files[i] != NULL; ++i) {
-        chaz_MakeBinary_add_src_file(self->binary, self->autogen_src_dir,
-                                     autogen_src_files[i]);
+        self->test_lib
+            = chaz_MakeFile_add_shared_lib(self->makefile, NULL, "testcfish",
+                                           cfish_version, cfish_major_version);
+        test_lib_objs = "$(TESTCFISH_SHARED_LIB_OBJS)";
+
+        compile_flags = chaz_MakeBinary_get_compile_flags(self->test_lib);
+        chaz_CFlags_add_define(compile_flags, "CFP_TESTCFISH", NULL);
+
+        link_flags = chaz_MakeBinary_get_link_flags(self->test_lib);
+        chaz_CFlags_enable_debugging(link_flags);
+        chaz_CFlags_append(link_flags,
+                           chaz_CFlags_get_string(extra_link_flags));
+        chaz_CFlags_add_shared_lib(link_flags, NULL, "cfish",
+                                   cfish_major_version);
+
+        chaz_MakeBinary_add_prereq(self->test_lib, "$(CFISH_SHARED_LIB)");
     }
+    else {
+        /* Static library for Go and Python. */
+
+        self->test_lib
+            = chaz_MakeFile_add_static_lib(self->makefile, NULL, "testcfish");
+        test_lib_objs = "$(TESTCFISH_STATIC_LIB_OBJS)";
+    }
+
+    chaz_MakeBinary_add_src_dir(self->test_lib, self->test_dir);
+    chaz_MakeBinary_add_src_file(self->test_lib, self->autogen_src_dir,
+                                 "testcfish_parcel.c");
 
     /* Additional rules. */
 
+    /* Object files depend on autogenerated headers. */
+    chaz_MakeFile_add_rule(self->makefile, lib_objs, self->autogen_target);
+    chaz_MakeFile_add_rule(self->makefile, test_lib_objs,
+                           self->autogen_target);
+
     if (strcmp(host, "c") == 0) {
         cfish_MakeFile_write_c_cfc_rules(self);
         cfish_MakeFile_write_c_test_rules(self);
     }
 
+    /* Targets to compile object files for Perl. */
     if (strcmp(host, "perl") == 0) {
-        char *core_objects = chaz_MakeBinary_obj_string(self->binary);
+        char *objects;
+
         chaz_MakeFile_add_rule(self->makefile, "core_objects",
                                "$(CFISH_SHARED_LIB_OBJS)");
-        chaz_ConfWriter_add_def("CORE_OBJECTS", core_objects);
-        free(core_objects);
-    }
-
-    /* Needed for parallel builds. */
-    for (i = 0; autogen_src_files[i] != NULL; ++i) {
-        char *path = chaz_Util_join(dir_sep, self->autogen_src_dir,
-                                    autogen_src_files[i], NULL);
-        chaz_MakeFile_add_rule(self->makefile, path, self->autogen_target);
-        free(path);
+        objects = chaz_MakeBinary_obj_string(self->lib);
+        chaz_ConfWriter_add_def("CORE_OBJECTS", objects);
+        free(objects);
+
+        chaz_MakeFile_add_rule(self->makefile, "test_objects",
+                               "$(TESTCFISH_SHARED_LIB_OBJS)");
+        objects = chaz_MakeBinary_obj_string(self->test_lib);
+        chaz_ConfWriter_add_def("TEST_OBJECTS", objects);
+        free(objects);
     }
 
-    rule = chaz_MakeFile_clean_rule(self->makefile);
-    chaz_MakeRule_add_recursive_rm_command(rule, "autogen");
-
     chaz_MakeFile_write(self->makefile);
 }
 
 static void
 cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
+    static const char *const autogen_src_files[] = {
+        "cfish_parcel.c",
+        "testcfish_parcel.c",
+        NULL
+    };
+
     chaz_MakeRule *rule;
 
     const char *dir_sep  = chaz_OS_dir_sep();
@@ -435,6 +474,8 @@ cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
     char *cfc_exe;
     char *cfc_command;
 
+    int i;
+
     cfc_dir = chaz_Util_join(dir_sep, self->base_dir, "..", "compiler", "c",
                              NULL);
     cfc_exe = chaz_Util_join("", cfc_dir, dir_sep, "cfc", exe_ext, NULL);
@@ -447,14 +488,24 @@ cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
     chaz_Make_list_files(self->core_dir, "cfh", S_cfh_file_callback, self);
     chaz_Make_list_files(self->test_dir, "cfh", S_cfh_file_callback, self);
 
-    rule = chaz_MakeFile_add_rule(self->makefile, self->autogen_target, cfc_exe);
+    rule = chaz_MakeFile_add_rule(self->makefile, self->autogen_target,
+                                  cfc_exe);
     chaz_MakeRule_add_prereq(rule, "$(CLOWNFISH_HEADERS)");
     cfc_command = chaz_Util_join("", cfc_exe, " --source=", self->core_dir,
                                  " --source=", self->test_dir,
                                  " --dest=autogen --header=cfc_header", NULL);
     chaz_MakeRule_add_command(rule, cfc_command);
 
+    /* Tell make how autogenerated source files are built. */
+    for (i = 0; autogen_src_files[i] != NULL; ++i) {
+        char *path = chaz_Util_join(dir_sep, self->autogen_src_dir,
+                                    autogen_src_files[i], NULL);
+        chaz_MakeFile_add_rule(self->makefile, path, self->autogen_target);
+        free(path);
+    }
+
     rule = chaz_MakeFile_clean_rule(self->makefile);
+    chaz_MakeRule_add_recursive_rm_command(rule, "autogen");
     chaz_MakeRule_add_make_command(rule, cfc_dir, "clean");
 
     rule = chaz_MakeFile_distclean_rule(self->makefile);
@@ -468,19 +519,25 @@ cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) {
 static void
 cfish_MakeFile_write_c_test_rules(cfish_MakeFile *self) {
     chaz_MakeBinary *exe;
-    chaz_CFlags     *link_cflags;
+    chaz_CFlags     *link_flags;
     chaz_MakeRule   *rule;
 
     exe = chaz_MakeFile_add_exe(self->makefile, "t", "test_cfish");
     chaz_MakeBinary_add_src_file(exe, "t", "test_cfish.c");
-    chaz_MakeFile_add_rule(self->makefile, "$(TEST_CFISH_EXE_OBJS)",
-                           self->autogen_target);
-    link_cflags = chaz_MakeBinary_get_link_flags(exe);
-    chaz_CFlags_add_shared_lib(link_cflags, NULL, "cfish",
+
+    link_flags = chaz_MakeBinary_get_link_flags(exe);
+    chaz_CFlags_add_rpath(link_flags, "\"$$PWD\"");
+    chaz_CFlags_add_shared_lib(link_flags, NULL, "testcfish",
                                cfish_major_version);
-    chaz_CFlags_add_rpath(link_cflags, "\"$$PWD\"");
+    chaz_CFlags_add_shared_lib(link_flags, NULL, "cfish",
+                               cfish_major_version);
+
+    chaz_MakeBinary_add_prereq(exe, "$(TESTCFISH_SHARED_LIB)");
     chaz_MakeBinary_add_prereq(exe, "$(CFISH_SHARED_LIB)");
 
+    chaz_MakeFile_add_rule(self->makefile, "$(TEST_CFISH_EXE_OBJS)",
+                           self->autogen_target);
+
     rule = chaz_MakeFile_add_rule(self->makefile, "test", "$(TEST_CFISH_EXE)");
     chaz_MakeRule_add_command(rule, "$(TEST_CFISH_EXE)");
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/go/build.go
----------------------------------------------------------------------
diff --git a/runtime/go/build.go b/runtime/go/build.go
index c6eb9e3..46d70cc 100644
--- a/runtime/go/build.go
+++ b/runtime/go/build.go
@@ -109,7 +109,7 @@ func configure() {
 	if !current(charmonizerC, charmonizerEXE) {
 		runCommand("cc", "-o", charmonizerEXE, charmonizerC)
 	}
-	if !current(charmonizerEXE, charmonyH) {
+	if !current(charmonizerEXE, charmonyH) || !current(charmonizerEXE, "Makefile") {
 		runCommand("./charmonizer", "--cc=cc", "--enable-c", "--host=go",
 			"--enable-makefile", "--disable-threads", "--", "-std=gnu99",
 			"-O2")
@@ -265,6 +265,7 @@ func writeConfigGO() {
 			"// #cgo CFLAGS: -I%s\n"+
 			"// #cgo CFLAGS: -I%s/autogen/include\n"+
 			"// #cgo LDFLAGS: -L%s\n"+
+			"// #cgo LDFLAGS: -ltestcfish\n"+
 			"// #cgo LDFLAGS: -lclownfish\n"+
 			"import \"C\"\n",
 		buildDir, buildDir, buildDir, buildDir)

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/perl/.gitignore
----------------------------------------------------------------------
diff --git a/runtime/perl/.gitignore b/runtime/perl/.gitignore
index 4e0ff0f..7c4733f 100644
--- a/runtime/perl/.gitignore
+++ b/runtime/perl/.gitignore
@@ -14,6 +14,8 @@
 /charmony.h
 /lib/Clownfish.c
 /lib/Clownfish.xs
+/lib/Clownfish/Test.c
+/lib/Clownfish/Test.xs
 /ppport.h
 /typemap
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/perl/buildlib/Clownfish/Build.pm
----------------------------------------------------------------------
diff --git a/runtime/perl/buildlib/Clownfish/Build.pm b/runtime/perl/buildlib/Clownfish/Build.pm
index 81b5fbf..0eef5c3 100644
--- a/runtime/perl/buildlib/Clownfish/Build.pm
+++ b/runtime/perl/buildlib/Clownfish/Build.pm
@@ -77,10 +77,16 @@ sub new {
         modules => [
             {
                 name          => 'Clownfish',
-                parcels       => [ 'Clownfish', 'TestClownfish' ],
+                parcels       => [ 'Clownfish' ],
                 make_target   => 'core_objects',
                 c_source_dirs => [ $XS_SOURCE_DIR ],
             },
+            {
+                name          => 'Clownfish::Test',
+                parcels       => [ 'TestClownfish' ],
+                make_target   => 'test_objects',
+                xs_prereqs    => [ 'Clownfish' ],
+            },
         ],
     };
     my $self = $class->SUPER::new( recursive_test_files => 1, %args );

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/perl/buildlib/Clownfish/Build/Binding.pm
----------------------------------------------------------------------
diff --git a/runtime/perl/buildlib/Clownfish/Build/Binding.pm b/runtime/perl/buildlib/Clownfish/Build/Binding.pm
index 8da4d83..71b0ff8 100644
--- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm
+++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm
@@ -67,7 +67,7 @@ END_XS_CODE
 
 sub bind_test {
     my $xs_code = <<'END_XS_CODE';
-MODULE = Clownfish   PACKAGE = Clownfish::Test
+MODULE = Clownfish::Test   PACKAGE = Clownfish::Test
 
 SV*
 create_test_suite()

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/perl/lib/Clownfish/Test.pm
----------------------------------------------------------------------
diff --git a/runtime/perl/lib/Clownfish/Test.pm b/runtime/perl/lib/Clownfish/Test.pm
index e637cd3..55aeb94 100644
--- a/runtime/perl/lib/Clownfish/Test.pm
+++ b/runtime/perl/lib/Clownfish/Test.pm
@@ -18,6 +18,14 @@ use Clownfish;
 our $VERSION = '0.005000';
 $VERSION = eval $VERSION;
 
+sub dl_load_flags { 1 }
+
+BEGIN {
+    require DynaLoader;
+    our @ISA = qw( DynaLoader );
+    bootstrap Clownfish::Test '0.5.0';
+}
+
 sub run_tests {
     my $class_name = shift;
     my $formatter  = Clownfish::TestHarness::TestFormatterTAP->new();

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/perl/t/binding/019-obj.t
----------------------------------------------------------------------
diff --git a/runtime/perl/t/binding/019-obj.t b/runtime/perl/t/binding/019-obj.t
index 3d22c4e..c5eec3b 100644
--- a/runtime/perl/t/binding/019-obj.t
+++ b/runtime/perl/t/binding/019-obj.t
@@ -17,6 +17,7 @@ use strict;
 use warnings;
 
 use Test::More tests => 25;
+use Clownfish::Test;
 
 package TestObj;
 use base qw( Clownfish::Obj );

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/perl/t/binding/023-string.t
----------------------------------------------------------------------
diff --git a/runtime/perl/t/binding/023-string.t b/runtime/perl/t/binding/023-string.t
index 4f839c5..cae8476 100644
--- a/runtime/perl/t/binding/023-string.t
+++ b/runtime/perl/t/binding/023-string.t
@@ -53,6 +53,7 @@ is( $buf, $wanted, 'iter next' );
 
 {
     package MyStringCallbackTest;
+    use Clownfish::Test;
     use base qw(Clownfish::Test::StringCallbackTest);
 
     our $string_ref;

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ef738c21/runtime/python/setup.py
----------------------------------------------------------------------
diff --git a/runtime/python/setup.py b/runtime/python/setup.py
index 717ce50..8860d3b 100644
--- a/runtime/python/setup.py
+++ b/runtime/python/setup.py
@@ -58,8 +58,10 @@ CHARMONIZER_C        = os.path.join(COMMON_SOURCE_DIR, 'charmonizer.c')
 CHARMONIZER_EXE_NAME = compiler.executable_filename('charmonizer')
 CHARMONIZER_EXE_PATH = os.path.join(os.curdir, CHARMONIZER_EXE_NAME)
 CHARMONY_H_PATH      = 'charmony.h'
-LIBCLOWNFISH_NAME    = 'libclownfish.a' # TODO portability
-LIBCLOWNFISH_PATH    = os.path.abspath(os.path.join(os.curdir, LIBCLOWNFISH_NAME))
+CORELIB_NAME         = 'libclownfish.a' # TODO portability
+CORELIB_PATH         = os.path.abspath(os.path.join(os.curdir, CORELIB_NAME))
+TESTLIB_NAME         = 'libtestcfish.a' # TODO portability
+TESTLIB_PATH         = os.path.abspath(os.path.join(os.curdir, TESTLIB_NAME))
 AUTOGEN_INCLUDE      = os.path.join('autogen', 'include')
 CFC_DIR              = os.path.join(BASE_DIR, 'compiler', 'python')
 CFC_BUILD_DIR        = ext_build_dir(os.path.join(CFC_DIR))
@@ -198,7 +200,10 @@ clownfish_extension = Extension('clownfish._clownfish',
                                     CFEXT_DIR,
                                     os.curdir,
                                  ],
-                                 extra_link_args = [LIBCLOWNFISH_PATH],
+                                 extra_link_args = [
+                                    CORELIB_PATH,
+                                    TESTLIB_PATH,
+                                 ],
                                  sources = c_filepaths)
 
 setup(name = 'clownfish',