New directory layout for installed Clownfish headers

The .cfh files of a parcel are installed to a separate directory:

    $prefix/$parcel/$version

The installed .cfp file is renamed to "parcel.json".

This makes it possible to parse only those .cfh files that are really
required. Also, .cfh files for different versions of a parcel can be
installed. A couple of checks for clashes between files and classes
from source and include directories become unnecessary.

For the C bindings, write headers for installed parcels to the autogen
directory first.

Enable major version checks for parcels from include directories.


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

Branch: refs/heads/master
Commit: 719095c8e27be1c235a91113732efa7c57953905
Parents: 6ab4fc6
Author: Nick Wellnhofer <[email protected]>
Authored: Fri Jul 15 20:20:54 2016 +0200
Committer: Nick Wellnhofer <[email protected]>
Committed: Fri Jul 22 14:17:26 2016 +0200

----------------------------------------------------------------------
 compiler/c/cfc.c                                |   2 +
 compiler/common/test/cfclash/bar/Bar.cfp        |   5 +-
 .../test/cfclash/class/AnimalExtension.cfp      |   5 +-
 compiler/common/test/cfclash/foo/Foo.cfh        |  25 ---
 compiler/common/test/cfclash/foo/Foo.cfp        |   4 -
 .../common/test/cfinc/Animal/v0.1.0/Animal.cfh  |  21 ++
 .../test/cfinc/Animal/v0.1.0/Animal/Dog.cfh     |  28 +++
 .../test/cfinc/Animal/v0.1.0/Animal/Util.cfh    |  23 +++
 .../common/test/cfinc/Animal/v0.1.0/parcel.json |   4 +
 compiler/common/test/cfinc/Foo/v1.0.0/Foo.cfh   |  25 +++
 .../common/test/cfinc/Foo/v1.0.0/parcel.json    |   4 +
 compiler/perl/lib/Clownfish/CFC.xs              |  17 +-
 compiler/perl/lib/Clownfish/CFC/Perl/Build.pm   |  22 +-
 compiler/perl/t/403-parcel.t                    |   7 +-
 compiler/src/CFCBindCore.c                      |  74 ++++++-
 compiler/src/CFCBindCore.h                      |   9 +
 compiler/src/CFCClass.c                         |  32 +--
 compiler/src/CFCHierarchy.c                     | 203 ++++++++++++++-----
 compiler/src/CFCParcel.c                        |  44 ----
 compiler/src/CFCParcel.h                        |  12 --
 compiler/src/CFCTestHierarchy.c                 |  66 +-----
 compiler/src/CFCTestParcel.c                    |   7 +-
 compiler/src/CFCVersion.c                       |  13 ++
 compiler/src/CFCVersion.h                       |   3 +
 devel/bin/setup_env.bat                         |   2 +-
 devel/bin/setup_env.sh                          |   2 +-
 runtime/c/install.bat                           |   5 +-
 runtime/c/install.sh                            |  19 +-
 runtime/core/Clownfish.cfp                      |   3 +-
 runtime/test/TestClownfish.cfp                  |   1 +
 30 files changed, 408 insertions(+), 279 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/c/cfc.c
----------------------------------------------------------------------
diff --git a/compiler/c/cfc.c b/compiler/c/cfc.c
index 369a0b1..d329708 100644
--- a/compiler/c/cfc.c
+++ b/compiler/c/cfc.c
@@ -248,6 +248,8 @@ main(int argc, char **argv) {
         CFCC_write_man_pages(c_binding);
     }
 
