You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2012/12/13 03:27:50 UTC

[lucy-commits] [3/12] git commit: refs/heads/chaz_compiler_flags - Regenerate charmonizer.c.

Regenerate charmonizer.c.


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

Branch: refs/heads/chaz_compiler_flags
Commit: 2dbf927c8df50353b5f46d75398994403ca6fdf3
Parents: 25c5b57
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Wed Dec 12 13:47:18 2012 -0800
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Wed Dec 12 17:09:01 2012 -0800

----------------------------------------------------------------------
 clownfish/compiler/common/charmonizer.c |  407 ++++++++++++++++-----
 clownfish/runtime/common/charmonizer.c  |  498 ++++++++++++++++++++------
 common/charmonizer.c                    |  496 ++++++++++++++++++++------
 3 files changed, 1075 insertions(+), 326 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/2dbf927c/clownfish/compiler/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/common/charmonizer.c b/clownfish/compiler/common/charmonizer.c
index 4e7ba0c..2797cdb 100644
--- a/clownfish/compiler/common/charmonizer.c
+++ b/clownfish/compiler/common/charmonizer.c
@@ -77,7 +77,7 @@ chaz_CC_capture_output(const char *source, size_t *output_len);
 /** Initialize the compiler environment.
  */
 void
-chaz_CC_init(const char *cc_command, const char *cc_flags);
+chaz_CC_init(const char *cc_command, const char *cflags);
 
 /* Clean up the environment.
  */
@@ -87,6 +87,36 @@ chaz_CC_clean_up(void);
 void
 chaz_CC_set_warnings_as_errors(const int flag);
 
+/* Concatenate onto the end of the "extra" cflags.  A space will be inserted
+ * automatically.
+ */
+void
+chaz_CC_add_extra_cflags(const char *);
+
+/* Accessor for the compiler executable's string representation.
+ */
+const char*
+chaz_CC_get_cc(void);
+
+/* Accessor for `cflags`.
+ */
+const char*
+chaz_CC_get_cflags(void);
+
+/* Accessor for `extra_cflags`.
+ */
+const char*
+chaz_CC_get_extra_cflags(void);
+
+int
+chaz_CC_gcc_version_num();
+
+const char*
+chaz_CC_gcc_version();
+
+int
+chaz_CC_compiler_is_msvc(void);
+
 #endif /* H_CHAZ_COMPILER */
 
 
@@ -433,8 +463,40 @@ chaz_Util_can_open_file(const char *file_path);
 #include <stddef.h>
 #include <stdio.h>
 
-/* Set up the Charmonizer environment.  This should be called before anything
- * else.
+#define CHAZ_PROBE_MAX_CC_LEN 100
+#define CHAZ_PROBE_MAX_CFLAGS_LEN 2000
+
+struct chaz_CLIArgs {
+    char cc[CHAZ_PROBE_MAX_CC_LEN + 1];
+    char cflags[CHAZ_PROBE_MAX_CFLAGS_LEN + 1];
+    int  charmony_h;
+    int  charmony_pm;
+    int  charmony_rb;
+    int  verbosity;
+};
+
+/* Parse command line arguments, initializing and filling in the supplied
+ * `args` struct.
+ *
+ *     APP_NAME --cc=CC_COMMAND
+ *              [--enable-c]
+ *              [--enable-perl]
+ *              [--enable-ruby]
+ *              [-- [CFLAGS]]
+ *
+ * @return true if argument parsing proceeds without incident, false if
+ * unexpected arguments are encountered or values are missing or invalid.
+ */
+int
+chaz_Probe_parse_cli_args(int argc, const char *argv[],
+                          struct chaz_CLIArgs *args);
+
+/* Exit after printing usage instructions to stderr.
+ */
+void
+chaz_Probe_die_usage(void);
+
+/* Set up the Charmonizer environment.
  *
  * If the environment variable CHARM_VERBOSITY has been set, it will be
  * processed at this time:
@@ -442,12 +504,9 @@ chaz_Util_can_open_file(const char *file_path);
  *      0 - silent
  *      1 - normal
  *      2 - debugging
- *
- * @param cc_command the string used to invoke the C compiler via system()
- * @param cc_flags flags which will be passed on to the C compiler
  */
 void
-chaz_Probe_init(const char *cc_command, const char *cc_flags);
+chaz_Probe_init(struct chaz_CLIArgs *args);
 
 /* Clean up the Charmonizer environment -- deleting tempfiles, etc.  This
  * should be called only after everything else finishes.
@@ -455,6 +514,23 @@ chaz_Probe_init(const char *cc_command, const char *cc_flags);
 void
 chaz_Probe_clean_up(void);
 
+/* Return an integer version of the GCC version number which is
+ * (10000 * __GNU_C__ + 100 * __GNUC_MINOR__ + __GNUC_PATCHLEVEL__).
+ */
+int
+chaz_Probe_gcc_version_num(void);
+
+/* If the compiler is GCC (or claims compatibility), return an X.Y.Z string
+ * version of the GCC version; otherwise, return NULL.
+ */
+const char*
+chaz_Probe_gcc_version(void);
+
+/* Returns true if the compiler is MSVC.
+ */
+int
+chaz_Probe_compiler_is_msvc(void);
+
 #endif /* Include guard. */
 
 
