0

[Android] Build gtest APKs like other APKs

After much work, we can build gtest APKs without first transforming .java files, resource files, or the AndroidManifest.xml. We can directly use java_apk.gypi and build like all other APKs.

Do that.

Also, native_test_apk.xml was the last user of common.xml and sdk-targets.xml, and so those can now be removed.

Review URL: https://chromiumcodereview.appspot.com/13828003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@193576 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
cjhopman@chromium.org
2013-04-11 04:47:10 +00:00
parent 85860d0286
commit fd895ffa0f
7 changed files with 4 additions and 718 deletions

@@ -1,3 +1,2 @@
apk-based runner for Chromium unit test bundles. Many of these files
are templates for generating an apk specific to a test bundle.
See generate_native_test.py or discuss with OWNERS.
apk-based runner for Chromium unit test bundles. This is a simple wrapper APK
that should include a single gtest native library.

@@ -1,202 +0,0 @@
#!/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.
# On Android we build unit test bundles as shared libraries. To run
# tests, we launch a special "test runner" apk which loads the library
# then jumps into it. Since java is required for many tests
# (e.g. PathUtils.java), a "pure native" test bundle is inadequate.
#
# This script, generate_native_test.py, is used to generate the source
# for an apk that wraps a unit test shared library bundle. That
# allows us to have a single boiler-plate application be used across
# all unit test bundles.
import logging
import optparse
import os
import re
import subprocess
import sys
# cmd_helper.py is under ../../build/android/
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..',
'..', 'build', 'android')))
from pylib import cmd_helper # pylint: disable=F0401
class NativeTestApkGenerator(object):
"""Generate a native test apk source tree.
TODO(jrg): develop this more so the activity name is replaced as
well. That will allow multiple test runners to be installed at the
same time. (The complication is that it involves renaming a java
class, which implies regeneration of a jni header, and on and on...)
"""
# Files or directories we need to copy to create a complete apk test shell.
_SOURCE_FILES = ['AndroidManifest.xml',
'native_test_apk.xml',
'res', # res/values/strings.xml
'java', # .../ChromeNativeTestActivity.java
]
# Files in the destion directory that have a "replaceme" string
# which should be replaced by the basename of the shared library.
# Note we also update the filename if 'replaceme' is itself found in
# the filename.
_REPLACEME_FILES = ['AndroidManifest.xml',
'native_test_apk.xml',
'res/values/strings.xml']
def __init__(self, native_library, strip_binary, output_directory,
target_abi):
self._native_library = native_library
self._strip_binary = strip_binary
self._output_directory = os.path.abspath(output_directory)
self._target_abi = target_abi
self._root_name = None
if self._native_library:
self._root_name = self._LibraryRoot()
logging.info('root name: %s', self._root_name)
def _LibraryRoot(self):
"""Return a root name for a shared library.
The root name should be suitable for substitution in apk files
like the manifest. For example, blah/foo/libbase_unittests.so
becomes base_unittests.
"""
rootfinder = re.match('.?lib(.+).so',
os.path.basename(self._native_library))
if rootfinder:
return rootfinder.group(1)
else:
return None
def _CopyTemplateFilesAndClearDir(self):
"""Copy files needed to build a new apk.
Uses rsync to avoid unnecessary io. This call also clears outstanding
files in the directory.
"""
srcdir = os.path.abspath(os.path.dirname(__file__))
destdir = self._output_directory
if not os.path.exists(destdir):
os.makedirs(destdir)
elif not '/out/' in destdir:
raise Exception('Unbelievable output directory; bailing for safety')
logging.info('rsync %s --> %s', self._SOURCE_FILES, destdir)
logging.info(cmd_helper.GetCmdOutput(
['rsync', '-aRv', '--delete', '--exclude', '.svn'] +
self._SOURCE_FILES + [destdir], cwd=srcdir))
def _ReplaceStrings(self):
"""Replace 'replaceme' strings in generated files with a root libname.
If we have no root libname (e.g. no shlib was specified), do nothing.
"""
if not self._root_name:
return
logging.info('Replacing "replaceme" with ' + self._root_name)
for f in self._REPLACEME_FILES:
dest = os.path.join(self._output_directory, f)
contents = open(dest).read()
contents = contents.replace('replaceme', self._root_name)
dest = dest.replace('replaceme', self._root_name) # update the filename!
open(dest, 'w').write(contents)
def _CopyLibrary(self):
"""Copy the shlib into the apk source tree (if relevant)."""
if self._native_library:
destdir = os.path.join(self._output_directory, 'libs/' + self._target_abi)
if not os.path.exists(destdir):
os.makedirs(destdir)
dest = os.path.join(destdir, os.path.basename(self._native_library))
logging.info('strip %s --> %s', self._native_library, dest)
cmd_helper.RunCmd(
[self._strip_binary, '--strip-unneeded', self._native_library, '-o',
dest])
def CreateBundle(self):
"""Create the apk bundle source and assemble components."""
self._CopyTemplateFilesAndClearDir()
self._ReplaceStrings()
self._CopyLibrary()
def Compile(self, ant_args):
"""Build the generated apk with ant.
Args:
ant_args: extra args to pass to ant
"""
cmd = ['ant']
if ant_args:
cmd.extend(ant_args)
cmd.append("-DAPP_ABI=" + self._target_abi)
cmd.extend(['-buildfile',
os.path.join(self._output_directory, 'native_test_apk.xml')])
logging.info(cmd)
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT)
(stdout, _) = p.communicate()
logging.info(stdout)
if p.returncode != 0:
logging.error('Ant return code %d', p.returncode)
sys.exit(p.returncode)
def main(argv):
parser = optparse.OptionParser()
parser.add_option('--verbose',
help='Be verbose')
parser.add_option('--native_library',
help='Full name of native shared library test bundle')
parser.add_option('--jars',
help='Space separated list of jars to be included')
parser.add_option('--output',
help='Output directory for generated files.')
parser.add_option('--app_abi', default='armeabi',
help='ABI for native shared library')
parser.add_option('--strip-binary',
help='Binary to use for stripping the native libraries.')
parser.add_option('--ant-args', action='append',
help='extra args for ant')
parser.add_option('--stamp-file',
help='Path to file to touch on success.')
parser.add_option('--no-compile', action='store_true',
help='Use this flag to disable ant compilation.')
options, _ = parser.parse_args(argv)
# It is not an error to specify no native library; the apk should
# still be generated and build. It will, however, print
# NATIVE_LOADER_FAILED when run.
if not options.output:
raise Exception('No output directory specified for generated files')
if options.verbose:
logging.basicConfig(level=logging.DEBUG, format=' %(message)s')
if not options.strip_binary:
options.strip_binary = os.getenv('STRIP')
if not options.strip_binary:
raise Exception('No tool for stripping the libraries has been supplied')
ntag = NativeTestApkGenerator(native_library=options.native_library,
strip_binary=options.strip_binary,
output_directory=options.output,
target_abi=options.app_abi)
ntag.CreateBundle()
if not options.no_compile:
ntag.Compile(options.ant_args)
if options.stamp_file:
with file(options.stamp_file, 'a'):
os.utime(options.stamp_file, None)
logging.info('COMPLETE.')
if __name__ == '__main__':
sys.exit(main(sys.argv))

