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

[lucy-commits] [1/3] git commit: refs/heads/master - Rework creation of Makefile clean rules

Updated Branches:
  refs/heads/master 17ff1b7ef -> a879c1629


Rework creation of Makefile clean rules

This allows to add custom commands to clean rules.


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

Branch: refs/heads/master
Commit: bf138d93f86cfd945bcbf2a611a11fd674d3fd29
Parents: 17ff1b7
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Wed May 1 18:14:58 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Wed May 1 18:14:58 2013 +0200

----------------------------------------------------------------------
 charmonizer/src/Charmonizer/Core/Make.c    |  226 +++++++++++------------
 charmonizer/src/Charmonizer/Core/Make.h    |   32 +++-
 clownfish/compiler/common/charmonizer.main |   21 ++-
 common/charmonizer.main                    |   21 ++-
 4 files changed, 158 insertions(+), 142 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/bf138d93/charmonizer/src/Charmonizer/Core/Make.c
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/Make.c b/charmonizer/src/Charmonizer/Core/Make.c
index 73ba316..eef026f 100644
--- a/charmonizer/src/Charmonizer/Core/Make.c
+++ b/charmonizer/src/Charmonizer/Core/Make.c
@@ -38,10 +38,8 @@ struct chaz_MakeFile {
     size_t          num_vars;
     chaz_MakeRule **rules;
     size_t          num_rules;
-    char          **cleanup_files;
-    size_t          num_cleanup_files;
-    char          **cleanup_dirs;
-    size_t          num_cleanup_dirs;
+    chaz_MakeRule  *clean;
+    chaz_MakeRule  *distclean;
 };
 
 /* Static vars. */
@@ -71,6 +69,15 @@ chaz_Make_detect(const char *make1, ...);
 static int
 chaz_Make_audition(const char *make);
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq);
+
+static void
+S_destroy_rule(chaz_MakeRule *rule);
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out);
+
 void
 chaz_Make_init(void) {
     const char *make;
@@ -157,13 +164,12 @@ chaz_MakeFile_new() {
     makefile->rules[0] = NULL;
     makefile->num_rules = 0;
 
-    makefile->cleanup_files = (char**)malloc(sizeof(char*));
-    makefile->cleanup_files[0] = NULL;
-    makefile->num_cleanup_files = 0;
+    makefile->clean     = S_new_rule("clean", NULL);
+    makefile->distclean = S_new_rule("distclean", "clean");
 
-    makefile->cleanup_dirs = (char**)malloc(sizeof(char*));
-    makefile->cleanup_dirs[0] = NULL;
-    makefile->num_cleanup_dirs = 0;
+    chaz_MakeRule_add_rm_command(makefile->distclean,
+                                 "charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
+                                 " charmony.h Makefile");
 
     return makefile;
 }
@@ -181,23 +187,12 @@ chaz_MakeFile_destroy(chaz_MakeFile *makefile) {
     free(makefile->vars);
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        if (rule->targets)  { free(rule->targets); }
-        if (rule->prereqs)  { free(rule->prereqs); }
-        if (rule->commands) { free(rule->commands); }
-        free(rule);
+        S_destroy_rule(makefile->rules[i]);
     }
     free(makefile->rules);
 
-    for (i = 0; makefile->cleanup_files[i]; i++) {
-        free(makefile->cleanup_files[i]);
-    }
-    free(makefile->cleanup_files);
-
-    for (i = 0; makefile->cleanup_dirs[i]; i++) {
-        free(makefile->cleanup_dirs[i]);
-    }
-    free(makefile->cleanup_dirs);
+    S_destroy_rule(makefile->clean);
+    S_destroy_rule(makefile->distclean);
 
     free(makefile);
 }
@@ -228,17 +223,10 @@ chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name,
 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  *rule      = S_new_rule(target, prereq);
     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;
@@ -249,28 +237,14 @@ chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
     return rule;
 }
 
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target) {
-    char   **files     = makefile->cleanup_files;
-    size_t   num_files = makefile->num_cleanup_files + 1;
-
-    files = (char**)realloc(files, (num_files + 1) * sizeof(char*));
-    files[num_files-1] = chaz_Util_strdup(target);
-    files[num_files]   = NULL;
-    makefile->cleanup_files     = files;
-    makefile->num_cleanup_files = num_files;
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile) {
+    return makefile->clean;
 }
 
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir) {
-    char   **dirs     = makefile->cleanup_dirs;
-    size_t   num_dirs = makefile->num_cleanup_dirs + 1;
-
-    dirs = (char**)realloc(dirs, (num_dirs + 1) * sizeof(char*));
-    dirs[num_dirs-1] = chaz_Util_strdup(dir);
-    dirs[num_dirs]   = NULL;
-    makefile->cleanup_dirs     = dirs;
-    makefile->num_cleanup_dirs = num_dirs;
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile) {
+    return makefile->distclean;
 }
 
 chaz_MakeRule*
@@ -295,7 +269,7 @@ chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -324,7 +298,8 @@ chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
+    /* TODO: Clean .obj file on Windows. */
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -356,7 +331,7 @@ chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, const char *name,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, shared_lib);
+    chaz_MakeRule_add_rm_command(makefile->clean, shared_lib);
 
     chaz_CFlags_destroy(local_flags);
     free(shared_lib);
@@ -382,69 +357,11 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) {
     fprintf(out, "\n");
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        fprintf(out, "%s :", rule->targets);
-        if (rule->prereqs) {
-            fprintf(out, " %s", rule->prereqs);
-        }
-        fprintf(out, "\n");
-        if (rule->commands) {
-            fprintf(out, "%s", rule->commands);
-        }
-        fprintf(out, "\n");
-    }
-
-    if (makefile->cleanup_files[0] || makefile->cleanup_dirs[0]) {
-        fprintf(out, "clean :\n");
-        if (shell_type == CHAZ_OS_POSIX) {
-            if (makefile->cleanup_files[0]) {
-                fprintf(out, "\trm -f");
-                for (i = 0; makefile->cleanup_files[i]; i++) {
-                    const char *file = makefile->cleanup_files[i];
-                    fprintf(out, " \\\n\t    %s", file);
-                }
-                fprintf(out, "\n");
-            }
-            if (makefile->cleanup_dirs[0]) {
-                fprintf(out, "\trm -rf");
-                for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                    const char *dir = makefile->cleanup_dirs[i];
-                    fprintf(out, " \\\n\t    %s", dir);
-                }
-                fprintf(out, "\n");
-            }
-        }
-        else if (shell_type == CHAZ_OS_CMD_EXE) {
-            for (i = 0; makefile->cleanup_files[i]; i++) {
-                const char *file = makefile->cleanup_files[i];
-                fprintf(out, "\tfor %%i in (%s) do @if exist %%i del /f %%i\n",
-                        file);
-            }
-            for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                const char *dir = makefile->cleanup_dirs[i];
-                fprintf(out,
-                        "\tfor %%i in (%s) do @if exist %%i rmdir /s /q %%i\n",
-                        dir);
-            }
-        }
-        else {
-            chaz_Util_die("Unsupported shell type: %d", shell_type);
-        }
-        fprintf(out, "\n");
+        S_write_rule(makefile->rules[i], out);
     }
 