@@ -581,7 +657,8 @@ chaz_CC_detect_known_compilers(void);
 /* Static vars. */
 static struct {
     char     *cc_command;
-    char     *cc_flags;
+    char     *cflags;
+    char     *extra_cflags;
     char     *try_exe_name;
     char     *try_obj_name;
     char      include_flag[10];
@@ -589,21 +666,24 @@ static struct {
     char      exe_flag[10];
     char      no_link_flag[10];
     char      error_flag[10];
-    int       defines___GNUC__;
-    int       defines__MSC_VER;
-    int       defines___clang__;
+    char      gcc_version_str[30];
+    int       intval___GNUC__;
+    int       intval___GNUC_MINOR__;
+    int       intval___GNUC_PATCHLEVEL__;
+    int       intval__MSC_VER;
+    int       intval___clang__;
     int       warnings_as_errors;
 } chaz_CC = {
     NULL, NULL, NULL, NULL,
-    "", "", "", "", "",
-    0, 0, 0, 0
+    "", "", "", "", "", "",
+    0, 0, 0, 0, 0, 0
 };
 
 void
 chaz_CC_set_warnings_as_errors(const int flag) {
     chaz_CC.warnings_as_errors = flag;
     if (chaz_CC.warnings_as_errors) {
-        if (chaz_CC.defines__MSC_VER)  {
+        if (chaz_CC.intval__MSC_VER)  {
             strcpy(chaz_CC.error_flag, "/WX");
         } else {
             strcpy(chaz_CC.error_flag, "-Werror");
@@ -621,9 +701,10 @@ chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
 
     if (chaz_Util_verbosity) { printf("Creating compiler object...\n"); }
 
-    /* Assign. */
+    /* Assign, init. */
     chaz_CC.cc_command      = chaz_Util_strdup(compiler_command);
-    chaz_CC.cc_flags        = chaz_Util_strdup(compiler_flags);
+    chaz_CC.cflags          = chaz_Util_strdup(compiler_flags);
+    chaz_CC.extra_cflags    = chaz_Util_strdup("");
 
     /* Set names for the targets which we "try" to compile. */
     {
@@ -662,36 +743,56 @@ chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
     chaz_CC_detect_known_compilers();
 }
 
-static const char detect_macro_code[] =
+static const char chaz_CC_detect_macro_code[] =
+    CHAZ_QUOTE(  #include <stdio.h>             )
     CHAZ_QUOTE(  int main() {                   )
     CHAZ_QUOTE(  #ifndef %s                     )
     CHAZ_QUOTE(  #error "nope"                  )
     CHAZ_QUOTE(  #endif                         )
+    CHAZ_QUOTE(      printf("%%d", %s);         )
     CHAZ_QUOTE(      return 0;                  )
     CHAZ_QUOTE(  }                              );
 
 static int
 chaz_CC_detect_macro(const char *macro) {
-    size_t size = sizeof(detect_macro_code) + strlen(macro) + 20;
+    size_t size = sizeof(chaz_CC_detect_macro_code)
+                  + (strlen(macro) * 2)
+                  + 20;
     char *code = (char*)malloc(size);
-    int retval;
-    sprintf(code, detect_macro_code, macro);
-    retval = chaz_CC_test_compile(code);
+    int retval = 0;
+    char *output;
+    size_t len;
+    sprintf(code, chaz_CC_detect_macro_code, macro, macro);
+    output = chaz_CC_capture_output(code, &len);
+    if (output) {
+        retval = atoi(output);
+        free(output);
+    }
     free(code);
     return retval;
 }
 
 static void
 chaz_CC_detect_known_compilers(void) {
-    chaz_CC.defines___GNUC__  = chaz_CC_detect_macro("__GNUC__");
-    chaz_CC.defines__MSC_VER  = chaz_CC_detect_macro("_MSC_VER");
-    chaz_CC.defines___clang__ = chaz_CC_detect_macro("__clang__");
+    chaz_CC.intval___GNUC__  = chaz_CC_detect_macro("__GNUC__");
+    if (chaz_CC.intval___GNUC__) {
+        chaz_CC.intval___GNUC_MINOR__
+            = chaz_CC_detect_macro("__GNUC_MINOR__");
+        chaz_CC.intval___GNUC_PATCHLEVEL__
+            = chaz_CC_detect_macro("__GNUC_PATCHLEVEL__");
+        sprintf(chaz_CC.gcc_version_str, "%d.%d.%d", chaz_CC.intval___GNUC__,
+                chaz_CC.intval___GNUC_MINOR__,
+                chaz_CC.intval___GNUC_PATCHLEVEL__);
+    }
+    chaz_CC.intval__MSC_VER  = chaz_CC_detect_macro("_MSC_VER");
+    chaz_CC.intval___clang__ = chaz_CC_detect_macro("__clang__");
 }
 
 void
 chaz_CC_clean_up(void) {
     free(chaz_CC.cc_command);
-    free(chaz_CC.cc_flags);
+    free(chaz_CC.cflags);
+    free(chaz_CC.extra_cflags);
     free(chaz_CC.try_obj_name);
     free(chaz_CC.try_exe_name);
 }
@@ -710,7 +811,8 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
                                  + strlen(source_path)
                                  + strlen(chaz_CC.exe_flag)
                                  + exe_file_buf_len
-                                 + strlen(chaz_CC.cc_flags)
+                                 + strlen(chaz_CC.cflags)
+                                 + strlen(chaz_CC.extra_cflags)
                                  + 200; /* command start, _charm_run, etc.  */
     char *command = (char*)malloc(command_max_size);
     int result;
@@ -719,11 +821,11 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
     chaz_Util_write_file(source_path, code);
 
     /* Prepare and run the compiler command. */
-    sprintf(command, "%s %s %s %s%s %s",
+    sprintf(command, "%s %s %s %s%s %s %s",
             chaz_CC.cc_command, chaz_CC.error_flag, 
             source_path, chaz_CC.exe_flag, 
             exe_file,
-            chaz_CC.cc_flags);
+            chaz_CC.cflags, chaz_CC.extra_cflags);
     if (chaz_Util_verbosity < 2) {
         chaz_OS_run_quietly(command);
     }
@@ -731,7 +833,7 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
         system(command);
     }
 
-    if (chaz_CC.defines__MSC_VER) {
+    if (chaz_CC.intval__MSC_VER) {
         /* Zap MSVC junk. */
         sprintf(junk, "%s.obj", exe_name);
         chaz_Util_remove_and_verify(junk);
@@ -766,7 +868,8 @@ chaz_CC_compile_obj(const char *source_path, const char *obj_name,
                                  + strlen(source_path)
                                  + strlen(chaz_CC.object_flag)
                                  + obj_file_buf_len
-                                 + strlen(chaz_CC.cc_flags)
+                                 + strlen(chaz_CC.cflags)
+                                 + strlen(chaz_CC.extra_cflags)
                                  + 200; /* command start, _charm_run, etc.  */
     char *command = (char*)malloc(command_max_size);
     int result;
@@ -775,11 +878,11 @@ chaz_CC_compile_obj(const char *source_path, const char *obj_name,
     chaz_Util_write_file(source_path, code);
 
     /* Prepare and run the compiler command. */
-    sprintf(command, "%s %s %s %s %s%s %s",
+    sprintf(command, "%s %s %s %s %s%s %s %s",
             chaz_CC.cc_command, chaz_CC.no_link_flag, chaz_CC.error_flag,
             source_path, chaz_CC.object_flag, 
             obj_file,
-            chaz_CC.cc_flags);
+            chaz_CC.cflags, chaz_CC.extra_cflags);
     if (chaz_Util_verbosity < 2) {
         chaz_OS_run_quietly(command);
     }
@@ -844,6 +947,56 @@ chaz_CC_capture_output(const char *source, size_t *output_len) {
     return captured_output;
 }
 
+void
+chaz_CC_add_extra_cflags(const char *flags) {
+    if (!strlen(chaz_CC.extra_cflags)) {
+        free(chaz_CC.extra_cflags);
+        chaz_CC.extra_cflags = chaz_Util_strdup(flags);
+    }
+    else {
+        size_t size = strlen(chaz_CC.extra_cflags)
+                      + 1   // Space separation
+                      + strlen(flags)
+                      + 1;  // NULL termination
+        char *newflags = (char*)malloc(size);
+        sprintf(newflags, "%s %s", chaz_CC.extra_cflags, flags);
+        free(chaz_CC.extra_cflags);
+        chaz_CC.extra_cflags = newflags;
+    }
+}
+
+const char*
+chaz_CC_get_cc(void) {
+    return chaz_CC.cc_command;
+}
+
+const char*
+chaz_CC_get_cflags(void) {
+    return chaz_CC.cflags;
+}
+
+const char*
+chaz_CC_get_extra_cflags(void) {
+    return chaz_CC.extra_cflags;
+}
+
+int
+chaz_CC_gcc_version_num(void) {
+    return 10000 * chaz_CC.intval___GNUC__
+           + 100 * chaz_CC.intval___GNUC_MINOR__
+           + chaz_CC.intval___GNUC_PATCHLEVEL__;
+}
+
+const char*
+chaz_CC_gcc_version(void) {
+    return chaz_CC.intval___GNUC__ ? chaz_CC.gcc_version_str : NULL;
+}
+
+int
+chaz_CC_compiler_is_msvc(void) {
+    return !!chaz_CC.intval__MSC_VER;
+}
+
 
 /***************************************************************************/
 
@@ -2293,24 +2446,123 @@ chaz_Util_can_open_file(const char *file_path) {
 /* #include "Charmonizer/Probe.h" */
 /* #include "Charmonizer/Core/HeaderChecker.h" */
 /* #include "Charmonizer/Core/ConfWriter.h" */
+/* #include "Charmonizer/Core/ConfWriterC.h" */
+/* #include "Charmonizer/Core/ConfWriterPerl.h" */
+/* #include "Charmonizer/Core/ConfWriterRuby.h" */
 /* #include "Charmonizer/Core/Util.h" */
 /* #include "Charmonizer/Core/Compiler.h" */
 /* #include "Charmonizer/Core/OperatingSystem.h" */
 
+int
+chaz_Probe_parse_cli_args(int argc, const char *argv[],
+                          struct chaz_CLIArgs *args) {
+    int i;
+    int output_enabled = 0;
+
+    /* Zero out args struct. */
+    memset(args, 0, sizeof(struct chaz_CLIArgs));
+
+    /* Parse most args. */
+    for (i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (strcmp(arg, "--") == 0) {
+            /* From here on out, everything will be a compiler flag. */
+            i++;
+            break;
+        }
+        if (strcmp(arg, "--enable-c") == 0) {
+            args->charmony_h = 1;
+            output_enabled = 1;
+        }
+        else if (strcmp(arg, "--enable-perl") == 0) {
+            args->charmony_pm = 1;
+            output_enabled = 1;
+        }
+        else if (strcmp(arg, "--enable-ruby") == 0) {
+            args->charmony_rb = 1;
+            output_enabled = 1;
+        }
+        else if (memcmp(arg, "--cc=", 5) == 0) {
+            if (strlen(arg) > CHAZ_PROBE_MAX_CC_LEN - 5) {
+                fprintf(stderr, "Exceeded max length for compiler command");
+                exit(1);
+            }
+            strcpy(args->cc, arg + 5);
+        }
+    } /* preserve value of i */
+
+    /* Accumulate compiler flags. */
+    for (; i < argc; i++) {
+        const char *arg = argv[i];
+        size_t new_len = strlen(arg) + strlen(args->cflags) + 2;
+        if (new_len >= CHAZ_PROBE_MAX_CFLAGS_LEN) {
+            fprintf(stderr, "Exceeded max length for compiler flags");
+            exit(1);
+        }
+        strcat(args->cflags, " ");
+        strcat(args->cflags, arg);
+    }
+
+    /* Process CHARM_VERBOSITY environment variable. */
+    {
+        const char *verbosity_env = getenv("CHARM_VERBOSITY");
+        if (verbosity_env && strlen(verbosity_env)) {
+            args->verbosity = strtol(verbosity_env, NULL, 10);
+        }
+    }
+
+    /* Validate. */
+    if (!strlen(args->cc) || !output_enabled) {
+        return false;
+    }
+
+    return true;
+}
+
+void
+chaz_Probe_die_usage(void) {
+    fprintf(stderr,
+            "Usage: ./charmonize --cc=CC_COMMAND [--enable-c] "
+            "[--enable-perl] [--enable-ruby] -- CFLAGS\n");
+    exit(1);
+}
+
 void
-chaz_Probe_init(const char *cc_command, const char *cc_flags) {
-    /* Proces CHARM_VERBOSITY environment variable. */
-    const char *verbosity_env = getenv("CHARM_VERBOSITY");
-    if (verbosity_env && strlen(verbosity_env)) {
-        chaz_Util_verbosity = strtol(verbosity_env, NULL, 10);
+chaz_Probe_init(struct chaz_CLIArgs *args) {
+    int output_enabled = 0;
+
+    {
+        /* Process CHARM_VERBOSITY environment variable. */
+        const char *verbosity_env = getenv("CHARM_VERBOSITY");
+        if (verbosity_env && strlen(verbosity_env)) {
+            chaz_Util_verbosity = strtol(verbosity_env, NULL, 10);
+        }
     }
 
     /* Dispatch other initializers. */
     chaz_OS_init();
-    chaz_CC_init(cc_command, cc_flags);
+    chaz_CC_init(args->cc, args->cflags);
     chaz_ConfWriter_init();
     chaz_HeadCheck_init();
 
+    /* Enable output. */
+    if (args->charmony_h) {
+        chaz_ConfWriterC_enable();
+        output_enabled = true;
+    }
+    if (args->charmony_pm) {
+        chaz_ConfWriterPerl_enable();
+        output_enabled = true;
+    }
+    if (args->charmony_rb) {
+        chaz_ConfWriterRuby_enable();
+        output_enabled = true;
+    }
+    if (!output_enabled) {
+        fprintf(stderr, "No output formats enabled\n");
+        exit(1);
+    }
+
     if (chaz_Util_verbosity) { printf("Initialization complete.\n"); }
 }
 
@@ -2325,6 +2577,20 @@ chaz_Probe_clean_up(void) {
     if (chaz_Util_verbosity) { printf("Cleanup complete.\n"); }
 }
 
+int
+chaz_Probe_gcc_version_num(void) {
+    return chaz_CC_gcc_version_num();
+}
+
+const char*
+chaz_Probe_gcc_version(void) {
+    return chaz_CC_gcc_version_num() ? chaz_CC_gcc_version() : NULL;
+}
+
+int
+chaz_Probe_compiler_is_msvc(void) {
+    return chaz_CC_compiler_is_msvc();
+}
 
 /***************************************************************************/
 
@@ -2765,66 +3031,17 @@ chaz_Integers_machine_is_big_endian(void) {
 /* #include "Charmonizer/Probe.h" */
 /* #include "Charmonizer/Probe/Integers.h" */
 
-#define MAX_CC_LEN 128
-#define MAX_FLAGS_LEN 2048
-
-struct CLIArgs {
-    char cc_command[MAX_CC_LEN + 1];
-    char cc_flags[MAX_FLAGS_LEN + 1];
-};
-
-/* Parse command line arguments. */
-static void
-S_parse_arguments(int argc, char **argv, struct CLIArgs *args) {
-    int i;
-
-    /* Parse most args. */
-    for (i = 1; i < argc; i++) {
-        char *arg = argv[i];
-        if (strcmp(arg, "--") == 0) {
-            /* From here on out, everything will be a compiler flag. */
-            i++;
-            break;
-        }
-        if (memcmp(arg, "--cc=", 5) == 0) {
-            if (strlen(arg) > MAX_CC_LEN - 5) {
-                fprintf(stderr, "Exceeded max length for compiler command");
-                exit(1);
-            }
-            strcpy(args->cc_command, arg + 5);
-        }
-    }
-
-    /* Accumulate compiler flags. */
-    for (; i < argc; i++) {
-        char *arg = argv[i];
-        if (strlen(arg) + strlen(args->cc_flags) + 2 >= MAX_FLAGS_LEN) {
-            fprintf(stderr, "Exceeded max length for compiler flags");
-            exit(1);
+int main(int argc, const char **argv) {
+    /* Initialize. */
+    {
+        struct chaz_CLIArgs args;
+        int result = chaz_Probe_parse_cli_args(argc, argv, &args);
+        if (!result) {
+            chaz_Probe_die_usage();
         }
-        strcat(args->cc_flags, " ");
-        strcat(args->cc_flags, arg);
-    }
-
-    /* Validate. */
-    if (!args->cc_command
-        || !strlen(args->cc_command)
-       ) {
-        fprintf(stderr,
-                "Usage: ./charmonizer --cc=CC_COMMAND -- CC_FLAGS\n");
-        exit(1);
+        chaz_Probe_init(&args);
     }
 
-}
-
-int main(int argc, char **argv) {
-    struct CLIArgs args;
-    memset(&args, 0, sizeof(struct CLIArgs));
-
-    S_parse_arguments(argc, argv, &args);
-    chaz_Probe_init(args.cc_command, args.cc_flags);
-    chaz_ConfWriterC_enable();
-
     /* Run probe modules. */
     chaz_Integers_run();
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/2dbf927c/clownfish/runtime/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/clownfish/runtime/common/charmonizer.c b/clownfish/runtime/common/charmonizer.c
index 4de6205..ef8aedc 100644
--- a/clownfish/runtime/common/charmonizer.c
+++ b/clownfish/runtime/common/charmonizer.c
@@ -77,7 +77,7 @@ chaz_CC_capture_output(const char *source, size_t *output_len);
 /** Initialize the compiler environment.
  */
 void
-chaz_CC_init(const char *cc_command, const char *cc_flags);
+chaz_CC_init(const char *cc_command, const char *cflags);
 
 /* Clean up the environment.
  */
@@ -87,6 +87,36 @@ chaz_CC_clean_up(void);
 void
 chaz_CC_set_warnings_as_errors(const int flag);
 
+/* Concatenate onto the end of the "extra" cflags.  A space will be inserted
+ * automatically.
+ */
+void
+chaz_CC_add_extra_cflags(const char *);
+
+/* Accessor for the compiler executable's string representation.
+ */
+const char*
+chaz_CC_get_cc(void);
+
+/* Accessor for `cflags`.
+ */
+const char*
+chaz_CC_get_cflags(void);
+
+/* Accessor for `extra_cflags`.
+ */
+const char*
+chaz_CC_get_extra_cflags(void);
+
+int
+chaz_CC_gcc_version_num();
+
+const char*
+chaz_CC_gcc_version();
+
+int
+chaz_CC_compiler_is_msvc(void);
+
 #endif /* H_CHAZ_COMPILER */
 
 
@@ -433,8 +463,40 @@ chaz_Util_can_open_file(const char *file_path);
 #include <stddef.h>
 #include <stdio.h>
 
-/* Set up the Charmonizer environment.  This should be called before anything
- * else.
+#define CHAZ_PROBE_MAX_CC_LEN 100
+#define CHAZ_PROBE_MAX_CFLAGS_LEN 2000
+
+struct chaz_CLIArgs {
+    char cc[CHAZ_PROBE_MAX_CC_LEN + 1];
+    char cflags[CHAZ_PROBE_MAX_CFLAGS_LEN + 1];
+    int  charmony_h;
+    int  charmony_pm;
+    int  charmony_rb;
+    int  verbosity;
+};
+
+/* Parse command line arguments, initializing and filling in the supplied
+ * `args` struct.
+ *
+ *     APP_NAME --cc=CC_COMMAND
+ *              [--enable-c]
+ *              [--enable-perl]
+ *              [--enable-ruby]
+ *              [-- [CFLAGS]]
+ *
+ * @return true if argument parsing proceeds without incident, false if
+ * unexpected arguments are encountered or values are missing or invalid.
+ */
+int
+chaz_Probe_parse_cli_args(int argc, const char *argv[],
+                          struct chaz_CLIArgs *args);
+
+/* Exit after printing usage instructions to stderr.
+ */
+void
+chaz_Probe_die_usage(void);
+
+/* Set up the Charmonizer environment.
  *
  * If the environment variable CHARM_VERBOSITY has been set, it will be
  * processed at this time:
@@ -442,12 +504,9 @@ chaz_Util_can_open_file(const char *file_path);
  *      0 - silent
  *      1 - normal
  *      2 - debugging
- *
- * @param cc_command the string used to invoke the C compiler via system()
- * @param cc_flags flags which will be passed on to the C compiler
  */
 void
-chaz_Probe_init(const char *cc_command, const char *cc_flags);
+chaz_Probe_init(struct chaz_CLIArgs *args);
 
 /* Clean up the Charmonizer environment -- deleting tempfiles, etc.  This
  * should be called only after everything else finishes.
@@ -455,6 +514,23 @@ chaz_Probe_init(const char *cc_command, const char *cc_flags);
 void
 chaz_Probe_clean_up(void);
 
+/* Return an integer version of the GCC version number which is
+ * (10000 * __GNU_C__ + 100 * __GNUC_MINOR__ + __GNUC_PATCHLEVEL__).
+ */
+int
+chaz_Probe_gcc_version_num(void);
+
+/* If the compiler is GCC (or claims compatibility), return an X.Y.Z string
+ * version of the GCC version; otherwise, return NULL.
+ */
+const char*
+chaz_Probe_gcc_version(void);
+
+/* Returns true if the compiler is MSVC.
+ */
+int
+chaz_Probe_compiler_is_msvc(void);
+
 #endif /* Include guard. */
 
 
@@ -522,6 +598,35 @@ void chaz_Booleans_run(void);
 
 /***************************************************************************/
 
+#line 21 "src/Charmonizer/Probe/BuildEnv.h"
+/* Charmonizer/Probe/BuildEnv.h -- Build environment.
+ *
+ * Capture various information about the build environment, including the C
+ * compiler's interface, the shell, the operating system, etc.
+ *
+ * The following symbols will be defined:
+ *
+ * CC - String representation of the C compiler executable.
+ * CFLAGS - C compiler flags.
+ * EXTRA_CFLAGS - Extra C compiler flags.
+ */
+
+#ifndef H_CHAZ_BUILDENV
+#define H_CHAZ_BUILDENV
+
+#include <stdio.h>
+
+/* Run the BuildEnv module.
+ */
+void chaz_BuildEnv_run(void);
+
+#endif /* H_CHAZ_BUILDENV */
+
+
+
+
+/***************************************************************************/
+
 #line 21 "src/Charmonizer/Probe/DirManip.h"
 /* Charmonizer/Probe/DirManip.h
  */
@@ -990,7 +1095,8 @@ chaz_CC_detect_known_compilers(void);
 /* Static vars. */
 static struct {
     char     *cc_command;
-    char     *cc_flags;
+    char     *cflags;
+    char     *extra_cflags;
     char     *try_exe_name;
     char     *try_obj_name;
     char      include_flag[10];
@@ -998,21 +1104,24 @@ static struct {
     char      exe_flag[10];
     char      no_link_flag[10];
     char      error_flag[10];
-    int       defines___GNUC__;
-    int       defines__MSC_VER;
-    int       defines___clang__;
+    char      gcc_version_str[30];
+    int       intval___GNUC__;
+    int       intval___GNUC_MINOR__;
+    int       intval___GNUC_PATCHLEVEL__;
+    int       intval__MSC_VER;
+    int       intval___clang__;
     int       warnings_as_errors;
 } chaz_CC = {
     NULL, NULL, NULL, NULL,
-    "", "", "", "", "",
-    0, 0, 0, 0
+    "", "", "", "", "", "",
+    0, 0, 0, 0, 0, 0
 };
 
 void
 chaz_CC_set_warnings_as_errors(const int flag) {
     chaz_CC.warnings_as_errors = flag;
     if (chaz_CC.warnings_as_errors) {
-        if (chaz_CC.defines__MSC_VER)  {
+        if (chaz_CC.intval__MSC_VER)  {
             strcpy(chaz_CC.error_flag, "/WX");
         } else {
             strcpy(chaz_CC.error_flag, "-Werror");
@@ -1030,9 +1139,10 @@ chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
 
     if (chaz_Util_verbosity) { printf("Creating compiler object...\n"); }
 
-    /* Assign. */
+    /* Assign, init. */
     chaz_CC.cc_command      = chaz_Util_strdup(compiler_command);
-    chaz_CC.cc_flags        = chaz_Util_strdup(compiler_flags);
+    chaz_CC.cflags          = chaz_Util_strdup(compiler_flags);
+    chaz_CC.extra_cflags    = chaz_Util_strdup("");
 
     /* Set names for the targets which we "try" to compile. */
     {
@@ -1071,36 +1181,56 @@ chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
     chaz_CC_detect_known_compilers();
 }
 
-static const char detect_macro_code[] =
+static const char chaz_CC_detect_macro_code[] =
+    CHAZ_QUOTE(  #include <stdio.h>             )
     CHAZ_QUOTE(  int main() {                   )
     CHAZ_QUOTE(  #ifndef %s                     )
     CHAZ_QUOTE(  #error "nope"                  )
     CHAZ_QUOTE(  #endif                         )
+    CHAZ_QUOTE(      printf("%%d", %s);         )
     CHAZ_QUOTE(      return 0;                  )
     CHAZ_QUOTE(  }                              );
 
 static int
 chaz_CC_detect_macro(const char *macro) {
-    size_t size = sizeof(detect_macro_code) + strlen(macro) + 20;
+    size_t size = sizeof(chaz_CC_detect_macro_code)
+                  + (strlen(macro) * 2)
+                  + 20;
     char *code = (char*)malloc(size);
-    int retval;
-    sprintf(code, detect_macro_code, macro);
-    retval = chaz_CC_test_compile(code);
+    int retval = 0;
+    char *output;
+    size_t len;
+    sprintf(code, chaz_CC_detect_macro_code, macro, macro);
+    output = chaz_CC_capture_output(code, &len);
+    if (output) {
+        retval = atoi(output);
+        free(output);
+    }
     free(code);
     return retval;
 }
 
 static void
 chaz_CC_detect_known_compilers(void) {
-    chaz_CC.defines___GNUC__  = chaz_CC_detect_macro("__GNUC__");
-    chaz_CC.defines__MSC_VER  = chaz_CC_detect_macro("_MSC_VER");
-    chaz_CC.defines___clang__ = chaz_CC_detect_macro("__clang__");
+    chaz_CC.intval___GNUC__  = chaz_CC_detect_macro("__GNUC__");
+    if (chaz_CC.intval___GNUC__) {
+        chaz_CC.intval___GNUC_MINOR__
+            = chaz_CC_detect_macro("__GNUC_MINOR__");
+        chaz_CC.intval___GNUC_PATCHLEVEL__
+            = chaz_CC_detect_macro("__GNUC_PATCHLEVEL__");
+        sprintf(chaz_CC.gcc_version_str, "%d.%d.%d", chaz_CC.intval___GNUC__,
+                chaz_CC.intval___GNUC_MINOR__,
+                chaz_CC.intval___GNUC_PATCHLEVEL__);
+    }
+    chaz_CC.intval__MSC_VER  = chaz_CC_detect_macro("_MSC_VER");
+    chaz_CC.intval___clang__ = chaz_CC_detect_macro("__clang__");
 }
 
 void
 chaz_CC_clean_up(void) {
     free(chaz_CC.cc_command);
-    free(chaz_CC.cc_flags);
+    free(chaz_CC.cflags);
+    free(chaz_CC.extra_cflags);
     free(chaz_CC.try_obj_name);
     free(chaz_CC.try_exe_name);
 }
@@ -1119,7 +1249,8 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
                                  + strlen(source_path)
                                  + strlen(chaz_CC.exe_flag)
                                  + exe_file_buf_len
-                                 + strlen(chaz_CC.cc_flags)
+                                 + strlen(chaz_CC.cflags)
+                                 + strlen(chaz_CC.extra_cflags)
                                  + 200; /* command start, _charm_run, etc.  */
     char *command = (char*)malloc(command_max_size);
     int result;
@@ -1128,11 +1259,11 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
     chaz_Util_write_file(source_path, code);
 
     /* Prepare and run the compiler command. */
-    sprintf(command, "%s %s %s %s%s %s",
+    sprintf(command, "%s %s %s %s%s %s %s",
             chaz_CC.cc_command, chaz_CC.error_flag, 
             source_path, chaz_CC.exe_flag, 
             exe_file,
-            chaz_CC.cc_flags);
+            chaz_CC.cflags, chaz_CC.extra_cflags);
     if (chaz_Util_verbosity < 2) {
         chaz_OS_run_quietly(command);
     }
@@ -1140,7 +1271,7 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
         system(command);
     }
 
-    if (chaz_CC.defines__MSC_VER) {
+    if (chaz_CC.intval__MSC_VER) {
         /* Zap MSVC junk. */
         sprintf(junk, "%s.obj", exe_name);
         chaz_Util_remove_and_verify(junk);
@@ -1175,7 +1306,8 @@ chaz_CC_compile_obj(const char *source_path, const char *obj_name,
                                  + strlen(source_path)
                                  + strlen(chaz_CC.object_flag)
                                  + obj_file_buf_len
-                                 + strlen(chaz_CC.cc_flags)
+                                 + strlen(chaz_CC.cflags)
+                                 + strlen(chaz_CC.extra_cflags)
                                  + 200; /* command start, _charm_run, etc.  */
     char *command = (char*)malloc(command_max_size);
     int result;
@@ -1184,11 +1316,11 @@ chaz_CC_compile_obj(const char *source_path, const char *obj_name,
     chaz_Util_write_file(source_path, code);
 
     /* Prepare and run the compiler command. */
-    sprintf(command, "%s %s %s %s %s%s %s",
+    sprintf(command, "%s %s %s %s %s%s %s %s",
             chaz_CC.cc_command, chaz_CC.no_link_flag, chaz_CC.error_flag,
             source_path, chaz_CC.object_flag, 
             obj_file,
-            chaz_CC.cc_flags);
+            chaz_CC.cflags, chaz_CC.extra_cflags);
     if (chaz_Util_verbosity < 2) {
         chaz_OS_run_quietly(command);
     }
@@ -1253,6 +1385,56 @@ chaz_CC_capture_output(const char *source, size_t *output_len) {
     return captured_output;
 }
 
+void
+chaz_CC_add_extra_cflags(const char *flags) {
+    if (!strlen(chaz_CC.extra_cflags)) {
+        free(chaz_CC.extra_cflags);
+        chaz_CC.extra_cflags = chaz_Util_strdup(flags);
+    }
+    else {
+        size_t size = strlen(chaz_CC.extra_cflags)
+                      + 1   // Space separation
+                      + strlen(flags)
+                      + 1;  // NULL termination
+        char *newflags = (char*)malloc(size);
+        sprintf(newflags, "%s %s", chaz_CC.extra_cflags, flags);
+        free(chaz_CC.extra_cflags);
+        chaz_CC.extra_cflags = newflags;
+    }
+}
+
+const char*
+chaz_CC_get_cc(void) {
+    return chaz_CC.cc_command;
+}
+
+const char*
+chaz_CC_get_cflags(void) {
+    return chaz_CC.cflags;
+}
+
+const char*
+chaz_CC_get_extra_cflags(void) {
+    return chaz_CC.extra_cflags;
+}
+
+int
+chaz_CC_gcc_version_num(void) {
+    return 10000 * chaz_CC.intval___GNUC__
+           + 100 * chaz_CC.intval___GNUC_MINOR__
+           + chaz_CC.intval___GNUC_PATCHLEVEL__;
+}
+
+const char*
+chaz_CC_gcc_version(void) {
+    return chaz_CC.intval___GNUC__ ? chaz_CC.gcc_version_str : NULL;
+}
+
+int
+chaz_CC_compiler_is_msvc(void) {
+    return !!chaz_CC.intval__MSC_VER;
+}
+
 
 /***************************************************************************/
 
@@ -2702,24 +2884,123 @@ chaz_Util_can_open_file(const char *file_path) {
 /* #include "Charmonizer/Probe.h" */
 /* #include "Charmonizer/Core/HeaderChecker.h" */
 /* #include "Charmonizer/Core/ConfWriter.h" */
+/* #include "Charmonizer/Core/ConfWriterC.h" */
+/* #include "Charmonizer/Core/ConfWriterPerl.h" */
+/* #include "Charmonizer/Core/ConfWriterRuby.h" */
 /* #include "Charmonizer/Core/Util.h" */
 /* #include "Charmonizer/Core/Compiler.h" */
 /* #include "Charmonizer/Core/OperatingSystem.h" */
 
+int
+chaz_Probe_parse_cli_args(int argc, const char *argv[],
+                          struct chaz_CLIArgs *args) {
+    int i;
+    int output_enabled = 0;
+
+    /* Zero out args struct. */
+    memset(args, 0, sizeof(struct chaz_CLIArgs));
+
+    /* Parse most args. */
+    for (i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (strcmp(arg, "--") == 0) {
+            /* From here on out, everything will be a compiler flag. */
+            i++;
+            break;
+        }
+        if (strcmp(arg, "--enable-c") == 0) {
+            args->charmony_h = 1;
+            output_enabled = 1;
+        }
+        else if (strcmp(arg, "--enable-perl") == 0) {
+            args->charmony_pm = 1;
+            output_enabled = 1;
+        }
+        else if (strcmp(arg, "--enable-ruby") == 0) {
+            args->charmony_rb = 1;
+            output_enabled = 1;
+        }
+        else if (memcmp(arg, "--cc=", 5) == 0) {
+            if (strlen(arg) > CHAZ_PROBE_MAX_CC_LEN - 5) {
+                fprintf(stderr, "Exceeded max length for compiler command");
+                exit(1);
+            }
+            strcpy(args->cc, arg + 5);
+        }
+    } /* preserve value of i */
+
+    /* Accumulate compiler flags. */
+    for (; i < argc; i++) {
+        const char *arg = argv[i];
+        size_t new_len = strlen(arg) + strlen(args->cflags) + 2;
+        if (new_len >= CHAZ_PROBE_MAX_CFLAGS_LEN) {
+            fprintf(stderr, "Exceeded max length for compiler flags");
+            exit(1);
+        }
+        strcat(args->cflags, " ");
+        strcat(args->cflags, arg);
+    }
+
+    /* Process CHARM_VERBOSITY environment variable. */
+    {
+        const char *verbosity_env = getenv("CHARM_VERBOSITY");
+        if (verbosity_env && strlen(verbosity_env)) {
+            args->verbosity = strtol(verbosity_env, NULL, 10);
+        }
+    }
+
+    /* Validate. */
+    if (!strlen(args->cc) || !output_enabled) {
+        return false;
+    }
+
+    return true;
+}
+
 void
-chaz_Probe_init(const char *cc_command, const char *cc_flags) {
-    /* Proces CHARM_VERBOSITY environment variable. */
-    const char *verbosity_env = getenv("CHARM_VERBOSITY");
-    if (verbosity_env && strlen(verbosity_env)) {
-        chaz_Util_verbosity = strtol(verbosity_env, NULL, 10);
+chaz_Probe_die_usage(void) {
+    fprintf(stderr,
+            "Usage: ./charmonize --cc=CC_COMMAND [--enable-c] "
+            "[--enable-perl] [--enable-ruby] -- CFLAGS\n");
+    exit(1);
+}
+
+void
+chaz_Probe_init(struct chaz_CLIArgs *args) {
+    int output_enabled = 0;
+
+    {
+        /* Process CHARM_VERBOSITY environment variable. */
+        const char *verbosity_env = getenv("CHARM_VERBOSITY");
+        if (verbosity_env && strlen(verbosity_env)) {
+            chaz_Util_verbosity = strtol(verbosity_env, NULL, 10);
+        }
     }
 
     /* Dispatch other initializers. */
     chaz_OS_init();
-    chaz_CC_init(cc_command, cc_flags);
+    chaz_CC_init(args->cc, args->cflags);
     chaz_ConfWriter_init();
     chaz_HeadCheck_init();
 
+    /* Enable output. */
+    if (args->charmony_h) {
+        chaz_ConfWriterC_enable();
+        output_enabled = true;
+    }
+    if (args->charmony_pm) {
+        chaz_ConfWriterPerl_enable();
+        output_enabled = true;
+    }
+    if (args->charmony_rb) {
+        chaz_ConfWriterRuby_enable();
+        output_enabled = true;
+    }
+    if (!output_enabled) {
+        fprintf(stderr, "No output formats enabled\n");
+        exit(1);
+    }
+
     if (chaz_Util_verbosity) { printf("Initialization complete.\n"); }
 }
 
@@ -2734,6 +3015,20 @@ chaz_Probe_clean_up(void) {
     if (chaz_Util_verbosity) { printf("Cleanup complete.\n"); }
 }
 
+int
+chaz_Probe_gcc_version_num(void) {
+    return chaz_CC_gcc_version_num();
+}
+
+const char*
+chaz_Probe_gcc_version(void) {
+    return chaz_CC_gcc_version_num() ? chaz_CC_gcc_version() : NULL;
+}
+
+int
+chaz_Probe_compiler_is_msvc(void) {
+    return chaz_CC_compiler_is_msvc();
+}
 
 /***************************************************************************/
 
@@ -2828,6 +3123,26 @@ chaz_Booleans_run(void) {
 
 /***************************************************************************/
 
+#line 17 "src/Charmonizer/Probe/BuildEnv.c"
+/* #include "Charmonizer/Core/HeaderChecker.h" */
+/* #include "Charmonizer/Core/ConfWriter.h" */
+/* #include "Charmonizer/Probe/BuildEnv.h" */
+
+void
+chaz_BuildEnv_run(void) {
+    chaz_ConfWriter_start_module("BuildEnv");
+
+    chaz_ConfWriter_add_def("CC", chaz_CC_get_cc());
+    chaz_ConfWriter_add_def("CFLAGS", chaz_CC_get_cflags());
+    chaz_ConfWriter_add_def("EXTRA_CFLAGS", chaz_CC_get_extra_cflags());
+
+    chaz_ConfWriter_end_module();
+}
+
+
+
+/***************************************************************************/
+
 #line 17 "src/Charmonizer/Probe/DirManip.c"
 /* #include "Charmonizer/Core/ConfWriter.h" */
 /* #include "Charmonizer/Core/Compiler.h" */
@@ -4439,6 +4754,7 @@ chaz_VariadicMacros_run(void) {
 #include <string.h>
 /* #include "Charmonizer/Probe.h" */
 /* #include "Charmonizer/Probe/AtomicOps.h" */
+/* #include "Charmonizer/Probe/BuildEnv.h" */
 /* #include "Charmonizer/Probe/DirManip.h" */
 /* #include "Charmonizer/Probe/Floats.h" */
 /* #include "Charmonizer/Probe/FuncMacro.h" */
@@ -4455,94 +4771,44 @@ chaz_VariadicMacros_run(void) {
 /* #include "Charmonizer/Core/ConfWriterPerl.h" */
 /* #include "Charmonizer/Core/ConfWriterRuby.h" */
 
-#define MAX_CC_LEN 128
-#define MAX_FLAGS_LEN 2048
-
-struct CLIArgs {
-    char cc_command[MAX_CC_LEN + 1];
-    char cc_flags[MAX_FLAGS_LEN + 1];
-    int  enable_c;
-    int  enable_perl;
-    int  enable_ruby;
-};
-
-/* Parse command line arguments. */
 static void
-S_parse_arguments(int argc, char **argv, struct CLIArgs *args) {
-    int i;
-    int output_enabled = 0;
-
-    /* Parse most args. */
-    for (i = 1; i < argc; i++) {
-        char *arg = argv[i];
-        if (strcmp(arg, "--") == 0) {
-            /* From here on out, everything will be a compiler flag. */
-            i++;
-            break;
-        }
-        if (strcmp(arg, "--enable-c") == 0) {
-            args->enable_c = 1;
-            output_enabled = 1;
-        }
-        else if (strcmp(arg, "--enable-perl") == 0) {
-            args->enable_perl = 1;
-            output_enabled = 1;
+S_add_compiler_flags(struct chaz_CLIArgs *args) {
+    if (chaz_Probe_gcc_version_num()) {
+        if (getenv("LUCY_VALGRIND")) {
+            chaz_CC_add_extra_cflags("-DLUCY_VALGRIND -fno-inline-functions");
         }
-        else if (strcmp(arg, "--enable-ruby") == 0) {
-            args->enable_ruby = 1;
-            output_enabled = 1;
+        else if (getenv("LUCY_DEBUG")) {
+            chaz_CC_add_extra_cflags(
+                "-DLUCY_DEBUG -pedantic -Wall -Wextra "
+                "-Wno-variadic-macros "
+            );
         }
-        else if (memcmp(arg, "--cc=", 5) == 0) {
-            if (strlen(arg) > MAX_CC_LEN - 5) {
-                fprintf(stderr, "Exceeded max length for compiler command");
-                exit(1);
-            }
-            strcpy(args->cc_command, arg + 5);
-        }
-    }
-
-    /* Accumulate compiler flags. */
-    for (; i < argc; i++) {
-        char *arg = argv[i];
-        if (strlen(arg) + strlen(args->cc_flags) + 2 >= MAX_FLAGS_LEN) {
-            fprintf(stderr, "Exceeded max length for compiler flags");
-            exit(1);
-        }
-        strcat(args->cc_flags, " ");
-        strcat(args->cc_flags, arg);
-
     }
-
-    /* Validate. */
-    if (!args->cc_command
-        || !strlen(args->cc_command)
-        || !output_enabled
-       ) {
-        fprintf(stderr,
-                "Usage: ./charmonize --cc=CC_COMMAND [--enable-c] "
-                "[--enable-perl] [--enable-ruby] -- CC_FLAGS\n");
-        exit(1);
-    }
-
 }
 
-int main(int argc, char **argv) {
-    struct CLIArgs args;
-    memset(&args, 0, sizeof(struct CLIArgs));
-
-    S_parse_arguments(argc, argv, &args);
-    chaz_Probe_init(args.cc_command, args.cc_flags);
-    if (args.enable_c) {
-        chaz_ConfWriterC_enable();
-    }
-    if (args.enable_perl) {
-        chaz_ConfWriterPerl_enable();
+int main(int argc, const char **argv) {
+    /* Initialize. */
+    {
+        struct chaz_CLIArgs args;
+        int result = chaz_Probe_parse_cli_args(argc, argv, &args);
+        if (!result) {
+            chaz_Probe_die_usage();
+        }
+        chaz_Probe_init(&args);
+        S_add_compiler_flags(&args);
     }
-    if (args.enable_ruby) {
-        chaz_ConfWriterRuby_enable();
+    {
+        int i;
+        for (i = 0; i < argc; i++) {
+            if (strncmp(argv[i], "--disable-threads", 17) == 0) {
+                chaz_CC_add_extra_cflags("-DLUCY_NOTHREADS");
+                break;
+            }
+        }
     }
 
     /* Run probe modules. */
+    chaz_BuildEnv_run();
     chaz_DirManip_run();
     chaz_Headers_run();
     chaz_AtomicOps_run();

http://git-wip-us.apache.org/repos/asf/lucy/blob/2dbf927c/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/common/charmonizer.c b/common/charmonizer.c
index f600dbd..ea65d94 100644
--- a/common/charmonizer.c
+++ b/common/charmonizer.c
@@ -77,7 +77,7 @@ chaz_CC_capture_output(const char *source, size_t *output_len);
 /** Initialize the compiler environment.
  */
 void
-chaz_CC_init(const char *cc_command, const char *cc_flags);
+chaz_CC_init(const char *cc_command, const char *cflags);
 
 /* Clean up the environment.
  */
@@ -87,6 +87,36 @@ chaz_CC_clean_up(void);
 void
 chaz_CC_set_warnings_as_errors(const int flag);
 
+/* Concatenate onto the end of the "extra" cflags.  A space will be inserted
+ * automatically.
+ */
+void
+chaz_CC_add_extra_cflags(const char *);
+
+/* Accessor for the compiler executable's string representation.
+ */
+const char*
+chaz_CC_get_cc(void);
+
+/* Accessor for `cflags`.
+ */
+const char*
+chaz_CC_get_cflags(void);
+
+/* Accessor for `extra_cflags`.
+ */
+const char*
+chaz_CC_get_extra_cflags(void);
+
+int
+chaz_CC_gcc_version_num();
+
+const char*
+chaz_CC_gcc_version();
+
+int
+chaz_CC_compiler_is_msvc(void);
+
 #endif /* H_CHAZ_COMPILER */
 
 
@@ -433,8 +463,40 @@ chaz_Util_can_open_file(const char *file_path);
 #include <stddef.h>
 #include <stdio.h>
 
-/* Set up the Charmonizer environment.  This should be called before anything
- * else.
+#define CHAZ_PROBE_MAX_CC_LEN 100
+#define CHAZ_PROBE_MAX_CFLAGS_LEN 2000
+
+struct chaz_CLIArgs {
+    char cc[CHAZ_PROBE_MAX_CC_LEN + 1];
+    char cflags[CHAZ_PROBE_MAX_CFLAGS_LEN + 1];
+    int  charmony_h;
+    int  charmony_pm;
+    int  charmony_rb;
+    int  verbosity;
+};
+
+/* Parse command line arguments, initializing and filling in the supplied
+ * `args` struct.
+ *
+ *     APP_NAME --cc=CC_COMMAND
+ *              [--enable-c]
+ *              [--enable-perl]
+ *              [--enable-ruby]
+ *              [-- [CFLAGS]]
+ *
+ * @return true if argument parsing proceeds without incident, false if
+ * unexpected arguments are encountered or values are missing or invalid.
+ */
+int
+chaz_Probe_parse_cli_args(int argc, const char *argv[],
+                          struct chaz_CLIArgs *args);
+
+/* Exit after printing usage instructions to stderr.
+ */
+void
+chaz_Probe_die_usage(void);
+
+/* Set up the Charmonizer environment.
  *
  * If the environment variable CHARM_VERBOSITY has been set, it will be
  * processed at this time:
@@ -442,12 +504,9 @@ chaz_Util_can_open_file(const char *file_path);
  *      0 - silent
  *      1 - normal
  *      2 - debugging
- *
- * @param cc_command the string used to invoke the C compiler via system()
- * @param cc_flags flags which will be passed on to the C compiler
  */
 void
-chaz_Probe_init(const char *cc_command, const char *cc_flags);
+chaz_Probe_init(struct chaz_CLIArgs *args);
 
 /* Clean up the Charmonizer environment -- deleting tempfiles, etc.  This
  * should be called only after everything else finishes.
@@ -455,6 +514,23 @@ chaz_Probe_init(const char *cc_command, const char *cc_flags);
 void
 chaz_Probe_clean_up(void);
 
+/* Return an integer version of the GCC version number which is
+ * (10000 * __GNU_C__ + 100 * __GNUC_MINOR__ + __GNUC_PATCHLEVEL__).
+ */
+int
+chaz_Probe_gcc_version_num(void);
+
+/* If the compiler is GCC (or claims compatibility), return an X.Y.Z string
+ * version of the GCC version; otherwise, return NULL.
+ */
+const char*
+chaz_Probe_gcc_version(void);
+
+/* Returns true if the compiler is MSVC.
+ */
+int
+chaz_Probe_compiler_is_msvc(void);
+
 #endif /* Include guard. */
 
 
@@ -522,6 +598,35 @@ void chaz_Booleans_run(void);
 
 /***************************************************************************/
 
+#line 21 "src/Charmonizer/Probe/BuildEnv.h"
+/* Charmonizer/Probe/BuildEnv.h -- Build environment.
+ *
+ * Capture various information about the build environment, including the C
+ * compiler's interface, the shell, the operating system, etc.
+ *
+ * The following symbols will be defined:
+ *
+ * CC - String representation of the C compiler executable.
+ * CFLAGS - C compiler flags.
+ * EXTRA_CFLAGS - Extra C compiler flags.
+ */
+
+#ifndef H_CHAZ_BUILDENV
+#define H_CHAZ_BUILDENV
+
+#include <stdio.h>
+
+/* Run the BuildEnv module.
+ */
+void chaz_BuildEnv_run(void);
+
+#endif /* H_CHAZ_BUILDENV */
+
+
+
+
+/***************************************************************************/
+
 #line 21 "src/Charmonizer/Probe/DirManip.h"
 /* Charmonizer/Probe/DirManip.h
  */
@@ -990,7 +1095,8 @@ chaz_CC_detect_known_compilers(void);
 /* Static vars. */
 static struct {
     char     *cc_command;
-    char     *cc_flags;
+    char     *cflags;
+    char     *extra_cflags;
     char     *try_exe_name;
     char     *try_obj_name;
     char      include_flag[10];
@@ -998,21 +1104,24 @@ static struct {
     char      exe_flag[10];
     char      no_link_flag[10];
     char      error_flag[10];
-    int       defines___GNUC__;
-    int       defines__MSC_VER;
-    int       defines___clang__;
+    char      gcc_version_str[30];
+    int       intval___GNUC__;
+    int       intval___GNUC_MINOR__;
+    int       intval___GNUC_PATCHLEVEL__;
+    int       intval__MSC_VER;
+    int       intval___clang__;
     int       warnings_as_errors;
 } chaz_CC = {
     NULL, NULL, NULL, NULL,
-    "", "", "", "", "",
-    0, 0, 0, 0
+    "", "", "", "", "", "",
+    0, 0, 0, 0, 0, 0
 };
 
 void
 chaz_CC_set_warnings_as_errors(const int flag) {
     chaz_CC.warnings_as_errors = flag;
     if (chaz_CC.warnings_as_errors) {
-        if (chaz_CC.defines__MSC_VER)  {
+        if (chaz_CC.intval__MSC_VER)  {
             strcpy(chaz_CC.error_flag, "/WX");
         } else {
             strcpy(chaz_CC.error_flag, "-Werror");
@@ -1030,9 +1139,10 @@ chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
 
     if (chaz_Util_verbosity) { printf("Creating compiler object...\n"); }
 
-    /* Assign. */
+    /* Assign, init. */
     chaz_CC.cc_command      = chaz_Util_strdup(compiler_command);
-    chaz_CC.cc_flags        = chaz_Util_strdup(compiler_flags);
+    chaz_CC.cflags          = chaz_Util_strdup(compiler_flags);
+    chaz_CC.extra_cflags    = chaz_Util_strdup("");
 
     /* Set names for the targets which we "try" to compile. */
     {
@@ -1071,36 +1181,56 @@ chaz_CC_init(const char *compiler_command, const char *compiler_flags) {
     chaz_CC_detect_known_compilers();
 }
 
-static const char detect_macro_code[] =
+static const char chaz_CC_detect_macro_code[] =
+    CHAZ_QUOTE(  #include <stdio.h>             )
     CHAZ_QUOTE(  int main() {                   )
     CHAZ_QUOTE(  #ifndef %s                     )
     CHAZ_QUOTE(  #error "nope"                  )
     CHAZ_QUOTE(  #endif                         )
+    CHAZ_QUOTE(      printf("%%d", %s);         )
     CHAZ_QUOTE(      return 0;                  )
     CHAZ_QUOTE(  }                              );
 
 static int
 chaz_CC_detect_macro(const char *macro) {
-    size_t size = sizeof(detect_macro_code) + strlen(macro) + 20;
+    size_t size = sizeof(chaz_CC_detect_macro_code)
+                  + (strlen(macro) * 2)
+                  + 20;
     char *code = (char*)malloc(size);
-    int retval;
-    sprintf(code, detect_macro_code, macro);
-    retval = chaz_CC_test_compile(code);
+    int retval = 0;
+    char *output;
+    size_t len;
+    sprintf(code, chaz_CC_detect_macro_code, macro, macro);
+    output = chaz_CC_capture_output(code, &len);
+    if (output) {
+        retval = atoi(output);
+        free(output);
+    }
     free(code);
     return retval;
 }
 
 static void
 chaz_CC_detect_known_compilers(void) {
-    chaz_CC.defines___GNUC__  = chaz_CC_detect_macro("__GNUC__");
-    chaz_CC.defines__MSC_VER  = chaz_CC_detect_macro("_MSC_VER");
-    chaz_CC.defines___clang__ = chaz_CC_detect_macro("__clang__");
+    chaz_CC.intval___GNUC__  = chaz_CC_detect_macro("__GNUC__");
+    if (chaz_CC.intval___GNUC__) {
+        chaz_CC.intval___GNUC_MINOR__
+            = chaz_CC_detect_macro("__GNUC_MINOR__");
+        chaz_CC.intval___GNUC_PATCHLEVEL__
+            = chaz_CC_detect_macro("__GNUC_PATCHLEVEL__");
+        sprintf(chaz_CC.gcc_version_str, "%d.%d.%d", chaz_CC.intval___GNUC__,
+                chaz_CC.intval___GNUC_MINOR__,
+                chaz_CC.intval___GNUC_PATCHLEVEL__);
+    }
+    chaz_CC.intval__MSC_VER  = chaz_CC_detect_macro("_MSC_VER");
+    chaz_CC.intval___clang__ = chaz_CC_detect_macro("__clang__");
 }
 
 void
 chaz_CC_clean_up(void) {
     free(chaz_CC.cc_command);
-    free(chaz_CC.cc_flags);
+    free(chaz_CC.cflags);
+    free(chaz_CC.extra_cflags);
     free(chaz_CC.try_obj_name);
     free(chaz_CC.try_exe_name);
 }
@@ -1119,7 +1249,8 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
                                  + strlen(source_path)
                                  + strlen(chaz_CC.exe_flag)
                                  + exe_file_buf_len
-                                 + strlen(chaz_CC.cc_flags)
+                                 + strlen(chaz_CC.cflags)
+                                 + strlen(chaz_CC.extra_cflags)
                                  + 200; /* command start, _charm_run, etc.  */
     char *command = (char*)malloc(command_max_size);
     int result;
@@ -1128,11 +1259,11 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
     chaz_Util_write_file(source_path, code);
 
     /* Prepare and run the compiler command. */
-    sprintf(command, "%s %s %s %s%s %s",
+    sprintf(command, "%s %s %s %s%s %s %s",
             chaz_CC.cc_command, chaz_CC.error_flag, 
             source_path, chaz_CC.exe_flag, 
             exe_file,
-            chaz_CC.cc_flags);
+            chaz_CC.cflags, chaz_CC.extra_cflags);
     if (chaz_Util_verbosity < 2) {
         chaz_OS_run_quietly(command);
     }
@@ -1140,7 +1271,7 @@ chaz_CC_compile_exe(const char *source_path, const char *exe_name,
         system(command);
     }
 
-    if (chaz_CC.defines__MSC_VER) {
+    if (chaz_CC.intval__MSC_VER) {
         /* Zap MSVC junk. */
         sprintf(junk, "%s.obj", exe_name);
         chaz_Util_remove_and_verify(junk);
@@ -1175,7 +1306,8 @@ chaz_CC_compile_obj(const char *source_path, const char *obj_name,
                                  + strlen(source_path)
                                  + strlen(chaz_CC.object_flag)
                                  + obj_file_buf_len
-                                 + strlen(chaz_CC.cc_flags)
+                                 + strlen(chaz_CC.cflags)
+                                 + strlen(chaz_CC.extra_cflags)
                                  + 200; /* command start, _charm_run, etc.  */
     char *command = (char*)malloc(command_max_size);
     int result;
@@ -1184,11 +1316,11 @@ chaz_CC_compile_obj(const char *source_path, const char *obj_name,
     chaz_Util_write_file(source_path, code);
 
     /* Prepare and run the compiler command. */
-    sprintf(command, "%s %s %s %s %s%s %s",
+    sprintf(command, "%s %s %s %s %s%s %s %s",
             chaz_CC.cc_command, chaz_CC.no_link_flag, chaz_CC.error_flag,
             source_path, chaz_CC.object_flag, 
             obj_file,
-            chaz_CC.cc_flags);
+            chaz_CC.cflags, chaz_CC.extra_cflags);
     if (chaz_Util_verbosity < 2) {
         chaz_OS_run_quietly(command);
     }
@@ -1253,6 +1385,56 @@ chaz_CC_capture_output(const char *source, size_t *output_len) {
     return captured_output;
 }
 
+void
+chaz_CC_add_extra_cflags(const char *flags) {
+    if (!strlen(chaz_CC.extra_cflags)) {
+        free(chaz_CC.extra_cflags);
+        chaz_CC.extra_cflags = chaz_Util_strdup(flags);
+    }
+    else {
+        size_t size = strlen(chaz_CC.extra_cflags)
+                      + 1   // Space separation
+                      + strlen(flags)
+                      + 1;  // NULL termination
+        char *newflags = (char*)malloc(size);
+        sprintf(newflags, "%s %s", chaz_CC.extra_cflags, flags);
+        free(chaz_CC.extra_cflags);
+        chaz_CC.extra_cflags = newflags;
+    }
+}
+
+const char*
+chaz_CC_get_cc(void) {
+    return chaz_CC.cc_command;
+}
+
+const char*
+chaz_CC_get_cflags(void) {
+    return chaz_CC.cflags;
+}
+
+const char*
+chaz_CC_get_extra_cflags(void) {
+    return chaz_CC.extra_cflags;
+}
+
+int
+chaz_CC_gcc_version_num(void) {
+    return 10000 * chaz_CC.intval___GNUC__
+           + 100 * chaz_CC.intval___GNUC_MINOR__
+           + chaz_CC.intval___GNUC_PATCHLEVEL__;
+}
+
+const char*
+chaz_CC_gcc_version(void) {
+    return chaz_CC.intval___GNUC__ ? chaz_CC.gcc_version_str : NULL;
+}
+
+int
+chaz_CC_compiler_is_msvc(void) {
+    return !!chaz_CC.intval__MSC_VER;
+}
+
 
 /***************************************************************************/
 
@@ -2702,24 +2884,123 @@ chaz_Util_can_open_file(const char *file_path) {
 /* #include "Charmonizer/Probe.h" */
 /* #include "Charmonizer/Core/HeaderChecker.h" */
 /* #include "Charmonizer/Core/ConfWriter.h" */
+/* #include "Charmonizer/Core/ConfWriterC.h" */
+/* #include "Charmonizer/Core/ConfWriterPerl.h" */
+/* #include "Charmonizer/Core/ConfWriterRuby.h" */
 /* #include "Charmonizer/Core/Util.h" */
 /* #include "Charmonizer/Core/Compiler.h" */
 /* #include "Charmonizer/Core/OperatingSystem.h" */
 
+int
+chaz_Probe_parse_cli_args(int argc, const char *argv[],
+                          struct chaz_CLIArgs *args) {
+    int i;
+    int output_enabled = 0;
+
+    /* Zero out args struct. */
+    memset(args, 0, sizeof(struct chaz_CLIArgs));
+
+    /* Parse most args. */
+    for (i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (strcmp(arg, "--") == 0) {
+            /* From here on out, everything will be a compiler flag. */
+            i++;
+            break;
+        }
+        if (strcmp(arg, "--enable-c") == 0) {
+            args->charmony_h = 1;
+            output_enabled = 1;
+        }
+        else if (strcmp(arg, "--enable-perl") == 0) {
+            args->charmony_pm = 1;
+            output_enabled = 1;
+        }
+        else if (strcmp(arg, "--enable-ruby") == 0) {
+            args->charmony_rb = 1;
+            output_enabled = 1;
+        }
+        else if (memcmp(arg, "--cc=", 5) == 0) {
+            if (strlen(arg) > CHAZ_PROBE_MAX_CC_LEN - 5) {
+                fprintf(stderr, "Exceeded max length for compiler command");
+                exit(1);
+            }
+            strcpy(args->cc, arg + 5);
+        }
+    } /* preserve value of i */
+
+    /* Accumulate compiler flags. */
+    for (; i < argc; i++) {
+        const char *arg = argv[i];
+        size_t new_len = strlen(arg) + strlen(args->cflags) + 2;
+        if (new_len >= CHAZ_PROBE_MAX_CFLAGS_LEN) {
+            fprintf(stderr, "Exceeded max length for compiler flags");
+            exit(1);
+        }
+        strcat(args->cflags, " ");
+        strcat(args->cflags, arg);
+    }
+
+    /* Process CHARM_VERBOSITY environment variable. */
+    {
+        const char *verbosity_env = getenv("CHARM_VERBOSITY");
+        if (verbosity_env && strlen(verbosity_env)) {
+            args->verbosity = strtol(verbosity_env, NULL, 10);
+        }
+    }
+
+    /* Validate. */
+    if (!strlen(args->cc) || !output_enabled) {
+        return false;
+    }
+
+    return true;
+}
+
 void
-chaz_Probe_init(const char *cc_command, const char *cc_flags) {
-    /* Proces CHARM_VERBOSITY environment variable. */
-    const char *verbosity_env = getenv("CHARM_VERBOSITY");
-    if (verbosity_env && strlen(verbosity_env)) {
-        chaz_Util_verbosity = strtol(verbosity_env, NULL, 10);
+chaz_Probe_die_usage(void) {
+    fprintf(stderr,
+            "Usage: ./charmonize --cc=CC_COMMAND [--enable-c] "
+            "[--enable-perl] [--enable-ruby] -- CFLAGS\n");
+    exit(1);
+}
+
+void
+chaz_Probe_init(struct chaz_CLIArgs *args) {
+    int output_enabled = 0;
+
+    {
+        /* Process CHARM_VERBOSITY environment variable. */
+        const char *verbosity_env = getenv("CHARM_VERBOSITY");
+        if (verbosity_env && strlen(verbosity_env)) {
+            chaz_Util_verbosity = strtol(verbosity_env, NULL, 10);
+        }
     }
 
     /* Dispatch other initializers. */
     chaz_OS_init();
-    chaz_CC_init(cc_command, cc_flags);
+    chaz_CC_init(args->cc, args->cflags);
     chaz_ConfWriter_init();
     chaz_HeadCheck_init();
 
+    /* Enable output. */
+    if (args->charmony_h) {
+        chaz_ConfWriterC_enable();
+        output_enabled = true;
+    }
+    if (args->charmony_pm) {
+        chaz_ConfWriterPerl_enable();
+        output_enabled = true;
+    }
+    if (args->charmony_rb) {
+        chaz_ConfWriterRuby_enable();
+        output_enabled = true;
+    }
+    if (!output_enabled) {
+        fprintf(stderr, "No output formats enabled\n");
+        exit(1);
+    }
+
     if (chaz_Util_verbosity) { printf("Initialization complete.\n"); }
 }
 
@@ -2734,6 +3015,20 @@ chaz_Probe_clean_up(void) {
     if (chaz_Util_verbosity) { printf("Cleanup complete.\n"); }
 }
 
+int
+chaz_Probe_gcc_version_num(void) {
+    return chaz_CC_gcc_version_num();
+}
+
+const char*
+chaz_Probe_gcc_version(void) {
+    return chaz_CC_gcc_version_num() ? chaz_CC_gcc_version() : NULL;
+}
+
+int
+chaz_Probe_compiler_is_msvc(void) {
+    return chaz_CC_compiler_is_msvc();
+}
 
 /***************************************************************************/
 
@@ -2828,6 +3123,26 @@ chaz_Booleans_run(void) {
 
 /***************************************************************************/
 
+#line 17 "src/Charmonizer/Probe/BuildEnv.c"
+/* #include "Charmonizer/Core/HeaderChecker.h" */
+/* #include "Charmonizer/Core/ConfWriter.h" */
+/* #include "Charmonizer/Probe/BuildEnv.h" */
+
+void
+chaz_BuildEnv_run(void) {
+    chaz_ConfWriter_start_module("BuildEnv");
+
+    chaz_ConfWriter_add_def("CC", chaz_CC_get_cc());
+    chaz_ConfWriter_add_def("CFLAGS", chaz_CC_get_cflags());
+    chaz_ConfWriter_add_def("EXTRA_CFLAGS", chaz_CC_get_extra_cflags());
+
+    chaz_ConfWriter_end_module();
+}
+
+
+
+/***************************************************************************/
+
 #line 17 "src/Charmonizer/Probe/DirManip.c"
 /* #include "Charmonizer/Core/ConfWriter.h" */
 /* #include "Charmonizer/Core/Compiler.h" */
@@ -4455,94 +4770,45 @@ chaz_VariadicMacros_run(void) {
 /* #include "Charmonizer/Core/ConfWriterPerl.h" */
 /* #include "Charmonizer/Core/ConfWriterRuby.h" */
 
-#define MAX_CC_LEN 128
-#define MAX_FLAGS_LEN 2048
-
-struct CLIArgs {
-    char cc_command[MAX_CC_LEN + 1];
-    char cc_flags[MAX_FLAGS_LEN + 1];
-    int  enable_c;
-    int  enable_perl;
-    int  enable_ruby;
-};
-
-/* Parse command line arguments. */
 static void
-S_parse_arguments(int argc, char **argv, struct CLIArgs *args) {
-    int i;
-    int output_enabled = 0;
-
-    /* Parse most args. */
-    for (i = 1; i < argc; i++) {
-        char *arg = argv[i];
-        if (strcmp(arg, "--") == 0) {
-            /* From here on out, everything will be a compiler flag. */
-            i++;
-            break;
-        }
-        if (strcmp(arg, "--enable-c") == 0) {
-            args->enable_c = 1;
-            output_enabled = 1;
-        }
-        else if (strcmp(arg, "--enable-perl") == 0) {
-            args->enable_perl = 1;
-            output_enabled = 1;
-        }
-        else if (strcmp(arg, "--enable-ruby") == 0) {
-            args->enable_ruby = 1;
-            output_enabled = 1;
-        }
-        else if (memcmp(arg, "--cc=", 5) == 0) {
-            if (strlen(arg) > MAX_CC_LEN - 5) {
-                fprintf(stderr, "Exceeded max length for compiler command");
-                exit(1);
-            }
-            strcpy(args->cc_command, arg + 5);
+S_add_compiler_flags(struct chaz_CLIArgs *args) {
+    if (chaz_Probe_gcc_version_num()) {
+        if (getenv("LUCY_VALGRIND")) {
+            chaz_CC_add_extra_cflags("-DLUCY_VALGRIND -fno-inline-functions");
         }
-    }
-
-    /* Accumulate compiler flags. */
-    for (; i < argc; i++) {
-        char *arg = argv[i];
-        if (strlen(arg) + strlen(args->cc_flags) + 2 >= MAX_FLAGS_LEN) {
-            fprintf(stderr, "Exceeded max length for compiler flags");
-            exit(1);
+        else if (getenv("LUCY_DEBUG")) {
+            chaz_CC_add_extra_cflags(
+                "-DLUCY_DEBUG -pedantic -Wall -Wextra "
+                "-Wno-variadic-macros "
+            );
         }
-        strcat(args->cc_flags, " ");
-        strcat(args->cc_flags, arg);
-
     }
-
-    /* Validate. */
-    if (!args->cc_command
-        || !strlen(args->cc_command)
-        || !output_enabled
-       ) {
-        fprintf(stderr,
-                "Usage: ./charmonize --cc=CC_COMMAND [--enable-c] "
-                "[--enable-perl] [--enable-ruby] -- CC_FLAGS\n");
-        exit(1);
-    }
-
 }
 
-int main(int argc, char **argv) {
-    struct CLIArgs args;
-    memset(&args, 0, sizeof(struct CLIArgs));
+int main(int argc, const char **argv) {
+    /* Initialize. */
+    {
+        struct chaz_CLIArgs args;
+        int result = chaz_Probe_parse_cli_args(argc, argv, &args);
+        if (!result) {
+            chaz_Probe_die_usage();
+        }
+        chaz_Probe_init(&args);
+        S_add_compiler_flags(&args);
 
-    S_parse_arguments(argc, argv, &args);
-    chaz_Probe_init(args.cc_command, args.cc_flags);
-    if (args.enable_c) {
-        chaz_ConfWriterC_enable();
     }
-    if (args.enable_perl) {
-        chaz_ConfWriterPerl_enable();
-    }
-    if (args.enable_ruby) {
-        chaz_ConfWriterRuby_enable();
+    {
+        int i;
+        for (i = 0; i < argc; i++) {
+            if (strncmp(argv[i], "--disable-threads", 17) == 0) {
+                chaz_CC_add_extra_cflags("-DLUCY_NOTHREADS");
+                break;
+            }
+        }
     }
 
     /* Run probe modules. */
+    chaz_BuildEnv_run();
     chaz_DirManip_run();
     chaz_Headers_run();
     chaz_AtomicOps_run();