@@ -1,87 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project name="replaceme" default="debug" basedir=".">
<description>
Building native test runner ChromeNativeTests_replaceme.apk
</description>
<!--
TODO(beverloo): Remove this property when all gyp files (also those in
WebKit) define the CHROMIUM_SRC property. This works because properties
in ant files are immutable.
-->
<property name="CHROMIUM_SRC" value="${PRODUCT_DIR}/../.." />
<import file="${CHROMIUM_SRC}/build/android/ant/common.xml"/>
<!--
TODO(yfriedman): Remove the need to specify this. We should generate the packages in a way such
that it's not required.
-->
<property name="source.absolute.dir" value="java/src"/>
<path id="javac.custom.classpath">
<pathelement location="${ANDROID_SDK}/android.jar" />
</path>
<property name="target.abi" value="${APP_ABI}"/>
<path id="native.libs.gdbserver">
<fileset file="${android.gdbserver}"/>
</path>
<!-- We expect PRODUCT_DIR to be set like the gyp var
(e.g. $ROOT/out/Debug) -->
<fail message="PRODUCT_DIR env var not set?">
<condition>
<not>
<isset property="PRODUCT_DIR"/>
</not>
</condition>
</fail>
<property name="out.dir" location="${PRODUCT_DIR}/replaceme_apk"/>
<property name="resource.absolute.dir" value="res"/>
<property name="gen.absolute.dir" value="${out.dir}/gen"/>
<path id="out.dex.jar.input.ref">
<filelist files="${INPUT_JARS_PATHS}"/>
</path>
<condition property="java.compilerargs"
value="-classpath ${toString:out.dex.jar.input.ref}">
<not>
<equals arg1="${toString:out.dex.jar.input.ref}" arg2=""/>
</not>
</condition>
<property name="native.libs.absolute.dir" location="${out.dir}/libs" />
<!-- Copy the below manifest file to a new directory because the project
base directory and output directory are the same and manifest merge
task takes the same file as source and target when doing copying.
Otherwise it'll generate an empty manifest file. -->
<copy file="AndroidManifest.xml" todir="${out.dir}/manifest"/>
<property name="manifest.abs.file" location="${out.dir}/manifest/AndroidManifest.xml"/>
<target name="-post-compile">
<!-- copy gdbserver to main libs directory if building debug. -->
<if>
<condition>
<equals arg1="${build.target}" arg2="debug" />
</condition>
<then>
<copy todir="${out.dir}/libs/${target.abi}">
<path refid="native.libs.gdbserver"/>
</copy>
</then>
</if>
</target>
<import file="${CHROMIUM_SRC}/build/android/ant/sdk-targets.xml"/>
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<!-- argument to pass to System.loadLibrary(). E.g. base_unittests
for loading libbase_unittests.so. -->
<string name="native_library">replaceme</string>
</resources>