Add support for LIT to Android.mk.

Now that test/lit.cfg can handle running tests on Android devices, we
can move testing over to LIT so that it's easier to stay in sync with
upstream (no longer have to run test/makemake.py to regenerate makefiles
for each test). Also, we can now actually run all of the xfail tests
(tests that are considered passing if compilation fails).

The libc++ tests can be run with:

    $ mm test-libcxx        # run all tests
    $ mm test-libcxx-host   # host only
    $ mm test-libcxx-device # device only (uses current lunch target)

Actually generating the cppflags and ldflags is done in test/device.cfg.
It's a little ugly, but it does a decent job of approximating our build
system while still allowing us to finish a test run in less than 7
hours. Additional devices can be added to the config as needed.

Change-Id: Ieba38912a213c43e54e03ab9b8c4e25f019b0305
diff --git a/Android.mk b/Android.mk
index 65b44b7..6914453 100644
--- a/Android.mk
+++ b/Android.mk
@@ -122,4 +122,16 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_SHARED_LIBRARY)
 
+LIT := $(ANDROID_BUILD_TOP)/external/llvm/utils/lit/lit.py
+test-libcxx-host: libc++
+	LIT=$(LIT) LIT_MODE=host make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
+test-libcxx-target: libc++
+	LIT=$(LIT) LIT_MODE=device make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
+
+# Don't want to just make test-libcxx-(host|target) dependencies of this because
+# the two families can't be run concurrently.
+test-libcxx: libc++
+	LIT=$(LIT) LIT_MODE=host make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
+	LIT=$(LIT) LIT_MODE=device make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
+
 endif  # TARGET_BUILD_APPS
