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/02/06 23:08:26 UTC

[lucy-commits] [2/4] git commit: refs/heads/c-bindings-cfc - Charmonizer module to generate Makefiles

Charmonizer module to generate Makefiles

Add various functions to create Makefiles with variables and rules. Also
implement chaz_Make_list_files which recursively finds all files in a
directory with a given extension. It executes the shell command 'find' on
POSIX systems and 'dir' on Windows.


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

Branch: refs/heads/c-bindings-cfc
Commit: f5bc24621b53014d17b6f80999f7dc31af9eb744
Parents: 19cb392
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Sun Dec 23 01:35:58 2012 +0100
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Wed Feb 6 23:03:54 2013 +0100

----------------------------------------------------------------------
 charmonizer/buildbin/meld.pl                       |    1 +
 charmonizer/src/Charmonizer/Core/Compiler.c        |   39 ++
 charmonizer/src/Charmonizer/Core/Compiler.h        |   12 +
 charmonizer/src/Charmonizer/Core/Make.c            |  400 +++++++++++++++
 charmonizer/src/Charmonizer/Core/Make.h            |   84 +++
 charmonizer/src/Charmonizer/Core/OperatingSystem.c |   73 +++-
 charmonizer/src/Charmonizer/Core/OperatingSystem.h |   29 +
 7 files changed, 634 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/f5bc2462/charmonizer/buildbin/meld.pl
----------------------------------------------------------------------
diff --git a/charmonizer/buildbin/meld.pl b/charmonizer/buildbin/meld.pl
index 7df3260..71f177d 100755
--- a/charmonizer/buildbin/meld.pl
+++ b/charmonizer/buildbin/meld.pl
@@ -73,6 +73,7 @@ my @core = qw(
     ConfWriterPerl
     ConfWriterRuby
     HeaderChecker
+    Make
     OperatingSystem
     Util
 );

http://git-wip-us.apache.org/repos/asf/lucy/blob/f5bc2462/charmonizer/src/Charmonizer/Core/Compiler.c
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/Compiler.c b/charmonizer/src/Charmonizer/Core/Compiler.c
index 485ecd7..1d3d48a 100644
--- a/charmonizer/src/Charmonizer/Core/Compiler.c
+++ b/charmonizer/src/Charmonizer/Core/Compiler.c
@@ -374,3 +374,42 @@ chaz_CC_compiler_is_msvc(void) {
     return !!chaz_CC.intval__MSC_VER;
 }
 
