build-coverage.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include <tools/ccanlint/ccanlint.h>
  2. #include <tools/tools.h>
  3. #include <ccan/talloc/talloc.h>
  4. #include <ccan/str/str.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <unistd.h>
  9. #include <limits.h>
  10. #include <errno.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <err.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. /* Note: we already test safe_mode in run_tests.c */
  17. static const char *can_run_coverage(struct manifest *m)
  18. {
  19. unsigned int timeleft = default_timeout_ms;
  20. char *output = run_command(m, &timeleft, "gcov -h");
  21. if (output)
  22. return talloc_asprintf(m, "No gcov support: %s", output);
  23. return NULL;
  24. }
  25. static bool build_module_objs_with_coverage(struct manifest *m, bool keep,
  26. struct score *score,
  27. char **modobjs)
  28. {
  29. struct ccan_file *i;
  30. *modobjs = talloc_strdup(m, "");
  31. list_for_each(&m->c_files, i, list) {
  32. char *err;
  33. char *fullfile = talloc_asprintf(m, "%s/%s", m->dir, i->name);
  34. i->cov_compiled = maybe_temp_file(m, "", keep, fullfile);
  35. err = compile_object(m, fullfile, ccan_dir, "",
  36. i->cov_compiled);
  37. if (err) {
  38. score_file_error(score, i, 0, err);
  39. talloc_free(i->cov_compiled);
  40. i->cov_compiled = NULL;
  41. return false;
  42. }
  43. *modobjs = talloc_asprintf_append(*modobjs,
  44. " %s", i->cov_compiled);
  45. }
  46. return true;
  47. }
  48. static char *obj_list(const struct manifest *m, const char *modobjs)
  49. {
  50. char *list;
  51. struct ccan_file *i;
  52. /* We expect to be linked with tap, unless that's us. */
  53. if (!streq(m->basename, "tap"))
  54. list = talloc_asprintf(m, "%s/ccan/tap.o", ccan_dir);
  55. else
  56. list = talloc_strdup(m, "");
  57. /* Objects from any other C files. */
  58. list_for_each(&m->other_test_c_files, i, list)
  59. list = talloc_asprintf_append(list, " %s", i->compiled);
  60. if (modobjs)
  61. list = talloc_append_string(list, modobjs);
  62. /* Other ccan modules (don't need coverage versions of those). */
  63. list_for_each(&m->dep_dirs, i, list) {
  64. if (i->compiled)
  65. list = talloc_asprintf_append(list, " %s", i->compiled);
  66. }
  67. return list;
  68. }
  69. static char *lib_list(const struct manifest *m)
  70. {
  71. unsigned int i, num;
  72. char **libs = get_libs(m, m->dir, &num, &m->info_file->compiled);
  73. char *ret = talloc_strdup(m, "");
  74. for (i = 0; i < num; i++)
  75. ret = talloc_asprintf_append(ret, "-l%s ", libs[i]);
  76. return ret;
  77. }
  78. static char *cov_compile(const void *ctx,
  79. struct manifest *m,
  80. struct ccan_file *file,
  81. const char *modobjs,
  82. bool keep)
  83. {
  84. char *errmsg;
  85. file->cov_compiled = maybe_temp_file(ctx, "", keep, file->fullname);
  86. errmsg = compile_and_link(ctx, file->fullname, ccan_dir,
  87. obj_list(m, modobjs),
  88. COVERAGE_CFLAGS,
  89. lib_list(m), file->cov_compiled);
  90. if (errmsg) {
  91. talloc_free(file->cov_compiled);
  92. file->cov_compiled = NULL;
  93. return errmsg;
  94. }
  95. return NULL;
  96. }
  97. /* FIXME: Coverage from testable examples as well. */
  98. static void do_compile_coverage_tests(struct manifest *m,
  99. bool keep,
  100. unsigned int *timeleft,
  101. struct score *score)
  102. {
  103. char *cmdout, *modobjs = NULL;
  104. struct ccan_file *i;
  105. if (!list_empty(&m->api_tests)
  106. && !build_module_objs_with_coverage(m, keep, score, &modobjs)) {
  107. score->error = "Failed to compile module objects with coverage";
  108. return;
  109. }
  110. list_for_each(&m->run_tests, i, list) {
  111. cmdout = cov_compile(m, m, i, NULL, keep);
  112. if (cmdout) {
  113. score->error = "Failed to compile test with coverage";
  114. score_file_error(score, i, 0, cmdout);
  115. }
  116. }
  117. list_for_each(&m->api_tests, i, list) {
  118. cmdout = cov_compile(m, m, i, modobjs, keep);
  119. if (cmdout) {
  120. score->error = "Failed to compile test with coverage";
  121. score_file_error(score, i, 0, cmdout);
  122. }
  123. }
  124. if (!score->error) {
  125. score->pass = true;
  126. score->score = score->total;
  127. }
  128. }
  129. struct ccanlint compile_coverage_tests = {
  130. .key = "compile-coverage-tests",
  131. .name = "Module tests compile with profiling",
  132. .check = do_compile_coverage_tests,
  133. .can_run = can_run_coverage,
  134. };
  135. REGISTER_TEST(compile_coverage_tests, &compile_tests, NULL);