examples_compile.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #include <tools/ccanlint/ccanlint.h>
  2. #include <tools/tools.h>
  3. #include <ccan/talloc/talloc.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <stdint.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <ctype.h>
  11. static const char *can_run(struct manifest *m)
  12. {
  13. if (safe_mode)
  14. return "Safe mode enabled";
  15. return NULL;
  16. }
  17. static char *obj_list(const struct manifest *m)
  18. {
  19. char *list;
  20. struct ccan_file *i;
  21. /* Object files for this module. */
  22. list_for_each(&m->c_files, i, list)
  23. list = talloc_asprintf_append(list, " %s", i->compiled);
  24. /* Other ccan modules we depend on. */
  25. list_for_each(&m->dep_dirs, i, list) {
  26. if (i->compiled)
  27. list = talloc_asprintf_append(list, " %s", i->compiled);
  28. }
  29. return list;
  30. }
  31. static char *lib_list(const struct manifest *m)
  32. {
  33. unsigned int i, num;
  34. char **libs = get_libs(m, ".", &num, &m->info_file->compiled);
  35. char *ret = talloc_strdup(m, "");
  36. for (i = 0; i < num; i++)
  37. ret = talloc_asprintf_append(ret, "-l%s ", libs[i]);
  38. return ret;
  39. }
  40. static char *compile(const void *ctx,
  41. struct manifest *m,
  42. struct ccan_file *file,
  43. bool keep)
  44. {
  45. char *errmsg;
  46. file->compiled = maybe_temp_file(ctx, "", keep, file->fullname);
  47. errmsg = compile_and_link(ctx, file->fullname, ccan_dir,
  48. obj_list(m), "", lib_list(m), file->compiled);
  49. if (errmsg) {
  50. talloc_free(file->compiled);
  51. return errmsg;
  52. }
  53. return NULL;
  54. }
  55. struct score {
  56. unsigned int score;
  57. char *errors;
  58. };
  59. static char *start_main(char *ret)
  60. {
  61. return talloc_asprintf_append(ret,
  62. "/* Fake function wrapper inserted */\n"
  63. "int main(int argc, char *argv[])\n"
  64. "{\n");
  65. }
  66. static char *mangle(struct manifest *m, struct ccan_file *example)
  67. {
  68. char **lines = get_ccan_file_lines(example);
  69. char *ret;
  70. bool in_function = false, fake_function = false;
  71. unsigned int i;
  72. ret = talloc_strdup(m, "/* Prepend a heap of headers. */\n"
  73. "#include <assert.h>\n"
  74. "#include <err.h>\n"
  75. "#include <fcntl.h>\n"
  76. "#include <stdbool.h>\n"
  77. "#include <stdint.h>\n"
  78. "#include <stdio.h>\n"
  79. "#include <stdlib.h>\n"
  80. "#include <string.h>\n"
  81. "#include <sys/stat.h>\n"
  82. "#include <sys/types.h>\n"
  83. "#include <unistd.h>\n");
  84. ret = talloc_asprintf_append(ret, "/* Include header from module. */\n"
  85. "#include <ccan/%s/%s.h>\n",
  86. m->basename, m->basename);
  87. ret = talloc_asprintf_append(ret, "/* Useful dummmy functions. */\n"
  88. "int somefunc(void);\n"
  89. "int somefunc(void) { return 0; }\n");
  90. /* Starts indented? Wrap it in a main() function. */
  91. if (lines[0] && isblank(lines[0][0])) {
  92. ret = start_main(ret);
  93. fake_function = true;
  94. in_function = true;
  95. }
  96. /* Primitive, very primitive. */
  97. for (i = 0; lines[i]; i++) {
  98. /* } at start of line ends a function. */
  99. if (in_function) {
  100. if (lines[i][0] == '}')
  101. in_function = false;
  102. } else {
  103. /* Character at start of line, with ( and no ;
  104. * == function start. */
  105. if (!isblank(lines[i][0])
  106. && strchr(lines[i], '(')
  107. && !strchr(lines[i], ';'))
  108. in_function = true;
  109. }
  110. /* ... means elided code. If followed by spaced line, means
  111. * next part is supposed to be inside a function. */
  112. if (strcmp(lines[i], "...") == 0) {
  113. if (!in_function
  114. && lines[i+1]
  115. && isblank(lines[i+1][0])) {
  116. /* This implies we start a function here. */
  117. ret = start_main(ret);
  118. fake_function = true;
  119. in_function = true;
  120. }
  121. ret = talloc_asprintf_append(ret,
  122. "/* ... removed */\n");
  123. continue;
  124. }
  125. ret = talloc_asprintf_append(ret, "%s\n", lines[i]);
  126. }
  127. if (fake_function)
  128. ret = talloc_asprintf_append(ret, "return 0;\n"
  129. "}\n");
  130. return ret;
  131. }
  132. static struct ccan_file *mangle_example(struct manifest *m,
  133. struct ccan_file *example, bool keep)
  134. {
  135. char *name, *contents;
  136. int fd;
  137. struct ccan_file *f;
  138. name = maybe_temp_file(example, ".c", keep,
  139. talloc_asprintf(m, "%s/mangled-%s",
  140. m->dir, example->name));
  141. f = new_ccan_file(example,
  142. talloc_dirname(example, name),
  143. talloc_basename(example, name));
  144. talloc_steal(f, name);
  145. fd = open(f->fullname, O_WRONLY | O_CREAT | O_EXCL, 0600);
  146. if (fd < 0)
  147. return NULL;
  148. contents = mangle(m, example);
  149. if (write(fd, contents, strlen(contents)) != strlen(contents)) {
  150. close(fd);
  151. return NULL;
  152. }
  153. close(fd);
  154. return f;
  155. }
  156. static void *build_examples(struct manifest *m, bool keep,
  157. unsigned int *timeleft)
  158. {
  159. struct ccan_file *i;
  160. struct score *score = talloc(m, struct score);
  161. score->score = 0;
  162. score->errors = NULL;
  163. list_for_each(&m->examples, i, list) {
  164. char *ret;
  165. examples_compile.total_score++;
  166. ret = compile(score, m, i, keep);
  167. if (!ret)
  168. score->score++;
  169. else {
  170. struct ccan_file *mangle = mangle_example(m, i, keep);
  171. talloc_free(ret);
  172. ret = compile(score, m, mangle, keep);
  173. if (!ret)
  174. score->score++;
  175. else {
  176. if (!score->errors)
  177. score->errors = ret;
  178. else {
  179. score->errors
  180. = talloc_append_string(score->errors,
  181. ret);
  182. talloc_free(ret);
  183. }
  184. }
  185. }
  186. }
  187. return score;
  188. }
  189. static unsigned int score_examples(struct manifest *m, void *check_result)
  190. {
  191. struct score *score = check_result;
  192. return score->score;
  193. }
  194. static const char *describe(struct manifest *m, void *check_result)
  195. {
  196. struct score *score = check_result;
  197. if (verbose >= 2 && score->errors)
  198. return talloc_asprintf(m, "Compile errors building examples:\n"
  199. "%s", score->errors);
  200. return NULL;
  201. }
  202. struct ccanlint examples_compile = {
  203. .key = "examples-compile",
  204. .name = "Module examples compile",
  205. .score = score_examples,
  206. .check = build_examples,
  207. .describe = describe,
  208. .can_run = can_run,
  209. };
  210. REGISTER_TEST(examples_compile, &has_examples, NULL);