Commit 03a59690 authored by Rusty Russell's avatar Rusty Russell

ccanlint: make compile commands return output.

We want to distinguish between warnings and errors: the first step is to
return the output even if the command doesn't fail.
parent f1c96e9d
...@@ -31,16 +31,17 @@ static void check_objs_build(struct manifest *m, ...@@ -31,16 +31,17 @@ static void check_objs_build(struct manifest *m,
score->total = 0; score->total = 0;
list_for_each(&m->c_files, i, list) { list_for_each(&m->c_files, i, list) {
char *err; char *output;
char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name); char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
i->compiled = maybe_temp_file(m, "", keep, fullfile); i->compiled = maybe_temp_file(m, "", keep, fullfile);
err = compile_object(m, fullfile, ccan_dir, "", i->compiled); if (!compile_object(m, fullfile, ccan_dir, "", i->compiled,
if (err) { &output)) {
talloc_free(i->compiled); talloc_free(i->compiled);
score->error = "Compiling object files"; 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) { if (!score->error) {
score->pass = true; score->pass = true;
......
...@@ -50,7 +50,7 @@ static void check_use_build(struct manifest *m, ...@@ -50,7 +50,7 @@ static void check_use_build(struct manifest *m,
unsigned int *timeleft, struct score *score) unsigned int *timeleft, struct score *score)
{ {
char *contents; char *contents;
char *tmpfile; char *tmpfile, *cmdout;
char *basename = talloc_asprintf(m, "%s/example.c", m->dir); char *basename = talloc_asprintf(m, "%s/example.c", m->dir);
int fd; int fd;
...@@ -71,12 +71,14 @@ static void check_use_build(struct manifest *m, ...@@ -71,12 +71,14 @@ static void check_use_build(struct manifest *m,
err(1, "Failure writing to temporary file %s", tmpfile); err(1, "Failure writing to temporary file %s", tmpfile);
close(fd); close(fd);
score->error = compile_and_link(m, tmpfile, ccan_dir, obj_list(m), "", if (compile_and_link(score, tmpfile, ccan_dir, obj_list(m), "",
lib_list(m), lib_list(m),
maybe_temp_file(m, "", keep, tmpfile)); maybe_temp_file(m, "", keep, tmpfile),
if (!score->error) { &cmdout)) {
score->pass = true; score->pass = true;
score->score = score->total; score->score = score->total;
} else {
score->error = cmdout;
} }
} }
......
...@@ -40,7 +40,7 @@ static void check_includes_build(struct manifest *m, ...@@ -40,7 +40,7 @@ static void check_includes_build(struct manifest *m,
unsigned int *timeleft, struct score *score) unsigned int *timeleft, struct score *score)
{ {
char *contents; char *contents;
char *tmpsrc, *tmpobj; char *tmpsrc, *tmpobj, *cmdout;
int fd; int fd;
struct ccan_file *mainh = main_header(m); struct ccan_file *mainh = main_header(m);
...@@ -57,14 +57,13 @@ static void check_includes_build(struct manifest *m, ...@@ -57,14 +57,13 @@ static void check_includes_build(struct manifest *m,
err(1, "writing to temporary file %s", tmpsrc); err(1, "writing to temporary file %s", tmpsrc);
close(fd); close(fd);
score->error = compile_object(m, tmpsrc, ccan_dir, "", tmpobj); if (compile_object(score, tmpsrc, ccan_dir, "", tmpobj, &cmdout)) {
if (score->error) {
score->error = talloc_asprintf(score,
"#include of the main header file:\n%s",
score->error);
} else {
score->pass = true; score->pass = true;
score->score = score->total; score->score = score->total;
} else {
score->error = talloc_asprintf(score,
"#include of the main header file:\n%s",
cmdout);
} }
} }
......
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
static const char *can_run_coverage(struct manifest *m) static const char *can_run_coverage(struct manifest *m)
{ {
unsigned int timeleft = default_timeout_ms; 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 talloc_asprintf(m, "No gcov support: %s", output);
return NULL; return NULL;
} }
...@@ -37,9 +37,8 @@ static bool build_module_objs_with_coverage(struct manifest *m, bool keep, ...@@ -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); char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
i->cov_compiled = maybe_temp_file(m, "", keep, fullfile); i->cov_compiled = maybe_temp_file(m, "", keep, fullfile);
err = compile_object(m, fullfile, ccan_dir, "", if (!compile_object(m, fullfile, ccan_dir, "",
i->cov_compiled); i->cov_compiled, &err)) {
if (err) {
score_file_error(score, i, 0, err); score_file_error(score, i, 0, err);
talloc_free(i->cov_compiled); talloc_free(i->cov_compiled);
i->cov_compiled = NULL; i->cov_compiled = NULL;
...@@ -95,19 +94,18 @@ static char *cov_compile(const void *ctx, ...@@ -95,19 +94,18 @@ static char *cov_compile(const void *ctx,
const char *modobjs, const char *modobjs,
bool keep) 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, if (!compile_and_link(ctx, file->fullname, ccan_dir,
obj_list(m, modobjs), obj_list(m, modobjs),
COVERAGE_CFLAGS, COVERAGE_CFLAGS,
lib_list(m), file->cov_compiled); lib_list(m), file->cov_compiled, &output)) {
if (errmsg) {
talloc_free(file->cov_compiled); talloc_free(file->cov_compiled);
file->cov_compiled = NULL; file->cov_compiled = NULL;
return errmsg; return output;
} }
talloc_free(output);
return NULL; return NULL;
} }
......
...@@ -25,9 +25,14 @@ static char *compile(struct manifest *m, ...@@ -25,9 +25,14 @@ static char *compile(struct manifest *m,
bool keep, bool keep,
struct ccan_file *cfile) 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, "", if (compile_object(m, cfile->fullname, ccan_dir, "",
cfile->compiled); 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,
......
...@@ -71,14 +71,14 @@ static char *compile(const void *ctx, ...@@ -71,14 +71,14 @@ static char *compile(const void *ctx,
char *errmsg; char *errmsg;
file->compiled = maybe_temp_file(ctx, "", keep, file->fullname); file->compiled = maybe_temp_file(ctx, "", keep, file->fullname);
errmsg = compile_and_link(ctx, file->fullname, ccan_dir, if (!compile_and_link(ctx, file->fullname, ccan_dir,
obj_list(m, link_with_module), obj_list(m, link_with_module),
fail ? "-DFAIL" : "", fail ? "-DFAIL" : "",
lib_list(m), file->compiled); lib_list(m), file->compiled, &errmsg)) {
if (errmsg) {
talloc_free(file->compiled); talloc_free(file->compiled);
return errmsg; return errmsg;
} }
talloc_free(errmsg);
return NULL; return NULL;
} }
......
...@@ -119,14 +119,14 @@ static char *compile(const void *ctx, ...@@ -119,14 +119,14 @@ static char *compile(const void *ctx,
char *errmsg; char *errmsg;
file->compiled = maybe_temp_file(ctx, "", keep, file->fullname); file->compiled = maybe_temp_file(ctx, "", keep, file->fullname);
errmsg = compile_and_link(ctx, file->fullname, ccan_dir, if (!compile_and_link(ctx, file->fullname, ccan_dir,
obj_list(m, file), obj_list(m, file),
"", lib_list(m), file->compiled); "", lib_list(m), file->compiled, &errmsg)) {
if (errmsg) {
talloc_free(file->compiled); talloc_free(file->compiled);
file->compiled = NULL; file->compiled = NULL;
return errmsg; return errmsg;
} }
talloc_free(errmsg);
return NULL; return NULL;
} }
......
...@@ -125,7 +125,6 @@ static void do_run_coverage_tests(struct manifest *m, ...@@ -125,7 +125,6 @@ static void do_run_coverage_tests(struct manifest *m,
struct ccan_file *i; struct ccan_file *i;
char *cmdout; char *cmdout;
char *covcmd; char *covcmd;
bool ok;
bool full_gcov = (verbose > 1); bool full_gcov = (verbose > 1);
struct list_head *list; struct list_head *list;
...@@ -137,20 +136,20 @@ static void do_run_coverage_tests(struct manifest *m, ...@@ -137,20 +136,20 @@ static void do_run_coverage_tests(struct manifest *m,
/* Run them all. */ /* Run them all. */
foreach_ptr(list, &m->run_tests, &m->api_tests) { foreach_ptr(list, &m->run_tests, &m->api_tests) {
list_for_each(list, i, list) { list_for_each(list, i, list) {
cmdout = run_command(m, timeleft, i->cov_compiled); if (run_command(score, timeleft, &cmdout,
if (cmdout) { "%s", i->cov_compiled)) {
covcmd = talloc_asprintf_append(covcmd, " %s",
i->fullname);
} else {
score->error = "Running test with coverage"; score->error = "Running test with coverage";
score_file_error(score, i, 0, cmdout); score_file_error(score, i, 0, cmdout);
return; 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 (!run_command(score, timeleft, &cmdout, "%s", covcmd)) {
if (!ok) {
score->error = talloc_asprintf(score, "Running gcov: %s", score->error = talloc_asprintf(score, "Running gcov: %s",
cmdout); cmdout);
return; return;
......
...@@ -35,11 +35,11 @@ static void do_run_tests(struct manifest *m, ...@@ -35,11 +35,11 @@ static void do_run_tests(struct manifest *m,
foreach_ptr(list, &m->run_tests, &m->api_tests) { foreach_ptr(list, &m->run_tests, &m->api_tests) {
list_for_each(list, i, list) { list_for_each(list, i, list) {
score->total++; score->total++;
cmdout = run_command(m, timeleft, i->compiled); if (run_command(m, timeleft, &cmdout, "%s",
if (cmdout) i->compiled))
score_file_error(score, i, 0, cmdout);
else
score->score++; score->score++;
else
score_file_error(score, i, 0, cmdout);
} }
} }
......
...@@ -19,10 +19,10 @@ ...@@ -19,10 +19,10 @@
static const char *can_run_vg(struct manifest *m) static const char *can_run_vg(struct manifest *m)
{ {
unsigned int timeleft = default_timeout_ms; unsigned int timeleft = default_timeout_ms;
char *output = run_command(m, &timeleft, char *output;
"valgrind -q --error-exitcode=0 true");
if (output) if (!run_command(m, &timeleft, &output,
"valgrind -q --error-exitcode=0 true"))
return talloc_asprintf(m, "No valgrind support: %s", output); return talloc_asprintf(m, "No valgrind support: %s", output);
return NULL; return NULL;
} }
...@@ -41,14 +41,14 @@ static void do_run_tests_vg(struct manifest *m, ...@@ -41,14 +41,14 @@ static void do_run_tests_vg(struct manifest *m,
foreach_ptr(list, &m->run_tests, &m->api_tests) { foreach_ptr(list, &m->run_tests, &m->api_tests) {
list_for_each(list, i, list) { list_for_each(list, i, list) {
score->total++; score->total++;
cmdout = run_command(m, timeleft, if (run_command(score, timeleft, &cmdout,
"valgrind -q --error-exitcode=100 %s", "valgrind -q --error-exitcode=100 %s",
i->compiled); i->compiled)) {
if (cmdout) { score->score++;
} else {
score->error = "Running under valgrind"; score->error = "Running under valgrind";
score_file_error(score, i, 0, cmdout); score_file_error(score, i, 0, cmdout);
} else }
score->score++;
} }
} }
......
...@@ -4,7 +4,7 @@ ...@@ -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, char *link_objects(const void *ctx, const char *basename, bool in_pwd,
const char *objs, char **errmsg) const char *objs, char **errmsg)
{ {
...@@ -13,35 +13,34 @@ char *link_objects(const void *ctx, const char *basename, bool in_pwd, ...@@ -13,35 +13,34 @@ char *link_objects(const void *ctx, const char *basename, bool in_pwd,
if (compile_verbose) if (compile_verbose)
printf("Linking objects into %s\n", file); printf("Linking objects into %s\n", file);
*errmsg = run_command(ctx, NULL, "ld -r -o %s %s", file, objs); if (run_command(ctx, NULL, errmsg, "ld -r -o %s %s", file, objs))
if (*errmsg) { return file;
talloc_free(file);
return NULL; talloc_free(file);
} return NULL;
return file;
} }
/* Compile a single C file to an object file. Returns errmsg if fails. */ /* Compile a single C file to an object file. */
char *compile_object(const void *ctx, const char *cfile, const char *ccandir, bool compile_object(const void *ctx, const char *cfile, const char *ccandir,
const char *extra_cflags, const char *extra_cflags,
const char *outfile) const char *outfile, char **output)
{ {
if (compile_verbose) if (compile_verbose)
printf("Compiling %s\n", outfile); 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", " -I%s %s -c -o %s %s",
ccandir, extra_cflags, outfile, cfile); ccandir, extra_cflags, outfile, cfile);
} }
/* Compile and link single C file, with object files. /* Compile and link single C file, with object files.
* Returns error message or NULL on success. */ * Returns false on failure. */
char *compile_and_link(const void *ctx, const char *cfile, const char *ccandir, bool compile_and_link(const void *ctx, const char *cfile, const char *ccandir,
const char *objs, const char *extra_cflags, const char *objs, const char *extra_cflags,
const char *libs, const char *outfile) const char *libs, const char *outfile, char **output)
{ {
if (compile_verbose) if (compile_verbose)
printf("Compiling and linking %s\n", outfile); 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", " -I%s %s -o %s %s %s %s",
ccandir, extra_cflags, outfile, cfile, objs, libs); ccandir, extra_cflags, outfile, cfile, objs, libs);
} }
...@@ -39,7 +39,7 @@ lines_from_cmd(const void *ctx, unsigned int *num, char *format, ...) ...@@ -39,7 +39,7 @@ lines_from_cmd(const void *ctx, unsigned int *num, char *format, ...)
* temp_file helps here. */ * temp_file helps here. */
static char *compile_info(const void *ctx, const char *dir) 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; size_t len;
int fd; int fd;
...@@ -63,9 +63,9 @@ static char *compile_info(const void *ctx, const char *dir) ...@@ -63,9 +63,9 @@ static char *compile_info(const void *ctx, const char *dir)
compiled = maybe_temp_file(ctx, "", false, "info"); compiled = maybe_temp_file(ctx, "", false, "info");
if (compile_and_link(ctx, info_c_file, ccandir, "", "", "", if (compile_and_link(ctx, info_c_file, ccandir, "", "", "",
compiled)) compiled, &output))
return NULL; return compiled;
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,
......
...@@ -143,35 +143,35 @@ char *run_with_timeout(const void *ctx, const char *cmd, ...@@ -143,35 +143,35 @@ char *run_with_timeout(const void *ctx, const char *cmd,
return ret; return ret;
} }
/* Returns output if command fails. */ /* Tallocs *output off ctx; return false if command fails. */
char *run_command(const void *ctx, unsigned int *time_ms, const char *fmt, ...) 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; bool ok;
unsigned int default_time = default_timeout_ms; unsigned int default_time = default_timeout_ms;
if (!time_ms) if (!time_ms)
time_ms = &default_time; time_ms = &default_time;
else if (*time_ms == 0) else if (*time_ms == 0) {
return talloc_strdup(ctx, "\n== TIMED OUT ==\n"); *output = talloc_strdup(ctx, "\n== TIMED OUT ==\n");
return false;
}
va_start(ap, fmt); va_start(ap, fmt);
cmd = talloc_vasprintf(ctx, fmt, ap); cmd = talloc_vasprintf(ctx, fmt, ap);
va_end(ap); va_end(ap);
contents = run_with_timeout(ctx, cmd, &ok, time_ms); *output = run_with_timeout(ctx, cmd, &ok, time_ms);
if (ok) { if (ok)
talloc_free(contents); return true;
return NULL; if (!*output)
}
if (!contents)
err(1, "Problem running child"); err(1, "Problem running child");
if (*time_ms == 0) if (*time_ms == 0)
contents = talloc_asprintf_append(contents, *output = talloc_asprintf_append(*output,
"\n== TIMED OUT ==\n"); "\n== TIMED OUT ==\n");
return contents; return false;
} }
static int unlink_all(char *dir) static int unlink_all(char *dir)
......
#ifndef CCAN_TOOLS_H #ifndef CCAN_TOOLS_H
#define CCAN_TOOLS_H #define CCAN_TOOLS_H
#include <stdbool.h> #include <stdbool.h>
#include <ccan/compiler/compiler.h>
#include "config.h" #include "config.h"
#ifndef CCAN_COMPILER #ifndef CCAN_COMPILER
...@@ -36,7 +37,10 @@ extern bool tools_verbose; ...@@ -36,7 +37,10 @@ extern bool tools_verbose;
char *talloc_basename(const void *ctx, const char *dir); char *talloc_basename(const void *ctx, const char *dir);
char *talloc_dirname(const void *ctx, const char *dir); char *talloc_dirname(const void *ctx, const char *dir);
char *talloc_getcwd(const void *ctx); 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, char *run_with_timeout(const void *ctx, const char *cmd,
bool *ok, unsigned *timeout_ms); bool *ok, unsigned *timeout_ms);
char *temp_dir(const void *ctx); char *temp_dir(const void *ctx);
...@@ -52,15 +56,14 @@ extern bool compile_verbose; ...@@ -52,15 +56,14 @@ extern bool compile_verbose;
/* Compile multiple object files into a single. */ /* Compile multiple object files into a single. */
char *link_objects(const void *ctx, const char *basename, bool in_pwd, char *link_objects(const void *ctx, const char *basename, bool in_pwd,
const char *objs, char **errmsg); const char *objs, char **errmsg);
/* Compile a single C file to an object file. Returns errmsg if fails. */ /* Compile a single C file to an object file. Returns false if fails. */
char *compile_object(const void *ctx, const char *cfile, const char *ccandir, bool compile_object(const void *ctx, const char *cfile, const char *ccandir,
const char *extra_cflags, const char *extra_cflags,
const char *outfile); const char *outfile, char **output);
/* Compile and link single C file, with object files, libs, etc. NULL on /* Compile and link single C file, with object files, libs, etc. */
* success, error output on fail. */ bool compile_and_link(const void *ctx, const char *cfile, const char *ccandir,
char *compile_and_link(const void *ctx, const char *cfile, const char *ccandir, const char *objs, const char *extra_cflags,
const char *objs, const char *extra_cflags, const char *libs, const char *outfile, char **output);
const char *libs, const char *outfile);
/* If in_pwd is false, return a file int temp_dir, otherwise a local file. */ /* 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, char *maybe_temp_file(const void *ctx, const char *extension, bool in_pwd,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment