1 #include <tools/ccanlint/ccanlint.h>
2 #include <tools/tools.h>
3 #include <ccan/htable/htable_type.h>
4 #include <ccan/foreach/foreach.h>
5 #include <ccan/talloc/talloc.h>
6 #include <ccan/grab_file/grab_file.h>
7 #include <ccan/str/str.h>
8 #include <ccan/str_talloc/str_talloc.h>
9 #include <ccan/hash/hash.h>
10 #include <ccan/read_write_all/read_write_all.h>
13 #include <sys/types.h>
17 #include "reduce_features.h"
19 bool features_were_reduced;
21 static const char *can_run(struct manifest *m)
24 return talloc_strdup(m, "Could not read config.h");
28 static size_t option_hash(const char *name)
30 return hash(name, strlen(name), 0);
33 static const char *option_name(const char *name)
38 static bool option_cmp(const char *name1, const char *name2)
40 return streq(name1, name2);
43 HTABLE_DEFINE_TYPE(char, option_name, option_hash, option_cmp, option);
45 static unsigned int add_options(struct htable_option *opts,
46 struct pp_conditions *cond)
50 num += add_options(opts, cond->parent);
51 if (cond->type == PP_COND_IF || cond->type == PP_COND_IFDEF) {
52 if (strstarts(cond->symbol, "HAVE_")) {
53 if (!htable_option_get(opts, cond->symbol)) {
54 htable_option_add(opts, cond->symbol);
62 static struct htable_option *get_used_options(struct manifest *m)
64 struct list_head *list;
67 struct htable_option *opts = htable_option_new();
68 struct line_info *info;
71 foreach_ptr(list, &m->c_files, &m->h_files) {
72 list_for_each(list, f, list) {
73 info = get_ccan_line_info(f);
74 struct pp_conditions *prev = NULL;
76 for (i = 0; i < f->num_lines; i++) {
77 if (info[i].cond && info[i].cond != prev) {
78 num += add_options(opts, info[i].cond);
86 htable_option_free(opts);
92 static struct htable_option *get_config_options(struct manifest *m)
94 const char **lines = (const char **)strsplit(m, config_header, "\n");
96 struct htable_option *opts = htable_option_new();
98 for (i = 0; i < talloc_array_length(lines) - 1; i++) {
101 if (!get_token(&lines[i], "#"))
103 if (!get_token(&lines[i], "define"))
105 sym = get_symbol_token(lines, &lines[i]);
106 if (!strstarts(sym, "HAVE_"))
108 /* Don't override endian... */
109 if (strends(sym, "_ENDIAN"))
111 if (!get_token(&lines[i], "1"))
113 htable_option_add(opts, sym);
118 static void do_reduce_features(struct manifest *m,
120 unsigned int *timeleft, struct score *score)
122 struct htable_option *options_used, *options_avail, *options;
123 struct htable_option_iter i;
128 /* This isn't really a test, as such. */
132 options_used = get_used_options(m);
136 options_avail = get_config_options(m);
139 for (sym = htable_option_first(options_used, &i);
141 sym = htable_option_next(options_used, &i)) {
142 if (htable_option_get(options_avail, sym)) {
144 options = htable_option_new();
145 htable_option_add(options, sym);
148 htable_option_free(options_avail);
149 htable_option_free(options_used);
154 /* Now make our own config.h variant, with our own options. */
155 hdr = talloc_strdup(m, "/* Modified by reduce_features */\n");
156 hdr = talloc_append_string(hdr, config_header);
157 for (sym = htable_option_first(options, &i);
159 sym = htable_option_next(options, &i)) {
160 hdr = talloc_asprintf_append
161 (hdr, "#undef %s\n#define %s 0\n", sym, sym);
163 fd = open("config.h", O_EXCL|O_CREAT|O_RDWR, 0600);
165 err(1, "Creating config.h");
166 if (!write_all(fd, hdr, strlen(hdr)))
167 err(1, "Writing config.h");
169 features_were_reduced = true;
172 struct ccanlint reduce_features = {
173 .key = "reduce_features",
174 .name = "Produce config.h with reduced features",
176 .check = do_reduce_features,
177 /* We only want to compile up versions with reduced featuress once
178 * objects for normal tests are built. */
179 .needs = "tests_compile"
181 REGISTER_TEST(reduce_features);