-    fprintf(out, "distclean : clean\n");
-    if (shell_type == CHAZ_OS_POSIX) {
-        fprintf(out, "\trm -f charmonizer$(EXE_EXT) charmony.h Makefile\n\n");
-    }
-    else if (shell_type == CHAZ_OS_CMD_EXE) {
-        fprintf(out,
-            "\tfor %%i in (charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
-            " charmony.h Makefile) do @if exist %%i del /f %%i\n\n");
-    }
-    else {
-        chaz_Util_die("Unsupported shell type: %d", shell_type);
-    }
+    S_write_rule(makefile->clean, out);
+    S_write_rule(makefile->distclean, out);
 
     if (chaz_Make.is_nmake) {
         /* Inference rule for .c files. */
@@ -485,6 +402,41 @@ chaz_MakeVar_append(chaz_MakeVar *var, const char *element) {
     var->num_elements++;
 }
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq) {
+    chaz_MakeRule *rule = (chaz_MakeRule*)malloc(sizeof(chaz_MakeRule));
+
+    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); }
+
+    return rule;
+}
+
+static void
+S_destroy_rule(chaz_MakeRule *rule) {
+    if (rule->targets)  { free(rule->targets); }
+    if (rule->prereqs)  { free(rule->prereqs); }
+    if (rule->commands) { free(rule->commands); }
+    free(rule);
+}
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out) {
+    fprintf(out, "%s :", rule->targets);
+    if (rule->prereqs) {
+        fprintf(out, " %s", rule->prereqs);
+    }
+    fprintf(out, "\n");
+    if (rule->commands) {
+        fprintf(out, "%s", rule->commands);
+    }
+    fprintf(out, "\n");
+}
+
 void
 chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target) {
     char *targets;
@@ -533,7 +485,47 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command) {
 }
 
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -f", files, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", files,
+                                 ") do @if exist %i del /f %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -rf", dirs, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", dirs,
+                                 ") do @if exist %i rmdir /s /q %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target) {
     char *command;
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/bf138d93/charmonizer/src/Charmonizer/Core/Make.h
----------------------------------------------------------------------
diff --git a/charmonizer/src/Charmonizer/Core/Make.h b/charmonizer/src/Charmonizer/Core/Make.h
index 47a55c5..97cae84 100644
--- a/charmonizer/src/Charmonizer/Core/Make.h
+++ b/charmonizer/src/Charmonizer/Core/Make.h
@@ -94,21 +94,19 @@ chaz_MakeRule*
 chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
                        const char *prereq);
 
-/** Add a file to the 'clean' target.
+/** Return the rule for the 'clean' target.
  *
  * @param makefile The makefile.
- * @param target The filename.
  */
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target);
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile);
 
-/** Add a directory to the 'clean' target.
+/** Return the rule for the 'distclean' target.
  *
  * @param makefile The makefile.
- * @param dir The directory.
  */
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir);
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile);
 
 /** Add a rule to link an executable. The executable will also be added to the
  * list of files to clean.
@@ -186,6 +184,22 @@ chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq);
 void
 chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
 
+/** Add a command to remove one or more files.
+ *
+ * @param rule The rule.
+ * @param files The list of files.
+ */
+void
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files);
+
+/** Add a command to remove one or more directories.
+ *
+ * @param rule The rule.
+ * @param dirs The list of directories.
+ */
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs);
+
 /** Add one or more commands to call another makefile recursively.
  *
  * @param rule The rule.
@@ -193,7 +207,7 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
  * @param target The target to call. Pass NULL for the default target.
  */
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target);
 
 #ifdef __cplusplus

http://git-wip-us.apache.org/repos/asf/lucy/blob/bf138d93/clownfish/compiler/common/charmonizer.main
----------------------------------------------------------------------
diff --git a/clownfish/compiler/common/charmonizer.main b/clownfish/compiler/common/charmonizer.main
index e3f89d4..4234025 100644
--- a/clownfish/compiler/common/charmonizer.main
+++ b/clownfish/compiler/common/charmonizer.main
@@ -127,6 +127,7 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     chaz_MakeFile *makefile;
     chaz_MakeVar  *var;
     chaz_MakeRule *rule;
+    chaz_MakeRule *clean_rule;
 
     int          cflags_style = chaz_CC_get_cflags_style();
     chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags();
@@ -252,16 +253,20 @@ S_write_makefile(struct chaz_CLIArgs *args) {
                                   " --branch-coverage"
                                   " --output-directory coverage"
                                   " cfc.info");
-
-        chaz_MakeFile_add_to_cleanup(makefile, "cfc.info");
-        chaz_MakeFile_add_dir_to_cleanup(makefile, "coverage");
     }
 
