Skip to content

Commit

Permalink
Don't use libandroid_support for modern API levels.
Browse files Browse the repository at this point in the history
If we're targeting a new enough platform version, we don't actually
need to cover any gaps in libc for libc++ support. In those cases,
save size in the APK by avoiding libandroid_support.

This is also a requirement for static executables, since using
libandroid_support with a modern libc.a will result in multiple symbol
definition errors.

Test: ./checkbuild.py && ./run_tests.py
Bug: android/ndk#272
Change-Id: Iec548d7a75cc407d091b1a2bc632df68756c717d
(cherry picked from commit cf5442c13a4cd0fe8b01e27de3850727007988f0)
  • Loading branch information
DanAlbert committed Feb 13, 2018
1 parent cd8555d commit d83e623
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 39 deletions.
21 changes: 19 additions & 2 deletions build/cmake/android.toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ list(APPEND ANDROID_LINKER_FLAGS -Wl,--exclude-libs,libatomic.a)
set(USE_NOSTDLIBXX TRUE)
set(ANDROID_STL_STATIC_LIBRARIES)
set(ANDROID_STL_SHARED_LIBRARIES)
set(ANDROID_STL_LDLIBS)
if(ANDROID_STL STREQUAL system)
set(USE_NOSTDLIBXX FALSE)
if(NOT "x${ANDROID_CPP_FEATURES}" STREQUAL "x")
Expand All @@ -338,9 +339,22 @@ elseif(ANDROID_STL STREQUAL gnustl_shared)
set(ANDROID_STL_STATIC_LIBRARIES supc++)
set(ANDROID_STL_SHARED_LIBRARIES gnustl_shared)
elseif(ANDROID_STL STREQUAL c++_static)
set(ANDROID_STL_STATIC_LIBRARIES c++)
list(APPEND ANDROID_STL_STATIC_LIBRARIES c++_static c++abi)
if(ANDROID_PLATFORM_LEVEL LESS 21)
list(APPEND ANDROID_STL_STATIC_LIBRARIES android_support)
endif()
if(ANDROID_ABI STREQUAL armeabi-v7a)
list(APPEND ANDROID_STL_STATIC_LIBRARIES unwind)
list(APPEND ANDROID_STL_LDLIBS dl)
endif()
elseif(ANDROID_STL STREQUAL c++_shared)
set(ANDROID_STL_SHARED_LIBRARIES c++)
if(ANDROID_PLATFORM_LEVEL LESS 21)
list(APPEND ANDROID_STL_STATIC_LIBRARIES android_support)
endif()
if(ANDROID_ABI STREQUAL armeabi-v7a)
list(APPEND ANDROID_STL_STATIC_LIBRARIES unwind)
endif()
list(APPEND ANDROID_STL_SHARED_LIBRARIES c++_shared)
elseif(ANDROID_STL STREQUAL none)
else()
message(FATAL_ERROR "Invalid Android STL: ${ANDROID_STL}.")
Expand Down Expand Up @@ -577,6 +591,9 @@ foreach(library ${ANDROID_STL_SHARED_LIBRARIES})
list(APPEND ANDROID_CXX_STANDARD_LIBRARIES
"${ANDROID_NDK}/sources/cxx-stl/${ANDROID_STL_PREFIX}/libs/${ANDROID_ABI}/lib${library}.so")
endforeach()
foreach(library ${ANDROID_STL_LDLIBS})
list(APPEND ANDROID_CXX_STANDARD_LIBRARIES "-l${library}")
endforeach()
set(CMAKE_C_STANDARD_LIBRARIES_INIT "-latomic -lm")
set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
if(ANDROID_CXX_STANDARD_LIBRARIES)
Expand Down
12 changes: 12 additions & 0 deletions build/core/setup-abi.mk
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ else
TARGET_PIE := false
endif

# If we're targeting a new enough platform version, we don't actually need to
# cover any gaps in libc for libc++ support. In those cases, save size in the
# APK by avoiding libandroid_support.
#
# This is also a requirement for static executables, since using
# libandroid_support with a modern libc.a will result in multiple symbol
# definition errors.
NDK_PLATFORM_NEEDS_ANDROID_SUPPORT := true
ifeq ($(call gte,$(TARGET_PLATFORM_LEVEL),21),$(true))
NDK_PLATFORM_NEEDS_ANDROID_SUPPORT := false
endif

