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, htable_option);
45 static struct htable_option *htable_option_new(void)
47 struct htable_option *opts = malloc(sizeof(*opts));
48 htable_option_init(opts);
52 static void htable_option_free(struct htable_option *opts)
54 htable_option_clear(opts);
58 static unsigned int add_options(struct htable_option *opts,
59 struct pp_conditions *cond)
63 num += add_options(opts, cond->parent);
64 if (cond->type == PP_COND_IF || cond->type == PP_COND_IFDEF) {
65 if (strstarts(cond->symbol, "HAVE_")) {
66 if (!htable_option_get(opts, cond->symbol)) {
67 htable_option_add(opts, cond->symbol);
75 static struct htable_option *get_used_options(struct manifest *m)
77 struct list_head *list;
80 struct htable_option *opts = htable_option_new();
81 struct line_info *info;
84 foreach_ptr(list, &m->c_files, &m->h_files) {
85 list_for_each(list, f, list) {
86 info = get_ccan_line_info(f);
87 struct pp_conditions *prev = NULL;
89 for (i = 0; i < f->num_lines; i++) {
90 if (info[i].cond && info[i].cond != prev) {
91 num += add_options(opts, info[i].cond);
99 htable_option_free(opts);
105 static struct htable_option *get_config_options(struct manifest *m)
107 const char **lines = (const char **)strsplit(m, config_header, "\n");
109 struct htable_option *opts = htable_option_new();
111 for (i = 0; i < talloc_array_length(lines) - 1; i++) {
114 if (!get_token(&lines[i], "#"))
116 if (!get_token(&lines[i], "define"))
118 sym = get_symbol_token(lines, &lines[i]);
119 if (!strstarts(sym, "HAVE_"))
121 /* Don't override endian... */
122 if (strends(sym, "_ENDIAN"))
124 if (!get_token(&lines[i], "1"))
126 htable_option_add(opts, sym);
131 static void do_reduce_features(struct manifest *m,
133 unsigned int *timeleft, struct score *score)
135 struct htable_option *options_used, *options_avail, *options;
136 struct htable_option_iter i;
141 /* This isn't really a test, as such. */
145 options_used = get_used_options(m);
149 options_avail = get_config_options(m);
152 for (sym = htable_option_first(options_used, &i);
154 sym = htable_option_next(options_used, &i)) {
155 if (htable_option_get(options_avail, sym)) {
157 options = htable_option_new();
158 htable_option_add(options, sym);
161 htable_option_free(options_avail);
162 htable_option_free(options_used);
167 /* Now make our own config.h variant, with our own options. */
168 hdr = talloc_strdup(m, "/* Modified by reduce_features */\n");
169 hdr = talloc_append_string(hdr, config_header);
170 for (sym = htable_option_first(options, &i);
172 sym = htable_option_next(options, &i)) {
173 hdr = talloc_asprintf_append
174 (hdr, "#undef %s\n#define %s 0\n", sym, sym);
176 if (mkdir("reduced-features", 0700) != 0 && errno != EEXIST)
177 err(1, "Creating reduced-features directory");
179 fd = open("reduced-features/config.h", O_TRUNC|O_CREAT|O_RDWR, 0600);
181 err(1, "Creating reduced-features/config.h");
182 if (!write_all(fd, hdr, strlen(hdr)))
183 err(1, "Writing reduced-features/config.h");
185 features_were_reduced = true;
188 struct ccanlint reduce_features = {
189 .key = "reduce_features",
190 .name = "Produce config.h with reduced features",
192 .check = do_reduce_features,
193 /* We only want to compile up versions with reduced featuress once
194 * objects for normal tests are built. */
195 .needs = "tests_compile"
197 REGISTER_TEST(reduce_features);