-    chaz_MakeFile_add_to_cleanup(makefile, "$(COMMON_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, "$(CFC_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, "$(TEST_CFC_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, parse_header_h);
-    chaz_MakeFile_add_to_cleanup(makefile, parse_header_c);
+    clean_rule = chaz_MakeFile_clean_rule(makefile);
+
+    chaz_MakeRule_add_rm_command(clean_rule, "$(COMMON_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, "$(CFC_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, "$(TEST_CFC_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, parse_header_h);
+    chaz_MakeRule_add_rm_command(clean_rule, parse_header_c);
+
+    if (args->code_coverage) {
+        chaz_MakeRule_add_rm_command(clean_rule, "cfc.info");
+        chaz_MakeRule_add_recursive_rm_command(clean_rule, "coverage");
+    }
 
     chaz_MakeFile_write(makefile);
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/bf138d93/common/charmonizer.main
----------------------------------------------------------------------
diff --git a/common/charmonizer.main b/common/charmonizer.main
index 84f9400..41b41a6 100644
--- a/common/charmonizer.main
+++ b/common/charmonizer.main
@@ -152,6 +152,7 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     chaz_MakeFile *makefile;
     chaz_MakeVar  *var;
     chaz_MakeRule *rule;
+    chaz_MakeRule *clean_rule;
 
     int          cflags_style = chaz_CC_get_cflags_style();
     chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags();
@@ -291,7 +292,7 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     chaz_CFlags_destroy(lemon_cflags);
 
     rule = chaz_MakeFile_add_rule(makefile, "$(CFC_EXE)", NULL);
-    chaz_MakeRule_add_command_make(rule, "$(CFC_DIR)", NULL);
+    chaz_MakeRule_add_make_command(rule, "$(CFC_DIR)", NULL);
 
     rule = chaz_MakeFile_add_rule(makefile, "$(AUTOGEN_DIR)", "$(CFC_EXE)");
     chaz_MakeRule_add_command(rule, "$(CFC_EXE) --source=$(CORE_DIR) "
@@ -367,15 +368,19 @@ S_write_makefile(struct chaz_CLIArgs *args) {
                                   " --branch-coverage"
                                   " --output-directory coverage"
                                   " lucy.info");
-
-        chaz_MakeFile_add_to_cleanup(makefile, "lucy.info");
-        chaz_MakeFile_add_dir_to_cleanup(makefile, "coverage");
     }
 
-    chaz_MakeFile_add_to_cleanup(makefile, "$(LUCY_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, json_parser_h);
-    chaz_MakeFile_add_to_cleanup(makefile, json_parser_c);
-    chaz_MakeFile_add_dir_to_cleanup(makefile, "$(AUTOGEN_DIR)");
+    clean_rule = chaz_MakeFile_clean_rule(makefile);
+
+    chaz_MakeRule_add_rm_command(clean_rule, "$(LUCY_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, json_parser_h);
+    chaz_MakeRule_add_rm_command(clean_rule, json_parser_c);
+    chaz_MakeRule_add_recursive_rm_command(clean_rule, "$(AUTOGEN_DIR)");
+
+    if (args->code_coverage) {
+        chaz_MakeRule_add_rm_command(clean_rule, "lucy.info");
+        chaz_MakeRule_add_recursive_rm_command(clean_rule, "coverage");
+    }
 
     chaz_MakeFile_write(makefile);
 


[lucy-commits] [2/3] git commit: refs/heads/master - Clean CFC when cleaning C library

Posted by nw...@apache.org.
Clean CFC when cleaning C library


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

Branch: refs/heads/master
Commit: 9f7001c83bce817d7301c4198da5809939804c0f
Parents: bf138d9
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Wed May 1 18:22:22 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Wed May 1 18:22:22 2013 +0200

----------------------------------------------------------------------
 common/charmonizer.main |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/9f7001c8/common/charmonizer.main
----------------------------------------------------------------------
diff --git a/common/charmonizer.main b/common/charmonizer.main
index 41b41a6..040cad1 100644
--- a/common/charmonizer.main
+++ b/common/charmonizer.main
@@ -153,6 +153,7 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     chaz_MakeVar  *var;
     chaz_MakeRule *rule;
     chaz_MakeRule *clean_rule;
+    chaz_MakeRule *distclean_rule;
 
     int          cflags_style = chaz_CC_get_cflags_style();
     chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags();
@@ -382,6 +383,11 @@ S_write_makefile(struct chaz_CLIArgs *args) {
         chaz_MakeRule_add_recursive_rm_command(clean_rule, "coverage");
     }
 
+    chaz_MakeRule_add_make_command(clean_rule, "$(CFC_DIR)", "clean");
+
+    distclean_rule = chaz_MakeFile_distclean_rule(makefile);
+    chaz_MakeRule_add_make_command(distclean_rule, "$(CFC_DIR)", "distclean");
+
     chaz_MakeFile_write(makefile);
 
     chaz_MakeFile_destroy(makefile);


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

Posted by nw...@apache.org.
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/a879c162
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/a879c162
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/a879c162

Branch: refs/heads/master
Commit: a879c16298974a6079b88ef398bb5ecb2c9d347f
Parents: 9f7001c
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Wed May 1 18:23:09 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Wed May 1 18:23:09 2013 +0200

----------------------------------------------------------------------
 clownfish/compiler/common/charmonizer.c |  279 +++++++++++++------------
 clownfish/runtime/common/charmonizer.c  |  258 ++++++++++++------------
 common/charmonizer.c                    |  283 ++++++++++++++------------
 3 files changed, 427 insertions(+), 393 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/a879c162/clownfish/compiler/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/common/charmonizer.c b/clownfish/compiler/common/charmonizer.c
index 4af9ba4..4b8e834 100644
--- a/clownfish/compiler/common/charmonizer.c
+++ b/clownfish/compiler/common/charmonizer.c
@@ -487,21 +487,19 @@ chaz_MakeRule*
 chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
                        const char *prereq);
 
-/** Add a file to the 'clean' target.
+/** Return the rule for the 'clean' target.
  *
  * @param makefile The makefile.
- * @param target The filename.
  */
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target);
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile);
 
-/** Add a directory to the 'clean' target.
+/** Return the rule for the 'distclean' target.
  *
  * @param makefile The makefile.
- * @param dir The directory.
  */
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir);
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile);
 
 /** Add a rule to link an executable. The executable will also be added to the
  * list of files to clean.
@@ -579,6 +577,22 @@ chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq);
 void
 chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
 
+/** Add a command to remove one or more files.
+ *
+ * @param rule The rule.
+ * @param files The list of files.
+ */
+void
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files);
+
+/** Add a command to remove one or more directories.
+ *
+ * @param rule The rule.
+ * @param dirs The list of directories.
+ */
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs);
+
 /** Add one or more commands to call another makefile recursively.
  *
  * @param rule The rule.
@@ -586,7 +600,7 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
  * @param target The target to call. Pass NULL for the default target.
  */
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target);
 
 #endif /* H_CHAZ_MAKE */
@@ -2911,10 +2925,8 @@ struct chaz_MakeFile {
     size_t          num_vars;
     chaz_MakeRule **rules;
     size_t          num_rules;
-    char          **cleanup_files;
-    size_t          num_cleanup_files;
-    char          **cleanup_dirs;
-    size_t          num_cleanup_dirs;
+    chaz_MakeRule  *clean;
+    chaz_MakeRule  *distclean;
 };
 
 /* Static vars. */