+const char*
+chaz_CC_link_command() {
+    if (chaz_CC.intval__MSC_VER) {
+        return "link";
+    }
+    else {
+        return chaz_CC.cc_command;
+    }
+}
+
+const char*
+chaz_CC_link_flags() {
+    return "";
+}
+
+const char*
+chaz_CC_link_shared_obj_flag() {
+    if (chaz_CC.intval__MSC_VER) {
+        return "/DLL";
+    }
+    else if (chaz_OS_is_darwin()) {
+        return "-dynamiclib ";
+    }
+    else {
+        return "-shared";
+    }
+}
+
+const char*
+chaz_CC_link_output_flag() {
+    if (chaz_CC.intval__MSC_VER) {
+        return "/OUT:";
+    }
+    else {
+        return "-o ";
+    }
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/f5bc2462/charmonizer/src/Charmonizer/Core/Compiler.h
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/Compiler.h b/charmonizer/src/Charmonizer/Core/Compiler.h
index 7f0fbda..a1291dd 100644
--- a/charmonizer/src/Charmonizer/Core/Compiler.h
+++ b/charmonizer/src/Charmonizer/Core/Compiler.h
@@ -98,6 +98,18 @@ chaz_CC_gcc_version();
 int
 chaz_CC_compiler_is_msvc(void);
 
+const char*
+chaz_CC_link_command();
+
+const char*
+chaz_CC_link_flags();
+
+const char*
+chaz_CC_link_shared_obj_flag();
+
+const char*
+chaz_CC_link_output_flag();
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy/blob/f5bc2462/charmonizer/src/Charmonizer/Core/Make.c
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/Make.c b/charmonizer/src/Charmonizer/Core/Make.c
new file mode 100644
index 0000000..267d39a
--- /dev/null
+++ b/charmonizer/src/Charmonizer/Core/Make.c
@@ -0,0 +1,400 @@
+/* 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 <string.h>
+#include "Charmonizer/Core/Make.h"
+#include "Charmonizer/Core/Compiler.h"
+#include "Charmonizer/Core/OperatingSystem.h"
+#include "Charmonizer/Core/Util.h"
+
+struct chaz_MakeVar {
+    char   *name;
+    char   *value;
+    size_t  num_elements;
+};
+
+struct chaz_MakeRule {
+    char *targets;
+    char *prereqs;
+    char *commands;
+};
+
+struct chaz_MakeFile {
+    chaz_MakeVar  **vars;
+    size_t          num_vars;
+    chaz_MakeRule **rules;
+    size_t          num_rules;
+    char          **cleanups;
+    size_t          num_cleanups;
+};
+
+chaz_MakeFile*
+chaz_MakeFile_new() {
+    chaz_MakeFile *makefile = (chaz_MakeFile*)malloc(sizeof(chaz_MakeFile));
+
+    makefile->vars = (chaz_MakeVar**)malloc(sizeof(chaz_MakeVar*));
+    makefile->vars[0] = NULL;
+    makefile->num_vars = 0;
+
+    makefile->rules = (chaz_MakeRule**)malloc(sizeof(chaz_MakeRule*));
+    makefile->rules[0] = NULL;
+    makefile->num_rules = 0;
+
+    makefile->cleanups = (char**)malloc(sizeof(char*));
+    makefile->cleanups[0] = NULL;
+    makefile->num_cleanups = 0;
+
+    return makefile;
+}
+
+chaz_MakeVar*
+chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name,
+                      const char *value) {
+    chaz_MakeVar  *var      = (chaz_MakeVar*)malloc(sizeof(chaz_MakeVar));
+    chaz_MakeVar **vars     = makefile->vars;
+    size_t         num_vars = makefile->num_vars + 1;
+
+    var->name         = chaz_Util_strdup(name);
+    var->value        = chaz_Util_strdup("");
+    var->num_elements = 0;
+
+    if (value) { chaz_MakeVar_append(var, value); }
+
+    vars = (chaz_MakeVar**)realloc(vars,
+                                   (num_vars + 1) * sizeof(chaz_MakeVar*));
+    vars[num_vars-1] = var;
+    vars[num_vars]   = NULL;
+    makefile->vars = vars;
+    makefile->num_vars = num_vars;
+
+    return var;
+}
+
+chaz_MakeRule*
+chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
+                       const char *prereq) {
+    chaz_MakeRule  *rule      = (chaz_MakeRule*)malloc(sizeof(chaz_MakeRule));
+    chaz_MakeRule **rules     = makefile->rules;
+    size_t          num_rules = makefile->num_rules + 1;
+
+    rule->targets  = NULL;
+    rule->prereqs  = NULL;
+    rule->commands = NULL;
+
+    if (target) { chaz_MakeRule_add_target(rule, target); }
+    if (prereq) { chaz_MakeRule_add_prereq(rule, prereq); }
+
+    rules = (chaz_MakeRule**)realloc(rules,
+                                     (num_rules + 1) * sizeof(chaz_MakeRule*));
+    rules[num_rules-1] = rule;
+    rules[num_rules]   = NULL;
+    makefile->rules = rules;
+    makefile->num_rules = num_rules;
+
+    return rule;
+}
+
+void
+chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target) {
+    char    *cleanup      = chaz_Util_strdup(target);
+    char   **cleanups     = makefile->cleanups;
+    size_t   num_cleanups = makefile->num_cleanups + 1;
+
+    cleanups = (char**)realloc(cleanups, (num_cleanups + 1) * sizeof(char*));
+    cleanups[num_cleanups-1] = cleanup;
+    cleanups[num_cleanups]   = NULL;
+    makefile->cleanups = cleanups;
+    makefile->num_cleanups = num_cleanups;
+}
+
+void
+chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
+                      const char *objects) {
+    const char    *pattern     = "%s %s %s %s%s";
+    const char    *link        = chaz_CC_link_command();
+    const char    *link_flags  = chaz_CC_link_flags();
+    const char    *output_flag = chaz_CC_link_output_flag();
+    chaz_MakeRule *rule;
+    char          *command;
+    size_t         size;
+
+    rule = chaz_MakeFile_add_rule(makefile, exe, objects);
+
+    size = strlen(pattern)
+           + strlen(link)
+           + strlen(link_flags)
+           + strlen(objects)
+           + strlen(output_flag)
+           + strlen(exe)
+           + 50;
+    command = (char*)malloc(size);
+    sprintf(command, pattern, link, link_flags, objects, output_flag, exe);
+    chaz_MakeRule_add_command(rule, command);
+
+    chaz_MakeFile_add_to_cleanup(makefile, exe);
+}
+
+void
+chaz_MakeFile_add_shared_obj(chaz_MakeFile *makefile, const char *shared_obj,
+                             const char *objects) {
+    const char    *pattern     = "%s %s %s %s %s%s";
+    const char    *link        = chaz_CC_link_command();
+    const char    *shobj_flags = chaz_CC_link_shared_obj_flag();
+    const char    *link_flags  = chaz_CC_link_flags();
+    const char    *output_flag = chaz_CC_link_output_flag();
+    chaz_MakeRule *rule;
+    char          *command;
+    size_t         size;
+
+    rule = chaz_MakeFile_add_rule(makefile, shared_obj, objects);
+
+    size = strlen(pattern)
+           + strlen(link)
+           + strlen(shobj_flags)
+           + strlen(link_flags)
+           + strlen(objects)
+           + strlen(output_flag)
+           + strlen(shared_obj)
+           + 50;
+    command = (char*)malloc(size);
+    sprintf(command, pattern, link, shobj_flags, link_flags, objects,
+            output_flag, shared_obj);
+    chaz_MakeRule_add_command(rule, command);
+
+    chaz_MakeFile_add_to_cleanup(makefile, shared_obj);
+}
+
+void
+chaz_MakeFile_write(chaz_MakeFile *makefile) {
+    FILE   *file;
+    size_t  i;
+
+    file = fopen("Makefile", "w");
+    if (!file) {
+        chaz_Util_die("Can't open Makefile\n");
+    }
+
+    for (i = 0; makefile->vars[i]; i++) {
+        chaz_MakeVar *var = makefile->vars[i];
+        fprintf(file, "%s = %s\n", var->name, var->value);
+    }
+    fprintf(file, "\n");
+
+    for (i = 0; makefile->rules[i]; i++) {
+        chaz_MakeRule *rule = makefile->rules[i];
+        fprintf(file, "%s :", rule->targets);
+        if (rule->prereqs) {
+            fprintf(file, " %s", rule->prereqs);
+        }
+        fprintf(file, "\n");
+        if (rule->commands) {
+            fprintf(file, "%s", rule->commands);
+        }
+        fprintf(file, "\n");
+    }
+
+    if (makefile->cleanups[0]) {
+        fprintf(file, "clean :\n\trm -f");
+        for (i = 0; makefile->cleanups[i]; i++) {
+            char *cleanup = makefile->cleanups[i];
+            fprintf(file, " \\\n\t    %s", cleanup);
+        }
+        fprintf(file, "\n\n");
+    }
+
+    fprintf(file, "distclean : clean\n");
+    fprintf(file, "\trm -f charmonizer charmony.h Makefile\n\n");
+
+    fclose(file);
+}
+
+void
+chaz_MakeVar_append(chaz_MakeVar *var, const char *element) {
+    char *value;
+
+    if (element[0] == '\0') { return; }
+
+    if (var->num_elements == 0) {
+        value = chaz_Util_strdup(element);
+    }
+    else {
+        value = (char*)malloc(strlen(var->value) + strlen(element) + 20);
+
+        if (var->num_elements == 1) {
+            sprintf(value, "\\\n    %s \\\n    %s", var->value, element);
+        }
+        else {
+            sprintf(value, "%s \\\n    %s", var->value, element);
+        }
+    }
+
+    free(var->value);
+    var->value = value;
+    var->num_elements++;
+}
+
+void
+chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target) {
+    char *targets;
+
+    if (!rule->targets) {
+        targets = chaz_Util_strdup(target);
+    }
+    else {
+        targets = (char*)malloc(strlen(rule->targets) + strlen(target) + 20);
+        sprintf(targets, "%s %s", rule->targets, target);
+        free(rule->targets);
+    }
+
+    rule->targets = targets;
+}
+
+void
+chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq) {
+    char *prereqs;
+
+    if (!rule->prereqs) {
+        prereqs = chaz_Util_strdup(prereq);
+    }
+    else {
+        prereqs = (char*)malloc(strlen(rule->prereqs) + strlen(prereq) + 20);
+        sprintf(prereqs, "%s %s", rule->prereqs, prereq);
+        free(rule->prereqs);
+    }
+
+    rule->prereqs = prereqs;
+}
+
+void
+chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command) {
+    char *commands;
+
+    if (!rule->commands) {
+        commands = (char*)malloc(strlen(command) + 20);
+        sprintf(commands, "\t%s\n", command);
+    }
+    else {
+        commands = (char*)malloc(strlen(rule->commands) + strlen(command) + 20);
+        sprintf(commands, "%s\t%s\n", rule->commands, command);
+        free(rule->commands);
+    }
+
+    rule->commands = commands;
+}
+
+void
+chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+                               const char *target) {
+    char *command;
+
+    if (!target) {
+        command = (char*)malloc(strlen(dir) + 20);
+        sprintf(command, "make -C %s", dir);
+    }
+    else {
+        command = (char*)malloc(strlen(dir) + strlen(target) + 20);
+        sprintf(command, "make -C %s %s", dir, target);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+
+    free(command);
+}
+
+void
+chaz_Make_list_files(const char *dir, const char *ext,
+                     chaz_Make_list_files_callback_t callback, void *context) {
+    int         shell_type = chaz_OS_shell_type();
+    const char *pattern;
+    char       *command;
+    char       *list;
+    char       *prefix;
+    char       *file;
+    size_t      command_size;
+    size_t      list_len;
+    size_t      prefix_len;
+
+    /* List files using shell. */
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        pattern = "find %s -name '*.%s' -type f";
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        pattern = "dir %s\\*.%s /s /b /a-d";
+    }
+    else {
+        chaz_Util_die("Unknown shell type %d", shell_type);
+    }
+
+    command_size = strlen(pattern) + strlen(dir) + strlen(ext) + 10;
+    command = (char*)malloc(command_size);
+    sprintf(command, pattern, dir, ext);
+    list = chaz_OS_run_and_capture(command, &list_len);
+    free(command);
+    if (!list) {
+        chaz_Util_die("Failed to list files in '%s'", dir);
+    }
+    list[list_len-1] = 0;
+
+    /* Find directory prefix to strip from files */
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        prefix_len = strlen(dir);
+        prefix = (char*)malloc(prefix_len + 2);
+        memcpy(prefix, dir, prefix_len);
+        prefix[prefix_len++] = '/';
+        prefix[prefix_len]   = '\0';
+    }
+    else {
+        char   *output;
+        size_t  output_len;
+
+        /* 'dir /s' returns absolute paths, so we have to find the absolute
+         * path of the directory. This is done by using the variable
+         * substitution feature of the 'for' command.
+         */
+        pattern = "for %%I in (%s) do echo %%~fI";
+        command_size = strlen(pattern) + strlen(dir) + 10;
+        command = (char*)malloc(command_size);
+        sprintf(command, pattern, dir);
+        output = chaz_OS_run_and_capture(command, &output_len);
+        free(command);
+        if (!output) { chaz_Util_die("Failed to find absolute path"); }
+
+        prefix_len = strcspn(output, "\r\n");
+        prefix = (char*)malloc(prefix_len + 2);
+        memcpy(prefix, output, prefix_len);
+        prefix[prefix_len++] = '\\';
+        prefix[prefix_len]   = '\0';
+        free(output);
+    }
+
+    /* Iterate file list and invoke callback. */
+
+    for (file = strtok(list, "\r\n"); file; file = strtok(NULL, "\r\n")) {
+        if (strlen(file) <= prefix_len
+            || memcmp(file, prefix, prefix_len) != 0
+           ) {
+            chaz_Util_die("Unexpected file name");
+        }
+
+        callback(file + prefix_len, context);
+    }
+
+    free(prefix);
+    free(list);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/f5bc2462/charmonizer/src/Charmonizer/Core/Make.h
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/Make.h b/charmonizer/src/Charmonizer/Core/Make.h
new file mode 100644
index 0000000..cfcb42a
--- /dev/null
+++ b/charmonizer/src/Charmonizer/Core/Make.h
@@ -0,0 +1,84 @@
+/* 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.
+ */
+
+/* Charmonizer/Core/Compiler.h
+ */
+
+#ifndef H_CHAZ_MAKE
+#define H_CHAZ_MAKE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct chaz_MakeFile chaz_MakeFile;
+typedef struct chaz_MakeVar chaz_MakeVar;
+typedef struct chaz_MakeRule chaz_MakeRule;
+
+typedef void (*chaz_Make_list_files_callback_t)(char *file, void *context);
+
+void
+chaz_Make_list_files(const char *dir, const char *ext,
+                     chaz_Make_list_files_callback_t callback, void *context);
+
+chaz_MakeFile*
+chaz_MakeFile_new();
+
+chaz_MakeVar*
+chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name,
+                      const char *value);
+
+chaz_MakeRule*
+chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
+                       const char *prereq);
+
+void
+chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target);
+
+void
+chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
+                      const char *objects);
+
+void
+chaz_MakeFile_add_shared_obj(chaz_MakeFile *makefile, const char *shared_obj,
+                             const char *objects);
+
+void
+chaz_MakeFile_write(chaz_MakeFile *makefile);
+
+void
+chaz_MakeVar_append(chaz_MakeVar *var, const char *element);
+
+void
+chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target);
+
+void
+chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq);
+
+void
+chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
+
+void
+chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+                               const char *target);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_CHAZ_MAKE */
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/f5bc2462/charmonizer/src/Charmonizer/Core/OperatingSystem.c
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/OperatingSystem.c b/charmonizer/src/Charmonizer/Core/OperatingSystem.c
index 2593e2a..3a9975f 100644
--- a/charmonizer/src/Charmonizer/Core/OperatingSystem.c
+++ b/charmonizer/src/Charmonizer/Core/OperatingSystem.c
@@ -17,21 +17,25 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <ctype.h>
 
 #include "Charmonizer/Core/Compiler.h"
 #include "Charmonizer/Core/Util.h"
 #include "Charmonizer/Core/ConfWriter.h"
 #include "Charmonizer/Core/OperatingSystem.h"
 
