reduce_features.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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>
  11. #include <errno.h>
  12. #include <err.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <fcntl.h>
  16. #include <unistd.h>
  17. #include "reduce_features.h"
  18. bool features_were_reduced;
  19. static const char *can_run(struct manifest *m)
  20. {
  21. if (!config_header)
  22. return talloc_strdup(m, "Could not read config.h");
  23. return NULL;
  24. }
  25. static size_t option_hash(const char *name)
  26. {
  27. return hash(name, strlen(name), 0);
  28. }
  29. static const char *option_name(const char *name)
  30. {
  31. return name;
  32. }
  33. static bool option_cmp(const char *name1, const char *name2)
  34. {
  35. return streq(name1, name2);
  36. }
  37. HTABLE_DEFINE_TYPE(char, option_name, option_hash, option_cmp, option);
  38. static unsigned int add_options(struct htable_option *opts,
  39. struct pp_conditions *cond)
  40. {
  41. unsigned int num = 0;
  42. if (cond->parent)
  43. num += add_options(opts, cond->parent);
  44. if (cond->type == PP_COND_IF || cond->type == PP_COND_IFDEF) {
  45. if (strstarts(cond->symbol, "HAVE_")) {
  46. if (!htable_option_get(opts, cond->symbol)) {
  47. htable_option_add(opts, cond->symbol);
  48. num++;
  49. }
  50. }
  51. }
  52. return num;
  53. }
  54. static struct htable_option *get_used_options(struct manifest *m)
  55. {
  56. struct list_head *list;
  57. struct ccan_file *f;
  58. unsigned int i, num;
  59. struct htable_option *opts = htable_option_new();
  60. struct line_info *info;
  61. num = 0;
  62. foreach_ptr(list, &m->c_files, &m->h_files) {
  63. list_for_each(list, f, list) {
  64. info = get_ccan_line_info(f);
  65. struct pp_conditions *prev = NULL;
  66. for (i = 0; i < f->num_lines; i++) {
  67. if (info[i].cond && info[i].cond != prev) {
  68. num += add_options(opts, info[i].cond);
  69. prev = info[i].cond;
  70. }
  71. }
  72. }
  73. }
  74. if (!num) {
  75. htable_option_free(opts);
  76. opts = NULL;
  77. }
  78. return opts;
  79. }
  80. static struct htable_option *get_config_options(struct manifest *m)
  81. {
  82. const char **lines = (const char **)strsplit(m, config_header, "\n");
  83. unsigned int i;
  84. struct htable_option *opts = htable_option_new();
  85. for (i = 0; i < talloc_array_length(lines) - 1; i++) {
  86. char *sym;
  87. if (!get_token(&lines[i], "#"))
  88. continue;
  89. if (!get_token(&lines[i], "define"))
  90. continue;
  91. sym = get_symbol_token(lines, &lines[i]);
  92. if (!strstarts(sym, "HAVE_"))
  93. continue;
  94. /* Don't override endian... */
  95. if (strends(sym, "_ENDIAN"))
  96. continue;
  97. if (!get_token(&lines[i], "1"))
  98. continue;
  99. htable_option_add(opts, sym);
  100. }
  101. return opts;
  102. }
  103. static void do_reduce_features(struct manifest *m,
  104. bool keep,
  105. unsigned int *timeleft, struct score *score)
  106. {
  107. struct htable_option *options_used, *options_avail, *options;
  108. struct htable_option_iter i;
  109. int fd;
  110. const char *sym;
  111. char *hdr;
  112. /* This isn't really a test, as such. */
  113. score->total = 0;
  114. score->pass = true;
  115. options_used = get_used_options(m);
  116. if (!options_used) {
  117. return;
  118. }
  119. options_avail = get_config_options(m);
  120. options = NULL;
  121. for (sym = htable_option_first(options_used, &i);
  122. sym;
  123. sym = htable_option_next(options_used, &i)) {
  124. if (htable_option_get(options_avail, sym)) {
  125. if (!options)
  126. options = htable_option_new();
  127. htable_option_add(options, sym);
  128. }
  129. }
  130. htable_option_free(options_avail);
  131. htable_option_free(options_used);
  132. if (!options)
  133. return;
  134. /* Now make our own config.h variant, with our own options. */
  135. hdr = talloc_strdup(m, "/* Modified by reduce_features */\n");
  136. hdr = talloc_append_string(hdr, config_header);
  137. for (sym = htable_option_first(options, &i);
  138. sym;
  139. sym = htable_option_next(options, &i)) {
  140. hdr = talloc_asprintf_append
  141. (hdr, "#undef %s\n#define %s 0\n", sym, sym);
  142. }
  143. if (mkdir("reduced-features", 0700) != 0)
  144. err(1, "Creating reduced-features directory");
  145. fd = open("reduced-features/config.h", O_EXCL|O_CREAT|O_RDWR, 0600);
  146. if (fd < 0)
  147. err(1, "Creating reduced-features/config.h");
  148. if (!write_all(fd, hdr, strlen(hdr)))
  149. err(1, "Writing reduced-features/config.h");
  150. close(fd);
  151. features_were_reduced = true;
  152. }
  153. struct ccanlint reduce_features = {
  154. .key = "reduce_features",
  155. .name = "Produce config.h with reduced features",
  156. .can_run = can_run,
  157. .check = do_reduce_features,
  158. /* We only want to compile up versions with reduced featuress once
  159. * objects for normal tests are built. */
  160. .needs = "tests_compile"
  161. };
  162. REGISTER_TEST(reduce_features);