@@ -2944,6 +2956,15 @@ chaz_Make_detect(const char *make1, ...);
 static int
 chaz_Make_audition(const char *make);
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq);
+
+static void
+S_destroy_rule(chaz_MakeRule *rule);
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out);
+
 void
 chaz_Make_init(void) {
     const char *make;
@@ -3030,13 +3051,12 @@ chaz_MakeFile_new() {
     makefile->rules[0] = NULL;
     makefile->num_rules = 0;
 
-    makefile->cleanup_files = (char**)malloc(sizeof(char*));
-    makefile->cleanup_files[0] = NULL;
-    makefile->num_cleanup_files = 0;
+    makefile->clean     = S_new_rule("clean", NULL);
+    makefile->distclean = S_new_rule("distclean", "clean");
 
-    makefile->cleanup_dirs = (char**)malloc(sizeof(char*));
-    makefile->cleanup_dirs[0] = NULL;
-    makefile->num_cleanup_dirs = 0;
+    chaz_MakeRule_add_rm_command(makefile->distclean,
+                                 "charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
+                                 " charmony.h Makefile");
 
     return makefile;
 }
@@ -3054,23 +3074,12 @@ chaz_MakeFile_destroy(chaz_MakeFile *makefile) {
     free(makefile->vars);
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        if (rule->targets)  { free(rule->targets); }
-        if (rule->prereqs)  { free(rule->prereqs); }
-        if (rule->commands) { free(rule->commands); }
-        free(rule);
+        S_destroy_rule(makefile->rules[i]);
     }
     free(makefile->rules);
 
-    for (i = 0; makefile->cleanup_files[i]; i++) {
-        free(makefile->cleanup_files[i]);
-    }
-    free(makefile->cleanup_files);
-
-    for (i = 0; makefile->cleanup_dirs[i]; i++) {
-        free(makefile->cleanup_dirs[i]);
-    }
-    free(makefile->cleanup_dirs);
+    S_destroy_rule(makefile->clean);
+    S_destroy_rule(makefile->distclean);
 
     free(makefile);
 }
@@ -3101,17 +3110,10 @@ chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name,
 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  *rule      = S_new_rule(target, prereq);
     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;
@@ -3122,28 +3124,14 @@ chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
     return rule;
 }
 
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target) {
-    char   **files     = makefile->cleanup_files;
-    size_t   num_files = makefile->num_cleanup_files + 1;
-
-    files = (char**)realloc(files, (num_files + 1) * sizeof(char*));
-    files[num_files-1] = chaz_Util_strdup(target);
-    files[num_files]   = NULL;
-    makefile->cleanup_files     = files;
-    makefile->num_cleanup_files = num_files;
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile) {
+    return makefile->clean;
 }
 
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir) {
-    char   **dirs     = makefile->cleanup_dirs;
-    size_t   num_dirs = makefile->num_cleanup_dirs + 1;
-
-    dirs = (char**)realloc(dirs, (num_dirs + 1) * sizeof(char*));
-    dirs[num_dirs-1] = chaz_Util_strdup(dir);
-    dirs[num_dirs]   = NULL;
-    makefile->cleanup_dirs     = dirs;
-    makefile->num_cleanup_dirs = num_dirs;
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile) {
+    return makefile->distclean;
 }
 
 chaz_MakeRule*
@@ -3168,7 +3156,7 @@ chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -3197,7 +3185,8 @@ chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
+    /* TODO: Clean .obj file on Windows. */
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -3229,7 +3218,7 @@ chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, const char *name,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, shared_lib);
+    chaz_MakeRule_add_rm_command(makefile->clean, shared_lib);
 
     chaz_CFlags_destroy(local_flags);
     free(shared_lib);
@@ -3255,69 +3244,11 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) {
     fprintf(out, "\n");
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        fprintf(out, "%s :", rule->targets);
-        if (rule->prereqs) {
-            fprintf(out, " %s", rule->prereqs);
-        }
-        fprintf(out, "\n");
-        if (rule->commands) {
-            fprintf(out, "%s", rule->commands);
-        }
-        fprintf(out, "\n");
-    }
-
-    if (makefile->cleanup_files[0] || makefile->cleanup_dirs[0]) {
-        fprintf(out, "clean :\n");
-        if (shell_type == CHAZ_OS_POSIX) {
-            if (makefile->cleanup_files[0]) {
-                fprintf(out, "\trm -f");
-                for (i = 0; makefile->cleanup_files[i]; i++) {
-                    const char *file = makefile->cleanup_files[i];
-                    fprintf(out, " \\\n\t    %s", file);
-                }
-                fprintf(out, "\n");
-            }
-            if (makefile->cleanup_dirs[0]) {
-                fprintf(out, "\trm -rf");
-                for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                    const char *dir = makefile->cleanup_dirs[i];
-                    fprintf(out, " \\\n\t    %s", dir);
-                }
-                fprintf(out, "\n");
-            }
-        }
-        else if (shell_type == CHAZ_OS_CMD_EXE) {
-            for (i = 0; makefile->cleanup_files[i]; i++) {
-                const char *file = makefile->cleanup_files[i];
-                fprintf(out, "\tfor %%i in (%s) do @if exist %%i del /f %%i\n",
-                        file);
-            }
-            for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                const char *dir = makefile->cleanup_dirs[i];
-                fprintf(out,
-                        "\tfor %%i in (%s) do @if exist %%i rmdir /s /q %%i\n",
-                        dir);
-            }
-        }
-        else {
-            chaz_Util_die("Unsupported shell type: %d", shell_type);
-        }
-        fprintf(out, "\n");
+        S_write_rule(makefile->rules[i], out);
     }
 
