generate_ppapi_include_tests.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env python
  2. # Copyright (c) 2012 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """This script should be run manually on occasion to make sure the gyp file and
  6. the includes tests are up to date.
  7. It does the following:
  8. - Verifies that all source code is in ppapi.gyp
  9. - Verifies that all sources in ppapi.gyp really do exist
  10. - Generates tests/test_c_includes.c
  11. - Generates tests/test_cpp_includes.cc
  12. These tests are checked in to SVN.
  13. """
  14. # TODO(dmichael): Make this script execute as a gyp action, move the include
  15. # tests to some 'generated' area, and remove them from version
  16. # control.
  17. from __future__ import print_function
  18. import re
  19. import os
  20. import sys
  21. import posixpath
  22. # A simple regular expression that should match source files for C++ and C.
  23. SOURCE_FILE_RE = re.compile('.+\.(cc|c|h)$')
  24. # IGNORE_RE is a regular expression that matches directories which contain
  25. # source that we don't (currently) expect to be in ppapi.gyp. This script will
  26. # not check whether source files under these directories are in the gyp file.
  27. # TODO(dmichael): Put examples back in the build.
  28. # TODO(brettw): Put proxy in the build when it's ready.
  29. IGNORE_RE = re.compile('^(examples|GLES2|proxy|tests\/clang).*')
  30. GYP_TARGETS_KEY = 'targets'
  31. GYP_SOURCES_KEY = 'sources'
  32. GYP_TARGET_NAME_KEY = 'target_name'
  33. # Return a set containing all source files found given an object read from a gyp
  34. # file.
  35. def GetAllGypSources(gyp_file_data):
  36. sources = set([])
  37. for target in gyp_file_data[GYP_TARGETS_KEY]:
  38. # Get a list of sources in the target that are not ignored, and 'normalize'
  39. # them. The main reason for this is to turn the forward slashes in the gyp
  40. # file in to backslashes when the script is run on Windows.
  41. source_list = [posixpath.normpath(src) for src in target[GYP_SOURCES_KEY]
  42. if not IGNORE_RE.match(src)]
  43. sources |= set(source_list)
  44. return sources
  45. # Search the directory named start_root and all its subdirectories for source
  46. # files.
  47. # Return a set containing the string names of all the source files found,
  48. # relative to start_root.
  49. def GetFileSources(start_root):
  50. file_set = set([])
  51. for root, dirs, files in os.walk(start_root):
  52. relative_root = os.path.relpath(root, start_root)
  53. if not IGNORE_RE.match(relative_root):
  54. for source in files:
  55. if SOURCE_FILE_RE.match(source):
  56. file_set |= set([os.path.join(relative_root, source)])
  57. return file_set
  58. # Make sure all source files are in the given gyp object (evaluated from a gyp
  59. # file), and that all source files listed in the gyp object exist in the
  60. # directory.
  61. def VerifyGypFile(gyp_file_data):
  62. gyp_sources = GetAllGypSources(gyp_file_data)
  63. file_sources = GetFileSources('.')
  64. in_gyp_not_file = gyp_sources - file_sources
  65. in_file_not_gyp = file_sources - gyp_sources
  66. if len(in_gyp_not_file):
  67. print('Found source file(s) in ppapi.gyp but not in the directory:', \
  68. in_gyp_not_file)
  69. if len(in_file_not_gyp):
  70. print('Found source file(s) in the directory but not in ppapi.gyp:', \
  71. in_file_not_gyp)
  72. error_count = len(in_gyp_not_file) + len(in_file_not_gyp)
  73. if error_count:
  74. sys.exit(error_count)
  75. def WriteLines(filename, lines):
  76. outfile = open(filename, 'w')
  77. for line in lines:
  78. outfile.write(line)
  79. outfile.write('\n')
  80. COPYRIGHT_STRING_C = \
  81. """/* Copyright (c) 2010 The Chromium Authors. All rights reserved.
  82. * Use of this source code is governed by a BSD-style license that can be
  83. * found in the LICENSE file.
  84. *
  85. * This test simply includes all the C headers to ensure they compile with a C
  86. * compiler. If it compiles, it passes.
  87. */
  88. """
  89. COPYRIGHT_STRING_CC = \
  90. """// Copyright (c) 2010 The Chromium Authors. All rights reserved.
  91. // Use of this source code is governed by a BSD-style license that can be
  92. // found in the LICENSE file.
  93. //
  94. // This test simply includes all the C++ headers to ensure they compile with a
  95. // C++ compiler. If it compiles, it passes.
  96. //
  97. """
  98. # Get the source file names out of the given gyp file data object (as evaluated
  99. # from a gyp file) for the given target name. Return the string names in
  100. # sorted order.
  101. def GetSourcesForTarget(target_name, gyp_file_data):
  102. for target in gyp_file_data[GYP_TARGETS_KEY]:
  103. if target[GYP_TARGET_NAME_KEY] == target_name:
  104. sources = target[GYP_SOURCES_KEY]
  105. sources.sort()
  106. return sources
  107. print('Warning: no target named ', target, ' found.')
  108. return []
  109. # Generate all_c_includes.h, which includes all C headers. This is part of
  110. # tests/test_c_sizes.c, which includes all C API files to ensure that all
  111. # the headers in ppapi/c can be compiled with a C compiler, and also asserts
  112. # (with compile-time assertions) that all structs and enums are a particular
  113. # size.
  114. def GenerateCIncludeTest(gyp_file_data):
  115. c_sources = GetSourcesForTarget('ppapi_c', gyp_file_data)
  116. lines = [COPYRIGHT_STRING_C]
  117. lines.append('#ifndef PPAPI_TESTS_ALL_C_INCLUDES_H_\n')
  118. lines.append('#define PPAPI_TESTS_ALL_C_INCLUDES_H_\n\n')
  119. for source in c_sources:
  120. lines.append('#include "ppapi/' + source + '"\n')
  121. lines.append('\n#endif /* PPAPI_TESTS_ALL_C_INCLUDES_H_ */\n')
  122. WriteLines('tests/all_c_includes.h', lines)
  123. # Generate all_cpp_includes.h, which is used by test_cpp_includes.cc to ensure
  124. # that all the headers in ppapi/cpp can be compiled with a C++ compiler.
  125. def GenerateCCIncludeTest(gyp_file_data):
  126. cc_sources = GetSourcesForTarget('ppapi_cpp_objects', gyp_file_data)
  127. header_re = re.compile('.+\.h$')
  128. lines = [COPYRIGHT_STRING_CC]
  129. lines.append('#ifndef PPAPI_TESTS_ALL_CPP_INCLUDES_H_\n')
  130. lines.append('#define PPAPI_TESTS_ALL_CPP_INCLUDES_H_\n\n')
  131. for source in cc_sources:
  132. if header_re.match(source):
  133. lines.append('#include "ppapi/' + source + '"\n')
  134. lines.append('\n#endif // PPAPI_TESTS_ALL_CPP_INCLUDES_H_\n')
  135. WriteLines('tests/all_cpp_includes.h', lines)
  136. def main():
  137. ppapi_gyp_file_name = 'ppapi.gyp'
  138. gyp_file_contents = open(ppapi_gyp_file_name).read()
  139. gyp_file_data = eval(gyp_file_contents)
  140. VerifyGypFile(gyp_file_data)
  141. GenerateCIncludeTest(gyp_file_data)
  142. GenerateCCIncludeTest(gyp_file_data)
  143. return 0
  144. if __name__ == '__main__':
  145. sys.exit(main())