+    CFCBindCore_copy_headers(core_binding, NULL);
+
     CFCHierarchy_write_log(hierarchy);
 
     CFCBase_decref((CFCBase*)c_binding);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfclash/bar/Bar.cfp
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfclash/bar/Bar.cfp 
b/compiler/common/test/cfclash/bar/Bar.cfp
index e5868f6..e5d281e 100644
--- a/compiler/common/test/cfclash/bar/Bar.cfp
+++ b/compiler/common/test/cfclash/bar/Bar.cfp
@@ -1,4 +1,7 @@
 {
     "name": "Bar",
-    "version": "v1.0.0"
+    "version": "v1.0.0",
+    "prerequisites": {
+        "Foo": "v1.0.0"
+    }
 }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfclash/class/AnimalExtension.cfp
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfclash/class/AnimalExtension.cfp 
b/compiler/common/test/cfclash/class/AnimalExtension.cfp
index 76f31d3..8b8e75b 100644
--- a/compiler/common/test/cfclash/class/AnimalExtension.cfp
+++ b/compiler/common/test/cfclash/class/AnimalExtension.cfp
@@ -1,5 +1,8 @@
 {
     "name": "AnimalExtension",
     "nickname": "AniExt",
-    "version": "v0.1.0"
+    "version": "v0.1.0",
+    "prerequisites": {
+        "Animal": null
+    }
 }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfclash/foo/Foo.cfh
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfclash/foo/Foo.cfh 
b/compiler/common/test/cfclash/foo/Foo.cfh
deleted file mode 100644
index b770d8a..0000000
--- a/compiler/common/test/cfclash/foo/Foo.cfh
+++ /dev/null
@@ -1,25 +0,0 @@
-/* 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.
- */
-
-parcel Foo;
-
-public class Foo inherits Clownfish::Obj {
-    int var;
-
-    public void
-    Method(Foo *self);
-}
-

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfclash/foo/Foo.cfp
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfclash/foo/Foo.cfp 
b/compiler/common/test/cfclash/foo/Foo.cfp
deleted file mode 100644
index 2995169..0000000
--- a/compiler/common/test/cfclash/foo/Foo.cfp
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "name": "Foo",
-    "version": "v1.0.0"
-}

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfinc/Animal/v0.1.0/Animal.cfh
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfinc/Animal/v0.1.0/Animal.cfh 
b/compiler/common/test/cfinc/Animal/v0.1.0/Animal.cfh
new file mode 100644
index 0000000..46130b7
--- /dev/null
+++ b/compiler/common/test/cfinc/Animal/v0.1.0/Animal.cfh
@@ -0,0 +1,21 @@
+/* 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.
+ */
+
+parcel Animal;
+
+class Clownfish::Obj { }
+
+abstract class Animal { }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Dog.cfh
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Dog.cfh 
b/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Dog.cfh
new file mode 100644
index 0000000..6d54baa
--- /dev/null
+++ b/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Dog.cfh
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+parcel Animal;
+
+class Animal::Dog inherits Animal {
+    public inert incremented Dog*
+    new();
+
+    public inert Dog*
+    init(Dog *self);
+
+    public void
+    Bark(Dog *self);
+}

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Util.cfh
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Util.cfh 
b/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Util.cfh
new file mode 100644
index 0000000..f5688a5
--- /dev/null
+++ b/compiler/common/test/cfinc/Animal/v0.1.0/Animal/Util.cfh
@@ -0,0 +1,23 @@
+/* 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.
+ */
+
+parcel Animal;
+
+inert class Animal::Util {
+    inert void
+    groom(Animal *animal);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfinc/Animal/v0.1.0/parcel.json
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfinc/Animal/v0.1.0/parcel.json 
b/compiler/common/test/cfinc/Animal/v0.1.0/parcel.json
new file mode 100644
index 0000000..e2b5ab5
--- /dev/null
+++ b/compiler/common/test/cfinc/Animal/v0.1.0/parcel.json
@@ -0,0 +1,4 @@
+{
+    "name": "Animal",
+    "version": "v0.1.0"
+}

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfinc/Foo/v1.0.0/Foo.cfh
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfinc/Foo/v1.0.0/Foo.cfh 
b/compiler/common/test/cfinc/Foo/v1.0.0/Foo.cfh
new file mode 100644
index 0000000..b770d8a
--- /dev/null
+++ b/compiler/common/test/cfinc/Foo/v1.0.0/Foo.cfh
@@ -0,0 +1,25 @@
+/* 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.
+ */
+
+parcel Foo;
+
+public class Foo inherits Clownfish::Obj {
+    int var;
+
+    public void
+    Method(Foo *self);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/common/test/cfinc/Foo/v1.0.0/parcel.json
----------------------------------------------------------------------
diff --git a/compiler/common/test/cfinc/Foo/v1.0.0/parcel.json 
b/compiler/common/test/cfinc/Foo/v1.0.0/parcel.json
new file mode 100644
index 0000000..2995169
--- /dev/null
+++ b/compiler/common/test/cfinc/Foo/v1.0.0/parcel.json
@@ -0,0 +1,4 @@
+{
+    "name": "Foo",
+    "version": "v1.0.0"
+}

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/perl/lib/Clownfish/CFC.xs
----------------------------------------------------------------------
diff --git a/compiler/perl/lib/Clownfish/CFC.xs 
b/compiler/perl/lib/Clownfish/CFC.xs
index 08930e1..74bce9d 100644
--- a/compiler/perl/lib/Clownfish/CFC.xs
+++ b/compiler/perl/lib/Clownfish/CFC.xs
@@ -1142,12 +1142,6 @@ add_inherited_parcel(self, inherited)
 PPCODE:
     CFCParcel_add_inherited_parcel(self, inherited);
 
-void
-check_prereqs(self)
-    CFCParcel *self;
-PPCODE:
-    CFCParcel_check_prereqs(self);
-
 int
 has_prereq(self, parcel)
     CFCParcel *self;
@@ -1190,7 +1184,6 @@ ALIAS:
     get_version       = 12
     get_prereqs       = 14
     included          = 16
-    required          = 18
     prereq_parcels    = 20
     inherited_parcels = 22
 PPCODE:
@@ -1234,9 +1227,6 @@ PPCODE:
         case 16:
             retval = newSViv(CFCParcel_included(self));
             break;
-        case 18:
-            retval = newSViv(CFCParcel_required(self));
-            break;
         case 20: {
                 CFCParcel **parcels = CFCParcel_prereq_parcels(self);
                 retval = S_array_of_cfcbase_to_av((CFCBase**)parcels);
@@ -1887,6 +1877,13 @@ CODE:
 }
 OUTPUT: RETVAL
 
+void
+copy_headers(self, dest_dir)
+    CFCBindCore *self;
+    const char *dest_dir;
+PPCODE:
+    CFCBindCore_copy_headers(self, dest_dir);
+
 
 MODULE = Clownfish::CFC  PACKAGE = Clownfish::CFC::Binding::Core::Function
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/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 dfb9417..f1c351f 100644
--- a/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
+++ b/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
@@ -199,24 +199,6 @@ sub cf_copy_include_file {
     die( "Clownfish include file " . catfile(@path) . " not found" );
 }
 
-sub ACTION_copy_clownfish_includes {
-    my $self = shift;
-
-    # Copy .cfh files to blib/arch/Clownfish/_include
-    my $inc_dir     = catdir( $self->blib, 'arch', 'Clownfish', '_include' );
-    my $source_dirs = $self->clownfish_params('source');
-
-    for my $source_dir (@$source_dirs) {
-        my $cfh_filepaths = $self->rscan_dir( $source_dir, qr/\.cf[hp]$/ );
-
-        for my $file (@$cfh_filepaths) {
-            my $rel  = abs2rel( $file, $source_dir );
-            my $dest = catfile( $inc_dir, $rel );
-            $self->copy_if_modified( from => $file, to => $dest );
-        }
-    }
-}
-
 my %hierarchy_cache;
 
 sub _compile_clownfish {
@@ -312,6 +294,9 @@ sub ACTION_clownfish {
         print "Writing typemap...\n";
         $self->add_to_cleanup('typemap');
         $perl_binding->write_xs_typemap;
+
+        my $inc_dir = catdir( $self->blib, 'arch', 'Clownfish', '_include' );
+        $core_binding->copy_headers($inc_dir);
     }
 
     # Rewrite XS if either any .cfh files or relevant .pm files were modified.
@@ -531,7 +516,6 @@ sub ACTION_code {
     $self->depends_on(qw(
         clownfish
         compile_custom_xs
-        copy_clownfish_includes
     ));
 
     $self->SUPER::ACTION_code;

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/perl/t/403-parcel.t
----------------------------------------------------------------------
diff --git a/compiler/perl/t/403-parcel.t b/compiler/perl/t/403-parcel.t
index ada6c31..c984af8 100644
--- a/compiler/perl/t/403-parcel.t
+++ b/compiler/perl/t/403-parcel.t
@@ -17,7 +17,7 @@ use strict;
 use warnings;
 
 use Clownfish::CFC::Test::TestUtils qw( test_files_dir );
-use Test::More tests => 35;
+use Test::More tests => 32;
 use File::Spec::Functions qw( catdir );
 
 BEGIN { use_ok('Clownfish::CFC::Model::Prereq') }
@@ -182,11 +182,6 @@ Clownfish::CFC::Model::Parcel->reap_singletons();
     my $crust = Clownfish::CFC::Model::Parcel->new_from_json( json => $json );
     $crust->register;
 
-    $crust->check_prereqs;
-    ok( !$foo->required, 'parcel not required' );
-    ok( $cfish->required, 'prereq required' );
-    ok( $crust->required, 'self required' );
-
     my $prereq_parcels = $crust->prereq_parcels;
     isa_ok( $prereq_parcels, 'ARRAY', 'prereq_parcels' );
     is( scalar(@$prereq_parcels), 1, 'number of prereq_parcels' );

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindCore.c b/compiler/src/CFCBindCore.c
index 7d43415..138297a 100644
--- a/compiler/src/CFCBindCore.c
+++ b/compiler/src/CFCBindCore.c
@@ -30,6 +30,7 @@
 #include "CFCHierarchy.h"
 #include "CFCParcel.h"
 #include "CFCUtil.h"
+#include "CFCVersion.h"
 
 #define STRING(s)  #s
 #define XSTRING(s) STRING(s)
@@ -133,11 +134,9 @@ CFCBindCore_write_all_modified(CFCBindCore *self, int 
modified) {
         CFCParcel **parcels = CFCParcel_all_parcels();
         for (size_t i = 0; parcels[i]; ++i) {
             CFCParcel *parcel = parcels[i];
-            if (CFCParcel_required(parcel)) {
-                S_write_parcel_h(self, parcel);
-                if (!CFCParcel_included(parcel)) {
-                    S_write_parcel_c(self, parcel);
-                }
+            S_write_parcel_h(self, parcel);
+            if (!CFCParcel_included(parcel)) {
+                S_write_parcel_c(self, parcel);
             }
         }
     }
@@ -695,4 +694,69 @@ S_charmony_alloca_defines() {
     return defines;
 }
 
+void
+CFCBindCore_copy_headers(CFCBindCore *self, const char *dest_dir) {
+    char *default_dest = NULL;
+
+    if (dest_dir == NULL) {
+        default_dest = CFCUtil_sprintf("%s" CHY_DIR_SEP "share" CHY_DIR_SEP
+                                       "clownfish" CHY_DIR_SEP "include",
+                                       CFCHierarchy_get_dest(self->hierarchy));
+        dest_dir = default_dest;
+    }
+
+    /* Copy .cfp files. */
+    CFCParcel **parcels = CFCParcel_all_parcels();
+    for (size_t i = 0; parcels[i] != NULL; i++) {
+        CFCParcel *parcel = parcels[i];
+        if (CFCParcel_included(parcel) || !CFCParcel_is_installed(parcel)) {
+            continue;
+        }
+
+        const char *source_path = CFCParcel_get_cfp_path(parcel);
+        const char *parcel_name = CFCParcel_get_name(parcel);
+        CFCVersion *version     = CFCParcel_get_version(parcel);
+        const char *vstring     = CFCVersion_get_vstring(version);
+
+        char *dest_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s" CHY_DIR_SEP
+                                          "%s" CHY_DIR_SEP "parcel.json",
+                                          dest_dir, parcel_name, vstring);
+
+        size_t len = 0;
+        char *content = CFCUtil_slurp_text(source_path, &len);
+        CFCUtil_write_file(dest_path, content, len);
+
+        FREEMEM(content);
+        FREEMEM(dest_path);
+    }
+
+    /* Copy .cfh files. */
+    CFCFile **files = CFCHierarchy_files(self->hierarchy);
+    for (size_t i = 0; files[i] != NULL; i++) {
+        CFCFile *file = files[i];
+        if (CFCFile_included(file)) { continue; }
+        CFCParcel *parcel = CFCFile_get_parcel(file);
+        if (!CFCParcel_is_installed(parcel)) { continue; }
+
+        const char *source_path = CFCFile_get_path(file);
+        const char *parcel_name = CFCParcel_get_name(parcel);
+        CFCVersion *version     = CFCParcel_get_version(parcel);
+        const char *vstring     = CFCVersion_get_vstring(version);
+        const char *path_part   = CFCFile_get_path_part(file);
+
+        char *dest_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s" CHY_DIR_SEP
+                                          "%s" CHY_DIR_SEP "%s.cfh", dest_dir,
+                                          parcel_name, vstring, path_part);
+
+        size_t len = 0;
+        char *content = CFCUtil_slurp_text(source_path, &len);
+        CFCUtil_write_file(dest_path, content, len);
+
+        FREEMEM(content);
+        FREEMEM(dest_path);
+    }
+
+    FREEMEM(default_dest);
+}
+
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCBindCore.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindCore.h b/compiler/src/CFCBindCore.h
index 04392ef..eff3efe 100644
--- a/compiler/src/CFCBindCore.h
+++ b/compiler/src/CFCBindCore.h
@@ -57,6 +57,15 @@ CFCBindCore_destroy(CFCBindCore *self);
 int
 CFCBindCore_write_all_modified(CFCBindCore *self, int modified);
 
+/** Copy .cfh and .cfp files for installed source parcels to the autogen
+ * directory.
+ *
+ * @param dest_dir Destination directory. Defaults to
+ * `autogen/share/clownfish/include` if NULL.
+ */
+void
+CFCBindCore_copy_headers(CFCBindCore *self, const char *dest_dir);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCClass.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCClass.c b/compiler/src/CFCClass.c
index 1bcc433..7fa7ff0 100644
--- a/compiler/src/CFCClass.c
+++ b/compiler/src/CFCClass.c
@@ -295,31 +295,21 @@ CFCClass_do_create(CFCClass *self, struct CFCParcel 
*parcel,
                     name, CFCParcel_get_name(parcel));
     }
 
-    // Skip class if it's from an include dir and the parcel was already
-    // processed in another source or include dir.
-    const char *class_source_dir  = CFCClass_get_source_dir(self);
-    const char *parcel_source_dir = CFCParcel_get_source_dir(parcel);
-    if (!CFCClass_included(self)
-        || !class_source_dir
-        || !parcel_source_dir
-        || strcmp(class_source_dir, parcel_source_dir) == 0
-    ) {
-        char *error;
-
-        CFCUTIL_TRY {
-            // Store in registry.
-            S_register(self);
-        }
-        CFCUTIL_CATCH(error);
+    char *error;
 
-        if (error) {
-            CFCBase_decref((CFCBase*)self);
-            CFCUtil_rethrow(error);
-        }
+    CFCUTIL_TRY {
+        // Store in registry.
+        S_register(self);
+    }
+    CFCUTIL_CATCH(error);
 
-        CFCParcel_add_struct_sym(parcel, self->struct_sym);
+    if (error) {
+        CFCBase_decref((CFCBase*)self);
+        CFCUtil_rethrow(error);
     }
 
+    CFCParcel_add_struct_sym(parcel, self->struct_sym);
+
     return self;
 }
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCHierarchy.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCHierarchy.c b/compiler/src/CFCHierarchy.c
index 6e0d787..c33c4f8 100644
--- a/compiler/src/CFCHierarchy.c
+++ b/compiler/src/CFCHierarchy.c
@@ -38,6 +38,7 @@
 #include "CFCUtil.h"
 #include "CFCParser.h"
 #include "CFCDocument.h"
+#include "CFCVersion.h"
 
 struct CFCHierarchy {
     CFCBase base;
@@ -67,10 +68,17 @@ typedef struct CFCFindFilesContext {
 } CFCFindFilesContext;
 
 static void
-S_parse_parcel_files(const char *source_dir, int is_included);
+S_parse_source_cfp_files(const char *source_dir);
 
 static void
-S_check_prereqs(CFCHierarchy *self);
+S_find_prereqs(CFCHierarchy *self, CFCParcel *parcel);
+
+static void
+S_find_prereq(CFCHierarchy *self, CFCParcel *parent, CFCPrereq *prereq);
+
+static CFCParcel*
+S_audition_parcel(const char *version_dir, const char *vstring,
+                  CFCVersion *min_version, CFCParcel *best);
 
 static void
 S_parse_cf_files(CFCHierarchy *self, const char *source_dir, int is_included);
@@ -208,21 +216,36 @@ void
 CFCHierarchy_build(CFCHierarchy *self) {
     // Read .cfp files.
     for (size_t i = 0; self->sources[i] != NULL; i++) {
-        S_parse_parcel_files(self->sources[i], false);
-    }
-    for (size_t i = 0; self->includes[i] != NULL; i++) {
-        S_parse_parcel_files(self->includes[i], true);
+        S_parse_source_cfp_files(self->sources[i]);
     }
 
-    S_check_prereqs(self);
+    // Copy array of source parcels.
+    CFCParcel **parcels = CFCParcel_all_parcels();
+    size_t num_source_parcels = 0;
+    while (parcels[num_source_parcels] != NULL) { num_source_parcels++; }
+    size_t alloc_size = num_source_parcels * sizeof(CFCParcel*);
+    CFCParcel **source_parcels = (CFCParcel**)MALLOCATE(alloc_size);
+    memcpy(source_parcels, parcels, alloc_size);
+
+    // Find prerequisite parcels.
+    for (size_t i = 0; i < num_source_parcels; i++) {
+        S_find_prereqs(self, source_parcels[i]);
+    }
 
     // Read .cfh and .md files.
     for (size_t i = 0; self->sources[i] != NULL; i++) {
         S_parse_cf_files(self, self->sources[i], false);
         S_find_doc_files(self->sources[i]);
     }
-    for (size_t i = 0; self->includes[i] != NULL; i++) {
-        S_parse_cf_files(self, self->includes[i], true);
+
+    // Read .cfh files of included parcels.
+    parcels = CFCParcel_all_parcels();
+    for (size_t i = 0; parcels[i] != NULL; i++) {
+        CFCParcel *parcel = parcels[i];
+        if (CFCParcel_included(parcel)) {
+            const char *source_dir = CFCParcel_get_source_dir(parcel);
+            S_parse_cf_files(self, source_dir, true);
+        }
     }
 
     for (int i = 0; self->classes[i] != NULL; i++) {
@@ -233,10 +256,12 @@ CFCHierarchy_build(CFCHierarchy *self) {
     for (size_t i = 0; self->trees[i] != NULL; i++) {
         CFCClass_grow_tree(self->trees[i]);
     }
+
+    FREEMEM(source_parcels);
 }
 
 static void
-S_parse_parcel_files(const char *source_dir, int is_included) {
+S_parse_source_cfp_files(const char *source_dir) {
     CFCFindFilesContext context;
     context.ext       = ".cfp";
     context.paths     = (char**)CALLOCATE(1, sizeof(char*));
@@ -248,21 +273,14 @@ S_parse_parcel_files(const char *source_dir, int 
is_included) {
         const char *path = context.paths[i];
         char *path_part = S_extract_path_part(path, source_dir, ".cfp");
         CFCFileSpec *file_spec
-            = CFCFileSpec_new(source_dir, path_part, ".cfp", is_included);
+            = CFCFileSpec_new(source_dir, path_part, ".cfp", false);
         CFCParcel *parcel = CFCParcel_new_from_file(file_spec);
         const char *name = CFCParcel_get_name(parcel);
         CFCParcel *existing = CFCParcel_fetch(name);
         if (existing) {
-            const char *existing_source_dir
-                = CFCParcel_get_source_dir(existing);
-            CFCUTIL_NULL_CHECK(existing_source_dir);
-            // Skip parcel if it's from an include dir and was already
-            // processed in another source or include dir.
-            if (!is_included || strcmp(source_dir, existing_source_dir) == 0) {
-                CFCUtil_die("Parcel '%s' defined twice in %s and %s",
-                            CFCParcel_get_name(parcel),
-                            CFCParcel_get_cfp_path(existing), path);
-            }
+            CFCUtil_die("Parcel '%s' defined twice in %s and %s",
+                        CFCParcel_get_name(parcel),
+                        CFCParcel_get_cfp_path(existing), path);
         }
         else {
             CFCParcel_register(parcel);
@@ -276,26 +294,122 @@ S_parse_parcel_files(const char *source_dir, int 
is_included) {
 }
 
 static void
-S_check_prereqs(CFCHierarchy *self) {
-    CFCParcel **parcels = CFCParcel_all_parcels();
+S_find_prereqs(CFCHierarchy *self, CFCParcel *parcel) {
+    CFCPrereq **prereqs = CFCParcel_get_prereqs(parcel);
+
+    for (size_t i = 0; prereqs[i] != NULL; i++) {
+        S_find_prereq(self, parcel, prereqs[i]);
+    }
+}
 
+static void
+S_find_prereq(CFCHierarchy *self, CFCParcel *parent, CFCPrereq *prereq) {
+    const char *name        = CFCPrereq_get_name(prereq);
+    CFCVersion *min_version = CFCPrereq_get_version(prereq);
+
+    // Check whether prereq was processed already.
+    CFCParcel **parcels = CFCParcel_all_parcels();
     for (int i = 0; parcels[i]; ++i) {
         CFCParcel *parcel = parcels[i];
-        if (!CFCParcel_included(parcel)) {
-            CFCParcel_check_prereqs(parcel);
+        const char *other_name = CFCParcel_get_name(parcel);
+
+        if (strcmp(other_name, name) == 0) {
+            CFCVersion *other_version = CFCParcel_get_version(parcel);
+            CFCVersion *major_version = CFCParcel_get_major_version(parcel);
+
+            if (CFCVersion_compare_to(major_version, min_version) <= 0
+                && CFCVersion_compare_to(min_version, other_version) <= 0
+               ) {
+                // Compatible version found.
+                return;
+            }
+            else {
+                CFCUtil_die("Parcel %s %s required by %s not compatible with"
+                            " version %s required by %s",
+                            name, other_version, "[TODO]",
+                            CFCVersion_get_vstring(min_version),
+                            CFCParcel_get_name(parent));
+            }
         }
     }
 
-    for (int i = 0; self->prereqs[i]; ++i) {
-        const char *prereq = self->prereqs[i];
-        CFCParcel *parcel = CFCParcel_fetch(prereq);
-        if (parcel == NULL) {
-            CFCUtil_die("Prerequisite parcel '%s' not found", prereq);
+    CFCParcel *parcel = NULL;
+
+    // TODO: Decide whether to prefer higher versions from directories
+    // that come later in the list of include dirs or stop processing once
+    // a suitable version was found in a dir.
+    for (size_t i = 0; self->includes[i] != NULL; i++) {
+        char *name_dir = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s",
+                                         self->includes[i], name);
+
+        if (CFCUtil_is_dir(name_dir)) {
+            void *dirhandle = CFCUtil_opendir(name_dir);
+            const char *entry = NULL;
+
+            while (NULL != (entry = CFCUtil_dirnext(dirhandle))) {
+                if (!CFCVersion_is_vstring(entry)) { continue; }
+
+                char *version_dir = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s",
+                                                    name_dir, entry);
+
+                if (CFCUtil_is_dir(version_dir)) {
+                    parcel = S_audition_parcel(version_dir, entry, min_version,
+                                               parcel);
+                }
+
+                FREEMEM(version_dir);
+            }
+
+            CFCUtil_closedir(dirhandle, name_dir);
+        }
+
+        FREEMEM(name_dir);
+    }
+
+    if (parcel == NULL) {
+        CFCUtil_die("Parcel %s %s required by %s not found",
+                    name, CFCVersion_get_vstring(min_version),
+                    CFCParcel_get_name(parent));
+    }
+
+    CFCParcel_register(parcel);
+
+    S_find_prereqs(self, parcel);
+
+    CFCBase_decref((CFCBase*)parcel);
+}
+
+static CFCParcel*
+S_audition_parcel(const char *version_dir, const char *vstring,
+                  CFCVersion *min_version, CFCParcel *best) {
+    CFCVersion *version      = CFCVersion_new(vstring);
+    CFCVersion *best_version = best ? CFCParcel_get_version(best) : NULL;
+
+    // Version must match min_version and be greater than the previous best.
+    if (CFCVersion_compare_to(version, min_version) >= 0
+        && (best_version == NULL
+            || CFCVersion_compare_to(version, best_version) > 0)
+       ) {
+        // Parse parcel JSON for major version check.
+        CFCFileSpec *file_spec = CFCFileSpec_new(version_dir, "parcel",
+                                                 ".json", true);
+        CFCParcel *parcel = CFCParcel_new_from_file(file_spec);
+        CFCVersion *major_version = CFCParcel_get_major_version(parcel);
+
+        if (CFCVersion_compare_to(major_version, min_version) <= 0) {
+            CFCBase_decref((CFCBase*)best);
+            best = parcel;
         }
         else {
-            CFCParcel_check_prereqs(parcel);
+            CFCBase_decref((CFCBase*)parcel);
         }
+
+        CFCBase_decref((CFCBase*)file_spec);
     }
+
+    CFCBase_decref((CFCBase*)version);
+
+    return best;
 }
 
 static void
@@ -331,26 +445,17 @@ S_parse_cf_files(CFCHierarchy *self, const char 
*source_dir, int is_included) {
             CFCUtil_die("%s:%d: parser error", source_path, lineno);
         }
 
-        // Add parsed file to pool if it's from a required parcel. Skip
-        // file if it's from an include dir and the parcel was already
-        // processed in another source or include dir.
-        CFCParcel *parcel = CFCFile_get_parcel(file);
-        const char *parcel_source_dir = CFCParcel_get_source_dir(parcel);
-        CFCUTIL_NULL_CHECK(parcel_source_dir);
-        if (CFCParcel_required(parcel)
-            && (!is_included || strcmp(source_dir, parcel_source_dir) == 0)) {
-            // Make sure path_part is unique because the name of the generated
-            // C header is derived from it.
-            CFCFile *existing = S_fetch_file(self, path_part);
-            if (existing) {
-                CFCUtil_die("File %s.cfh found twice in %s and %s",
-                            path_part, CFCFile_get_source_dir(existing),
-                            source_dir);
-            }
-
-            S_add_file(self, file);
+        // Make sure path_part is unique because the name of the generated
+        // C header is derived from it.
+        CFCFile *existing = S_fetch_file(self, path_part);
+        if (existing) {
+            CFCUtil_die("File %s.cfh found twice in %s and %s",
+                        path_part, CFCFile_get_source_dir(existing),
+                        source_dir);
         }
 
+        S_add_file(self, file);
+
         CFCBase_decref((CFCBase*)file);
         CFCBase_decref((CFCBase*)file_spec);
         FREEMEM(path_part);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.c b/compiler/src/CFCParcel.c
index b7f93d5..3b79d71 100644
--- a/compiler/src/CFCParcel.c
+++ b/compiler/src/CFCParcel.c
@@ -42,7 +42,6 @@ struct CFCParcel {
     char *PREFIX;
     char *privacy_sym;
     int is_installed;
-    int is_required;
     char **inherited_parcels;
     size_t num_inherited_parcels;
     char **struct_syms;
@@ -209,7 +208,6 @@ CFCParcel_init(CFCParcel *self, const char *name, const 
char *nickname,
 
     // Initialize flags.
     self->is_installed = false;
-    self->is_required  = false;
 
     // Initialize arrays.
     self->inherited_parcels = (char**)CALLOCATE(1, sizeof(char*));
@@ -451,11 +449,6 @@ CFCParcel_included(CFCParcel *self) {
     return self->file_spec ? CFCFileSpec_included(self->file_spec) : false;
 }
 
-int
-CFCParcel_required(CFCParcel *self) {
-    return self->is_required;
-}
-
 void
 CFCParcel_add_inherited_parcel(CFCParcel *self, CFCParcel *inherited) {
     const char *name     = CFCParcel_get_name(self);
@@ -508,43 +501,6 @@ CFCParcel_prereq_parcels(CFCParcel *self) {
     return parcels;
 }
 
-void
-CFCParcel_check_prereqs(CFCParcel *self) {
-    // This is essentially a depth-first search of the dependency graph.
-    // It might be possible to skip indirect dependencies, at least if
-    // they're not part of the inheritance chain. But for now, all
-    // dependencies are marked recursively.
-
-    if (self->is_required) { return; }
-    self->is_required = true;
-
-    const char *name = CFCParcel_get_name(self);
-
-    for (int i = 0; self->prereqs[i]; ++i) {
-        CFCPrereq *prereq = self->prereqs[i];
-
-        const char *req_name   = CFCPrereq_get_name(prereq);
-        CFCParcel  *req_parcel = CFCParcel_fetch(req_name);
-        if (!req_parcel) {
-            // TODO: Add include path to error message.
-            CFCUtil_die("Parcel '%s' required by '%s' not found", req_name,
-                        name);
-        }
-
-        CFCVersion *version     = req_parcel->version;
-        CFCVersion *req_version = CFCPrereq_get_version(prereq);
-        if (CFCVersion_compare_to(version, req_version) < 0) {
-            const char *vstring     = CFCVersion_get_vstring(version);
-            const char *req_vstring = CFCVersion_get_vstring(req_version);
-            CFCUtil_die("Version %s of parcel '%s' required by '%s' is lower"
-                        " than required version %s",
-                        vstring, req_name, name, req_vstring);
-        }
-
-        CFCParcel_check_prereqs(req_parcel);
-    }
-}
-
 int
 CFCParcel_has_prereq(CFCParcel *self, CFCParcel *parcel) {
     const char *name = CFCParcel_get_name(parcel);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCParcel.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.h b/compiler/src/CFCParcel.h
index 47dc445..ddcc2bd 100644
--- a/compiler/src/CFCParcel.h
+++ b/compiler/src/CFCParcel.h
@@ -136,12 +136,6 @@ CFCParcel_get_source_dir(CFCParcel *self);
 int
 CFCParcel_included(CFCParcel *self);
 
-/** Return true if the parcel is required. This is only valid after all
- * prerequisites were checked.
- */
-int
-CFCParcel_required(CFCParcel *self);
-
 /** Add another Parcel containing superclasses that subclasses in the Parcel
  * extend.
  */
@@ -165,12 +159,6 @@ CFCParcel_get_prereqs(CFCParcel *self);
 CFCParcel**
 CFCParcel_prereq_parcels(CFCParcel *self);
 
-/** Recursively verify that all prerequisite parcels are present in the
- * required version. Mark all needed parcels including 'self' as required.
- */
-void
-CFCParcel_check_prereqs(CFCParcel *self);
-
 /** Return true if parcel equals self or is a direct prerequisite of self.
  */
 int

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCTestHierarchy.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestHierarchy.c b/compiler/src/CFCTestHierarchy.c
index 03d0df8..6fa1aae 100644
--- a/compiler/src/CFCTestHierarchy.c
+++ b/compiler/src/CFCTestHierarchy.c
@@ -55,7 +55,7 @@ S_run_clash_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_HIERARCHY = {
     "Clownfish::CFC::Model::Hierarchy",
-    47,
+    41,
     S_run_tests
 };
 
@@ -168,13 +168,14 @@ static void
 S_run_include_tests(CFCTest *test) {
     char *cfbase_path = CFCTest_path("cfbase");
     char *cfext_path  = CFCTest_path("cfext");
+    char *cfinc_path  = CFCTest_path("cfinc");
 
     {
         CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN);
         CFCHierarchy_add_source_dir(hierarchy, cfext_path);
-        CFCHierarchy_add_include_dir(hierarchy, cfbase_path);
+        CFCHierarchy_add_include_dir(hierarchy, cfinc_path);
         const char **include_dirs = CFCHierarchy_get_include_dirs(hierarchy);
-        STR_EQ(test, include_dirs[0], cfbase_path, "include_dirs[0]");
+        STR_EQ(test, include_dirs[0], cfinc_path, "include_dirs[0]");
         OK(test, include_dirs[1] == NULL, "include_dirs[1]");
 
         CFCHierarchy_build(hierarchy);
@@ -235,49 +236,21 @@ S_run_include_tests(CFCTest *test) {
         CFCParcel_reap_singletons();
     }
 
-    {
-        CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN);
-        CFCHierarchy_add_include_dir(hierarchy, cfbase_path);
-        CFCHierarchy_add_include_dir(hierarchy, cfext_path);
-        CFCHierarchy_add_prereq(hierarchy, "AnimalExtension");
-
-        CFCHierarchy_build(hierarchy);
-
-        CFCParcel *animal = CFCParcel_fetch("Animal");
-        OK(test, animal != NULL, "parcel Animal registered");
-        OK(test, CFCParcel_required(animal), "parcel Animal required");
-        CFCParcel *animal_ext = CFCParcel_fetch("AnimalExtension");
-        OK(test, animal_ext != NULL, "parcel AnimalExtension registered");
-        OK(test, CFCParcel_required(animal_ext),
-           "parcel AnimalExtension required");
-
-        CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy);
-        int num_classes = 0;
-        while (classes[num_classes]) {
-            ++num_classes;
-        }
-        INT_EQ(test, num_classes, 5, "class count");
-
-        FREEMEM(classes);
-        CFCBase_decref((CFCBase*)hierarchy);
-        CFCClass_clear_registry();
-        CFCParcel_reap_singletons();
-    }
-
     rmdir(AUTOGEN_INCLUDE);
     rmdir(AUTOGEN_SOURCE);
     rmdir(AUTOGEN);
 
     FREEMEM(cfbase_path);
     FREEMEM(cfext_path);
+    FREEMEM(cfinc_path);
 }
 
 static void
 S_run_clash_tests(CFCTest *test) {
     char *cfbase_path        = CFCTest_path("cfbase");
+    char *cfinc_path         = CFCTest_path("cfinc");
     char *cfclash_file_path  = CFCTest_path("cfclash" CHY_DIR_SEP "file");
     char *cfclash_class_path = CFCTest_path("cfclash" CHY_DIR_SEP "class");
-    char *cfclash_foo_path   = CFCTest_path("cfclash" CHY_DIR_SEP "foo");
     char *cfclash_bar_path   = CFCTest_path("cfclash" CHY_DIR_SEP "bar");
 
     if (getenv("CLOWNFISH_VALGRIND")) {
@@ -307,7 +280,7 @@ S_run_clash_tests(CFCTest *test) {
     else {
         CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN);
         CFCHierarchy_add_source_dir(hierarchy, cfclash_class_path);
-        CFCHierarchy_add_include_dir(hierarchy, cfbase_path);
+        CFCHierarchy_add_include_dir(hierarchy, cfinc_path);
         char *error;
 
         CFCUTIL_TRY {
@@ -322,38 +295,22 @@ S_run_clash_tests(CFCTest *test) {
         CFCParcel_reap_singletons();
     }
 
-    {
-        CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN);
-        CFCHierarchy_add_source_dir(hierarchy, cfbase_path);
-        CFCHierarchy_add_include_dir(hierarchy, cfclash_file_path);
-
-        CFCHierarchy_build(hierarchy);
-        CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy);
-        int count = 0;
-        while (ordered[count]) { count++; }
-        INT_EQ(test, count, 4, "source/include filename clash");
-
-        FREEMEM(ordered);
-        CFCBase_decref((CFCBase*)hierarchy);
-        CFCClass_clear_registry();
-        CFCParcel_reap_singletons();
-    }
-
     if (getenv("CLOWNFISH_VALGRIND")) {
         SKIP(test, 1, "Exceptions leak");
     }
     else {
         CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN);
         CFCHierarchy_add_source_dir(hierarchy, cfclash_bar_path);
-        CFCHierarchy_add_include_dir(hierarchy, cfclash_foo_path);
-        CFCHierarchy_add_include_dir(hierarchy, cfbase_path);
+        CFCHierarchy_add_include_dir(hierarchy, cfinc_path);
         char *error;
 
         CFCUTIL_TRY {
             CFCHierarchy_build(hierarchy);
         }
         CFCUTIL_CATCH(error);
-        OK(test, error && strstr(error, "from source dir found"),
+        const char *message =
+            "Class Baz from source dir found in parcel Foo from include dir";
+        OK(test, error && strstr(error, message),
            "source class with included parcel");
 
         CFCBase_decref((CFCBase*)hierarchy);
@@ -368,7 +325,6 @@ S_run_clash_tests(CFCTest *test) {
     FREEMEM(cfbase_path);
     FREEMEM(cfclash_file_path);
     FREEMEM(cfclash_class_path);
-    FREEMEM(cfclash_foo_path);
     FREEMEM(cfclash_bar_path);
 }
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCTestParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestParcel.c b/compiler/src/CFCTestParcel.c
index 8103351..878ab02 100644
--- a/compiler/src/CFCTestParcel.c
+++ b/compiler/src/CFCTestParcel.c
@@ -46,7 +46,7 @@ S_run_extended_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_PARCEL = {
     "Clownfish::CFC::Model::Parcel",
-    44,
+    41,
     S_run_tests
 };
 
@@ -266,11 +266,6 @@ S_run_extended_tests(CFCTest *test) {
         CFCParcel *crust = CFCParcel_new_from_json(crust_json, NULL);
         CFCParcel_register(crust);
 
-        CFCParcel_check_prereqs(crust);
-        INT_EQ(test, CFCParcel_required(foo), false, "parcel not required");
-        INT_EQ(test, CFCParcel_required(cfish), true, "prereq required");
-        INT_EQ(test, CFCParcel_required(crust), true, "self required");
-
         CFCParcel **prereq_parcels = CFCParcel_prereq_parcels(crust);
         OK(test, prereq_parcels[0] != NULL, "prereq_parcels[0]");
         const char *name = CFCParcel_get_name(prereq_parcels[0]);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCVersion.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCVersion.c b/compiler/src/CFCVersion.c
index 74d3c39..e68c5a6 100644
--- a/compiler/src/CFCVersion.c
+++ b/compiler/src/CFCVersion.c
@@ -39,6 +39,19 @@ static const CFCMeta CFCVERSION_META = {
     (CFCBase_destroy_t)CFCVersion_destroy
 };
 
+int
+CFCVersion_is_vstring(const char *vstring) {
+    if (*vstring++ != 'v') { return false; }
+
+    do {
+        if (!CFCUtil_isdigit(*vstring++)) { return false; }
+        while (CFCUtil_isdigit(*vstring)) { vstring++; }
+        if (*vstring == '\0') { return true; }
+    } while (*vstring++ == '.');
+
+    return false;
+}
+
 CFCVersion*
 CFCVersion_new(const char *vstring) {
     CFCVersion *self = (CFCVersion*)CFCBase_allocate(&CFCVERSION_META);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/compiler/src/CFCVersion.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCVersion.h b/compiler/src/CFCVersion.h
index e81a012..4b669fc 100644
--- a/compiler/src/CFCVersion.h
+++ b/compiler/src/CFCVersion.h
@@ -32,6 +32,9 @@ extern "C" {
 
 typedef struct CFCVersion CFCVersion;
 
+int
+CFCVersion_is_vstring(const char *vstring);
+
 /**
  * @param vstring - A version string consisting of a lower-case 'v' followed
  * by one or more unsigned integers separated by dots.

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/devel/bin/setup_env.bat
----------------------------------------------------------------------
diff --git a/devel/bin/setup_env.bat b/devel/bin/setup_env.bat
index 25e76ec..10e109b 100644
--- a/devel/bin/setup_env.bat
+++ b/devel/bin/setup_env.bat
@@ -35,7 +35,7 @@ call :add_to_path "%LIB%" "%runtime_dir%\c"
 set LIB=%retval%
 call :add_to_path "%LIBRARY_PATH%" "%runtime_dir%\c"
 set LIBRARY_PATH=%retval%
-call :add_to_path "%CLOWNFISH_INCLUDE%" "%runtime_dir%\core"
+call :add_to_path "%CLOWNFISH_INCLUDE%" 
"%runtime_dir%\c\autogen\share\clownfish\include"
 set CLOWNFISH_INCLUDE=%retval%
 call :add_to_path "%PERL5LIB%" "%compiler_dir%\perl\blib\arch"
 set PERL5LIB=%retval%

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/devel/bin/setup_env.sh
----------------------------------------------------------------------
diff --git a/devel/bin/setup_env.sh b/devel/bin/setup_env.sh
index f943772..367d589 100644
--- a/devel/bin/setup_env.sh
+++ b/devel/bin/setup_env.sh
@@ -68,7 +68,7 @@ runtime_dir=$base_dir/runtime
 export PATH=`add_to_path "$PATH" "$compiler_dir/c"`
 export CPATH=`add_to_path "$CPATH" "$runtime_dir/perl/xs"`
 export LIBRARY_PATH=`add_to_path "$LIBRARY_PATH" "$runtime_dir/c"`
-export CLOWNFISH_INCLUDE=`add_to_path "$CLOWNFISH_INCLUDE" "$runtime_dir/core"`
+export CLOWNFISH_INCLUDE=`add_to_path "$CLOWNFISH_INCLUDE" 
"$runtime_dir/c/autogen/share/clownfish/include"`
 export PERL5LIB=`add_to_path "$PERL5LIB" "$compiler_dir/perl/blib/arch"`
 export PERL5LIB=`add_to_path "$PERL5LIB" "$compiler_dir/perl/blib/lib"`
 export PERL5LIB=`add_to_path "$PERL5LIB" "$runtime_dir/perl/blib/arch"`

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/runtime/c/install.bat
----------------------------------------------------------------------
diff --git a/runtime/c/install.bat b/runtime/c/install.bat
index 98aa582..592a7aa 100644
--- a/runtime/c/install.bat
+++ b/runtime/c/install.bat
@@ -41,9 +41,8 @@ copy libcfish-%major_version%.dll.a "%prefix%\lib" >nul
 rem Install executables.
 copy ..\..\compiler\c\cfc.exe "%prefix%\bin" >nul
 
-rem Install Clownfish header files.
-xcopy /siy ..\core\*.cfh "%prefix%\share\clownfish\include" >nul
-xcopy /siy ..\core\*.cfp "%prefix%\share\clownfish\include" >nul
+rem Install Clownfish header files and HTML documentation.
+xcopy /siy autogen\share "%prefix%" >nul
 
 rem Install man pages.
 xcopy /siy autogen\man "%prefix%" >nul

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/runtime/c/install.sh
----------------------------------------------------------------------
diff --git a/runtime/c/install.sh b/runtime/c/install.sh
index 16953eb..237e0dd 100755
--- a/runtime/c/install.sh
+++ b/runtime/c/install.sh
@@ -115,24 +115,13 @@ esac
 mkdir -p "$prefix/bin"
 cp ../../compiler/c/cfc "$prefix/bin/cfc"
 
-# Install Clownfish header files.
-for src in `find ../core -name '*.cf[hp]'`; do
-    file=${src#../core/}
-    dest=$prefix/share/clownfish/include/$file
-    dir=`dirname "$dest"`
-    mkdir -p "$dir"
-    cp $src "$dest"
-done
+# Install Clownfish header files and HTML documentation.
+mkdir -p "$prefix/share"
+cp -R autogen/share/* "$prefix/share"
 
 # Install man pages.
 mkdir -p "$prefix/man"
-# Resolve symbolic links.
-man_dir=$(cd "$prefix/man" && pwd -P)
-if [ -n "$man_dir" ]; then
-    cp -R autogen/man "$man_dir"
-else
-    echo "Warning: Invalid directory $prefix/man"
-fi
+cp -R autogen/man/* "$prefix/man"
 
 # Create pkg-config file.
 mkdir -p "$prefix/lib/pkgconfig"

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/runtime/core/Clownfish.cfp
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish.cfp b/runtime/core/Clownfish.cfp
index 23da323..edb708f 100644
--- a/runtime/core/Clownfish.cfp
+++ b/runtime/core/Clownfish.cfp
@@ -1,5 +1,6 @@
 {
     "name": "Clownfish",
     "nickname": "Cfish",
-    "version": "v0.5.0"
+    "version": "v0.5.0",
+    "major_version": "v0.5.0"
 }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/719095c8/runtime/test/TestClownfish.cfp
----------------------------------------------------------------------
diff --git a/runtime/test/TestClownfish.cfp b/runtime/test/TestClownfish.cfp
index 6db4b4a..abae9c0 100644
--- a/runtime/test/TestClownfish.cfp
+++ b/runtime/test/TestClownfish.cfp
@@ -1,6 +1,7 @@
 {
     "name": "TestClownfish",
     "nickname": "TestCfish",
+    "installed": false,
     "version": "v0.5.0",
     "prerequisites": {
         "Clownfish": "v0.5.0"

Reply via email to