From: Rusty Russell Date: Tue, 1 Mar 2011 07:18:11 +0000 (+1030) Subject: ccanlint: create reduce-feature config.h X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=dfc94d4a4b80729b092089536caa33c0620a5ea9 ccanlint: create reduce-feature config.h A common mistake is not to try compiling with features disabled in config.h. The ideal case would determine how features interact and test all combinations of them: this simply disables any features mentioned in the code which were previously enabled. --- diff --git a/tools/ccanlint/tests/reduce_features.c b/tools/ccanlint/tests/reduce_features.c new file mode 100644 index 00000000..2a389ce5 --- /dev/null +++ b/tools/ccanlint/tests/reduce_features.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "reduce_features.h" + +bool features_were_reduced; + +static const char *can_run(struct manifest *m) +{ + if (!config_header) + return talloc_strdup(m, "Could not read config.h"); + return NULL; +} + +static size_t option_hash(const char *name) +{ + return hash(name, strlen(name), 0); +} + +static const char *option_name(const char *name) +{ + return name; +} + +static bool option_cmp(const char *name1, const char *name2) +{ + return streq(name1, name2); +} + +HTABLE_DEFINE_TYPE(char, option_name, option_hash, option_cmp, option); + +static unsigned int add_options(struct htable_option *opts, + struct pp_conditions *cond) +{ + unsigned int num = 0; + if (cond->parent) + num += add_options(opts, cond->parent); + if (cond->type == PP_COND_IF || cond->type == PP_COND_IFDEF) { + if (strstarts(cond->symbol, "HAVE_")) { + if (!htable_option_get(opts, cond->symbol)) { + htable_option_add(opts, cond->symbol); + num++; + } + } + } + return num; +} + +static struct htable_option *get_used_options(struct manifest *m) +{ + struct list_head *list; + struct ccan_file *f; + unsigned int i, num; + struct htable_option *opts = htable_option_new(); + struct line_info *info; + + num = 0; + foreach_ptr(list, &m->c_files, &m->h_files) { + list_for_each(list, f, list) { + info = get_ccan_line_info(f); + struct pp_conditions *prev = NULL; + + for (i = 0; i < f->num_lines; i++) { + if (info[i].cond && info[i].cond != prev) { + num += add_options(opts, info[i].cond); + prev = info[i].cond; + } + } + } + } + + if (!num) { + htable_option_free(opts); + opts = NULL; + } + return opts; +} + +static struct htable_option *get_config_options(struct manifest *m) +{ + const char **lines = (const char **)strsplit(m, config_header, "\n"); + unsigned int i; + struct htable_option *opts = htable_option_new(); + + for (i = 0; i < talloc_array_length(lines) - 1; i++) { + char *sym; + + if (!get_token(&lines[i], "#")) + continue; + if (!get_token(&lines[i], "define")) + continue; + sym = get_symbol_token(lines, &lines[i]); + if (!strstarts(sym, "HAVE_")) + continue; + /* Don't override endian... */ + if (strends(sym, "_ENDIAN")) + continue; + if (!get_token(&lines[i], "1")) + continue; + htable_option_add(opts, sym); + } + return opts; +} + +static void do_reduce_features(struct manifest *m, + bool keep, + unsigned int *timeleft, struct score *score) +{ + struct htable_option *options_used, *options_avail, *options; + struct htable_option_iter i; + int fd; + const char *sym; + char *hdr; + + /* This isn't really a test, as such. */ + score->total = 0; + score->pass = true; + + options_used = get_used_options(m); + if (!options_used) { + return; + } + options_avail = get_config_options(m); + + options = NULL; + for (sym = htable_option_first(options_used, &i); + sym; + sym = htable_option_next(options_used, &i)) { + if (htable_option_get(options_avail, sym)) { + if (!options) + options = htable_option_new(); + htable_option_add(options, sym); + } + } + htable_option_free(options_avail); + htable_option_free(options_used); + + if (!options) + return; + + /* Now make our own config.h variant, with our own options. */ + hdr = talloc_strdup(m, "/* Modified by reduce_features */\n"); + hdr = talloc_append_string(hdr, config_header); + for (sym = htable_option_first(options, &i); + sym; + sym = htable_option_next(options, &i)) { + hdr = talloc_asprintf_append + (hdr, "#undef %s\n#define %s 0\n", sym, sym); + } + fd = open("config.h", O_EXCL|O_CREAT|O_RDWR, 0600); + if (fd < 0) + err(1, "Creating config.h"); + if (!write_all(fd, hdr, strlen(hdr))) + err(1, "Writing config.h"); + close(fd); + features_were_reduced = true; +} + +struct ccanlint reduce_features = { + .key = "reduce_features", + .name = "Produce config.h with reduced features", + .can_run = can_run, + .check = do_reduce_features, + .needs = "tests_compile" +}; +REGISTER_TEST(reduce_features); diff --git a/tools/ccanlint/tests/reduce_features.h b/tools/ccanlint/tests/reduce_features.h new file mode 100644 index 00000000..f646941a --- /dev/null +++ b/tools/ccanlint/tests/reduce_features.h @@ -0,0 +1,4 @@ +#ifndef CCANLINT_REDUCE_FEATURES_H +#define CCANLINT_REDUCE_FEATURES_H +extern bool features_were_reduced; +#endif /* CCANLINT_REDUCE_FEATURES_H */