-    fprintf(out, "distclean : clean\n");
-    if (shell_type == CHAZ_OS_POSIX) {
-        fprintf(out, "\trm -f charmonizer$(EXE_EXT) charmony.h Makefile\n\n");
-    }
-    else if (shell_type == CHAZ_OS_CMD_EXE) {
-        fprintf(out,
-            "\tfor %%i in (charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
-            " charmony.h Makefile) do @if exist %%i del /f %%i\n\n");
-    }
-    else {
-        chaz_Util_die("Unsupported shell type: %d", shell_type);
-    }
+    S_write_rule(makefile->clean, out);
+    S_write_rule(makefile->distclean, out);
 
     if (chaz_Make.is_nmake) {
         /* Inference rule for .c files. */
@@ -3358,6 +3289,41 @@ chaz_MakeVar_append(chaz_MakeVar *var, const char *element) {
     var->num_elements++;
 }
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq) {
+    chaz_MakeRule *rule = (chaz_MakeRule*)malloc(sizeof(chaz_MakeRule));
+
+    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); }
+
+    return rule;
+}
+
+static void
+S_destroy_rule(chaz_MakeRule *rule) {
+    if (rule->targets)  { free(rule->targets); }
+    if (rule->prereqs)  { free(rule->prereqs); }
+    if (rule->commands) { free(rule->commands); }
+    free(rule);
+}
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out) {
+    fprintf(out, "%s :", rule->targets);
+    if (rule->prereqs) {
+        fprintf(out, " %s", rule->prereqs);
+    }
+    fprintf(out, "\n");
+    if (rule->commands) {
+        fprintf(out, "%s", rule->commands);
+    }
+    fprintf(out, "\n");
+}
+
 void
 chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target) {
     char *targets;
@@ -3406,7 +3372,47 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command) {
 }
 
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -f", files, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", files,
+                                 ") do @if exist %i del /f %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -rf", dirs, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", dirs,
+                                 ") do @if exist %i rmdir /s /q %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target) {
     char *command;
 
@@ -5237,6 +5243,7 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     chaz_MakeFile *makefile;
     chaz_MakeVar  *var;
     chaz_MakeRule *rule;
+    chaz_MakeRule *clean_rule;
 
     int          cflags_style = chaz_CC_get_cflags_style();
     chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags();
@@ -5362,16 +5369,20 @@ S_write_makefile(struct chaz_CLIArgs *args) {
                                   " --branch-coverage"
                                   " --output-directory coverage"
                                   " cfc.info");
-
-        chaz_MakeFile_add_to_cleanup(makefile, "cfc.info");
-        chaz_MakeFile_add_dir_to_cleanup(makefile, "coverage");
     }
 
-    chaz_MakeFile_add_to_cleanup(makefile, "$(COMMON_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, "$(CFC_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, "$(TEST_CFC_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, parse_header_h);
-    chaz_MakeFile_add_to_cleanup(makefile, parse_header_c);
+    clean_rule = chaz_MakeFile_clean_rule(makefile);
+
+    chaz_MakeRule_add_rm_command(clean_rule, "$(COMMON_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, "$(CFC_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, "$(TEST_CFC_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, parse_header_h);
+    chaz_MakeRule_add_rm_command(clean_rule, parse_header_c);
+
+    if (args->code_coverage) {
+        chaz_MakeRule_add_rm_command(clean_rule, "cfc.info");
+        chaz_MakeRule_add_recursive_rm_command(clean_rule, "coverage");
+    }
 
     chaz_MakeFile_write(makefile);
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/a879c162/clownfish/runtime/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/clownfish/runtime/common/charmonizer.c b/clownfish/runtime/common/charmonizer.c
index 8850f95..b4d50eb 100644
--- a/clownfish/runtime/common/charmonizer.c
+++ b/clownfish/runtime/common/charmonizer.c
@@ -487,21 +487,19 @@ chaz_MakeRule*
 chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
                        const char *prereq);
 
-/** Add a file to the 'clean' target.
+/** Return the rule for the 'clean' target.
  *
  * @param makefile The makefile.
- * @param target The filename.
  */
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target);
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile);
 
-/** Add a directory to the 'clean' target.
+/** Return the rule for the 'distclean' target.
  *
  * @param makefile The makefile.
- * @param dir The directory.
  */
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir);
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile);
 
 /** Add a rule to link an executable. The executable will also be added to the
  * list of files to clean.
@@ -579,6 +577,22 @@ chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq);
 void
 chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
 
+/** Add a command to remove one or more files.
+ *
+ * @param rule The rule.
+ * @param files The list of files.
+ */
+void
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files);
+
+/** Add a command to remove one or more directories.
+ *
+ * @param rule The rule.
+ * @param dirs The list of directories.
+ */
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs);
+
 /** Add one or more commands to call another makefile recursively.
  *
  * @param rule The rule.
@@ -586,7 +600,7 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
  * @param target The target to call. Pass NULL for the default target.
  */
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target);
 
 #endif /* H_CHAZ_MAKE */
@@ -3190,10 +3204,8 @@ struct chaz_MakeFile {
     size_t          num_vars;
     chaz_MakeRule **rules;
     size_t          num_rules;
-    char          **cleanup_files;
-    size_t          num_cleanup_files;
-    char          **cleanup_dirs;
-    size_t          num_cleanup_dirs;
+    chaz_MakeRule  *clean;
+    chaz_MakeRule  *distclean;
 };
 
 /* Static vars. */
@@ -3223,6 +3235,15 @@ chaz_Make_detect(const char *make1, ...);
 static int
 chaz_Make_audition(const char *make);
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq);
+
+static void
+S_destroy_rule(chaz_MakeRule *rule);
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out);
+
 void
 chaz_Make_init(void) {
     const char *make;
@@ -3309,13 +3330,12 @@ chaz_MakeFile_new() {
     makefile->rules[0] = NULL;
     makefile->num_rules = 0;
 
-    makefile->cleanup_files = (char**)malloc(sizeof(char*));
-    makefile->cleanup_files[0] = NULL;
-    makefile->num_cleanup_files = 0;
+    makefile->clean     = S_new_rule("clean", NULL);
+    makefile->distclean = S_new_rule("distclean", "clean");
 
-    makefile->cleanup_dirs = (char**)malloc(sizeof(char*));
-    makefile->cleanup_dirs[0] = NULL;
-    makefile->num_cleanup_dirs = 0;
+    chaz_MakeRule_add_rm_command(makefile->distclean,
+                                 "charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
+                                 " charmony.h Makefile");
 
     return makefile;
 }
@@ -3333,23 +3353,12 @@ chaz_MakeFile_destroy(chaz_MakeFile *makefile) {
     free(makefile->vars);
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        if (rule->targets)  { free(rule->targets); }
-        if (rule->prereqs)  { free(rule->prereqs); }
-        if (rule->commands) { free(rule->commands); }
-        free(rule);
+        S_destroy_rule(makefile->rules[i]);
     }
     free(makefile->rules);
 
-    for (i = 0; makefile->cleanup_files[i]; i++) {
-        free(makefile->cleanup_files[i]);
-    }
-    free(makefile->cleanup_files);
-
-    for (i = 0; makefile->cleanup_dirs[i]; i++) {
-        free(makefile->cleanup_dirs[i]);
-    }
-    free(makefile->cleanup_dirs);
+    S_destroy_rule(makefile->clean);
+    S_destroy_rule(makefile->distclean);
 
     free(makefile);
 }
