|  | #!/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()) |