# Separate the debug and release objects. This prevents rebuilding
# everything when you switch between these two modes. For projects
# with lots of C++ sources, this can be a considerable time saver.
Expand Down
19 changes: 10 additions & 9 deletions build/tools/make_standalone_toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,14 @@ def copy_stlport_libs(src_dir, dst_dir, triple, abi, thumb=False):
os.path.join(dst_libdir, 'libstdc++.a'))


def copy_libcxx_libs(src_dir, dst_dir, include_libunwind):
def copy_libcxx_libs(src_dir, dst_dir, abi, api):
shutil.copy2(os.path.join(src_dir, 'libc++_shared.so'), dst_dir)
shutil.copy2(os.path.join(src_dir, 'libc++_static.a'), dst_dir)
shutil.copy2(os.path.join(src_dir, 'libandroid_support.a'), dst_dir)
if api < 21:
shutil.copy2(os.path.join(src_dir, 'libandroid_support.a'), dst_dir)
shutil.copy2(os.path.join(src_dir, 'libc++abi.a'), dst_dir)

if include_libunwind:
if abi == 'armeabi-v7a':
shutil.copy2(os.path.join(src_dir, 'libunwind.a'), dst_dir)

# libc++ is different from the other STLs. It has a libc++.(a|so) that is a
Expand Down Expand Up @@ -461,11 +462,12 @@ def create_toolchain(install_path, arch, api, gcc_path, clang_path,
elif stl == 'libc++':
libcxx_dir = os.path.join(NDK_DIR, 'sources/cxx-stl/llvm-libc++')
libcxxabi_dir = os.path.join(NDK_DIR, 'sources/cxx-stl/llvm-libc++abi')
support_dir = os.path.join(NDK_DIR, 'sources/android/support')
copy_directory_contents(os.path.join(libcxx_dir, 'include'),
cxx_headers)
copy_directory_contents(os.path.join(support_dir, 'include'),
support_headers)
if api < 21:
support_dir = os.path.join(NDK_DIR, 'sources/android/support')
copy_directory_contents(os.path.join(support_dir, 'include'),
support_headers)

# I have no idea why we need this, but the old one does it too.
copy_directory_contents(
Expand All @@ -484,11 +486,10 @@ def create_toolchain(install_path, arch, api, gcc_path, clang_path,
for abi in get_abis(arch):
src_libdir = get_src_libdir(libcxx_dir, abi)
dest_libdir = get_dest_libdir(install_path, triple, abi)
include_libunwind = arch == 'arm'
copy_libcxx_libs(src_libdir, dest_libdir, include_libunwind)
copy_libcxx_libs(src_libdir, dest_libdir, abi, api)
if arch == 'arm':
thumb_libdir = os.path.join(dest_libdir, 'thumb')
copy_libcxx_libs(src_libdir, thumb_libdir, include_libunwind)
copy_libcxx_libs(src_libdir, thumb_libdir, abi, api)
elif stl == 'stlport':
stlport_dir = os.path.join(NDK_DIR, 'sources/cxx-stl/stlport')
gabixx_dir = os.path.join(NDK_DIR, 'sources/cxx-stl/gabi++')
Expand Down
26 changes: 6 additions & 20 deletions sources/android/support/Android.mk
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
LOCAL_PATH := $(call my-dir)

android_support_export_c_includes := $(LOCAL_PATH)/include
# libandroid_support is only needed on LP32.
ifeq ($(filter $(NDK_KNOWN_DEVICE_ABI64S),$(TARGET_ARCH_ABI)),)

ifneq ($(filter $(NDK_KNOWN_DEVICE_ABI64S),$(TARGET_ARCH_ABI)),)
is_lp64 := true
else
is_lp64 :=
endif
android_support_export_c_includes := $(LOCAL_PATH)/include

ifneq ($(LIBCXX_FORCE_REBUILD),true) # Using prebuilt

Expand All @@ -27,17 +24,6 @@ android_support_cflags := \
-fdata-sections \
-fvisibility=hidden \

ifeq ($(is_lp64),true)
# 64-bit ABIs

# We don't need this file on LP32 because libc++ has its own fallbacks for these
# functions. We can't use those fallbacks for LP64 because the file contains all
# the strto*_l functions. LP64 had some of those in L, so the inlines in libc++
# collide with the out-of-line declarations in bionic.
android_support_sources := \
src/locale_support.cpp \

else
# 32-bit ABIs

BIONIC_PATH := ../../../../bionic
Expand Down Expand Up @@ -117,6 +103,7 @@ android_support_sources := \
$(BIONIC_PATH)/libm/upstream-freebsd/lib/msun/src/s_sin.c \
$(BIONIC_PATH)/libm/upstream-freebsd/lib/msun/src/s_tan.c \
$(BIONIC_PATH)/libm/upstream-freebsd/lib/msun/src/s_tanh.c \
src/locale_support.cpp \
src/posix_memalign.cpp \
src/swprintf.cpp \
src/wcstox.cpp \
Expand All @@ -133,9 +120,6 @@ android_support_sources += \
#android_support_sources += $(BIONIC_PATH)/libm/x86/lrint.S
endif

endif # 64-/32-bit ABIs

# This is only available as a static library for now.
include $(CLEAR_VARS)
LOCAL_MODULE := android_support
LOCAL_SRC_FILES := $(android_support_sources)
Expand All @@ -152,3 +136,5 @@ LOCAL_EXPORT_C_INCLUDES := $(android_support_export_c_includes)
include $(BUILD_STATIC_LIBRARY)

endif # Prebuilt/building

endif # LP32
14 changes: 10 additions & 4 deletions sources/cxx-stl/llvm-libc++/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,27 +99,33 @@ def main(args):
static_lib_dir = os.path.join(obj_out, 'local', abi)
install_dir = os.path.join(lib_out, abi)
is_arm = abi.startswith('armeabi')
needs_android_support = abi in ('armeabi-v7a', 'x86')

if is_arm:
shutil.copy2(
os.path.join(static_lib_dir, 'libunwind.a'), install_dir)

shutil.copy2(os.path.join(static_lib_dir, 'libc++abi.a'), install_dir)
shutil.copy2(
os.path.join(static_lib_dir, 'libandroid_support.a'), install_dir)
if needs_android_support:
shutil.copy2(os.path.join(
static_lib_dir, 'libandroid_support.a'), install_dir)
shutil.copy2(
os.path.join(static_lib_dir, 'libc++_static.a'), install_dir)

# Create linker scripts for the libraries we use so that we link things
# properly even when we're not using ndk-build. The linker will read
# the script in place of the library so that we link the unwinder and
# other support libraries appropriately.
static_libs = ['-lc++_static', '-lc++abi', '-landroid_support']
static_libs = ['-lc++_static', '-lc++abi']
if needs_android_support:
static_libs.append('-landroid_support')
if is_arm:
static_libs.extend(['-lunwind', '-ldl', '-latomic'])
make_linker_script(os.path.join(install_dir, 'libc++.a'), static_libs)

shared_libs = ['-landroid_support']
shared_libs = []
if needs_android_support:
shared_libs.append('-landroid_support')
if is_arm:
shared_libs.extend(['-lunwind', '-latomic'])
shared_libs.append('-lc++_shared')
Expand Down
8 changes: 4 additions & 4 deletions tests/build/link_order/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def find_link_args(link_line):
return args


def check_link_order(link_line, abi):
def check_link_order(link_line, abi, api):
"""Determines if a given link command has the correct ordering.
Args:
Expand All @@ -72,11 +72,11 @@ def check_link_order(link_line, abi):
between the expected link order and the actual link order.
"""
libunwind_arg = ['libunwind.a'] if abi == 'armeabi-v7a' else []
android_support_arg = ['libandroid_support.a'] if api < 21 else []
expected = [
'crtbegin_so.o',
'foo.o',
'libandroid_support.a',
] + libunwind_arg + [
] + android_support_arg + libunwind_arg + [
# The most important part of this test is checking that libgcc comes
# *before* the shared libraries so we can be sure we're actually
# getting libgcc symbols rather than getting them from some shared
Expand Down Expand Up @@ -129,5 +129,5 @@ def run_test(ndk_path, abi, platform, _toolchain, build_flags):
if link_line is None:
return False, 'Did not find link line in out:\n{}'.format(out)

result, diff = check_link_order(link_line, abi)
result, diff = check_link_order(link_line, abi, platform)
return result, '' if diff is None else os.linesep.join(diff)
4 changes: 4 additions & 0 deletions tests/device/android_support/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def build_unsupported(_abi, api, _toolchain):
if api >= 21:
return 'android-{}'.format(api)
return None

0 comments on commit d83e623

Please sign in to comment.