| #!/usr/bin/env python | |
| # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| """This script should be run manually on occasion to make sure the gyp file and | |
| the includes tests are up to date. | |
| It does the following: | |
| - Verifies that all source code is in ppapi.gyp | |
| - Verifies that all sources in ppapi.gyp really do exist | |
| - Generates tests/test_c_includes.c | |
| - Generates tests/test_cpp_includes.cc | |
| These tests are checked in to SVN. | |
| """ | |
| # TODO(dmichael): Make this script execute as a gyp action, move the include | |
| # tests to some 'generated' area, and remove them from version | |
| # control. | |
| import re | |
| import os | |
| import sys | |
| import posixpath | |
| # A simple regular expression that should match source files for C++ and C. | |
| SOURCE_FILE_RE = re.compile('.+\.(cc|c|h)$') | |
| # IGNORE_RE is a regular expression that matches directories which contain | |
| # source that we don't (currently) expect to be in ppapi.gyp. This script will | |
| # not check whether source files under these directories are in the gyp file. | |
| # TODO(dmichael): Put examples back in the build. | |
| # TODO(brettw): Put proxy in the build when it's ready. | |
| IGNORE_RE = re.compile('^(examples|GLES2|proxy|tests\/clang).*') | |
| GYP_TARGETS_KEY = 'targets' | |
| GYP_SOURCES_KEY = 'sources' | |
| GYP_TARGET_NAME_KEY = 'target_name' | |
| # Return a set containing all source files found given an object read from a gyp | |
| # file. | |
| def GetAllGypSources(gyp_file_data): | |
| sources = set([]) | |
| for target in gyp_file_data[GYP_TARGETS_KEY]: | |
| # Get a list of sources in the target that are not ignored, and 'normalize' | |
| # them. The main reason for this is to turn the forward slashes in the gyp | |
| # file in to backslashes when the script is run on Windows. | |
| source_list = [posixpath.normpath(src) for src in target[GYP_SOURCES_KEY] | |
| if not IGNORE_RE.match(src)] | |
| sources |= set(source_list) | |
| return sources | |
| # Search the directory named start_root and all its subdirectories for source | |
| # files. | |
| # Return a set containing the string names of all the source files found, | |
| # relative to start_root. | |
| def GetFileSources(start_root): | |
| file_set = set([]) | |
| for root, dirs, files in os.walk(start_root): | |
| relative_root = os.path.relpath(root, start_root) | |
| if not IGNORE_RE.match(relative_root): | |
| for source in files: | |
| if SOURCE_FILE_RE.match(source): | |
| file_set |= set([os.path.join(relative_root, source)]) | |
| return file_set | |
| # Make sure all source files are in the given gyp object (evaluated from a gyp | |
| # file), and that all source files listed in the gyp object exist in the | |
| # directory. | |
| def VerifyGypFile(gyp_file_data): | |
| gyp_sources = GetAllGypSources(gyp_file_data) | |
| file_sources = GetFileSources('.') | |
| in_gyp_not_file = gyp_sources - file_sources | |
| in_file_not_gyp = file_sources - gyp_sources | |
| if len(in_gyp_not_file): | |
| print 'Found source file(s) in ppapi.gyp but not in the directory:', \ | |
| in_gyp_not_file | |
| if len(in_file_not_gyp): | |
| print 'Found source file(s) in the directory but not in ppapi.gyp:', \ | |
| in_file_not_gyp | |
| error_count = len(in_gyp_not_file) + len(in_file_not_gyp) | |
| if error_count: | |
| sys.exit(error_count) | |
| def WriteLines(filename, lines): | |
| outfile = open(filename, 'w') | |
| for line in lines: | |
| outfile.write(line) | |
| outfile.write('\n') | |
| COPYRIGHT_STRING_C = \ | |
| """/* Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| * | |
| * This test simply includes all the C headers to ensure they compile with a C | |
| * compiler. If it compiles, it passes. | |
| */ | |
| """ | |
| COPYRIGHT_STRING_CC = \ | |
| """// Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // This test simply includes all the C++ headers to ensure they compile with a | |
| // C++ compiler. If it compiles, it passes. | |
| // | |
| """ | |
| # Get the source file names out of the given gyp file data object (as evaluated | |
| # from a gyp file) for the given target name. Return the string names in | |
| # sorted order. | |
| def GetSourcesForTarget(target_name, gyp_file_data): | |
| for target in gyp_file_data[GYP_TARGETS_KEY]: | |
| if target[GYP_TARGET_NAME_KEY] == target_name: | |
| sources = target[GYP_SOURCES_KEY] | |
| sources.sort() | |
| return sources | |
| print 'Warning: no target named ', target, ' found.' | |
| return [] | |
| # Generate all_c_includes.h, which includes all C headers. This is part of | |
| # tests/test_c_sizes.c, which includes all C API files to ensure that all | |
| # the headers in ppapi/c can be compiled with a C compiler, and also asserts | |
| # (with compile-time assertions) that all structs and enums are a particular | |
| # size. | |
| def GenerateCIncludeTest(gyp_file_data): | |
| c_sources = GetSourcesForTarget('ppapi_c', gyp_file_data) | |
| lines = [COPYRIGHT_STRING_C] | |
| lines.append('#ifndef PPAPI_TESTS_ALL_C_INCLUDES_H_\n') | |
| lines.append('#define PPAPI_TESTS_ALL_C_INCLUDES_H_\n\n') | |
| for source in c_sources: | |
| lines.append('#include "ppapi/' + source + '"\n') | |
| lines.append('\n#endif /* PPAPI_TESTS_ALL_C_INCLUDES_H_ */\n') | |
| WriteLines('tests/all_c_includes.h', lines) | |
| # Generate all_cpp_includes.h, which is used by test_cpp_includes.cc to ensure | |
| # that all the headers in ppapi/cpp can be compiled with a C++ compiler. | |
| def GenerateCCIncludeTest(gyp_file_data): | |
| cc_sources = GetSourcesForTarget('ppapi_cpp_objects', gyp_file_data) | |
| header_re = re.compile('.+\.h$') | |
| lines = [COPYRIGHT_STRING_CC] | |
| lines.append('#ifndef PPAPI_TESTS_ALL_CPP_INCLUDES_H_\n') | |
| lines.append('#define PPAPI_TESTS_ALL_CPP_INCLUDES_H_\n\n') | |
| for source in cc_sources: | |
| if header_re.match(source): | |
| lines.append('#include "ppapi/' + source + '"\n') | |
| lines.append('\n#endif // PPAPI_TESTS_ALL_CPP_INCLUDES_H_\n') | |
| WriteLines('tests/all_cpp_includes.h', lines) | |
| def main(): | |
| ppapi_gyp_file_name = 'ppapi.gyp' | |
| gyp_file_contents = open(ppapi_gyp_file_name).read() | |
| gyp_file_data = eval(gyp_file_contents) | |
| VerifyGypFile(gyp_file_data) | |
| GenerateCIncludeTest(gyp_file_data) | |
| GenerateCCIncludeTest(gyp_file_data) | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) |