@@ -3380,17 +3389,10 @@ chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name,
 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  *rule      = S_new_rule(target, prereq);
     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;
@@ -3401,28 +3403,14 @@ chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
     return rule;
 }
 
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target) {
-    char   **files     = makefile->cleanup_files;
-    size_t   num_files = makefile->num_cleanup_files + 1;
-
-    files = (char**)realloc(files, (num_files + 1) * sizeof(char*));
-    files[num_files-1] = chaz_Util_strdup(target);
-    files[num_files]   = NULL;
-    makefile->cleanup_files     = files;
-    makefile->num_cleanup_files = num_files;
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile) {
+    return makefile->clean;
 }
 
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir) {
-    char   **dirs     = makefile->cleanup_dirs;
-    size_t   num_dirs = makefile->num_cleanup_dirs + 1;
-
-    dirs = (char**)realloc(dirs, (num_dirs + 1) * sizeof(char*));
-    dirs[num_dirs-1] = chaz_Util_strdup(dir);
-    dirs[num_dirs]   = NULL;
-    makefile->cleanup_dirs     = dirs;
-    makefile->num_cleanup_dirs = num_dirs;
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile) {
+    return makefile->distclean;
 }
 
 chaz_MakeRule*
@@ -3447,7 +3435,7 @@ chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -3476,7 +3464,8 @@ chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
+    /* TODO: Clean .obj file on Windows. */
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -3508,7 +3497,7 @@ chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, const char *name,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, shared_lib);
+    chaz_MakeRule_add_rm_command(makefile->clean, shared_lib);
 
     chaz_CFlags_destroy(local_flags);
     free(shared_lib);
@@ -3534,69 +3523,11 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) {
     fprintf(out, "\n");
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        fprintf(out, "%s :", rule->targets);
-        if (rule->prereqs) {
-            fprintf(out, " %s", rule->prereqs);
-        }
-        fprintf(out, "\n");
-        if (rule->commands) {
-            fprintf(out, "%s", rule->commands);
-        }
-        fprintf(out, "\n");
+        S_write_rule(makefile->rules[i], out);
     }
 
-    if (makefile->cleanup_files[0] || makefile->cleanup_dirs[0]) {
-        fprintf(out, "clean :\n");
-        if (shell_type == CHAZ_OS_POSIX) {
-            if (makefile->cleanup_files[0]) {
-                fprintf(out, "\trm -f");
-                for (i = 0; makefile->cleanup_files[i]; i++) {
-                    const char *file = makefile->cleanup_files[i];
-                    fprintf(out, " \\\n\t    %s", file);
-                }
-                fprintf(out, "\n");
-            }
-            if (makefile->cleanup_dirs[0]) {
-                fprintf(out, "\trm -rf");
-                for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                    const char *dir = makefile->cleanup_dirs[i];
-                    fprintf(out, " \\\n\t    %s", dir);
-                }
-                fprintf(out, "\n");
-            }
-        }
-        else if (shell_type == CHAZ_OS_CMD_EXE) {
-            for (i = 0; makefile->cleanup_files[i]; i++) {
-                const char *file = makefile->cleanup_files[i];
-                fprintf(out, "\tfor %%i in (%s) do @if exist %%i del /f %%i\n",
-                        file);
-            }
-            for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                const char *dir = makefile->cleanup_dirs[i];
-                fprintf(out,
-                        "\tfor %%i in (%s) do @if exist %%i rmdir /s /q %%i\n",
-                        dir);
-            }
-        }
-        else {
-            chaz_Util_die("Unsupported shell type: %d", shell_type);
-        }
-        fprintf(out, "\n");
-    }
-
-    fprintf(out, "distclean : clean\n");
-    if (shell_type == CHAZ_OS_POSIX) {
-        fprintf(out, "\trm -f charmonizer$(EXE_EXT) charmony.h Makefile\n\n");
-    }
-    else if (shell_type == CHAZ_OS_CMD_EXE) {
-        fprintf(out,
-            "\tfor %%i in (charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
-            " charmony.h Makefile) do @if exist %%i del /f %%i\n\n");
-    }
-    else {
-        chaz_Util_die("Unsupported shell type: %d", shell_type);
-    }
+    S_write_rule(makefile->clean, out);
+    S_write_rule(makefile->distclean, out);
 
     if (chaz_Make.is_nmake) {
         /* Inference rule for .c files. */
@@ -3637,6 +3568,41 @@ chaz_MakeVar_append(chaz_MakeVar *var, const char *element) {
     var->num_elements++;
 }
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq) {
+    chaz_MakeRule *rule = (chaz_MakeRule*)malloc(sizeof(chaz_MakeRule));
+
+    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); }
+
+    return rule;
+}
+
+static void
+S_destroy_rule(chaz_MakeRule *rule) {
+    if (rule->targets)  { free(rule->targets); }
+    if (rule->prereqs)  { free(rule->prereqs); }
+    if (rule->commands) { free(rule->commands); }
+    free(rule);
+}
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out) {
+    fprintf(out, "%s :", rule->targets);
+    if (rule->prereqs) {
+        fprintf(out, " %s", rule->prereqs);
+    }
+    fprintf(out, "\n");
+    if (rule->commands) {
+        fprintf(out, "%s", rule->commands);
+    }
+    fprintf(out, "\n");
+}
+
 void
 chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target) {
     char *targets;
@@ -3685,7 +3651,47 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command) {
 }
 
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -f", files, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", files,
+                                 ") do @if exist %i del /f %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -rf", dirs, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", dirs,
+                                 ") do @if exist %i rmdir /s /q %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target) {
     char *command;
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/a879c162/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/common/charmonizer.c b/common/charmonizer.c
index 4efb4a6..ba3849d 100644
--- a/common/charmonizer.c
+++ b/common/charmonizer.c
@@ -487,21 +487,19 @@ chaz_MakeRule*
 chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
                        const char *prereq);
 
-/** Add a file to the 'clean' target.
+/** Return the rule for the 'clean' target.
  *
  * @param makefile The makefile.
- * @param target The filename.
  */
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target);
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile);
 