diff --git a/test.mk b/test.mk
new file mode 100644
index 0000000..31e8ed2
--- /dev/null
+++ b/test.mk
@@ -0,0 +1,6 @@
+.NOTPARALLEL:
+default:
+	cp $(ANDROID_BUILD_TOP)/external/libcxx/test/lit.$(LIT_MODE).cfg \
+	   $(ANDROID_BUILD_TOP)/external/libcxx/test/lit.site.cfg
+	-python $(LIT) -sv $(ANDROID_BUILD_TOP)/external/libcxx/test
+	rm $(ANDROID_BUILD_TOP)/external/libcxx/test/lit.site.cfg
diff --git a/test/device.cfg b/test/device.cfg
new file mode 100644
index 0000000..8c60438
--- /dev/null
+++ b/test/device.cfg
@@ -0,0 +1,203 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import os
+
+devices = {
+    'hammerhead': 'arm',
+}
+
+triples = {
+    'hammerhead': 'arm-linux-androideabi',
+}
+
+# use -I
+includes = {
+    'generic': [
+        'external/libcxx/include',
+        'external/libcxx/test/support',
+        'libnativehelper/include/nativehelper',
+    ],
+    'arm': [
+        'build/core/combo/include/arch/linux-arm/',
+    ],
+}
+
+# use -isystem
+system_includes = {
+    'generic': [
+        'system/core/include',
+        'hardware/libhardware/include',
+        'hardware/libhardware_legacy/include',
+        'hardware/ril/include',
+        'libnativehelper/include',
+        'frameworks/native/include',
+        'frameworks/native/opengl/include',
+        'frameworks/av/include',
+        'frameworks/base/include',
+        'external/skia/include',
+        'bionic/libc/include',
+        'bionic/libc/kernel/uapi',
+        'bionic/libm/include',
+        'prebuilts/clang/linux-x86/host/3.5/lib/clang/3.5/include/',
+    ],
+    'arm': [
+        'hardware/qcom/msm8x74/kernel-headers',
+        'bionic/libc/arch-arm/include',
+        'bionic/libc/kernel/uapi/asm-arm',
+        'bionic/libm/include/arm',
+    ],
+    'hammerhead': [
+        'out/target/product/hammerhead/obj/include',
+        'out/target/product/hammerhead/obj/include/clang',
+        'device/lge/hammerhead/kernel-headers',
+    ],
+}
+
+compiler_flags = {
+    'generic': [
+        '-fdata-sections',
+        '-ffunction-sections',
+        '-fmessage-length=0',
+        '-fno-short-enums',
+        '-fno-strict-aliasing',
+        '-fomit-frame-pointer',
+        '-fpic',
+        '-fPIE',
+        '-fstack-protector',
+        '-funwind-tables',
+        '-fvisibility-inlines-hidden',
+        '-no-canonical-prefixes',
+        '-no-integrated-as',
+        '-nostdlibinc',
+        '-std=c++11',
+    ],
+    'arm': [
+        '-B', os.path.join(config.android_root, 'prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/arm-linux-androideabi/bin'),
+        '-target', 'arm-linux-androideabi',
+        '-include', os.path.join(config.android_root, 'build/core/combo/include/arch/linux-arm/AndroidConfig.h'),
+    ]
+}
+
+arch_flags = {
+    'arm': [
+        '-msoft-float',
+        '-march=armv7-a',
+        '-mfloat-abi=softfp',
+        '-mfpu=neon',
+        '-mthumb',
+    ],
+}
+
+defines = [
+    '-D_FORTIFY_SOURCE=2',
+    '-DANDROID',
+    '-D__compiler_offsetof=__builtin_offsetof',
+]
+
+warning_flags = [
+    '-W',
+    '-Wall',
+    '-Werror=address',
+    '-Werror=format-security',
+    '-Werror=int-conversion',
+    '-Werror=non-virtual-dtor',
+    '-Werror=return-type',
+    '-Werror=sequence-point',
+    '-Winit-self',
+    '-Wno-multichar',
+    '-Wno-unused',
+    '-Wpointer-arith',
+    '-Wsign-promo',
+    '-Wstrict-aliasing=2',
+]
+
+link_flags = {
+    'generic': [
+        '-nostdlib',
+        '-Bdynamic',
+        '-fPIE',
+        '-pie',
+        '-Wl,-dynamic-linker,/system/bin/linker',
+        '-Wl,--gc-sections',
+        '-Wl,-z,nocopyreloc',
+        '-Wl,-z,noexecstack',
+        '-Wl,-z,relro',
+        '-Wl,-z,now',
+        '-Wl,--warn-shared-textrel',
+        '-Wl,--fatal-warnings',
+        '-Wl,--icf=safe',
+        '-Wl,--no-undefined',
+        '-no-integrated-as',
+        '-Wl,--no-whole-archive',
+        '-L', os.path.join(os.getenv('ANDROID_PRODUCT_OUT'), 'obj/lib'),
+        '-Wl,-rpath-link={}'.format(os.path.join(os.getenv('ANDROID_PRODUCT_OUT'), 'obj/lib')),
+        '-lc++',
+        '-lc',
+        '-lm',
+    ],
+    'arm': [
+        '-Wl,--fix-cortex-a8',
+        '-target', 'arm-linux-androideabi',
+        '-B', os.path.join(config.android_root, 'prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/arm-linux-androideabi/bin'),
+    ],
+}
+
+crtbegin = {
+    'hammerhead': 'out/target/product/hammerhead/obj/lib/crtbegin_dynamic.o',
+}
+
+crtend = {
+    'hammerhead': 'out/target/product/hammerhead/obj/lib/crtend_android.o',
+}
+
+builtins = {
+    'arm': [
+        os.path.join(config.android_root, 'prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/arm-linux-androideabi/lib/libatomic.a'),
+        os.path.join(config.android_root, 'prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/lib/gcc/arm-linux-androideabi/4.8/libgcc.a'),
+    ],
+    'hammerhead': [
+        os.path.join(config.android_root, 'out/target/product/hammerhead/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a'),
+    ],
+}
+
+
+def compiler_flags_for(device):
+    arch = devices[device]
+    flags = warning_flags + defines + arch_flags[arch]
+
+    all_includes = includes['generic'] + includes[arch]
+    for inc in all_includes:
+        flags += ['-I', os.path.join(config.android_root, inc)]
+
+    all_system_includes = (system_includes['generic'] +
+                           system_includes[arch] +
+                           system_includes[device])
+    for inc in all_system_includes:
+        flags += ['-isystem', os.path.join(config.android_root, inc)]
+
+    flags += compiler_flags['generic'] + compiler_flags[arch]
+    return flags
+
+# don't care about the leading aosp_
+device = os.getenv('TARGET_PRODUCT').split('_')[-1]
+config.target_triple = triples[device]
+config.cppflags = compiler_flags_for(device)
+config.ldflags = (
+    link_flags['generic'] +
+    link_flags[devices[device]] +
+    builtins[devices[device]] +
+    builtins[device]
+)
+config.crtbegin = os.path.join(config.android_root, crtbegin[device])
+config.crtend = os.path.join(config.android_root, crtend[device])
diff --git a/test/lit.device.cfg b/test/lit.device.cfg
new file mode 100644
index 0000000..53ef96e
--- /dev/null
+++ b/test/lit.device.cfg
@@ -0,0 +1,17 @@
+import os
+
+config.android = True
+config.android_root = os.getenv('ANDROID_BUILD_TOP')
+config.cxx_under_test = os.path.join(
+    config.android_root, 'prebuilts/clang/linux-x86/host/3.5/bin/clang++')
+config.libcxx_src_root = os.path.join(config.android_root, 'external/libcxx')
+config.libcxx_obj_root = os.getenv('ANDROID_PRODUCT_OUT')
+config.python_executable = '/usr/bin/python'
+
+# load target's cxxflags and ldflags
+lit_config.load_config(
+    config, os.path.join(config.libcxx_src_root, 'test/device.cfg'))
+
+# Let the main config do the real work.
+lit_config.load_config(
+    config, os.path.join(config.libcxx_src_root, 'test/lit.cfg'))
diff --git a/test/lit.host.cfg b/test/lit.host.cfg
new file mode 100644
index 0000000..e2d9813
--- /dev/null
+++ b/test/lit.host.cfg
@@ -0,0 +1,15 @@
+import os
+
+android_root = os.getenv('ANDROID_BUILD_TOP')
+config.cxx_under_test = os.path.join(
+    android_root, 'prebuilts/clang/linux-x86/host/3.5/bin/clang++')
+config.cxx_has_stdcxx0x_flag = True
+config.libcxx_src_root = os.path.join(android_root, 'external/libcxx')
+config.libcxx_obj_root = os.getenv('ANDROID_HOST_OUT')
+config.python_executable = "/usr/bin/python"
+config.enable_shared = True
+config.cxx_abi = "none"
+
+# Let the main config do the real work.
+lit_config.load_config(
+    config, os.path.join(config.libcxx_src_root, 'test/lit.cfg'))