+#define CHAZ_OS_TARGET_PATH  "_charmonizer_target"
+#define CHAZ_OS_NAME_MAX     31
+
 static struct {
+    char name[CHAZ_OS_NAME_MAX+1];
     char dev_null[20];
     char exe_ext[5];
     char obj_ext[5];
+    char shared_obj_ext[7];
     char local_command_start[3];
     int  shell_type;
-} chaz_OS = { "", "", "", "", 0 };
-#define CHAZ_OS_POSIX    1
-#define CHAZ_OS_CMD_EXE  2
+} chaz_OS = { "", "", "", "", "", "", 0 };
 
 void
 chaz_OS_init(void) {
@@ -45,16 +49,43 @@ chaz_OS_init(void) {
 
     /* Detect shell based on whether the bitbucket is "/dev/null" or "nul". */
     if (chaz_Util_can_open_file("/dev/null")) {
+        char   *uname;
+        size_t  uname_len;
+        size_t i;
+
+        chaz_OS.shell_type = CHAZ_OS_POSIX;
+
+        /* Detect Unix name. */
+        uname = chaz_OS_run_and_capture("uname", &uname_len);
+        for (i = 0; i < CHAZ_OS_NAME_MAX && i < uname_len; i++) {
+            char c = uname[i];
+            if (!c || isspace(c)) { break; }
+            chaz_OS.name[i] = tolower(c);
+        }
+        if (i > 0) { chaz_OS.name[i] = '\0'; }
+        else       { strcpy(chaz_OS.name, "unknown_unix"); }
+        free(uname);
+
         strcpy(chaz_OS.dev_null, "/dev/null");
         strcpy(chaz_OS.exe_ext, "");
         strcpy(chaz_OS.obj_ext, ".o");
+        if (memcmp(chaz_OS.name, "darwin", 6) == 0) {
+            strcpy(chaz_OS.shared_obj_ext, ".dylib");
+        }
+        else if (memcmp(chaz_OS.name, "cygwin", 6) == 0) {
+            strcpy(chaz_OS.shared_obj_ext, ".dll");
+        }
+        else {
+            strcpy(chaz_OS.shared_obj_ext, ".so");
+        }
         strcpy(chaz_OS.local_command_start, "./");
-        chaz_OS.shell_type = CHAZ_OS_POSIX;
     }
     else if (chaz_Util_can_open_file("nul")) {
+        strcpy(chaz_OS.name, "windows");
         strcpy(chaz_OS.dev_null, "nul");
         strcpy(chaz_OS.exe_ext, ".exe");
         strcpy(chaz_OS.obj_ext, ".obj");
+        strcpy(chaz_OS.shared_obj_ext, ".dll");
         strcpy(chaz_OS.local_command_start, ".\\");
         chaz_OS.shell_type = CHAZ_OS_CMD_EXE;
     }
@@ -65,6 +96,21 @@ chaz_OS_init(void) {
 }
 
 const char*
+chaz_OS_name(void) {
+    return chaz_OS.name;
+}
+
+int
+chaz_OS_is_darwin(void) {
+    return memcmp(chaz_OS.name, "darwin", 6) == 0;
+}
+
+int
+chaz_OS_is_cygwin(void) {
+    return memcmp(chaz_OS.name, "cygwin", 6) == 0;
+}
+
+const char*
 chaz_OS_exe_ext(void) {
     return chaz_OS.exe_ext;
 }
@@ -75,11 +121,21 @@ chaz_OS_obj_ext(void) {
 }
 
 const char*
+chaz_OS_shared_obj_ext(void) {
+    return chaz_OS.shared_obj_ext;
+}
+
+const char*
 chaz_OS_dev_null(void) {
     return chaz_OS.dev_null;
 }
 
 int
+chaz_OS_shell_type(void) {
+    return chaz_OS.shell_type;
+}
+
+int
 chaz_OS_remove(const char *name) {
     /*
      * On Windows it can happen that another process, typically a
@@ -153,6 +209,15 @@ chaz_OS_run_redirected(const char *command, const char *path) {
     return retval;
 }
 
+char*
+chaz_OS_run_and_capture(const char *command, size_t *output_len) {
+    char *output;
+    chaz_OS_run_redirected(command, CHAZ_OS_TARGET_PATH);
+    output = chaz_Util_slurp_file(CHAZ_OS_TARGET_PATH, output_len);
+    chaz_Util_remove_and_verify(CHAZ_OS_TARGET_PATH);
+    return output;
+}
+
 void
 chaz_OS_mkdir(const char *filepath) {
     char *command = NULL;

http://git-wip-us.apache.org/repos/asf/lucy/blob/f5bc2462/charmonizer/src/Charmonizer/Core/OperatingSystem.h
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/OperatingSystem.h b/charmonizer/src/Charmonizer/Core/OperatingSystem.h
index fe936d6..490c1a0 100644
--- a/charmonizer/src/Charmonizer/Core/OperatingSystem.h
+++ b/charmonizer/src/Charmonizer/Core/OperatingSystem.h
@@ -25,6 +25,9 @@
 extern "C" {
 #endif
 
+#define CHAZ_OS_POSIX    1
+#define CHAZ_OS_CMD_EXE  2
+
 /* Safely remove a file named [name]. Needed because of Windows quirks.
  * Returns true on success, false on failure.
  */
@@ -50,6 +53,11 @@ chaz_OS_run_redirected(const char *command, const char *path);
 int
 chaz_OS_run_local_redirected(const char *command, const char *path);
 
+/* Run a command and return the output from stdout.
+ */
+char*
+chaz_OS_run_and_capture(const char *command, size_t *output_len);
+
 /* Attempt to create a directory.
  */
 void
@@ -60,6 +68,17 @@ chaz_OS_mkdir(const char *filepath);
 void
 chaz_OS_rmdir(const char *filepath);
 
+/* Return the operating system name.
+ */
+const char*
+chaz_OS_name(void);
+
+int
+chaz_OS_is_darwin(void);
+
+int
+chaz_OS_is_cygwin(void);
+
 /* Return the extension for an executable on this system.
  */
 const char*
@@ -70,11 +89,21 @@ chaz_OS_exe_ext(void);
 const char*
 chaz_OS_obj_ext(void);
 
+/* Return the extension for a shared object on this system.
+ */
+const char*
+chaz_OS_shared_obj_ext(void);
+
 /* Return the equivalent of /dev/null on this system.
  */
 const char*
 chaz_OS_dev_null(void);
 
+/* Return the shell type of this system.
+ */
+int
+chaz_OS_shell_type(void);
+
 /* Initialize the Charmonizer/Core/OperatingSystem module.
  */
 void