#!/usr/bin/python # 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 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_cc_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).*') 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 test_c_includes.c, which is a test to ensure that all the headers in # ppapi/c can be compiled with a C compiler. def GenerateCIncludeTest(gyp_file_data): c_sources = GetSourcesForTarget('ppapi_c', gyp_file_data) lines = [COPYRIGHT_STRING_C] for source in c_sources: lines.append('#include "ppapi/' + source + '"\n') WriteLines('tests/test_c_includes.c', lines) # Generate test_cc_includes.cc, which is a test 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] for source in cc_sources: if header_re.match(source): lines.append('#include "ppapi/' + source + '"\n') WriteLines('tests/test_cc_includes.cc', 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())