-/** Add a directory to the 'clean' target.
+/** Return the rule for the 'distclean' target.
  *
  * @param makefile The makefile.
- * @param dir The directory.
  */
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir);
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile);
 
 /** Add a rule to link an executable. The executable will also be added to the
  * list of files to clean.
@@ -579,6 +577,22 @@ chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq);
 void
 chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
 
+/** Add a command to remove one or more files.
+ *
+ * @param rule The rule.
+ * @param files The list of files.
+ */
+void
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files);
+
+/** Add a command to remove one or more directories.
+ *
+ * @param rule The rule.
+ * @param dirs The list of directories.
+ */
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs);
+
 /** Add one or more commands to call another makefile recursively.
  *
  * @param rule The rule.
@@ -586,7 +600,7 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command);
  * @param target The target to call. Pass NULL for the default target.
  */
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target);
 
 #endif /* H_CHAZ_MAKE */
@@ -3190,10 +3204,8 @@ struct chaz_MakeFile {
     size_t          num_vars;
     chaz_MakeRule **rules;
     size_t          num_rules;
-    char          **cleanup_files;
-    size_t          num_cleanup_files;
-    char          **cleanup_dirs;
-    size_t          num_cleanup_dirs;
+    chaz_MakeRule  *clean;
+    chaz_MakeRule  *distclean;
 };
 
 /* Static vars. */
@@ -3223,6 +3235,15 @@ chaz_Make_detect(const char *make1, ...);
 static int
 chaz_Make_audition(const char *make);
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq);
+
+static void
+S_destroy_rule(chaz_MakeRule *rule);
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out);
+
 void
 chaz_Make_init(void) {
     const char *make;
@@ -3309,13 +3330,12 @@ chaz_MakeFile_new() {
     makefile->rules[0] = NULL;
     makefile->num_rules = 0;
 
-    makefile->cleanup_files = (char**)malloc(sizeof(char*));
-    makefile->cleanup_files[0] = NULL;
-    makefile->num_cleanup_files = 0;
+    makefile->clean     = S_new_rule("clean", NULL);
+    makefile->distclean = S_new_rule("distclean", "clean");
 
-    makefile->cleanup_dirs = (char**)malloc(sizeof(char*));
-    makefile->cleanup_dirs[0] = NULL;
-    makefile->num_cleanup_dirs = 0;
+    chaz_MakeRule_add_rm_command(makefile->distclean,
+                                 "charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
+                                 " charmony.h Makefile");
 
     return makefile;
 }
@@ -3333,23 +3353,12 @@ chaz_MakeFile_destroy(chaz_MakeFile *makefile) {
     free(makefile->vars);
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        if (rule->targets)  { free(rule->targets); }
-        if (rule->prereqs)  { free(rule->prereqs); }
-        if (rule->commands) { free(rule->commands); }
-        free(rule);
+        S_destroy_rule(makefile->rules[i]);
     }
     free(makefile->rules);
 
-    for (i = 0; makefile->cleanup_files[i]; i++) {
-        free(makefile->cleanup_files[i]);
-    }
-    free(makefile->cleanup_files);
-
-    for (i = 0; makefile->cleanup_dirs[i]; i++) {
-        free(makefile->cleanup_dirs[i]);
-    }
-    free(makefile->cleanup_dirs);
+    S_destroy_rule(makefile->clean);
+    S_destroy_rule(makefile->distclean);
 
     free(makefile);
 }
@@ -3380,17 +3389,10 @@ chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name,
 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  *rule      = S_new_rule(target, prereq);
     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;
@@ -3401,28 +3403,14 @@ chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target,
     return rule;
 }
 
-void
-chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target) {
-    char   **files     = makefile->cleanup_files;
-    size_t   num_files = makefile->num_cleanup_files + 1;
-
-    files = (char**)realloc(files, (num_files + 1) * sizeof(char*));
-    files[num_files-1] = chaz_Util_strdup(target);
-    files[num_files]   = NULL;
-    makefile->cleanup_files     = files;
-    makefile->num_cleanup_files = num_files;
+chaz_MakeRule*
+chaz_MakeFile_clean_rule(chaz_MakeFile *makefile) {
+    return makefile->clean;
 }
 
-void
-chaz_MakeFile_add_dir_to_cleanup(chaz_MakeFile *makefile, const char *dir) {
-    char   **dirs     = makefile->cleanup_dirs;
-    size_t   num_dirs = makefile->num_cleanup_dirs + 1;
-
-    dirs = (char**)realloc(dirs, (num_dirs + 1) * sizeof(char*));
-    dirs[num_dirs-1] = chaz_Util_strdup(dir);
-    dirs[num_dirs]   = NULL;
-    makefile->cleanup_dirs     = dirs;
-    makefile->num_cleanup_dirs = num_dirs;
+chaz_MakeRule*
+chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile) {
+    return makefile->distclean;
 }
 
 chaz_MakeRule*
@@ -3447,7 +3435,7 @@ chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -3476,7 +3464,8 @@ chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, exe);
+    chaz_MakeRule_add_rm_command(makefile->clean, exe);
+    /* TODO: Clean .obj file on Windows. */
 
     chaz_CFlags_destroy(local_flags);
     free(command);
@@ -3508,7 +3497,7 @@ chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, const char *name,
                              local_flags_string, NULL);
     chaz_MakeRule_add_command(rule, command);
 
-    chaz_MakeFile_add_to_cleanup(makefile, shared_lib);
+    chaz_MakeRule_add_rm_command(makefile->clean, shared_lib);
 
     chaz_CFlags_destroy(local_flags);
     free(shared_lib);
@@ -3534,69 +3523,11 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) {
     fprintf(out, "\n");
 
     for (i = 0; makefile->rules[i]; i++) {
-        chaz_MakeRule *rule = makefile->rules[i];
-        fprintf(out, "%s :", rule->targets);
-        if (rule->prereqs) {
-            fprintf(out, " %s", rule->prereqs);
-        }
-        fprintf(out, "\n");
-        if (rule->commands) {
-            fprintf(out, "%s", rule->commands);
-        }
-        fprintf(out, "\n");
-    }
-
-    if (makefile->cleanup_files[0] || makefile->cleanup_dirs[0]) {
-        fprintf(out, "clean :\n");
-        if (shell_type == CHAZ_OS_POSIX) {
-            if (makefile->cleanup_files[0]) {
-                fprintf(out, "\trm -f");
-                for (i = 0; makefile->cleanup_files[i]; i++) {
-                    const char *file = makefile->cleanup_files[i];
-                    fprintf(out, " \\\n\t    %s", file);
-                }
-                fprintf(out, "\n");
-            }
-            if (makefile->cleanup_dirs[0]) {
-                fprintf(out, "\trm -rf");
-                for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                    const char *dir = makefile->cleanup_dirs[i];
-                    fprintf(out, " \\\n\t    %s", dir);
-                }
-                fprintf(out, "\n");
-            }
-        }
-        else if (shell_type == CHAZ_OS_CMD_EXE) {
-            for (i = 0; makefile->cleanup_files[i]; i++) {
-                const char *file = makefile->cleanup_files[i];
-                fprintf(out, "\tfor %%i in (%s) do @if exist %%i del /f %%i\n",
-                        file);
-            }
-            for (i = 0; makefile->cleanup_dirs[i]; i++) {
-                const char *dir = makefile->cleanup_dirs[i];
-                fprintf(out,
-                        "\tfor %%i in (%s) do @if exist %%i rmdir /s /q %%i\n",
-                        dir);
-            }
-        }
-        else {
-            chaz_Util_die("Unsupported shell type: %d", shell_type);
-        }
-        fprintf(out, "\n");
+        S_write_rule(makefile->rules[i], out);
     }
 
