]> git.ozlabs.org Git - ccan/commitdiff
ccanlint: make compile commands return output.
authorRusty Russell <rusty@rustcorp.com.au>
Sun, 14 Nov 2010 11:40:04 +0000 (22:10 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Sun, 14 Nov 2010 11:40:04 +0000 (22:10 +1030)
We want to distinguish between warnings and errors: the first step is to
return the output even if the command doesn't fail.

14 files changed:
tools/ccanlint/compulsory_tests/build_objs.c
tools/ccanlint/compulsory_tests/check_build.c
tools/ccanlint/compulsory_tests/check_includes_build.c
tools/ccanlint/tests/build-coverage.c
tools/ccanlint/tests/compile_test_helpers.c
tools/ccanlint/tests/compile_tests.c
tools/ccanlint/tests/examples_compile.c
tools/ccanlint/tests/run-coverage.c
tools/ccanlint/tests/run_tests.c
tools/ccanlint/tests/run_tests_valgrind.c
tools/compile.c
tools/depends.c
tools/tools.c
tools/tools.h

index aa8e7b36a5ebce098d9967d359eb86147395cf8e..77f0a70cd832da52fb47921c2b70acce4c79b00d 100644 (file)
@@ -31,16 +31,17 @@ static void check_objs_build(struct manifest *m,
                score->total = 0;
 
        list_for_each(&m->c_files, i, list) {
                score->total = 0;
 
        list_for_each(&m->c_files, i, list) {
-               char *err;
+               char *output;
                char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
 
                i->compiled = maybe_temp_file(m, "", keep, fullfile);
                char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
 
                i->compiled = maybe_temp_file(m, "", keep, fullfile);
-               err = compile_object(m, fullfile, ccan_dir, "", i->compiled);
-               if (err) {
+               if (!compile_object(m, fullfile, ccan_dir, "", i->compiled,
+                                   &output)) {
                        talloc_free(i->compiled);
                        score->error = "Compiling object files";
                        talloc_free(i->compiled);
                        score->error = "Compiling object files";
-                       score_file_error(score, i, 0, err);
+                       score_file_error(score, i, 0, output);
                }
                }
+               talloc_free(output);
        }
        if (!score->error) {
                score->pass = true;
        }
        if (!score->error) {
                score->pass = true;
index 9175b91835f5bb2271f6e645d9040038030c8663..830ea91427d4faef8116d686287969ef5215f906 100644 (file)
@@ -50,7 +50,7 @@ static void check_use_build(struct manifest *m,
                            unsigned int *timeleft, struct score *score)
 {
        char *contents;
                            unsigned int *timeleft, struct score *score)
 {
        char *contents;
-       char *tmpfile;
+       char *tmpfile, *cmdout;
        char *basename = talloc_asprintf(m, "%s/example.c", m->dir);
        int fd;
 
        char *basename = talloc_asprintf(m, "%s/example.c", m->dir);
        int fd;
 
@@ -71,12 +71,14 @@ static void check_use_build(struct manifest *m,
                err(1, "Failure writing to temporary file %s", tmpfile);
        close(fd);
 
                err(1, "Failure writing to temporary file %s", tmpfile);
        close(fd);
 
-       score->error = compile_and_link(m, tmpfile, ccan_dir, obj_list(m), "",
-                                       lib_list(m),
-                                       maybe_temp_file(m, "", keep, tmpfile));
-       if (!score->error) {
+       if (compile_and_link(score, tmpfile, ccan_dir, obj_list(m), "",
+                            lib_list(m),
+                            maybe_temp_file(m, "", keep, tmpfile),
+                            &cmdout)) {
                score->pass = true;
                score->score = score->total;
                score->pass = true;
                score->score = score->total;
+       } else {
+               score->error = cmdout;
        }
 }
 
        }
 }
 
index cc5edc4ccaabbf2525b9072a4e64da3ceef6d02f..4e2badda9ce3ff6863812b3a9c5d3734745779a4 100644 (file)
@@ -40,7 +40,7 @@ static void check_includes_build(struct manifest *m,
                                 unsigned int *timeleft, struct score *score)
 {
        char *contents;
                                 unsigned int *timeleft, struct score *score)
 {
        char *contents;
-       char *tmpsrc, *tmpobj;
+       char *tmpsrc, *tmpobj, *cmdout;
        int fd;
        struct ccan_file *mainh = main_header(m);
 
        int fd;
        struct ccan_file *mainh = main_header(m);
 
@@ -57,14 +57,13 @@ static void check_includes_build(struct manifest *m,
                err(1, "writing to temporary file %s", tmpsrc);
        close(fd);
 
                err(1, "writing to temporary file %s", tmpsrc);
        close(fd);
 
-       score->error = compile_object(m, tmpsrc, ccan_dir, "", tmpobj);
-       if (score->error) {
-               score->error = talloc_asprintf(score,
-                                      "#include of the main header file:\n%s",
-                                      score->error);
-       } else {
+       if (compile_object(score, tmpsrc, ccan_dir, "", tmpobj, &cmdout)) {
                score->pass = true;
                score->score = score->total;
                score->pass = true;
                score->score = score->total;
+       } else {
+               score->error = talloc_asprintf(score,
+                                      "#include of the main header file:\n%s",
+                                      cmdout);
        }
 }
 
        }
 }
 
index 6eb6ab5de8f0a1c2b5761f8b221131ce73e0e55d..9415647f8f46974705af95fc2c96eca7a0af964b 100644 (file)
@@ -18,9 +18,9 @@
 static const char *can_run_coverage(struct manifest *m)
 {
        unsigned int timeleft = default_timeout_ms;
 static const char *can_run_coverage(struct manifest *m)
 {
        unsigned int timeleft = default_timeout_ms;
-       char *output = run_command(m, &timeleft, "gcov -h");
+       char *output;
 
 
-       if (output)
+       if (!run_command(m, &timeleft, &output, "gcov -h"))
                return talloc_asprintf(m, "No gcov support: %s", output);
        return NULL;
 }
                return talloc_asprintf(m, "No gcov support: %s", output);
        return NULL;
 }
@@ -37,9 +37,8 @@ static bool build_module_objs_with_coverage(struct manifest *m, bool keep,
                char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
 
                i->cov_compiled = maybe_temp_file(m, "", keep, fullfile);
                char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
 
                i->cov_compiled = maybe_temp_file(m, "", keep, fullfile);
-               err = compile_object(m, fullfile, ccan_dir, "",
-                                    i->cov_compiled);
-               if (err) {
+               if (!compile_object(m, fullfile, ccan_dir, "",
+                                   i->cov_compiled, &err)) {
                        score_file_error(score, i, 0, err);
                        talloc_free(i->cov_compiled);
                        i->cov_compiled = NULL;
                        score_file_error(score, i, 0, err);
                        talloc_free(i->cov_compiled);
                        i->cov_compiled = NULL;
@@ -95,19 +94,18 @@ static char *cov_compile(const void *ctx,
                         const char *modobjs,
                         bool keep)
 {
                         const char *modobjs,
                         bool keep)
 {
-       char *errmsg;
+       char *output;
 
        file->cov_compiled = maybe_temp_file(ctx, "", keep, file->fullname);
 
        file->cov_compiled = maybe_temp_file(ctx, "", keep, file->fullname);
-       errmsg = compile_and_link(ctx, file->fullname, ccan_dir,
-                                 obj_list(m, modobjs),
-                                 COVERAGE_CFLAGS,
-                                 lib_list(m), file->cov_compiled);
-       if (errmsg) {
+       if (!compile_and_link(ctx, file->fullname, ccan_dir,
+                             obj_list(m, modobjs),
+                             COVERAGE_CFLAGS,
+                             lib_list(m), file->cov_compiled, &output)) {
                talloc_free(file->cov_compiled);
                file->cov_compiled = NULL;
                talloc_free(file->cov_compiled);
                file->cov_compiled = NULL;
-               return errmsg;
+               return output;
        }
        }
-
+       talloc_free(output);
        return NULL;
 }
 
        return NULL;
 }
 
index e2e3ed843f82a9477da9a2ffef48179e1aea19a7..3d5a8a74548a3c83f9213d4ae8a7fedac1e4b23a 100644 (file)
@@ -25,9 +25,14 @@ static char *compile(struct manifest *m,
                     bool keep,
                     struct ccan_file *cfile)
 {
                     bool keep,
                     struct ccan_file *cfile)
 {
+       char *output;
        cfile->compiled = maybe_temp_file(m, ".o", keep, cfile->fullname);
        cfile->compiled = maybe_temp_file(m, ".o", keep, cfile->fullname);
-       return compile_object(m, cfile->fullname, ccan_dir, "",
-                             cfile->compiled);
+       if (compile_object(m, cfile->fullname, ccan_dir, "",
+                          cfile->compiled, &output)) {
+               talloc_free(output);
+               return NULL;
+       }
+       return output;
 }
 
 static void do_compile_test_helpers(struct manifest *m,
 }
 
 static void do_compile_test_helpers(struct manifest *m,
index b54ce958529f5e0a278f0d1f1e054abc4cbde54a..3549cdedf6611c0ce33bf4866b767a25de018e11 100644 (file)
@@ -71,14 +71,14 @@ static char *compile(const void *ctx,
        char *errmsg;
 
        file->compiled = maybe_temp_file(ctx, "", keep, file->fullname);
        char *errmsg;
 
        file->compiled = maybe_temp_file(ctx, "", keep, file->fullname);
-       errmsg = compile_and_link(ctx, file->fullname, ccan_dir,
-                                 obj_list(m, link_with_module),
-                                 fail ? "-DFAIL" : "",
-                                 lib_list(m), file->compiled);
-       if (errmsg) {
+       if (!compile_and_link(ctx, file->fullname, ccan_dir,
+                             obj_list(m, link_with_module),
+                             fail ? "-DFAIL" : "",
+                             lib_list(m), file->compiled, &errmsg)) {
                talloc_free(file->compiled);
                return errmsg;
        }
                talloc_free(file->compiled);
                return errmsg;
        }
+       talloc_free(errmsg);
        return NULL;
 }
 
        return NULL;
 }
 
index 3946bdb3cb7ece4c4daa19001cbb0a5a9fb650a6..1b2360ed52e3820e13f65e24ece05e22a3dfff67 100644 (file)
@@ -119,14 +119,14 @@ static char *compile(const void *ctx,
        char *errmsg;
 
        file->compiled = maybe_temp_file(ctx, "", keep, file->fullname);
        char *errmsg;
 
        file->compiled = maybe_temp_file(ctx, "", keep, file->fullname);
-       errmsg = compile_and_link(ctx, file->fullname, ccan_dir,
-                                 obj_list(m, file),
-                                 "", lib_list(m), file->compiled);
-       if (errmsg) {
+       if (!compile_and_link(ctx, file->fullname, ccan_dir,
+                             obj_list(m, file),
+                             "", lib_list(m), file->compiled, &errmsg)) {
                talloc_free(file->compiled);
                file->compiled = NULL;
                return errmsg;
        }
                talloc_free(file->compiled);
                file->compiled = NULL;
                return errmsg;
        }
+       talloc_free(errmsg);
        return NULL;
 }
 
        return NULL;
 }
 
index 8e756c7db732faed28d89028c6c9d0b7a2afb48b..a526d55e8237cf4ed58afac49cc30d208a1a5d20 100644 (file)
@@ -125,7 +125,6 @@ static void do_run_coverage_tests(struct manifest *m,
        struct ccan_file *i;
        char *cmdout;
        char *covcmd;
        struct ccan_file *i;
        char *cmdout;
        char *covcmd;
-       bool ok;
        bool full_gcov = (verbose > 1);
        struct list_head *list;
 
        bool full_gcov = (verbose > 1);
        struct list_head *list;
 
@@ -137,20 +136,20 @@ static void do_run_coverage_tests(struct manifest *m,
        /* Run them all. */
        foreach_ptr(list, &m->run_tests, &m->api_tests) {
                list_for_each(list, i, list) {
        /* Run them all. */
        foreach_ptr(list, &m->run_tests, &m->api_tests) {
                list_for_each(list, i, list) {
-                       cmdout = run_command(m, timeleft, i->cov_compiled);
-                       if (cmdout) {
+                       if (run_command(score, timeleft, &cmdout,
+                                       "%s", i->cov_compiled)) {
+                               covcmd = talloc_asprintf_append(covcmd, " %s",
+                                                               i->fullname);
+                       } else {
                                score->error = "Running test with coverage";
                                score_file_error(score, i, 0, cmdout);
                                return;
                        }
                                score->error = "Running test with coverage";
                                score_file_error(score, i, 0, cmdout);
                                return;
                        }
-                       covcmd = talloc_asprintf_append(covcmd, " %s",
-                                                       i->fullname);
                }
        }
 
        /* Now run gcov: we want output even if it succeeds. */
                }
        }
 
        /* Now run gcov: we want output even if it succeeds. */
-       cmdout = run_with_timeout(m, covcmd, &ok, timeleft);
-       if (!ok) {
+       if (!run_command(score, timeleft, &cmdout, "%s", covcmd)) {
                score->error = talloc_asprintf(score, "Running gcov: %s",
                                               cmdout);
                return;
                score->error = talloc_asprintf(score, "Running gcov: %s",
                                               cmdout);
                return;
index 0a8434c6e5a35563bfd3eae06f61cbf0e7554c84..f32e0534ff11d1272e3e76c0ceb3498e6e155e8e 100644 (file)
@@ -35,11 +35,11 @@ static void do_run_tests(struct manifest *m,
        foreach_ptr(list, &m->run_tests, &m->api_tests) {
                list_for_each(list, i, list) {
                        score->total++;
        foreach_ptr(list, &m->run_tests, &m->api_tests) {
                list_for_each(list, i, list) {
                        score->total++;
-                       cmdout = run_command(m, timeleft, i->compiled);
-                       if (cmdout)
-                               score_file_error(score, i, 0, cmdout);
-                       else
+                       if (run_command(m, timeleft, &cmdout, "%s",
+                                       i->compiled))
                                score->score++;
                                score->score++;
+                       else
+                               score_file_error(score, i, 0, cmdout);
                }
        }
 
                }
        }
 
index e0c2ab9197db29d8fbe60c2194d1cbbd9e68e4d1..7ab67dbcd83f7550bf4b84a141c480fcc0c9a60a 100644 (file)
 static const char *can_run_vg(struct manifest *m)
 {
        unsigned int timeleft = default_timeout_ms;
 static const char *can_run_vg(struct manifest *m)
 {
        unsigned int timeleft = default_timeout_ms;
-       char *output = run_command(m, &timeleft,
-                                  "valgrind -q --error-exitcode=0 true");
+       char *output;
 
 
-       if (output)
+       if (!run_command(m, &timeleft, &output,
+                        "valgrind -q --error-exitcode=0 true"))
                return talloc_asprintf(m, "No valgrind support: %s", output);
        return NULL;
 }
                return talloc_asprintf(m, "No valgrind support: %s", output);
        return NULL;
 }
@@ -41,14 +41,14 @@ static void do_run_tests_vg(struct manifest *m,
        foreach_ptr(list, &m->run_tests, &m->api_tests) {
                list_for_each(list, i, list) {
                        score->total++;
        foreach_ptr(list, &m->run_tests, &m->api_tests) {
                list_for_each(list, i, list) {
                        score->total++;
-                       cmdout = run_command(m, timeleft,
-                                    "valgrind -q --error-exitcode=100 %s",
-                                    i->compiled);
-                       if (cmdout) {
+                       if (run_command(score, timeleft, &cmdout,
+                                       "valgrind -q --error-exitcode=100 %s",
+                                       i->compiled)) {
+                               score->score++;
+                       } else {
                                score->error = "Running under valgrind";
                                score_file_error(score, i, 0, cmdout);
                                score->error = "Running under valgrind";
                                score_file_error(score, i, 0, cmdout);
-                       } else
-                               score->score++;
+                       }
                }
        }
 
                }
        }
 
index 8f80734b095d5ad06f0aec2f696b3197eaf0a4c2..3ab1afaa3158cd44fa050da15892a355f476db6a 100644 (file)
@@ -4,7 +4,7 @@
 
 bool compile_verbose = false;
 
 
 bool compile_verbose = false;
 
-/* Compile multiple object files into a single.  Returns errmsg if fails. */
+/* Compile multiple object files into a single.  Returns NULL if fails. */
 char *link_objects(const void *ctx, const char *basename, bool in_pwd,
                   const char *objs, char **errmsg)
 {
 char *link_objects(const void *ctx, const char *basename, bool in_pwd,
                   const char *objs, char **errmsg)
 {
@@ -13,35 +13,34 @@ char *link_objects(const void *ctx, const char *basename, bool in_pwd,
        if (compile_verbose)
                printf("Linking objects into %s\n", file);
 
        if (compile_verbose)
                printf("Linking objects into %s\n", file);
 
-       *errmsg = run_command(ctx, NULL, "ld -r -o %s %s", file, objs);
-       if (*errmsg) {
-               talloc_free(file);
-               return NULL;
-       }
-       return file;
+       if (run_command(ctx, NULL, errmsg, "ld -r -o %s %s", file, objs))
+               return file;
+
+       talloc_free(file);
+       return NULL;
 }
 
 }
 
-/* Compile a single C file to an object file.  Returns errmsg if fails. */
-char *compile_object(const void *ctx, const char *cfile, const char *ccandir,
-                    const char *extra_cflags,
-                    const char *outfile)
+/* Compile a single C file to an object file. */
+bool compile_object(const void *ctx, const char *cfile, const char *ccandir,
+                   const char *extra_cflags,
+                   const char *outfile, char **output)
 {
        if (compile_verbose)
                printf("Compiling %s\n", outfile);
 {
        if (compile_verbose)
                printf("Compiling %s\n", outfile);
-       return run_command(ctx, NULL, CCAN_COMPILER " " CCAN_CFLAGS
+       return run_command(ctx, NULL, output, CCAN_COMPILER " " CCAN_CFLAGS
                           " -I%s %s -c -o %s %s",
                           ccandir, extra_cflags, outfile, cfile);
 }
 
 /* Compile and link single C file, with object files.
                           " -I%s %s -c -o %s %s",
                           ccandir, extra_cflags, outfile, cfile);
 }
 
 /* Compile and link single C file, with object files.
- * Returns error message or NULL on success. */
-char *compile_and_link(const void *ctx, const char *cfile, const char *ccandir,
-                      const char *objs, const char *extra_cflags,
-                      const char *libs, const char *outfile)
+ * Returns false on failure. */
+bool compile_and_link(const void *ctx, const char *cfile, const char *ccandir,
+                     const char *objs, const char *extra_cflags,
+                     const char *libs, const char *outfile, char **output)
 {
        if (compile_verbose)
                printf("Compiling and linking %s\n", outfile);
 {
        if (compile_verbose)
                printf("Compiling and linking %s\n", outfile);
-       return run_command(ctx, NULL, CCAN_COMPILER " " CCAN_CFLAGS
+       return run_command(ctx, NULL, output, CCAN_COMPILER " " CCAN_CFLAGS
                           " -I%s %s -o %s %s %s %s",
                           ccandir, extra_cflags, outfile, cfile, objs, libs);
 }
                           " -I%s %s -o %s %s %s %s",
                           ccandir, extra_cflags, outfile, cfile, objs, libs);
 }
index e2666d97f778ae2007127561b22415117cba9875..4bac1b063fbcb1cdc5aea75ed3b543d8ebe9fb53 100644 (file)
@@ -39,7 +39,7 @@ lines_from_cmd(const void *ctx, unsigned int *num, char *format, ...)
  * temp_file helps here. */
 static char *compile_info(const void *ctx, const char *dir)
 {
  * temp_file helps here. */
 static char *compile_info(const void *ctx, const char *dir)
 {
-       char *info_c_file, *info, *ccandir, *compiled;
+       char *info_c_file, *info, *ccandir, *compiled, *output;
        size_t len;
        int fd;
 
        size_t len;
        int fd;
 
@@ -63,9 +63,9 @@ static char *compile_info(const void *ctx, const char *dir)
 
        compiled = maybe_temp_file(ctx, "", false, "info");
        if (compile_and_link(ctx, info_c_file, ccandir, "", "", "",
 
        compiled = maybe_temp_file(ctx, "", false, "info");
        if (compile_and_link(ctx, info_c_file, ccandir, "", "", "",
-                            compiled))
-               return NULL;
-       return compiled;
+                            compiled, &output))
+               return compiled;
+       return NULL;
 }
 
 static char **get_one_deps(const void *ctx, const char *dir,
 }
 
 static char **get_one_deps(const void *ctx, const char *dir,
index 20fcc9bb5bfba7fd142e5735e3a8841c9c3e50b2..eeaff6f17f644233f7aa1772ab27c69aad69f81f 100644 (file)
@@ -143,35 +143,35 @@ char *run_with_timeout(const void *ctx, const char *cmd,
        return ret;
 }
 
        return ret;
 }
 
-/* Returns output if command fails. */
-char *run_command(const void *ctx, unsigned int *time_ms, const char *fmt, ...)
+/* Tallocs *output off ctx; return false if command fails. */
+bool run_command(const void *ctx, unsigned int *time_ms, char **output,
+                const char *fmt, ...)
 {
        va_list ap;
 {
        va_list ap;
-       char *cmd, *contents;
+       char *cmd;
        bool ok;
        unsigned int default_time = default_timeout_ms;
 
        if (!time_ms)
                time_ms = &default_time;
        bool ok;
        unsigned int default_time = default_timeout_ms;
 
        if (!time_ms)
                time_ms = &default_time;
-       else if (*time_ms == 0)
-               return talloc_strdup(ctx, "\n== TIMED OUT ==\n");
+       else if (*time_ms == 0) {
+               *output = talloc_strdup(ctx, "\n== TIMED OUT ==\n");
+               return false;
+       }
 
        va_start(ap, fmt);
        cmd = talloc_vasprintf(ctx, fmt, ap);
        va_end(ap);
 
 
        va_start(ap, fmt);
        cmd = talloc_vasprintf(ctx, fmt, ap);
        va_end(ap);
 
-       contents = run_with_timeout(ctx, cmd, &ok, time_ms);
-       if (ok) {
-               talloc_free(contents);
-               return NULL;
-       }
-
-       if (!contents)
+       *output = run_with_timeout(ctx, cmd, &ok, time_ms);
+       if (ok)
+               return true;
+       if (!*output)
                err(1, "Problem running child");
        if (*time_ms == 0)
                err(1, "Problem running child");
        if (*time_ms == 0)
-               contents = talloc_asprintf_append(contents,
-                                                 "\n== TIMED OUT ==\n");
-       return contents;
+               *output = talloc_asprintf_append(*output,
+                                                "\n== TIMED OUT ==\n");
+       return false;
 }
 
 static int unlink_all(char *dir)
 }
 
 static int unlink_all(char *dir)
index 168a47bd28e0c595b3162c1c58d6a376d428c524..d39f01977683ef605798da2a7c6fdb40ed907a9c 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef CCAN_TOOLS_H
 #define CCAN_TOOLS_H
 #include <stdbool.h>
 #ifndef CCAN_TOOLS_H
 #define CCAN_TOOLS_H
 #include <stdbool.h>
+#include <ccan/compiler/compiler.h>
 #include "config.h"
 
 #ifndef CCAN_COMPILER
 #include "config.h"
 
 #ifndef CCAN_COMPILER
@@ -36,7 +37,10 @@ extern bool tools_verbose;
 char *talloc_basename(const void *ctx, const char *dir);
 char *talloc_dirname(const void *ctx, const char *dir);
 char *talloc_getcwd(const void *ctx);
 char *talloc_basename(const void *ctx, const char *dir);
 char *talloc_dirname(const void *ctx, const char *dir);
 char *talloc_getcwd(const void *ctx);
-char *run_command(const void *ctx, unsigned int *time_ms, const char *fmt, ...);
+bool PRINTF_FMT(4,5) run_command(const void *ctx,
+                                unsigned int *time_ms,
+                                char **output,
+                                const char *fmt, ...);
 char *run_with_timeout(const void *ctx, const char *cmd,
                       bool *ok, unsigned *timeout_ms);
 char *temp_dir(const void *ctx);
 char *run_with_timeout(const void *ctx, const char *cmd,
                       bool *ok, unsigned *timeout_ms);
 char *temp_dir(const void *ctx);
@@ -52,15 +56,14 @@ extern bool compile_verbose;
 /* Compile multiple object files into a single. */
 char *link_objects(const void *ctx, const char *basename, bool in_pwd,
                   const char *objs, char **errmsg);
 /* Compile multiple object files into a single. */
 char *link_objects(const void *ctx, const char *basename, bool in_pwd,
                   const char *objs, char **errmsg);
-/* Compile a single C file to an object file.  Returns errmsg if fails. */
-char *compile_object(const void *ctx, const char *cfile, const char *ccandir,
-                    const char *extra_cflags,
-                    const char *outfile);
-/* Compile and link single C file, with object files, libs, etc.  NULL on
- * success, error output on fail. */
-char *compile_and_link(const void *ctx, const char *cfile, const char *ccandir,
-                      const char *objs, const char *extra_cflags,
-                      const char *libs, const char *outfile);
+/* Compile a single C file to an object file.  Returns false if fails. */
+bool compile_object(const void *ctx, const char *cfile, const char *ccandir,
+                   const char *extra_cflags,
+                   const char *outfile, char **output);
+/* Compile and link single C file, with object files, libs, etc. */
+bool compile_and_link(const void *ctx, const char *cfile, const char *ccandir,
+                     const char *objs, const char *extra_cflags,
+                     const char *libs, const char *outfile, char **output);
 
 /* If in_pwd is false, return a file int temp_dir, otherwise a local file. */
 char *maybe_temp_file(const void *ctx, const char *extension, bool in_pwd,
 
 /* If in_pwd is false, return a file int temp_dir, otherwise a local file. */
 char *maybe_temp_file(const void *ctx, const char *extension, bool in_pwd,