Commit dfc94d4a authored by Rusty Russell's avatar Rusty Russell

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.
parent 27b8937c
#include <tools/ccanlint/ccanlint.h>
#include <tools/tools.h>
#include <ccan/htable/htable_type.h>
#include <ccan/foreach/foreach.h>
#include <ccan/talloc/talloc.h>
#include <ccan/grab_file/grab_file.h>
#include <ccan/str/str.h>
#include <ccan/str_talloc/str_talloc.h>
#include <ccan/hash/hash.h>
#include <ccan/read_write_all/read_write_all.h>
#include <errno.h>
#include <err.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#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);
#ifndef CCANLINT_REDUCE_FEATURES_H
#define CCANLINT_REDUCE_FEATURES_H
extern bool features_were_reduced;
#endif /* CCANLINT_REDUCE_FEATURES_H */
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