diff --git a/Android.bp b/Android.bp index 7e83ac620..7ba35635e 100644 --- a/Android.bp +++ b/Android.bp @@ -128,13 +128,46 @@ cc_library_shared { }, } +// This target is used to extract the build commands for a test executable. +// See run_tests.py. +cc_binary { + name: "libcxx_test_template", + srcs: [ + "libcxx_test_template.cpp", + ], + cppflags: [ + "-fsized-deallocation", + "-fexceptions", + "-Wno-format-zero-length", + "-Wno-implicit-fallthrough", + "-Wno-non-virtual-dtor", + "-Wno-return-stack-address", + "-Wno-unused-local-typedef", -// ANDROIDMK TRANSLATION ERROR: unsupported conditional -// ifdef LIBCXX_TESTING -// ANDROIDMK TRANSLATION ERROR: unsupported include -// include $(LOCAL_PATH)/buildcmds/Android.mk - -// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional -// endif -// TARGET_BUILD_APPS + "-UNDEBUG", + // Optimization is causing relocation for nothrow new to be thrown away. + // http://llvm.org/bugs/show_bug.cgi?id=21421 + "-O0", + ], + ldflags: [ + // This makes the tests run a little faster. + "-Wl,--strip-all", + ], + rtti: true, + local_include_dirs: [ + "test/support", + ], + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + compile_multilib: "both", + host_supported: true, + gnu_extensions: false, + cpp_std: "c++17", +} diff --git a/Android.mk b/Android.mk deleted file mode 100644 index f10c5075e..000000000 --- a/Android.mk +++ /dev/null @@ -1 +0,0 @@ -# This empty Android.mk file is required to shadow buildcmds/Android.mk diff --git a/buildcmds/.gitignore b/buildcmds/.gitignore deleted file mode 100644 index a77d525cd..000000000 --- a/buildcmds/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -cxx_under_test -cxx.cmds -link.cmds -testconfig.mk diff --git a/buildcmds/Android.mk b/buildcmds/Android.mk deleted file mode 100644 index 03d719ea6..000000000 --- a/buildcmds/Android.mk +++ /dev/null @@ -1,45 +0,0 @@ -# -# 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. -# - -LOCAL_PATH := $(call my-dir) - -# Don't build for unbundled branches -ifeq (,$(TARGET_BUILD_APPS)) - -include $(CLEAR_VARS) -LOCAL_MODULE := libc++_build_commands_$(ANDROID_DEVICE) -LOCAL_SRC_FILES := dummy.cpp -LOCAL_CXX_STL := libc++ -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../test/support -LOCAL_CPPFLAGS := \ - -std=c++17 \ - -fsized-deallocation \ - -fexceptions \ - -UNDEBUG \ - -Wno-error=non-virtual-dtor \ - -Wno-format-zero-length \ - -Wno-reserved-user-defined-literal \ - -Wno-unused-local-typedef \ - -Wno-unused-variable \ - -# Optimization is causing relocation for nothrow new to be thrown away. -# http://llvm.org/bugs/show_bug.cgi?id=21421 -LOCAL_CPPFLAGS += -O0 - -LOCAL_RTTI_FLAG := -frtti -include $(LOCAL_PATH)/testconfig.mk - -endif diff --git a/buildcmds/buildcmdscc b/buildcmds/buildcmdscc deleted file mode 100755 index b169e92ca..000000000 --- a/buildcmds/buildcmdscc +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -CXX=$1 -ARGS=${*:2} -DIR=external/libcxx/buildcmds -echo $ANDROID_BUILD_TOP/$CXX > $DIR/cxx_under_test - -echo $ARGS | grep -P '\S+\.cpp\b' > /dev/null -if [ $? -eq 0 ]; then - echo $ARGS | perl -ne 's/\S+\.cpp\b/%SOURCE%/; print' \ - | perl -ne 's/\S+\.o\b/%OUT%/; print' > $DIR/cxx.cmds -else - echo $ARGS | perl -ne 's/out\/\S+\/EXECUTABLES\/\S+\.o\b/%SOURCE%/; print' \ - | perl -ne 's/-o\s+\S+\b/-o %OUT%/; print' > $DIR/link.cmds -fi - -$CXX $ARGS diff --git a/buildcmds/dummy.cpp b/buildcmds/dummy.cpp deleted file mode 100644 index 4cce7f667..000000000 --- a/buildcmds/dummy.cpp +++ /dev/null @@ -1,3 +0,0 @@ -int main() { - return 0; -} diff --git a/libcxx_test_template.cpp b/libcxx_test_template.cpp new file mode 100644 index 000000000..237c8ce18 --- /dev/null +++ b/libcxx_test_template.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/pylintrc b/pylintrc new file mode 100644 index 000000000..41ceec17f --- /dev/null +++ b/pylintrc @@ -0,0 +1,11 @@ +[MESSAGES CONTROL] +disable=design,fixme + +[BASIC] +good-names=i, + j, + k, + ex, + Run, + _, + cc diff --git a/run_tests.py b/run_tests.py index bc988f15c..f510c41bc 100755 --- a/run_tests.py +++ b/run_tests.py @@ -22,7 +22,6 @@ import logging import os import sys - THIS_DIR = os.path.dirname(os.path.realpath(__file__)) ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..')) @@ -46,68 +45,101 @@ def check_call(cmd, *args, **kwargs): return subprocess.check_call(cmd, *args, **kwargs) +def check_output(cmd, *args, **kwargs): + """subprocess.check_output with logging.""" + import subprocess + logger().info('check_output %s', ' '.join(cmd)) + return subprocess.check_output(cmd, *args, **kwargs) + + class ArgParser(argparse.ArgumentParser): """Parses command line arguments.""" + def __init__(self): super(ArgParser, self).__init__() - self.add_argument( - '--compiler', choices=('clang', 'gcc'), default='clang') - self.add_argument( - '--bitness', choices=(32, 64), type=int, default=32) + self.add_argument('--bitness', choices=(32, 64), type=int, default=32) self.add_argument('--host', action='store_true') -def gen_test_config(bitness, compiler, host): - """Generates the test configuration makefile for buildcmds.""" - testconfig_mk_path = os.path.join(THIS_DIR, 'buildcmds/testconfig.mk') - with open(testconfig_mk_path, 'w') as test_config: - if compiler == 'clang': - print('LOCAL_CLANG := true', file=test_config) - elif compiler == 'gcc': - print('LOCAL_CLANG := false', file=test_config) +def extract_build_cmds(commands, exe_name): + """Extracts build command information from `ninja -t commands` output. - if bitness == 32: - print('LOCAL_MULTILIB := 32', file=test_config) - elif bitness == 64: - print('LOCAL_MULTILIB := 64', file=test_config) + Args: + commands: String containing the output of `ninja -t commands` for the + libcxx_test_template. + exe_name: The basename of the built executable. - if compiler == 'clang': - print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc $(CLANG_CXX)', - file=test_config) - else: - if host: - prefix = 'HOST_' - else: - prefix = 'TARGET_' - print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc ' - '$($(LOCAL_2ND_ARCH_VAR_PREFIX){}CXX)'.format(prefix), - file=test_config) + Returns: + Tuple of (compiler, compiler_flags, linker_flags). + """ + cc = None + cflags = None + ldflags = None + template_name = 'external/libcxx/libcxx_test_template.cpp' - if host: - print('include $(BUILD_HOST_EXECUTABLE)', file=test_config) - else: - print('include $(BUILD_EXECUTABLE)', file=test_config) + for cmd in commands.splitlines(): + cmd_args = cmd.split() + if cc is None and template_name in cmd_args: + for i, arg in enumerate(cmd_args): + if arg == '-o': + cmd_args[i + 1] = '%OUT%' + elif arg == template_name: + cmd_args[i] = '%SOURCE%' + # Drop dependency tracking args since they can cause file + # not found errors at test time. + if arg == '-MD': + cmd_args[i] = '' + if arg == '-MF': + cmd_args[i] = '' + cmd_args[i + 1] = '' + if cmd_args[0] == 'PWD=/proc/self/cwd': + cmd_args = cmd_args[1:] + if cmd_args[0].endswith('gomacc'): + cmd_args = cmd_args[1:] + cc = cmd_args[0] + cflags = cmd_args[1:] + if ldflags is None: + is_ld = False + for i, arg in enumerate(cmd_args): + # Here we assume that the rspfile contains the path to the + # object file and nothing else. + if arg.startswith('@'): + cmd_args[i] = '%SOURCE%' + if arg == '-o' and cmd_args[i + 1].endswith(exe_name): + cmd_args[i + 1] = '%OUT%' + is_ld = True + if is_ld: + ldflags = cmd_args[1:] + + return cc, cflags, ldflags -def mmm(path): - """Invokes the Android build command mmm.""" - makefile = os.path.join(path, 'Android.mk') - main_mk = 'build/core/main.mk' +def get_build_cmds(bitness, host): + """Use ninja -t commands to find the build commands for an executable.""" + out_dir = os.getenv('OUT_DIR', os.path.join(ANDROID_DIR, 'out')) + product_out = os.getenv('ANDROID_PRODUCT_OUT') - env = dict(os.environ) - env['ONE_SHOT_MAKEFILE'] = makefile - env['LIBCXX_TESTING'] = 'true' - cmd = [ - 'make', '-j', '-C', ANDROID_DIR, '-f', main_mk, - 'MODULES-IN-' + path.replace('/', '-'), - ] - check_call(cmd, env=env) + if host: + rel_out_dir = os.path.relpath( + os.path.join(out_dir, 'soong/host/linux-x86/bin'), ANDROID_DIR) + target = os.path.join(rel_out_dir, 'libcxx_test_template64') + else: + exe_name = 'libcxx_test_template' + str(bitness) + rel_out_dir = os.path.relpath(product_out, ANDROID_DIR) + target = os.path.join(rel_out_dir, 'system/bin', exe_name) + # Generate $OUT_DIR/combined-$TARGET_PRODUCT.ninja and build the + # template target's dependencies. + check_call(['make', '-C', ANDROID_DIR, target]) -def gen_build_cmds(bitness, compiler, host): - """Generates the build commands file for the test runner.""" - gen_test_config(bitness, compiler, host) - mmm('external/libcxx/buildcmds') + ninja_path = os.path.join( + out_dir, 'combined-' + os.getenv('TARGET_PRODUCT') + '.ninja') + commands = check_output([ + os.path.join(ANDROID_DIR, 'prebuilts/build-tools/linux-x86/bin/ninja'), + '-C', ANDROID_DIR, '-f', ninja_path, '-t', 'commands', target + ]) + + return extract_build_cmds(commands, os.path.basename(target)) def main(): @@ -116,20 +148,27 @@ def main(): args, lit_args = ArgParser().parse_known_args() lit_path = os.path.join(ANDROID_DIR, 'external/llvm/utils/lit/lit.py') - gen_build_cmds(args.bitness, args.compiler, args.host) + cc, cflags, ldflags = get_build_cmds(args.bitness, args.host) mode_str = 'host' if args.host else 'device' android_mode_arg = '--param=android_mode=' + mode_str + cxx_under_test_arg = '--param=cxx_under_test=' + cc + cxx_template_arg = '--param=cxx_template=' + ' '.join(cflags) + link_template_arg = '--param=link_template=' + ' '.join(ldflags) site_cfg_path = os.path.join(THIS_DIR, 'test/lit.site.cfg') - site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path - default_test_path = os.path.join(THIS_DIR, 'test') + libcxx_site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path + libcxxabi_site_cfg_arg = '--param=libcxxabi_site_config=' + site_cfg_path + default_test_paths = [ + os.path.join(THIS_DIR, 'test'), + os.path.join(ANDROID_DIR, 'external/libcxxabi/test') + ] have_filter_args = False for arg in lit_args: - # If the argument is a valid path with default_test_path, it is a test + # If the argument is a valid path with default_test_paths, it is a test # filter. real_path = os.path.realpath(arg) - if not real_path.startswith(default_test_path): + if not any(real_path.startswith(path) for path in default_test_paths): continue if not os.path.exists(real_path): continue @@ -137,10 +176,13 @@ def main(): have_filter_args = True break # No need to keep scanning. - lit_args = ['-sv', android_mode_arg, site_cfg_arg] + lit_args + lit_args = [ + '-sv', android_mode_arg, cxx_under_test_arg, cxx_template_arg, + link_template_arg, libcxx_site_cfg_arg, libcxxabi_site_cfg_arg + ] + lit_args cmd = ['python', lit_path] + lit_args if not have_filter_args: - cmd.append(default_test_path) + cmd += default_test_paths sys.exit(call(cmd)) diff --git a/test/libcxx/ndk/test/config.py b/test/libcxx/ndk/test/config.py index 85ccd8492..5b8945c7f 100644 --- a/test/libcxx/ndk/test/config.py +++ b/test/libcxx/ndk/test/config.py @@ -1,7 +1,6 @@ import os import libcxx.test.config -import libcxx.android.build import libcxx.android.test.format @@ -9,7 +8,6 @@ class Configuration(libcxx.test.config.Configuration): def __init__(self, lit_config, config): super(Configuration, self).__init__(lit_config, config) self.cxx_under_test = None - self.build_cmds_dir = None self.cxx_template = None self.link_template = None diff --git a/utils/libcxx/android/build.py b/utils/libcxx/android/build.py deleted file mode 100644 index a0d1be332..000000000 --- a/utils/libcxx/android/build.py +++ /dev/null @@ -1,13 +0,0 @@ -import os -import subprocess - - -def mm(path, android_build_top): - env = os.environ - env['ONE_SHOT_MAKEFILE'] = os.path.join(path, 'Android.mk') - - cmd = [ - 'make', '-C', android_build_top, '-f', 'build/core/main.mk', - 'MODULES-IN-' + path.replace('/', '-'), '-B' - ] - return not subprocess.Popen(cmd, stdout=None, stderr=None, env=env).wait() diff --git a/utils/libcxx/android/test/config.py b/utils/libcxx/android/test/config.py index 898d10bfc..1356f0556 100644 --- a/utils/libcxx/android/test/config.py +++ b/utils/libcxx/android/test/config.py @@ -2,7 +2,6 @@ import os import re import libcxx.test.config -import libcxx.android.build import libcxx.android.compiler import libcxx.android.test.format @@ -10,11 +9,9 @@ import libcxx.android.test.format class Configuration(libcxx.test.config.Configuration): def __init__(self, lit_config, config): super(Configuration, self).__init__(lit_config, config) - self.build_cmds_dir = None def configure(self): self.configure_src_root() - self.configure_build_cmds() self.configure_obj_root() self.configure_cxx() @@ -32,34 +29,24 @@ class Configuration(libcxx.test.config.Configuration): list(self.config.available_features)) def configure_obj_root(self): - test_config_file = os.path.join(self.build_cmds_dir, 'testconfig.mk') - if 'HOST_NATIVE_TEST' in open(test_config_file).read(): + if self.lit_config.params.get('android_mode') == 'host': self.libcxx_obj_root = os.getenv('ANDROID_HOST_OUT') else: self.libcxx_obj_root = os.getenv('ANDROID_PRODUCT_OUT') - def configure_build_cmds(self): - os.chdir(self.config.android_root) - self.build_cmds_dir = 'external/libcxx/buildcmds' - if not libcxx.android.build.mm(self.build_cmds_dir, - self.config.android_root): - raise RuntimeError('Could not generate build commands.') - def configure_cxx(self): - cxx_under_test_file = os.path.join(self.build_cmds_dir, - 'cxx_under_test') - cxx_under_test = open(cxx_under_test_file).read().strip() - - cxx_template_file = os.path.join(self.build_cmds_dir, 'cxx.cmds') - cxx_template = open(cxx_template_file).read().strip() - - link_template_file = os.path.join(self.build_cmds_dir, 'link.cmds') - link_template = open(link_template_file).read().strip() + cxx_under_test = self.lit_config.params.get('cxx_under_test') + cxx_template = self.lit_config.params.get('cxx_template') + link_template = self.lit_config.params.get('link_template') self.cxx = libcxx.android.compiler.AndroidCXXCompiler( cxx_under_test, cxx_template, link_template) def configure_triple(self): + # The libcxxabi test suite needs this but it doesn't actually + # use it for anything important. + self.config.host_triple = '' + self.config.target_triple = self.cxx.get_triple() def configure_features(self):