-    fprintf(out, "distclean : clean\n");
-    if (shell_type == CHAZ_OS_POSIX) {
-        fprintf(out, "\trm -f charmonizer$(EXE_EXT) charmony.h Makefile\n\n");
-    }
-    else if (shell_type == CHAZ_OS_CMD_EXE) {
-        fprintf(out,
-            "\tfor %%i in (charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)"
-            " charmony.h Makefile) do @if exist %%i del /f %%i\n\n");
-    }
-    else {
-        chaz_Util_die("Unsupported shell type: %d", shell_type);
-    }
+    S_write_rule(makefile->clean, out);
+    S_write_rule(makefile->distclean, out);
 
     if (chaz_Make.is_nmake) {
         /* Inference rule for .c files. */
@@ -3637,6 +3568,41 @@ chaz_MakeVar_append(chaz_MakeVar *var, const char *element) {
     var->num_elements++;
 }
 
+static chaz_MakeRule*
+S_new_rule(const char *target, const char *prereq) {
+    chaz_MakeRule *rule = (chaz_MakeRule*)malloc(sizeof(chaz_MakeRule));
+
+    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); }
+
+    return rule;
+}
+
+static void
+S_destroy_rule(chaz_MakeRule *rule) {
+    if (rule->targets)  { free(rule->targets); }
+    if (rule->prereqs)  { free(rule->prereqs); }
+    if (rule->commands) { free(rule->commands); }
+    free(rule);
+}
+
+static void
+S_write_rule(chaz_MakeRule *rule, FILE *out) {
+    fprintf(out, "%s :", rule->targets);
+    if (rule->prereqs) {
+        fprintf(out, " %s", rule->prereqs);
+    }
+    fprintf(out, "\n");
+    if (rule->commands) {
+        fprintf(out, "%s", rule->commands);
+    }
+    fprintf(out, "\n");
+}
+
 void
 chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target) {
     char *targets;
@@ -3685,7 +3651,47 @@ chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command) {
 }
 
 void
-chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir,
+chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -f", files, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", files,
+                                 ") do @if exist %i del /f %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs) {
+    int   shell_type = chaz_OS_shell_type();
+    char *command;
+
+    if (shell_type == CHAZ_OS_POSIX) {
+        command = chaz_Util_join(" ", "rm -rf", dirs, NULL);
+    }
+    else if (shell_type == CHAZ_OS_CMD_EXE) {
+        command = chaz_Util_join("", "for %i in (", dirs,
+                                 ") do @if exist %i rmdir /s /q %i\n", NULL);
+    }
+    else {
+        chaz_Util_die("Unsupported shell type: %d", shell_type);
+    }
+
+    chaz_MakeRule_add_command(rule, command);
+    free(command);
+}
+
+void
+chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir,
                                const char *target) {
     char *command;
 
@@ -6436,6 +6442,8 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     chaz_MakeFile *makefile;
     chaz_MakeVar  *var;
     chaz_MakeRule *rule;
+    chaz_MakeRule *clean_rule;
+    chaz_MakeRule *distclean_rule;
 
     int          cflags_style = chaz_CC_get_cflags_style();
     chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags();
@@ -6575,7 +6583,7 @@ S_write_makefile(struct chaz_CLIArgs *args) {
     chaz_CFlags_destroy(lemon_cflags);
 
     rule = chaz_MakeFile_add_rule(makefile, "$(CFC_EXE)", NULL);
-    chaz_MakeRule_add_command_make(rule, "$(CFC_DIR)", NULL);
+    chaz_MakeRule_add_make_command(rule, "$(CFC_DIR)", NULL);
 
     rule = chaz_MakeFile_add_rule(makefile, "$(AUTOGEN_DIR)", "$(CFC_EXE)");
     chaz_MakeRule_add_command(rule, "$(CFC_EXE) --source=$(CORE_DIR) "
@@ -6651,15 +6659,24 @@ S_write_makefile(struct chaz_CLIArgs *args) {
                                   " --branch-coverage"
                                   " --output-directory coverage"
                                   " lucy.info");
+    }
+
+    clean_rule = chaz_MakeFile_clean_rule(makefile);
 
-        chaz_MakeFile_add_to_cleanup(makefile, "lucy.info");
-        chaz_MakeFile_add_dir_to_cleanup(makefile, "coverage");
+    chaz_MakeRule_add_rm_command(clean_rule, "$(LUCY_OBJS)");
+    chaz_MakeRule_add_rm_command(clean_rule, json_parser_h);
+    chaz_MakeRule_add_rm_command(clean_rule, json_parser_c);
+    chaz_MakeRule_add_recursive_rm_command(clean_rule, "$(AUTOGEN_DIR)");
+
+    if (args->code_coverage) {
+        chaz_MakeRule_add_rm_command(clean_rule, "lucy.info");
+        chaz_MakeRule_add_recursive_rm_command(clean_rule, "coverage");
     }
 
-    chaz_MakeFile_add_to_cleanup(makefile, "$(LUCY_OBJS)");
-    chaz_MakeFile_add_to_cleanup(makefile, json_parser_h);
-    chaz_MakeFile_add_to_cleanup(makefile, json_parser_c);
-    chaz_MakeFile_add_dir_to_cleanup(makefile, "$(AUTOGEN_DIR)");
+    chaz_MakeRule_add_make_command(clean_rule, "$(CFC_DIR)", "clean");
+
+    distclean_rule = chaz_MakeFile_distclean_rule(makefile);
+    chaz_MakeRule_add_make_command(distclean_rule, "$(CFC_DIR)", "distclean");
 
     chaz_MakeFile_write(makefile);