diff options
author | 2014-04-28 16:00:30 +0000 | |
---|---|---|
committer | 2014-04-28 16:00:30 +0000 | |
commit | d6656854697b2039fb88a4afd6bc1995bf6dfa02 (patch) | |
tree | d1719b1179f5fbf28de53691ee71208f22ab7741 /platform_tools/android | |
parent | 472f830351a7a113cf72655daf29758aff9772bd (diff) |
Generate tests/Android.mk from gyp
gyp/apptype_console.gypi:
Don't include console app dependencies when building for Android framework.
gyp/tests.gyp:
Add/remove libraries for framework build.
platform_tools/android/bin/android_framework_gyp.py:
Moved to gyp_gen.
clean_up_gypd_files moved to this script.
platform_tools/android/bin/gyp_to_android.py:
Call new function for generating tool makefile.
Set LOCAL_MODULE.
platform_tools/android/gyp_gen/gypd_parser.py:
Support relative paths.
platform_tools/android/gyp_gen/makefile_writer.py:
Factor out helper functions to be used by tool writer.
LOCAL_MODULE is set elsewhere.
platform_tools/android/gyp_gen/tool_makefile_writer.py:
Multipurpose file for writing makefiles for tools. Should be able to use
it mostly unchanged for bench, gm, etc.
platform_tools/android/gyp_gen/vars_dict_lib.py:
Make the comments follow the style guide.
Add set().
Rename __li to __ordered_set
More/update tests:
platform_tools/android/tests/android_framework_gyp_tests.py
platform_tools/android/tests/expectations/Android.mk
platform_tools/android/tests/expectations/tool/Android.mk
platform_tools/android/tests/expectations/write_local_vars_append_arm
platform_tools/android/tests/expectations/write_local_vars_append_foo
platform_tools/android/tests/expectations/write_local_vars_append_no_name
platform_tools/android/tests/expectations/write_local_vars_no_append_arm
platform_tools/android/tests/expectations/write_local_vars_no_append_foo
platform_tools/android/tests/expectations/write_local_vars_no_append_no_name
platform_tools/android/tests/gyp_to_android_tests.py
platform_tools/android/tests/makefile_writer_tests.py
platform_tools/android/tests/ordered_set_tests.py
platform_tools/android/tests/test_variables.py
BUG=skia:2447
May require an update to the bot to remove pyc files.
R=halcanary@google.com, djsollen@google.com
Author: scroggo@google.com
Review URL: https://codereview.chromium.org/235883015
git-svn-id: http://skia.googlecode.com/svn/trunk@14408 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'platform_tools/android')
19 files changed, 595 insertions, 222 deletions
diff --git a/platform_tools/android/bin/gyp_to_android.py b/platform_tools/android/bin/gyp_to_android.py index f7199b8ddb..f43d597a15 100755 --- a/platform_tools/android/bin/gyp_to_android.py +++ b/platform_tools/android/bin/gyp_to_android.py @@ -10,7 +10,6 @@ Script for generating the Android framework's version of Skia from gyp files. """ -import android_framework_gyp import os import shutil import sys @@ -25,53 +24,48 @@ SKIA_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir, GYP_GEN_DIR = os.path.join(SKIA_DIR, 'platform_tools', 'android', 'gyp_gen') sys.path.append(GYP_GEN_DIR) +import android_framework_gyp import gypd_parser import generate_user_config import makefile_writer +import tool_makefile_writer import vars_dict_lib # Folder containing all gyp files and generated gypd files. GYP_FOLDER = 'gyp' -# TODO(scroggo): Update the docstrings to match the style guide: -# http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Comments -def clean_gypd_files(folder): - """ - Remove the gypd files generated by android_framework_gyp.main(). - @param folder Folder in which to delete all files ending with 'gypd'. - """ - assert os.path.isdir(folder) - files = os.listdir(folder) - for f in files: - if f.endswith('gypd'): - os.remove(os.path.join(folder, f)) def generate_var_dict(target_dir, target_file, skia_arch_type, have_neon): - """ - Create a VarsDict for a particular arch type. Each paramater is passed - directly to android_framework_gyp.main(). - @param target_dir Directory containing gyp files. - @param target_file Target gyp file. - @param skia_arch_type Target architecture. - @param have_neon Whether the target should build for neon. - @return a VarsDict containing the variable definitions determined by gyp. + """Create a VarsDict for a particular arch type. + + Each paramater is passed directly to android_framework_gyp.main(). + + Args: + target_dir: Directory containing gyp files. + target_file: Target gyp file. + skia_arch_type: Target architecture. + have_neon: Whether the target should build for neon. + Returns: + A VarsDict containing the variable definitions determined by gyp. """ result_file = android_framework_gyp.main(target_dir, target_file, skia_arch_type, have_neon) var_dict = vars_dict_lib.VarsDict() - gypd_parser.parse_gypd(var_dict, result_file) - clean_gypd_files(target_dir) + gypd_parser.parse_gypd(var_dict, result_file, '.') + android_framework_gyp.clean_gypd_files(target_dir) print '.', return var_dict def main(target_dir=None, require_sk_user_config=False): - """ - Read gyp files and create Android.mk for the Android framework's - external/skia. - @param target_dir Directory in which to place 'Android.mk'. If None, the file - will be placed in skia's root directory. - @param require_sk_user_config If True, raise an AssertionError if - SkUserConfig.h does not exist. + """Create Android.mk for the Android framework's external/skia. + + Builds Android.mk using Skia's gyp files. + + Args: + target_dir: Directory in which to place 'Android.mk'. If None, the file + will be placed in skia's root directory. + require_sk_user_config: If True, raise an AssertionError if + SkUserConfig.h does not exist. """ # Create a temporary folder to hold gyp and gypd files. Create it in SKIA_DIR # so that it is a sibling of gyp/, so the relationships between gyp files and @@ -119,6 +113,8 @@ def main(target_dir=None, require_sk_user_config=False): x86_var_dict, mips_var_dict, arm64_var_dict] common = vars_dict_lib.intersect(var_dict_list) + common.LOCAL_MODULE.add('libskia') + # Create SkUserConfig user_config = os.path.join(SKIA_DIR, 'include', 'config', 'SkUserConfig.h') if target_dir: @@ -131,8 +127,26 @@ def main(target_dir=None, require_sk_user_config=False): require_sk_user_config=require_sk_user_config, target_dir=dst_dir, ordered_set=common.DEFINES) - # Now that the defines have been written to SkUserConfig, they are not - # needed in Android.mk. + tool_makefile_writer.generate_tool(gyp_dir=tmp_folder, + target_file='tests.gyp', + skia_trunk=target_dir, + dest_dir='tests', + skia_lib_var_dict=common, + local_module_name='skia_test', + local_module_tags=['eng', 'tests']) + + # TODO (scroggo): Generate bench/Android.mk. See skbug.com/2448 + #tool_makefile_writer.generate_tool(gyp_dir=tmp_folder, + # target_file='bench.gyp', + # skia_trunk=target_dir, + # dest_dir='bench', + # skia_lib_var_dict=common, + # local_module_name='skia_bench', + # local_module_tags=['tests']) + + # Now that the defines have been written to SkUserConfig and they've been + # used to skip adding them to the tools makefiles, they are not needed in + # Android.mk. Reset DEFINES. common.DEFINES.reset() # Further trim arm_neon_var_dict with arm_var_dict. After this call, diff --git a/platform_tools/android/bin/android_framework_gyp.py b/platform_tools/android/gyp_gen/android_framework_gyp.py index 5d5befc084..67d391a883 100644 --- a/platform_tools/android/bin/android_framework_gyp.py +++ b/platform_tools/android/gyp_gen/android_framework_gyp.py @@ -16,7 +16,7 @@ SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) # Unlike gyp_skia, this file is nested deep inside Skia. Find Skia's trunk dir. # This line depends on the fact that the script is three levels deep -# (specifically, it is in platform_tools/android/bin). +# (specifically, it is in platform_tools/android/gyp_gen). SKIA_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir, os.pardir)) DIR_CONTENTS = os.listdir(SKIA_DIR) @@ -40,15 +40,18 @@ sys.path.insert(0, os.path.join(GYP_SOURCE_DIR, 'pylib')) import gyp def main(target_dir, target_file, skia_arch_type, have_neon): - """ - Create gypd files based on target_file. - @param target_dir Directory containing all gyp files, including common.gypi - @param target_file Gyp file to start on. Other files within target_dir will - be read if target_file depends on them. - @param skia_arch_type Target architecture to pass to gyp. - @param have_neon Whether to generate files including neon optimizations. - Only meaningful if skia_arch_type is 'arm'. - @return path Path to root gypd file created by running gyp. + """Create gypd files based on target_file. + + Args: + target_dir: Directory containing all gyp files, including common.gypi + target_file: Gyp file to start on. Other files within target_dir will + be read if target_file depends on them. + skia_arch_type: Target architecture to pass to gyp. + have_neon: Whether to generate files including neon optimizations. + Only meaningful if skia_arch_type is 'arm'. + + Returns: + path: Path to root gypd file created by running gyp. """ # Set GYP_DEFINES for building for the android framework. gyp_defines = ('skia_android_framework=1 OS=android skia_arch_type=%s ' @@ -85,3 +88,16 @@ def main(target_dir, target_file, skia_arch_type, have_neon): raise Exception("gyp failed to produce gypd file!") return gypd_file + + +def clean_gypd_files(folder): + """Remove the gypd files generated by main(). + + Args: + folder: Folder in which to delete all files ending with 'gypd'. + """ + assert os.path.isdir(folder) + files = os.listdir(folder) + for f in files: + if f.endswith('gypd'): + os.remove(os.path.join(folder, f)) diff --git a/platform_tools/android/gyp_gen/gypd_parser.py b/platform_tools/android/gyp_gen/gypd_parser.py index fc4dc68e96..b0e1417046 100644 --- a/platform_tools/android/gyp_gen/gypd_parser.py +++ b/platform_tools/android/gyp_gen/gypd_parser.py @@ -5,19 +5,32 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -""" -Functions for parsing the gypd output from gyp. +"""Functions for parsing the gypd output from gyp. """ -def parse_dictionary(var_dict, d, current_target_name): - """ - Helper function to get the meaningful entries in a dictionary. - @param var_dict VarsDict object for storing the results of the parsing. - @param d Dictionary object to parse. - @param current_target_name The current target being parsed. If this - dictionary is a target, this will be its entry - 'target_name'. Otherwise, this will be the name of - the target which contains this dictionary. + +import os + + +def parse_dictionary(var_dict, d, current_target_name, dest_dir): + """Helper function to get the meaningful entries in a dictionary. + + Parse dictionary d, and store unique relevant entries in var_dict. + Recursively parses internal dictionaries and files that are referenced. + When parsing the 'libraries' list from gyp, entries in the form + '-l<name>' get assigned to var_dict.LOCAL_SHARED_LIBRARIES as 'lib<name>', + and entries in the form '[lib]<name>.a' get assigned to + var_dict.LOCAL_STATIC_LIBRARIES as 'lib<name>'. + + Args: + var_dict: VarsDict object for storing the results of the parsing. + d: Dictionary object to parse. + current_target_name: The current target being parsed. If this dictionary + is a target, this will be its entry 'target_name'. Otherwise, this will + be the name of the target which contains this dictionary. + dest_dir: Destination for the eventual Android.mk that will be created from + this parse, relative to Skia trunk. Used to determine path for source + files. """ for source in d.get('sources', []): # Compare against a lowercase version, in case files are named .H or .GYPI @@ -30,9 +43,10 @@ def parse_dictionary(var_dict, d, current_target_name): # are also included. No need to parse them again. continue # The path is relative to the gyp folder, but Android wants the path - # relative to the root. - source = source.replace('../src', 'src', 1) - var_dict.LOCAL_SRC_FILES.add(source) + # relative to dest_dir. + rel_source = os.path.relpath(source, os.pardir) + rel_source = os.path.relpath(rel_source, dest_dir) + var_dict.LOCAL_SRC_FILES.add(rel_source) for lib in d.get('libraries', []): if lib.endswith('.a'): @@ -60,14 +74,14 @@ def parse_dictionary(var_dict, d, current_target_name): # Although the original reference is to a .gyp, parse the corresponding # gypd file, which was constructed by gyp. sub_path = sub_path + 'd' - parse_gypd(var_dict, sub_path, sub_targets) + parse_gypd(var_dict, sub_path, dest_dir, sub_targets) if 'default_configuration' in d: config_name = d['default_configuration'] # default_configuration is meaningless without configurations assert('configurations' in d) config = d['configurations'][config_name] - parse_dictionary(var_dict, config, current_target_name) + parse_dictionary(var_dict, config, current_target_name, dest_dir) for flag in d.get('cflags', []): var_dict.LOCAL_CFLAGS.add(flag) @@ -75,28 +89,44 @@ def parse_dictionary(var_dict, d, current_target_name): var_dict.LOCAL_CPPFLAGS.add(flag) for include in d.get('include_dirs', []): - # The input path will be relative to gyp/, but Android wants relative to - # LOCAL_PATH - include = include.replace('..', '$(LOCAL_PATH)', 1) + if include.startswith('external'): + # This path is relative to the Android root. Leave it alone. + rel_include = include + else: + # As with source, the input path will be relative to gyp/, but Android + # wants relative to dest_dir. + rel_include = os.path.relpath(include, os.pardir) + rel_include = os.path.relpath(rel_include, dest_dir) + rel_include = os.path.join('$(LOCAL_PATH)', rel_include) + # Remove a trailing slash, if present. - if include.endswith('/'): - include = include[:-1] - var_dict.LOCAL_C_INCLUDES.add(include) + if rel_include.endswith('/'): + rel_include = rel_include[:-1] + var_dict.LOCAL_C_INCLUDES.add(rel_include) # For the top level, libskia, include directories should be exported. + # FIXME (scroggo): Do not hard code this. if current_target_name == 'libskia': - var_dict.LOCAL_EXPORT_C_INCLUDE_DIRS.add(include) + var_dict.LOCAL_EXPORT_C_INCLUDE_DIRS.add(rel_include) for define in d.get('defines', []): var_dict.DEFINES.add(define) -def parse_gypd(var_dict, path, desired_targets=None): - """ - Parse a gypd file. - @param var_dict VarsDict object for storing the result of the parse. - @param path Path to gypd file. - @param desired_targets List of targets to be parsed from this file. If empty, - parse all targets. +def parse_gypd(var_dict, path, dest_dir, desired_targets=None): + """Parse a gypd file. + + Open a file that consists of python dictionaries representing build targets. + Parse those dictionaries using parse_dictionary. Recursively parses + referenced files. + + Args: + var_dict: VarsDict object for storing the result of the parse. + path: Path to gypd file. + dest_dir: Destination for the eventual Android.mk that will be created from + this parse, relative to Skia trunk. Used to determine path for source + files and include directories. + desired_targets: List of targets to be parsed from this file. If empty, + parse all targets. """ d = {} with open(path, 'r') as f: @@ -116,5 +146,5 @@ def parse_gypd(var_dict, path, desired_targets=None): # Add it to our known targets so we don't parse it again var_dict.KNOWN_TARGETS.add(target_name) - parse_dictionary(var_dict, target, target_name) + parse_dictionary(var_dict, target, target_name, dest_dir) diff --git a/platform_tools/android/gyp_gen/makefile_writer.py b/platform_tools/android/gyp_gen/makefile_writer.py index 1b977ca1e6..212979925c 100644 --- a/platform_tools/android/gyp_gen/makefile_writer.py +++ b/platform_tools/android/gyp_gen/makefile_writer.py @@ -12,12 +12,13 @@ Functions for creating an Android.mk from already created dictionaries. import os def write_group(f, name, items, append): - """ - Helper function to list all names passed to a variable. - @param f File open for writing (Android.mk) - @param name Name of the makefile variable (e.g. LOCAL_CFLAGS) - @param items list of strings to be passed to the variable. - @param append Whether to append to the variable or overwrite it. + """Helper function to list all names passed to a variable. + + Args: + f: File open for writing (Android.mk) + name: Name of the makefile variable (e.g. LOCAL_CFLAGS) + items: list of strings to be passed to the variable. + append: Whether to append to the variable or overwrite it. """ if not items: return @@ -36,12 +37,13 @@ def write_group(f, name, items, append): def write_local_vars(f, var_dict, append, name): - """ - Helper function to write all the members of var_dict to the makefile. - @param f File open for writing (Android.mk) - @param var_dict VarsDict holding the unique values for one configuration. - @param append Whether to append to each makefile variable or overwrite it. - @param name If not None, a string to be appended to each key. + """Helper function to write all the members of var_dict to the makefile. + + Args: + f: File open for writing (Android.mk) + var_dict: VarsDict holding the unique values for one configuration. + append: Whether to append to each makefile variable or overwrite it. + name: If not None, a string to be appended to each key. """ for key in var_dict.keys(): _key = key @@ -121,46 +123,65 @@ SKIA_TOOLS = ( #include $(BASE_PATH)/gm/Android.mk # unit-tests -#include $(BASE_PATH)/tests/Android.mk - -# pathOps unit-tests -# TODO include those sources! +include $(BASE_PATH)/tests/Android.mk """ ) class VarsDictData(object): - """ - Helper class for keeping a VarsDict along with a name and an optional - condition. + """Helper class to keep a VarsDict along with a name and optional condition. """ def __init__(self, vars_dict, name, condition=None): - """ - Create a new VarsDictData. - @param vars_dict A VarsDict. Can be accessed via self.vars_dict. - @param name Name associated with the VarsDict. Can be accessed via - self.name. - @param condition Optional string representing a condition. If not None, - used to create a conditional inside the makefile. + """Create a new VarsDictData. + + Args: + vars_dict: A VarsDict. Can be accessed via self.vars_dict. + name: Name associated with the VarsDict. Can be accessed via + self.name. + condition: Optional string representing a condition. If not None, + used to create a conditional inside the makefile. """ self.vars_dict = vars_dict self.condition = condition self.name = name +def write_local_path(f): + """Add the LOCAL_PATH line to the makefile. + + Args: + f: File open for writing. + """ + f.write('LOCAL_PATH:= $(call my-dir)\n') + +def write_clear_vars(f): + """Add the CLEAR_VARS line to the makefile. + + Args: + f: File open for writing. + """ + f.write('include $(CLEAR_VARS)\n') + +def write_include_stlport(f): + """Add a line to include stlport. + + Args: + f: File open for writing. + """ + f.write('include external/stlport/libstlport.mk\n') + def write_android_mk(target_dir, common, deviations_from_common): - """ - Given all the variables, write the final make file. - @param target_dir The full path to the directory to write Android.mk, or None - to use the current working directory. - @param common VarsDict holding variables definitions common to all - configurations. - @param deviations_from_common List of VarsDictData, one for each possible - configuration. VarsDictData.name will be - appended to each key before writing it to the - makefile. VarsDictData.condition, if not None, - will be written to the makefile as a condition - to determine whether to include - VarsDictData.vars_dict. + """Given all the variables, write the final make file. + + Args: + target_dir: The full path to the directory to write Android.mk, or None + to use the current working directory. + common: VarsDict holding variables definitions common to all + configurations. + deviations_from_common: List of VarsDictData, one for each possible + configuration. VarsDictData.name will be appended to each key before + writing it to the makefile. VarsDictData.condition, if not None, will be + written to the makefile as a condition to determine whether to include + VarsDictData.vars_dict. """ target_file = 'Android.mk' if target_dir: @@ -168,12 +189,11 @@ def write_android_mk(target_dir, common, deviations_from_common): with open(target_file, 'w') as f: f.write(AUTOGEN_WARNING) f.write('BASE_PATH := $(call my-dir)\n') - f.write('LOCAL_PATH:= $(call my-dir)\n') + write_local_path(f) f.write(DEBUGGING_HELP) - f.write('include $(CLEAR_VARS)\n') - + write_clear_vars(f) f.write('LOCAL_ARM_MODE := thumb\n') # need a flag to tell the C side when we're on devices with large memory @@ -204,8 +224,7 @@ def write_android_mk(target_dir, common, deviations_from_common): if data.condition: f.write('endif\n\n') - f.write('include external/stlport/libstlport.mk\n') - f.write('LOCAL_MODULE:= libskia\n') + write_include_stlport(f) f.write('include $(BUILD_SHARED_LIBRARY)\n') f.write(SKIA_TOOLS) diff --git a/platform_tools/android/gyp_gen/tool_makefile_writer.py b/platform_tools/android/gyp_gen/tool_makefile_writer.py new file mode 100644 index 0000000000..bdcd8846b7 --- /dev/null +++ b/platform_tools/android/gyp_gen/tool_makefile_writer.py @@ -0,0 +1,92 @@ +#!/usr/bin/python + +# Copyright 2014 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Code for generating Android.mk for a tool.""" + + +import android_framework_gyp +import gypd_parser +import makefile_writer +import os +import vars_dict_lib + + +def write_tool_android_mk(target_dir, var_dict): + """Write Android.mk for a Skia tool. + + Args: + target_dir: Destination for the makefile. Must not be None. + var_dict: VarsDict containing variables for the makefile. + """ + target_file = os.path.join(target_dir, 'Android.mk') + with open(target_file, 'w') as f: + f.write(makefile_writer.AUTOGEN_WARNING) + makefile_writer.write_local_path(f) + makefile_writer.write_clear_vars(f) + + makefile_writer.write_local_vars(f, var_dict, False, None) + + makefile_writer.write_include_stlport(f) + f.write('include $(BUILD_EXECUTABLE)\n') + + +def generate_tool(gyp_dir, target_file, skia_trunk, dest_dir, + skia_lib_var_dict, local_module_name, local_module_tags): + """Common steps for building one of the skia tools. + + Parse a gyp file and create an Android.mk for this tool. + + Args: + gyp_dir: Directory containing gyp files. + target_file: gyp file for the project to be built, contained in gyp_dir. + skia_trunk: Trunk of Skia, used for determining the destination to write + 'Android.mk'. + dest_dir: Destination for 'Android.mk', relative to skia_trunk. Used for + both writing relative paths in the makefile and for determining the + destination to write the it. + skia_lib_var_dict: VarsDict representing libskia. Used as a reference to + ensure we do not duplicate anything in this Android.mk. + local_module_name: Name for this tool, to set as LOCAL_MODULE. + local_module_tags: Tags to pass to LOCAL_MODULE_TAG. + """ + result_file = android_framework_gyp.main(target_dir=gyp_dir, + target_file=target_file, + skia_arch_type='other', + have_neon=False) + + var_dict = vars_dict_lib.VarsDict() + + # Add known targets from skia_lib, so we do not reparse them. + var_dict.KNOWN_TARGETS.set(skia_lib_var_dict.KNOWN_TARGETS) + + gypd_parser.parse_gypd(var_dict, result_file, dest_dir) + + android_framework_gyp.clean_gypd_files(gyp_dir) + + var_dict.LOCAL_MODULE.add(local_module_name) + for tag in local_module_tags: + var_dict.LOCAL_MODULE_TAGS.add(tag) + + # No need for defines that are already in skia_lib. + for define in skia_lib_var_dict.DEFINES: + try: + var_dict.DEFINES.remove(define) + except ValueError: + # Okay if the define was not part of the parse for our tool. + pass + + if skia_trunk: + full_dest = os.path.join(skia_trunk, dest_dir) + else: + full_dest = dest_dir + + # If the path does not exist, create it. This will happen during testing, + # where there is no subdirectory for each tool (just a temporary folder). + if not os.path.exists(full_dest): + os.mkdir(full_dest) + + write_tool_android_mk(target_dir=full_dest, var_dict=var_dict) diff --git a/platform_tools/android/gyp_gen/vars_dict_lib.py b/platform_tools/android/gyp_gen/vars_dict_lib.py index a4ef67e8b7..6be2402a04 100644 --- a/platform_tools/android/gyp_gen/vars_dict_lib.py +++ b/platform_tools/android/gyp_gen/vars_dict_lib.py @@ -13,59 +13,76 @@ import types # we want to make sure the image decoders are in a particular order. See # images.gyp for more information. class OrderedSet(object): - """ - Ordered set of unique items that supports addition and removal. + """Ordered set of unique items that supports addition and removal. + + Retains the order in which items are inserted. """ def __init__(self): - self.__li = [] + self.__ordered_set = [] def add(self, item): + """Add item, if it is not already in the set. + + item is appended to the end if it is not already in the set. + + Args: + item: The item to add. """ - Add item, if it is not already in the set. - @param item The item to add. - """ - if item not in self.__li: - self.__li.append(item) + if item not in self.__ordered_set: + self.__ordered_set.append(item) def __contains__(self, item): + """Whether the set contains item. + + Args: + item: The item to search for in the set. + + Returns: + bool: Whether the item is in the set. """ - Whether the set contains item. - @param item The item to search for in the set. - @return bool Whether the item is in the set. - """ - return item in self.__li + return item in self.__ordered_set def __iter__(self): + """Iterator for the set. """ - Iterator for the set. - """ - return self.__li.__iter__() + return self.__ordered_set.__iter__() def remove(self, item): """ Remove item from the set. - @param item Item to be removed. + + Args: + item: Item to be removed. + + Raises: + ValueError if item is not in the set. """ - return self.__li.remove(item) + self.__ordered_set.remove(item) def __len__(self): + """Number of items in the set. """ - Number of items in the set. - """ - return len(self.__li) + return len(self.__ordered_set) def __getitem__(self, index): + """Return item at index. """ - Return item at index. - """ - return self.__li[index] + return self.__ordered_set[index] def reset(self): + """Reset to empty. """ - Reset to empty. + self.__ordered_set = [] + + def set(self, other): + """Replace this ordered set with another. + + Args: + other: OrderedSet to replace this one. After this call, this OrderedSet + will contain exactly the same elements as other. """ - self.__li = [] + self.__ordered_set = list(other.__ordered_set) VAR_NAMES = ['LOCAL_CFLAGS', 'LOCAL_CPPFLAGS', @@ -75,12 +92,15 @@ VAR_NAMES = ['LOCAL_CFLAGS', 'LOCAL_C_INCLUDES', 'LOCAL_EXPORT_C_INCLUDE_DIRS', 'DEFINES', - 'KNOWN_TARGETS'] + 'KNOWN_TARGETS', + # These are not parsed by gyp, but set manually. + 'LOCAL_MODULE_TAGS', + 'LOCAL_MODULE'] class VarsDict(collections.namedtuple('VarsDict', VAR_NAMES)): - """ - Custom class for storing the arguments to Android.mk variables. Can be - treated as a dictionary with fixed keys. + """Custom class for storing the arguments to Android.mk variables. + + Can also be treated as a dictionary with fixed keys. """ __slots__ = () @@ -93,14 +113,12 @@ class VarsDict(collections.namedtuple('VarsDict', VAR_NAMES)): return tuple.__new__(cls, lists) def keys(self): - """ - Return the field names as strings. + """Return the field names as strings. """ return self._fields def __getitem__(self, index): - """ - Return an item, indexed by a number or a string. + """Return an item, indexed by a number or a string. """ if type(index) == types.IntType: # Treat the index as an array index into a tuple. @@ -112,13 +130,17 @@ class VarsDict(collections.namedtuple('VarsDict', VAR_NAMES)): def intersect(var_dict_list): - """ + """Compute intersection of VarsDicts. + Find the intersection of a list of VarsDicts and trim each input to its unique entries. - @param var_dict_list list of VarsDicts. WARNING: each VarsDict will be - modified in place, to remove the common elements! - @return VarsDict containing list entries common to all VarsDicts in - var_dict_list + + Args: + var_dict_list: list of VarsDicts. WARNING: each VarsDict will be + modified in place, to remove the common elements! + Returns: + VarsDict containing list entries common to all VarsDicts in + var_dict_list """ intersection = VarsDict() # First VarsDict diff --git a/platform_tools/android/tests/android_framework_gyp_tests.py b/platform_tools/android/tests/android_framework_gyp_tests.py new file mode 100644 index 0000000000..0b52c6b038 --- /dev/null +++ b/platform_tools/android/tests/android_framework_gyp_tests.py @@ -0,0 +1,82 @@ +#!/usr/bin/python + +# Copyright 2014 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Test gyp_to_android.py +""" + +import os +import shutil +import sys +import tempfile +import test_variables +import unittest + +# Path to android_framework_gyp +sys.path.append(test_variables.GYP_GEN_DIR) + +import android_framework_gyp + +GYPD_SUFFIX = ".gypd" +GYP_SUFFIX = ".gyp" +GYPI_SUFFIX = ".gypi" +OTHER_SUFFIX = ".txt" + +class CleanGypdTest(unittest.TestCase): + + def setUp(self): + self.__tmp_dir = tempfile.mkdtemp() + self.__num_files = 10 + # Fill the dir with four types of files. .gypd files should be deleted by + # clean_gypd_files(), while the rest should be left alone. + for i in range(self.__num_files): + self.create_file('%s%s' % (str(i), GYPD_SUFFIX)) + self.create_file('%s%s' % (str(i), GYPI_SUFFIX)) + self.create_file('%s%s' % (str(i), GYP_SUFFIX)) + self.create_file('%s%s' % (str(i), OTHER_SUFFIX)) + + def create_file(self, basename): + """Create a file named 'basename' in self.__tmp_dir. + """ + f = tempfile.mkstemp(dir=self.__tmp_dir) + os.rename(f[1], os.path.join(self.__tmp_dir, basename)) + self.assert_file_exists(basename) + + def assert_file_exists(self, basename): + """Assert that 'basename' exists in self.__tmp_dir. + """ + full_name = os.path.join(self.__tmp_dir, basename) + self.assertTrue(os.path.exists(full_name)) + + def assert_file_does_not_exist(self, basename): + """Assert that 'basename' does not exist in self.__tmp_dir. + """ + full_name = os.path.join(self.__tmp_dir, basename) + self.assertFalse(os.path.exists(full_name)) + + def test_clean(self): + """Test that clean_gypd_files() deletes .gypd files, and leaves others. + """ + android_framework_gyp.clean_gypd_files(self.__tmp_dir) + for i in range(self.__num_files): + self.assert_file_exists('%s%s' % (str(i), GYPI_SUFFIX)) + self.assert_file_exists('%s%s' % (str(i), GYP_SUFFIX)) + self.assert_file_exists('%s%s' % (str(i), OTHER_SUFFIX)) + # Only the GYPD files should have been deleted. + self.assert_file_does_not_exist('%s%s' % (str(i), GYPD_SUFFIX)) + + def tearDown(self): + shutil.rmtree(self.__tmp_dir) + + +def main(): + loader = unittest.TestLoader() + suite = loader.loadTestsFromTestCase(CleanGypdTest) + unittest.TextTestRunner(verbosity=2).run(suite) + +if __name__ == "__main__": + main() diff --git a/platform_tools/android/tests/expectations/Android.mk b/platform_tools/android/tests/expectations/Android.mk index 9fab0ac2d9..bba6824d86 100644 --- a/platform_tools/android/tests/expectations/Android.mk +++ b/platform_tools/android/tests/expectations/Android.mk @@ -73,6 +73,12 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \ LOCAL_CFLAGS += \ -Ddefines +LOCAL_MODULE_TAGS := \ + local_module_tags + +LOCAL_MODULE := \ + local_module + ifeq ($(COND), true) LOCAL_CFLAGS_foo += \ local_cflags_foo @@ -98,6 +104,12 @@ LOCAL_EXPORT_C_INCLUDE_DIRS_foo += \ LOCAL_CFLAGS_foo += \ -Ddefines_foo +LOCAL_MODULE_TAGS_foo += \ + local_module_tags_foo + +LOCAL_MODULE_foo += \ + local_module_foo + endif LOCAL_CFLAGS_bar += \ @@ -124,8 +136,13 @@ LOCAL_EXPORT_C_INCLUDE_DIRS_bar += \ LOCAL_CFLAGS_bar += \ -Ddefines_bar +LOCAL_MODULE_TAGS_bar += \ + local_module_tags_bar + +LOCAL_MODULE_bar += \ + local_module_bar + include external/stlport/libstlport.mk -LOCAL_MODULE:= libskia include $(BUILD_SHARED_LIBRARY) ############################################################# @@ -139,7 +156,4 @@ include $(BUILD_SHARED_LIBRARY) #include $(BASE_PATH)/gm/Android.mk # unit-tests -#include $(BASE_PATH)/tests/Android.mk - -# pathOps unit-tests -# TODO include those sources! +include $(BASE_PATH)/tests/Android.mk diff --git a/platform_tools/android/tests/expectations/tool/Android.mk b/platform_tools/android/tests/expectations/tool/Android.mk new file mode 100644 index 0000000000..faac45d1ef --- /dev/null +++ b/platform_tools/android/tests/expectations/tool/Android.mk @@ -0,0 +1,41 @@ + +############################################################################### +# +# THIS FILE IS AUTOGENERATED BY GYP_TO_ANDROID.PY. DO NOT EDIT. +# +############################################################################### + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_CFLAGS += \ + local_cflags + +LOCAL_CPPFLAGS := \ + local_cppflags + +LOCAL_SRC_FILES := \ + local_src_files + +LOCAL_SHARED_LIBRARIES := \ + local_shared_libraries + +LOCAL_STATIC_LIBRARIES := \ + local_static_libraries + +LOCAL_C_INCLUDES := \ + local_c_includes + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + local_export_c_include_dirs + +LOCAL_CFLAGS += \ + -Ddefines + +LOCAL_MODULE_TAGS := \ + local_module_tags + +LOCAL_MODULE := \ + local_module + +include external/stlport/libstlport.mk +include $(BUILD_EXECUTABLE) diff --git a/platform_tools/android/tests/expectations/write_local_vars_append_arm b/platform_tools/android/tests/expectations/write_local_vars_append_arm index 3e5f18094b..60c2bce5a2 100644 --- a/platform_tools/android/tests/expectations/write_local_vars_append_arm +++ b/platform_tools/android/tests/expectations/write_local_vars_append_arm @@ -22,3 +22,9 @@ LOCAL_EXPORT_C_INCLUDE_DIRS_arm += \ LOCAL_CFLAGS_arm += \ -Ddefines +LOCAL_MODULE_TAGS_arm += \ + local_module_tags + +LOCAL_MODULE_arm += \ + local_module + diff --git a/platform_tools/android/tests/expectations/write_local_vars_append_foo b/platform_tools/android/tests/expectations/write_local_vars_append_foo index 66c4f91488..eef5a6e48e 100644 --- a/platform_tools/android/tests/expectations/write_local_vars_append_foo +++ b/platform_tools/android/tests/expectations/write_local_vars_append_foo @@ -22,3 +22,9 @@ LOCAL_EXPORT_C_INCLUDE_DIRS_foo += \ LOCAL_CFLAGS_foo += \ -Ddefines +LOCAL_MODULE_TAGS_foo += \ + local_module_tags + +LOCAL_MODULE_foo += \ + local_module + diff --git a/platform_tools/android/tests/expectations/write_local_vars_append_no_name b/platform_tools/android/tests/expectations/write_local_vars_append_no_name index e0b31c53b7..e51ede9ed6 100644 --- a/platform_tools/android/tests/expectations/write_local_vars_append_no_name +++ b/platform_tools/android/tests/expectations/write_local_vars_append_no_name @@ -22,3 +22,9 @@ LOCAL_EXPORT_C_INCLUDE_DIRS += \ LOCAL_CFLAGS += \ -Ddefines +LOCAL_MODULE_TAGS += \ + local_module_tags + +LOCAL_MODULE += \ + local_module + diff --git a/platform_tools/android/tests/expectations/write_local_vars_no_append_arm b/platform_tools/android/tests/expectations/write_local_vars_no_append_arm index c77a9bb96c..79a5d09472 100644 --- a/platform_tools/android/tests/expectations/write_local_vars_no_append_arm +++ b/platform_tools/android/tests/expectations/write_local_vars_no_append_arm @@ -22,3 +22,9 @@ LOCAL_EXPORT_C_INCLUDE_DIRS_arm := \ LOCAL_CFLAGS_arm += \ -Ddefines +LOCAL_MODULE_TAGS_arm := \ + local_module_tags + +LOCAL_MODULE_arm := \ + local_module + diff --git a/platform_tools/android/tests/expectations/write_local_vars_no_append_foo b/platform_tools/android/tests/expectations/write_local_vars_no_append_foo index d93b242678..cef7b8d18f 100644 --- a/platform_tools/android/tests/expectations/write_local_vars_no_append_foo +++ b/platform_tools/android/tests/expectations/write_local_vars_no_append_foo @@ -22,3 +22,9 @@ LOCAL_EXPORT_C_INCLUDE_DIRS_foo := \ LOCAL_CFLAGS_foo += \ -Ddefines +LOCAL_MODULE_TAGS_foo := \ + local_module_tags + +LOCAL_MODULE_foo := \ + local_module + diff --git a/platform_tools/android/tests/expectations/write_local_vars_no_append_no_name b/platform_tools/android/tests/expectations/write_local_vars_no_append_no_name index e7caec4ad2..59cd2e0376 100644 --- a/platform_tools/android/tests/expectations/write_local_vars_no_append_no_name +++ b/platform_tools/android/tests/expectations/write_local_vars_no_append_no_name @@ -22,3 +22,9 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \ LOCAL_CFLAGS += \ -Ddefines +LOCAL_MODULE_TAGS := \ + local_module_tags + +LOCAL_MODULE := \ + local_module + diff --git a/platform_tools/android/tests/gyp_to_android_tests.py b/platform_tools/android/tests/gyp_to_android_tests.py index cb2a3e0c8c..512ce36548 100644 --- a/platform_tools/android/tests/gyp_to_android_tests.py +++ b/platform_tools/android/tests/gyp_to_android_tests.py @@ -21,6 +21,8 @@ sys.path.append(test_variables.BIN_DIR) import gyp_to_android + + class AndroidMkCreationTest(unittest.TestCase): def setUp(self): @@ -31,74 +33,23 @@ class AndroidMkCreationTest(unittest.TestCase): gyp_to_android.main(self.__tmp_dir) # Now there should be a file named 'Android.mk' inside __tmp_dir - path_to_android_mk = os.path.join(self.__tmp_dir, 'Android.mk') + path_to_android_mk = os.path.join(self.__tmp_dir, + test_variables.ANDROID_MK) self.assertTrue(os.path.exists(path_to_android_mk)) - def tearDown(self): - # Remove self.__tmp_dir, which is no longer needed. - shutil.rmtree(self.__tmp_dir) - - -GYPD_SUFFIX = ".gypd" -GYP_SUFFIX = ".gyp" -GYPI_SUFFIX = ".gypi" -OTHER_SUFFIX = ".txt" - -class CleanGypdTest(unittest.TestCase): - - def setUp(self): - self.__tmp_dir = tempfile.mkdtemp() - self.__num_files = 10 - # Fill the dir with four types of files. .gypd files should be deleted by - # clean_gypd_files(), while the rest should be left alone. - for i in range(self.__num_files): - self.create_file('%s%s' % (str(i), GYPD_SUFFIX)) - self.create_file('%s%s' % (str(i), GYPI_SUFFIX)) - self.create_file('%s%s' % (str(i), GYP_SUFFIX)) - self.create_file('%s%s' % (str(i), OTHER_SUFFIX)) - - def create_file(self, basename): - """ - Create a file named 'basename' in self.__tmp_dir. - """ - f = tempfile.mkstemp(dir=self.__tmp_dir) - os.rename(f[1], os.path.join(self.__tmp_dir, basename)) - self.assert_file_exists(basename) - - def assert_file_exists(self, basename): - """ - Assert that 'basename' exists in self.__tmp_dir. - """ - full_name = os.path.join(self.__tmp_dir, basename) - self.assertTrue(os.path.exists(full_name)) - - def assert_file_does_not_exist(self, basename): - """ - Assert that 'basename' does not exist in self.__tmp_dir. - """ - full_name = os.path.join(self.__tmp_dir, basename) - self.assertFalse(os.path.exists(full_name)) - - def test_clean(self): - """ - Test that clean_gypd_files() deletes .gypd files, and leaves others. - """ - gyp_to_android.clean_gypd_files(self.__tmp_dir) - for i in range(self.__num_files): - self.assert_file_exists('%s%s' % (str(i), GYPI_SUFFIX)) - self.assert_file_exists('%s%s' % (str(i), GYP_SUFFIX)) - self.assert_file_exists('%s%s' % (str(i), OTHER_SUFFIX)) - # Only the GYPD files should have been deleted. - self.assert_file_does_not_exist('%s%s' % (str(i), GYPD_SUFFIX)) + # In addition, there should be an 'Android.mk' inside /tests/ + path_to_tests_android_mk = os.path.join(self.__tmp_dir, 'tests', + test_variables.ANDROID_MK) + self.assertTrue(os.path.exists(path_to_tests_android_mk)) def tearDown(self): + # Remove self.__tmp_dir, which is no longer needed. shutil.rmtree(self.__tmp_dir) def main(): loader = unittest.TestLoader() suite = loader.loadTestsFromTestCase(AndroidMkCreationTest) - suite.addTest(loader.loadTestsFromTestCase(CleanGypdTest)) unittest.TextTestRunner(verbosity=2).run(suite) if __name__ == "__main__": diff --git a/platform_tools/android/tests/makefile_writer_tests.py b/platform_tools/android/tests/makefile_writer_tests.py index 1b42bf37d2..6b726579a3 100644 --- a/platform_tools/android/tests/makefile_writer_tests.py +++ b/platform_tools/android/tests/makefile_writer_tests.py @@ -21,11 +21,13 @@ import utils sys.path.append(test_variables.GYP_GEN_DIR) import makefile_writer +import tool_makefile_writer import vars_dict_lib -MAKEFILE_NAME = 'Android.mk' +MAKEFILE_NAME = test_variables.ANDROID_MK REBASELINE_MSG = ('If you\'ve modified makefile_writer.py, run ' '"makefile_writer_tests.py --rebaseline" to rebaseline') +TOOL_DIR = 'tool' def generate_dummy_vars_dict(name): """Create a VarsDict and fill it with dummy entries. @@ -109,6 +111,16 @@ def generate_dummy_makefile(target_dir): common=common_vars_dict, deviations_from_common=deviations) +def generate_dummy_tool_makefile(target_dir): + """Create a dummy makefile for a tool. + + Args: + target_dir: directory in which to write the resulting Android.mk + """ + vars_dict = generate_dummy_vars_dict(None) + tool_makefile_writer.write_tool_android_mk(target_dir=target_dir, + var_dict=vars_dict) + class MakefileWriterTest(unittest.TestCase): @@ -169,6 +181,15 @@ class MakefileWriterTest(unittest.TestCase): shutil.rmtree(outdir) + def test_tool_writer(self): + outdir = tempfile.mkdtemp() + tool_dir = os.path.join(outdir, TOOL_DIR) + os.mkdir(tool_dir) + generate_dummy_tool_makefile(tool_dir) + + utils.compare_to_expectation(os.path.join(tool_dir, MAKEFILE_NAME), + os.path.join(TOOL_DIR, MAKEFILE_NAME), + self.assertTrue, REBASELINE_MSG) def main(): loader = unittest.TestLoader() @@ -187,6 +208,8 @@ def rebaseline(): with open(os.path.join(utils.EXPECTATIONS_DIR, filename), 'w') as f: makefile_writer.write_local_vars(f, vars_dict, append, name) + generate_dummy_tool_makefile(os.path.join(utils.EXPECTATIONS_DIR, TOOL_DIR)) + if __name__ == '__main__': parser = argparse.ArgumentParser() diff --git a/platform_tools/android/tests/ordered_set_tests.py b/platform_tools/android/tests/ordered_set_tests.py index 01016d9735..5ec4597e73 100644 --- a/platform_tools/android/tests/ordered_set_tests.py +++ b/platform_tools/android/tests/ordered_set_tests.py @@ -28,8 +28,7 @@ class OrderedSetTest(unittest.TestCase): self.__set = OrderedSet() def test_methods(self): - """ - Test methods on OrderedSet. + """Test methods on OrderedSet. """ RANGE = 10 for i in range(RANGE): @@ -67,6 +66,38 @@ class OrderedSetTest(unittest.TestCase): self.__set.reset() self.assertEqual(len(self.__set), 0) + def test_set(self): + """Test OrderedSet.set(). + """ + # Create a set with dummy values. + my_set = OrderedSet() + RANGE = 10 + for i in range(RANGE): + my_set.add(create_dummy_var(i)) + my_len = len(my_set) + self.assertEqual(my_len, RANGE) + + # Copy it to another set. + other_set = OrderedSet() + self.assertEqual(len(other_set), 0) + other_set.set(my_set) + + # Both sets should contain the same values, in the same order. + iterator = iter(my_set) + for item in other_set: + self.assertTrue(item == iterator.next()) + with self.assertRaises(StopIteration): + iterator.next() + self.assertEqual(my_len, len(other_set)) + + # But the sets are different. Changing one will not affect the other. + self.assertFalse(other_set is my_set) + other_var = 'something_else' + other_set.add(other_var) + self.assertEqual(my_len + 1, len(other_set)) + self.assertEqual(my_len, len(my_set)) + self.assertNotIn(other_var, my_set) + def main(): loader = unittest.TestLoader() diff --git a/platform_tools/android/tests/test_variables.py b/platform_tools/android/tests/test_variables.py index dd49a7e4e9..cc0bf1c3a9 100644 --- a/platform_tools/android/tests/test_variables.py +++ b/platform_tools/android/tests/test_variables.py @@ -20,3 +20,5 @@ BIN_DIR = os.path.join(ANDROID_DIR, 'bin') # Path to generator files. GYP_GEN_DIR = os.path.join(ANDROID_DIR, 'gyp_gen') + +ANDROID_MK = 'Android.mk' |