Add LunaSVG

This commit is contained in:
Isuru Samarathunga
2025-10-18 09:26:01 +05:30
parent 4597d0a4aa
commit 57bc80f4f9
187 changed files with 12435 additions and 24 deletions

View File

@ -0,0 +1,40 @@
set(NDK_DEFAULT_ABIS "arm64-v8a;armeabi-v7a;x86;x86_64")
set(NDK_DEPRECATED_ABIS "")
set(NDK_KNOWN_DEVICE_ABI32S "armeabi-v7a;x86")
set(NDK_KNOWN_DEVICE_ABI64S "arm64-v8a;riscv64;x86_64")
set(NDK_KNOWN_DEVICE_ABIS "arm64-v8a;armeabi-v7a;riscv64;x86;x86_64")
set(NDK_ABI_armeabi-v7a_PROC "armv7-a")
set(NDK_ABI_armeabi-v7a_ARCH "arm")
set(NDK_ABI_armeabi-v7a_TRIPLE "arm-linux-androideabi")
set(NDK_ABI_armeabi-v7a_LLVM_TRIPLE "armv7-none-linux-androideabi")
set(NDK_ABI_armeabi-v7a_MIN_OS_VERSION "21")
set(NDK_PROC_armv7-a_ABI "armeabi-v7a")
set(NDK_ARCH_arm_ABI "armeabi-v7a")
set(NDK_ABI_arm64-v8a_PROC "aarch64")
set(NDK_ABI_arm64-v8a_ARCH "arm64")
set(NDK_ABI_arm64-v8a_TRIPLE "aarch64-linux-android")
set(NDK_ABI_arm64-v8a_LLVM_TRIPLE "aarch64-none-linux-android")
set(NDK_ABI_arm64-v8a_MIN_OS_VERSION "21")
set(NDK_PROC_aarch64_ABI "arm64-v8a")
set(NDK_ARCH_arm64_ABI "arm64-v8a")
set(NDK_ABI_riscv64_PROC "riscv64")
set(NDK_ABI_riscv64_ARCH "riscv64")
set(NDK_ABI_riscv64_TRIPLE "riscv64-linux-android")
set(NDK_ABI_riscv64_LLVM_TRIPLE "riscv64-none-linux-android")
set(NDK_ABI_riscv64_MIN_OS_VERSION "35")
set(NDK_PROC_riscv64_ABI "riscv64")
set(NDK_ARCH_riscv64_ABI "riscv64")
set(NDK_ABI_x86_PROC "i686")
set(NDK_ABI_x86_ARCH "x86")
set(NDK_ABI_x86_TRIPLE "i686-linux-android")
set(NDK_ABI_x86_LLVM_TRIPLE "i686-none-linux-android")
set(NDK_ABI_x86_MIN_OS_VERSION "21")
set(NDK_PROC_i686_ABI "x86")
set(NDK_ARCH_x86_ABI "x86")
set(NDK_ABI_x86_64_PROC "x86_64")
set(NDK_ABI_x86_64_ARCH "x86_64")
set(NDK_ABI_x86_64_TRIPLE "x86_64-linux-android")
set(NDK_ABI_x86_64_LLVM_TRIPLE "x86_64-none-linux-android")
set(NDK_ABI_x86_64_MIN_OS_VERSION "21")
set(NDK_PROC_x86_64_ABI "x86_64")
set(NDK_ARCH_x86_64_ABI "x86_64")

View File

@ -0,0 +1,64 @@
include(${CMAKE_ANDROID_NDK}/build/cmake/abis.cmake)
include(${CMAKE_ANDROID_NDK}/build/cmake/platforms.cmake)
function(adjust_api_level api_level result_name)
# If no platform version was chosen by the user, default to the minimum
# version supported by this NDK.
if(NOT api_level)
message(STATUS
"ANDROID_PLATFORM not set. Defaulting to minimum supported version "
"${NDK_MIN_PLATFORM_LEVEL}.")
set(api_level "android-${NDK_MIN_PLATFORM_LEVEL}")
endif()
if(api_level STREQUAL "latest")
message(STATUS
"Using latest available ANDROID_PLATFORM: ${NDK_MAX_PLATFORM_LEVEL}.")
set(api_level "android-${NDK_MAX_PLATFORM_LEVEL}")
endif()
string(REPLACE "android-" "" result ${api_level})
# Aliases defined by meta/platforms.json include codename aliases for platform
# API levels as well as cover any gaps in platforms that may not have had NDK
# APIs.
if(NOT "${NDK_PLATFORM_ALIAS_${result}}" STREQUAL "")
message(STATUS
"${api_level} is an alias for ${NDK_PLATFORM_ALIAS_${result}}. Adjusting "
"ANDROID_PLATFORM to match.")
set(api_level "${NDK_PLATFORM_ALIAS_${result}}")
string(REPLACE "android-" "" result ${api_level})
endif()
# Pull up to the minimum supported version if an old API level was requested.
if(result LESS NDK_MIN_PLATFORM_LEVEL)
message(STATUS
"${api_level} is unsupported. Using minimum supported version "
"${NDK_MIN_PLATFORM_LEVEL}.")
set(api_level "android-${NDK_MIN_PLATFORM_LEVEL}")
string(REPLACE "android-" "" result ${api_level})
endif()
# Pull up any ABI-specific minimum API levels.
set(min_for_abi ${NDK_ABI_${ANDROID_ABI}_MIN_OS_VERSION})
if(result LESS min_for_abi)
message(STATUS
"android-${result} is not supported for ${ANDROID_ABI}. Using minimum "
"supported ${ANDROID_ABI} version ${min_for_abi}.")
set(api_level android-${min_for_abi})
set(result ${min_for_abi})
endif()
# ANDROID_PLATFORM beyond the maximum is an error. The correct way to specify
# the latest version is ANDROID_PLATFORM=latest.
if(result GREATER NDK_MAX_PLATFORM_LEVEL)
message(SEND_ERROR
"${api_level} is above the maximum supported version "
"${NDK_MAX_PLATFORM_LEVEL}. Choose a supported API level or set "
"ANDROID_PLATFORM to \"latest\".")
endif()
set(${result_name} ${result} PARENT_SCOPE)
endfunction()

View File

@ -0,0 +1,752 @@
# Copyright (C) 2016 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.
# Configurable variables.
# Modeled after the ndk-build system.
# For any variables defined in:
# https://developer.android.com/ndk/guides/android_mk.html
# https://developer.android.com/ndk/guides/application_mk.html
# if it makes sense for CMake, then replace LOCAL, APP, or NDK with ANDROID, and
# we have that variable below.
#
# ANDROID_TOOLCHAIN
# ANDROID_ABI
# ANDROID_PLATFORM
# ANDROID_STL
# ANDROID_PIE
# ANDROID_CPP_FEATURES
# ANDROID_ALLOW_UNDEFINED_SYMBOLS
# ANDROID_ARM_MODE
# ANDROID_DISABLE_FORMAT_STRING_CHECKS
# ANDROID_CCACHE
# ANDROID_SANITIZE
cmake_minimum_required(VERSION 3.12.0)
# Inhibit all of CMake's own NDK handling code.
set(CMAKE_SYSTEM_VERSION 1)
# Android NDK
get_filename_component(ANDROID_NDK_EXPECTED_PATH
"${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
if(NOT ANDROID_NDK)
set(ANDROID_NDK "${ANDROID_NDK_EXPECTED_PATH}")
else()
# Allow the user to specify their own NDK path, but emit a warning. This is an
# uncommon use case, but helpful if users want to use a bleeding edge
# toolchain file with a stable NDK.
# https://github.com/android-ndk/ndk/issues/473
get_filename_component(ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE)
if(NOT "${ANDROID_NDK}" STREQUAL "${ANDROID_NDK_EXPECTED_PATH}")
message(WARNING "Using custom NDK path (ANDROID_NDK is set): ${ANDROID_NDK}")
endif()
endif()
unset(ANDROID_NDK_EXPECTED_PATH)
file(TO_CMAKE_PATH "${ANDROID_NDK}" ANDROID_NDK)
# Android NDK revision
# Possible formats:
# * r16, build 1234: 16.0.1234
# * r16b, build 1234: 16.1.1234
# * r16 beta 1, build 1234: 16.0.1234-beta1
#
# Canary builds are not specially marked.
file(READ "${ANDROID_NDK}/source.properties" ANDROID_NDK_SOURCE_PROPERTIES)
set(ANDROID_NDK_REVISION_REGEX
"^Pkg\\.Desc = Android NDK\nPkg\\.Revision = ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-beta([0-9]+))?")
if(NOT ANDROID_NDK_SOURCE_PROPERTIES MATCHES "${ANDROID_NDK_REVISION_REGEX}")
message(SEND_ERROR "Failed to parse Android NDK revision: ${ANDROID_NDK}/source.properties.\n${ANDROID_NDK_SOURCE_PROPERTIES}")
endif()
set(ANDROID_NDK_MAJOR "${CMAKE_MATCH_1}")
set(ANDROID_NDK_MINOR "${CMAKE_MATCH_2}")
set(ANDROID_NDK_BUILD "${CMAKE_MATCH_3}")
set(ANDROID_NDK_BETA "${CMAKE_MATCH_5}")
if(ANDROID_NDK_BETA STREQUAL "")
set(ANDROID_NDK_BETA "0")
endif()
set(ANDROID_NDK_REVISION
"${ANDROID_NDK_MAJOR}.${ANDROID_NDK_MINOR}.${ANDROID_NDK_BUILD}${CMAKE_MATCH_4}")
# Touch toolchain variable to suppress "unused variable" warning.
# This happens if CMake is invoked with the same command line the second time.
if(CMAKE_TOOLCHAIN_FILE)
endif()
# Compatibility for configurable variables.
# Compatible with configurable variables from the other toolchain file:
# https://github.com/taka-no-me/android-cmake
# TODO: We should consider dropping compatibility to simplify things once most
# of our users have migrated to our standard set of configurable variables.
if(ANDROID_TOOLCHAIN_NAME AND NOT ANDROID_TOOLCHAIN)
if(ANDROID_TOOLCHAIN_NAME MATCHES "-clang([0-9].[0-9])?$")
set(ANDROID_TOOLCHAIN clang)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "-[0-9].[0-9]$")
set(ANDROID_TOOLCHAIN gcc)
endif()
endif()
if(ANDROID_ABI STREQUAL "armeabi-v7a with NEON")
set(ANDROID_ABI armeabi-v7a)
elseif(ANDROID_TOOLCHAIN_NAME AND NOT ANDROID_ABI)
if(ANDROID_TOOLCHAIN_NAME MATCHES "^arm-linux-androideabi-")
set(ANDROID_ABI armeabi-v7a)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^aarch64-linux-android-")
set(ANDROID_ABI arm64-v8a)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^x86-")
set(ANDROID_ABI x86)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^x86_64-")
set(ANDROID_ABI x86_64)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^mipsel-linux-android-")
set(ANDROID_ABI mips)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^mips64el-linux-android-")
set(ANDROID_ABI mips64)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^riscv64-")
set(ANDROID_ABI riscv64)
endif()
endif()
if(ANDROID_NATIVE_API_LEVEL AND NOT ANDROID_PLATFORM)
if(ANDROID_NATIVE_API_LEVEL MATCHES "^android-[0-9]+$")
set(ANDROID_PLATFORM ${ANDROID_NATIVE_API_LEVEL})
elseif(ANDROID_NATIVE_API_LEVEL MATCHES "^[0-9]+$")
set(ANDROID_PLATFORM android-${ANDROID_NATIVE_API_LEVEL})
endif()
endif()
if(DEFINED ANDROID_APP_PIE AND NOT DEFINED ANDROID_PIE)
set(ANDROID_PIE "${ANDROID_APP_PIE}")
endif()
if(ANDROID_STL_FORCE_FEATURES AND NOT DEFINED ANDROID_CPP_FEATURES)
set(ANDROID_CPP_FEATURES "rtti exceptions")
endif()
if(DEFINED ANDROID_NO_UNDEFINED AND NOT DEFINED ANDROID_ALLOW_UNDEFINED_SYMBOLS)
if(ANDROID_NO_UNDEFINED)
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS FALSE)
else()
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS TRUE)
endif()
endif()
if(DEFINED ANDROID_SO_UNDEFINED AND NOT DEFINED ANDROID_ALLOW_UNDEFINED_SYMBOLS)
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS "${ANDROID_SO_UNDEFINED}")
endif()
if(DEFINED ANDROID_FORCE_ARM_BUILD AND NOT ANDROID_ARM_MODE)
if(ANDROID_FORCE_ARM_BUILD)
set(ANDROID_ARM_MODE arm)
else()
set(ANDROID_ARM_MODE thumb)
endif()
endif()
if(NDK_CCACHE AND NOT ANDROID_CCACHE)
set(ANDROID_CCACHE "${NDK_CCACHE}")
endif()
# Default values for configurable variables.
if(NOT ANDROID_TOOLCHAIN)
set(ANDROID_TOOLCHAIN clang)
elseif(ANDROID_TOOLCHAIN STREQUAL gcc)
message(FATAL_ERROR "GCC is no longer supported. See "
"https://android.googlesource.com/platform/ndk/+/master/docs/ClangMigration.md.")
endif()
if(NOT ANDROID_ABI)
set(ANDROID_ABI armeabi-v7a)
endif()
if(ANDROID_ABI STREQUAL armeabi)
message(FATAL_ERROR "armeabi is no longer supported. Use armeabi-v7a.")
elseif(ANDROID_ABI MATCHES "^(mips|mips64)$")
message(FATAL_ERROR "MIPS and MIPS64 are no longer supported.")
endif()
if(DEFINED ANDROID_ARM_NEON AND NOT ANDROID_ARM_NEON)
message(FATAL_ERROR "Disabling Neon is no longer supported")
endif()
if(ANDROID_ABI STREQUAL armeabi-v7a)
set(ANDROID_ARM_NEON TRUE)
endif()
include(${ANDROID_NDK}/build/cmake/abis.cmake)
include(${ANDROID_NDK}/build/cmake/platforms.cmake)
# If no platform version was chosen by the user, default to the minimum version
# supported by this NDK.
if(NOT ANDROID_PLATFORM)
message(STATUS "\
ANDROID_PLATFORM not set. Defaulting to minimum supported version
${NDK_MIN_PLATFORM_LEVEL}.")
set(ANDROID_PLATFORM "android-${NDK_MIN_PLATFORM_LEVEL}")
endif()
if(ANDROID_PLATFORM STREQUAL "latest")
message(STATUS
"Using latest available ANDROID_PLATFORM: ${NDK_MAX_PLATFORM_LEVEL}.")
set(ANDROID_PLATFORM "android-${NDK_MAX_PLATFORM_LEVEL}")
string(REPLACE "android-" "" ANDROID_PLATFORM_LEVEL ${ANDROID_PLATFORM})
endif()
string(REPLACE "android-" "" ANDROID_PLATFORM_LEVEL ${ANDROID_PLATFORM})
# Aliases defined by meta/platforms.json include codename aliases for platform
# API levels as well as cover any gaps in platforms that may not have had NDK
# APIs.
if(NOT "${NDK_PLATFORM_ALIAS_${ANDROID_PLATFORM_LEVEL}}" STREQUAL "")
message(STATUS "\
${ANDROID_PLATFORM} is an alias for \
${NDK_PLATFORM_ALIAS_${ANDROID_PLATFORM_LEVEL}}. Adjusting ANDROID_PLATFORM to \
match.")
set(ANDROID_PLATFORM "${NDK_PLATFORM_ALIAS_${ANDROID_PLATFORM_LEVEL}}")
string(REPLACE "android-" "" ANDROID_PLATFORM_LEVEL ${ANDROID_PLATFORM})
endif()
# Pull up to the minimum supported version if an old API level was requested.
if(ANDROID_PLATFORM_LEVEL LESS NDK_MIN_PLATFORM_LEVEL)
message(STATUS "\
${ANDROID_PLATFORM} is unsupported. Using minimum supported version \
${NDK_MIN_PLATFORM_LEVEL}.")
set(ANDROID_PLATFORM "android-${NDK_MIN_PLATFORM_LEVEL}")
string(REPLACE "android-" "" ANDROID_PLATFORM_LEVEL ${ANDROID_PLATFORM})
endif()
# Pull up any ABI-specific minimum API levels.
set(min_for_abi ${NDK_ABI_${ANDROID_ABI}_MIN_OS_VERSION})
if(ANDROID_PLATFORM_LEVEL LESS min_for_abi)
message(STATUS
"${ANDROID_PLATFORM} is not supported for ${ANDROID_ABI}. Using minimum "
"supported ${ANDROID_ABI} version ${min_for_abi}.")
set(ANDROID_PLATFORM android-${min_for_abi})
set(ANDROID_PLATFORM_LEVEL ${min_for_abi})
endif()
# ANDROID_PLATFORM beyond the maximum is an error. The correct way to specify
# the latest version is ANDROID_PLATFORM=latest.
if(ANDROID_PLATFORM_LEVEL GREATER NDK_MAX_PLATFORM_LEVEL)
message(SEND_ERROR "\
${ANDROID_PLATFORM} is above the maximum supported version \
${NDK_MAX_PLATFORM_LEVEL}. Choose a supported API level or set \
ANDROID_PLATFORM to \"latest\".")
endif()
if(NOT ANDROID_STL)
set(ANDROID_STL c++_static)
endif()
if("${ANDROID_STL}" STREQUAL "gnustl_shared" OR
"${ANDROID_STL}" STREQUAL "gnustl_static" OR
"${ANDROID_STL}" STREQUAL "stlport_shared" OR
"${ANDROID_STL}" STREQUAL "stlport_static")
message(FATAL_ERROR "\
${ANDROID_STL} is no longer supported. Please switch to either c++_shared or \
c++_static. See https://developer.android.com/ndk/guides/cpp-support.html \
for more information.")
endif()
if("hwaddress" IN_LIST ANDROID_SANITIZE AND "${CMAKE_ANDROID_STL_TYPE}" STREQUAL "c++_static")
message(FATAL_ERROR "\
hwaddress does not support c++_static. Use system or c++_shared.")
endif()
set(ANDROID_PIE TRUE)
if(NOT ANDROID_ARM_MODE)
set(ANDROID_ARM_MODE thumb)
endif()
# Export configurable variables for the try_compile() command.
set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
ANDROID_ABI
ANDROID_ALLOW_UNDEFINED_SYMBOLS
ANDROID_ARM_MODE
ANDROID_ARM_NEON
ANDROID_CCACHE
ANDROID_CPP_FEATURES
ANDROID_DISABLE_FORMAT_STRING_CHECKS
ANDROID_PIE
ANDROID_PLATFORM
ANDROID_STL
ANDROID_TOOLCHAIN
ANDROID_USE_LEGACY_TOOLCHAIN_FILE
)
# Standard cross-compiling stuff.
set(ANDROID TRUE)
set(CMAKE_SYSTEM_NAME Android)
# https://github.com/android-ndk/ndk/issues/890
#
# ONLY doesn't do anything when CMAKE_FIND_ROOT_PATH is empty. Without this,
# CMake will wrongly search host sysroots for headers/libraries. The actual path
# used here is fairly meaningless since CMake doesn't handle the NDK sysroot
# layout (per-arch and per-verion subdirectories for libraries), so find_library
# is handled separately by CMAKE_SYSTEM_LIBRARY_PATH.
list(APPEND CMAKE_FIND_ROOT_PATH "${ANDROID_NDK}")
# Allow users to override these values in case they want more strict behaviors.
# For example, they may want to prevent the NDK's libz from being picked up so
# they can use their own.
# https://github.com/android-ndk/ndk/issues/517
if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
endif()
if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
endif()
if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
endif()
# ABI.
set(CMAKE_ANDROID_ARCH_ABI ${ANDROID_ABI})
if(ANDROID_ABI STREQUAL armeabi-v7a)
set(ANDROID_SYSROOT_ABI arm)
set(ANDROID_TOOLCHAIN_NAME arm-linux-androideabi)
set(CMAKE_SYSTEM_PROCESSOR armv7-a)
set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)
elseif(ANDROID_ABI STREQUAL arm64-v8a)
set(ANDROID_SYSROOT_ABI arm64)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(ANDROID_TOOLCHAIN_NAME aarch64-linux-android)
set(ANDROID_LLVM_TRIPLE aarch64-none-linux-android)
elseif(ANDROID_ABI STREQUAL x86)
set(ANDROID_SYSROOT_ABI x86)
set(CMAKE_SYSTEM_PROCESSOR i686)
set(ANDROID_TOOLCHAIN_NAME i686-linux-android)
set(ANDROID_LLVM_TRIPLE i686-none-linux-android)
elseif(ANDROID_ABI STREQUAL x86_64)
set(ANDROID_SYSROOT_ABI x86_64)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(ANDROID_TOOLCHAIN_NAME x86_64-linux-android)
set(ANDROID_LLVM_TRIPLE x86_64-none-linux-android)
elseif(ANDROID_ABI STREQUAL riscv64)
set(ANDROID_SYSROOT_ABI riscv64)
set(CMAKE_SYSTEM_PROCESSOR riscv64)
set(ANDROID_TOOLCHAIN_NAME riscv64-linux-android)
set(ANDROID_LLVM_TRIPLE riscv64-none-linux-android)
else()
message(FATAL_ERROR "Invalid Android ABI: ${ANDROID_ABI}.")
endif()
set(ANDROID_LLVM_TRIPLE "${ANDROID_LLVM_TRIPLE}${ANDROID_PLATFORM_LEVEL}")
set(ANDROID_COMPILER_FLAGS)
set(ANDROID_COMPILER_FLAGS_CXX)
set(ANDROID_COMPILER_FLAGS_DEBUG)
set(ANDROID_COMPILER_FLAGS_RELEASE)
set(ANDROID_LINKER_FLAGS)
set(ANDROID_LINKER_FLAGS_EXE)
set(ANDROID_LINKER_FLAGS_RELEASE)
set(ANDROID_LINKER_FLAGS_RELWITHDEBINFO)
set(ANDROID_LINKER_FLAGS_MINSIZEREL)
# STL.
set(ANDROID_CXX_STANDARD_LIBRARIES)
if(ANDROID_STL STREQUAL system)
list(APPEND ANDROID_COMPILER_FLAGS_CXX "-stdlib=libstdc++")
if(NOT "x${ANDROID_CPP_FEATURES}" STREQUAL "x")
list(APPEND ANDROID_CXX_STANDARD_LIBRARIES "-lc++abi")
endif()
elseif(ANDROID_STL STREQUAL c++_static)
list(APPEND ANDROID_LINKER_FLAGS "-static-libstdc++")
elseif(ANDROID_STL STREQUAL c++_shared)
elseif(ANDROID_STL STREQUAL none)
list(APPEND ANDROID_COMPILER_FLAGS_CXX "-nostdinc++")
list(APPEND ANDROID_LINKER_FLAGS "-nostdlib++")
else()
message(FATAL_ERROR "Invalid STL: ${ANDROID_STL}.")
endif()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
set(ANDROID_HOST_TAG linux-x86_64)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
set(ANDROID_HOST_TAG darwin-x86_64)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(ANDROID_HOST_TAG windows-x86_64)
endif()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(ANDROID_TOOLCHAIN_SUFFIX .exe)
endif()
# Toolchain.
set(ANDROID_TOOLCHAIN_ROOT
"${ANDROID_NDK}/toolchains/llvm/prebuilt/${ANDROID_HOST_TAG}")
list(APPEND CMAKE_PREFIX_PATH "${ANDROID_TOOLCHAIN_ROOT}")
# NB: This variable causes CMake to automatically pass --sysroot to the
# toolchain. Studio currently relies on this to recognize Android builds. If
# this variable is removed, ensure that flag is still passed.
# TODO: Teach Studio to recognize Android builds based on --target.
set(CMAKE_SYSROOT "${ANDROID_TOOLCHAIN_ROOT}/sysroot")
# Allows CMake to find headers in the architecture-specific include directories.
set(CMAKE_LIBRARY_ARCHITECTURE "${ANDROID_TOOLCHAIN_NAME}")
# In addition to <root>/<prefix>/lib/<arch>, cmake also searches <root>/<prefix>.
# Adding the API specific path to the beginning of CMAKE_SYSTEM_PREFIX_PATH, to
# make sure it is searched first.
set(CMAKE_SYSTEM_PREFIX_PATH
"/usr/lib/${ANDROID_TOOLCHAIN_NAME}/${ANDROID_PLATFORM_LEVEL}"
"${CMAKE_SYSTEM_PREFIX_PATH}"
)
set(ANDROID_HOST_PREBUILTS "${ANDROID_NDK}/prebuilt/${ANDROID_HOST_TAG}")
set(ANDROID_C_COMPILER
"${ANDROID_TOOLCHAIN_ROOT}/bin/clang${ANDROID_TOOLCHAIN_SUFFIX}")
set(ANDROID_CXX_COMPILER
"${ANDROID_TOOLCHAIN_ROOT}/bin/clang++${ANDROID_TOOLCHAIN_SUFFIX}")
set(ANDROID_ASM_COMPILER
"${ANDROID_TOOLCHAIN_ROOT}/bin/clang${ANDROID_TOOLCHAIN_SUFFIX}")
set(CMAKE_C_COMPILER_TARGET ${ANDROID_LLVM_TRIPLE})
set(CMAKE_CXX_COMPILER_TARGET ${ANDROID_LLVM_TRIPLE})
set(CMAKE_ASM_COMPILER_TARGET ${ANDROID_LLVM_TRIPLE})
set(ANDROID_AR
"${ANDROID_TOOLCHAIN_ROOT}/bin/llvm-ar${ANDROID_TOOLCHAIN_SUFFIX}")
set(ANDROID_RANLIB
"${ANDROID_TOOLCHAIN_ROOT}/bin/llvm-ranlib${ANDROID_TOOLCHAIN_SUFFIX}")
set(ANDROID_STRIP
"${ANDROID_TOOLCHAIN_ROOT}/bin/llvm-strip${ANDROID_TOOLCHAIN_SUFFIX}")
if(${CMAKE_VERSION} VERSION_LESS "3.19")
# Older CMake won't pass -target when running the compiler identification
# test, which causes the test to fail on flags like -mthumb.
# https://github.com/android/ndk/issues/1427
message(WARNING "An old version of CMake is being used that cannot "
"automatically detect compiler attributes. Compiler identification is "
"being bypassed. Some values may be wrong or missing. Update to CMake "
"3.19 or newer to use CMake's built-in compiler identification.")
set(CMAKE_C_COMPILER_ID_RUN TRUE)
set(CMAKE_CXX_COMPILER_ID_RUN TRUE)
set(CMAKE_C_COMPILER_ID Clang)
set(CMAKE_CXX_COMPILER_ID Clang)
# No need to auto-detect the computed standard defaults because CMake 3.6
# doesn't know about anything past C11 or C++14 (neither does 3.10, so no
# need to worry about 3.7-3.9), and any higher standards that Clang might
# use are clamped to those values.
set(CMAKE_C_STANDARD_COMPUTED_DEFAULT 11)
set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT 14)
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU")
include(${ANDROID_NDK}/build/cmake/compiler_id.cmake)
endif()
# Generic flags.
list(APPEND ANDROID_COMPILER_FLAGS
-g
-DANDROID
-fdata-sections
-ffunction-sections
-funwind-tables
-fstack-protector-strong
-no-canonical-prefixes)
if(ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES)
list(APPEND ANDROID_COMPILER_FLAGS -D__BIONIC_NO_PAGE_SIZE_MACRO)
if(ANDROID_ABI STREQUAL arm64-v8a OR ANDROID_ABI STREQUAL x86_64)
list(APPEND ANDROID_LINKER_FLAGS -Wl,-z,max-page-size=16384)
endif()
endif()
if(ANDROID_WEAK_API_DEFS)
list(APPEND ANDROID_COMPILER_FLAGS
-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-Werror=unguarded-availability)
endif()
if("hwaddress" IN_LIST ANDROID_SANITIZE)
list(APPEND ANDROID_COMPILER_FLAGS -fsanitize=hwaddress -fno-omit-frame-pointer)
list(APPEND ANDROID_LINKER_FLAGS -fsanitize=hwaddress)
endif()
if("memtag" IN_LIST ANDROID_SANITIZE)
list(APPEND ANDROID_COMPILER_FLAGS -fsanitize=memtag-stack -fno-omit-frame-pointer)
list(APPEND ANDROID_LINKER_FLAGS -fsanitize=memtag-stack,memtag-heap -fsanitize-memtag-mode=sync)
if(ANDROID_ABI STREQUAL arm64-v8a)
list(APPEND ANDROID_COMPILER_FLAGS -march=armv8-a+memtag)
list(APPEND ANDROID_LINKER_FLAGS -march=armv8-a+memtag)
endif()
endif()
# https://github.com/android/ndk/issues/885
# If we're using LLD we need to use a slower build-id algorithm to work around
# the old version of LLDB in Android Studio, which doesn't understand LLD's
# default hash ("fast").
list(APPEND ANDROID_LINKER_FLAGS -Wl,--build-id=sha1)
if(ANDROID_PLATFORM_LEVEL LESS 30)
# https://github.com/android/ndk/issues/1196
# https://github.com/android/ndk/issues/1589
list(APPEND ANDROID_LINKER_FLAGS -Wl,--no-rosegment)
endif()
if (NOT ANDROID_ALLOW_UNDEFINED_VERSION_SCRIPT_SYMBOLS)
list(APPEND ANDROID_LINKER_FLAGS -Wl,--no-undefined-version)
endif()
list(APPEND ANDROID_LINKER_FLAGS -Wl,--fatal-warnings)
# --gc-sections should not be present for debug builds because that can strip
# functions that the user may want to evaluate while debugging.
list(APPEND ANDROID_LINKER_FLAGS_RELEASE -Wl,--gc-sections)
list(APPEND ANDROID_LINKER_FLAGS_RELWITHDEBINFO -Wl,--gc-sections)
list(APPEND ANDROID_LINKER_FLAGS_MINSIZEREL -Wl,--gc-sections)
# Debug and release flags.
list(APPEND ANDROID_COMPILER_FLAGS_RELEASE -O3)
list(APPEND ANDROID_COMPILER_FLAGS_RELEASE -DNDEBUG)
if(ANDROID_TOOLCHAIN STREQUAL clang)
list(APPEND ANDROID_COMPILER_FLAGS_DEBUG -fno-limit-debug-info)
endif()
# Toolchain and ABI specific flags.
if(ANDROID_ABI STREQUAL x86 AND ANDROID_PLATFORM_LEVEL LESS 24)
# http://b.android.com/222239
# http://b.android.com/220159 (internal http://b/31809417)
# x86 devices have stack alignment issues.
list(APPEND ANDROID_COMPILER_FLAGS -mstackrealign)
endif()
list(APPEND ANDROID_COMPILER_FLAGS -D_FORTIFY_SOURCE=2)
set(CMAKE_C_STANDARD_LIBRARIES_INIT "-latomic -lm")
set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
if(ANDROID_CXX_STANDARD_LIBRARIES)
string(REPLACE ";" "\" \"" ANDROID_CXX_STANDARD_LIBRARIES "\"${ANDROID_CXX_STANDARD_LIBRARIES}\"")
set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_CXX_STANDARD_LIBRARIES_INIT} ${ANDROID_CXX_STANDARD_LIBRARIES}")
endif()
# Configuration specific flags.
# PIE is supported on all currently supported Android releases, but it is not
# supported with static executables, so we still provide ANDROID_PIE as an
# escape hatch for those.
if(ANDROID_PIE)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif()
if(ANDROID_CPP_FEATURES)
separate_arguments(ANDROID_CPP_FEATURES)
foreach(feature ${ANDROID_CPP_FEATURES})
if(NOT ${feature} MATCHES "^(rtti|exceptions|no-rtti|no-exceptions)$")
message(FATAL_ERROR "Invalid Android C++ feature: ${feature}.")
endif()
list(APPEND ANDROID_COMPILER_FLAGS_CXX
-f${feature})
endforeach()
string(REPLACE ";" " " ANDROID_CPP_FEATURES "${ANDROID_CPP_FEATURES}")
endif()
if(NOT ANDROID_ALLOW_UNDEFINED_SYMBOLS)
list(APPEND ANDROID_LINKER_FLAGS
-Wl,--no-undefined)
endif()
if(ANDROID_ABI MATCHES "armeabi")
# Clang does not set this up properly when using -fno-integrated-as.
# https://github.com/android-ndk/ndk/issues/906
list(APPEND ANDROID_COMPILER_FLAGS "-march=armv7-a")
if(ANDROID_ARM_MODE STREQUAL thumb)
list(APPEND ANDROID_COMPILER_FLAGS -mthumb)
elseif(ANDROID_ARM_MODE STREQUAL arm)
# Default behavior.
else()
message(FATAL_ERROR "Invalid Android ARM mode: ${ANDROID_ARM_MODE}.")
endif()
endif()
# CMake automatically forwards all compiler flags to the linker, and clang
# doesn't like having -Wa flags being used for linking. To prevent CMake from
# doing this would require meddling with the CMAKE_<LANG>_COMPILE_OBJECT rules,
# which would get quite messy.
list(APPEND ANDROID_LINKER_FLAGS -Qunused-arguments)
if(ANDROID_DISABLE_FORMAT_STRING_CHECKS)
list(APPEND ANDROID_COMPILER_FLAGS
-Wno-error=format-security)
else()
list(APPEND ANDROID_COMPILER_FLAGS
-Wformat -Werror=format-security)
endif()
# Convert these lists into strings.
string(REPLACE ";" " " ANDROID_COMPILER_FLAGS "${ANDROID_COMPILER_FLAGS}")
string(REPLACE ";" " " ANDROID_COMPILER_FLAGS_CXX "${ANDROID_COMPILER_FLAGS_CXX}")
string(REPLACE ";" " " ANDROID_COMPILER_FLAGS_DEBUG "${ANDROID_COMPILER_FLAGS_DEBUG}")
string(REPLACE ";" " " ANDROID_COMPILER_FLAGS_RELEASE "${ANDROID_COMPILER_FLAGS_RELEASE}")
string(REPLACE ";" " " ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}")
string(REPLACE ";" " " ANDROID_LINKER_FLAGS_EXE "${ANDROID_LINKER_FLAGS_EXE}")
string(REPLACE ";" " " ANDROID_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE}")
string(REPLACE ";" " " ANDROID_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO}")
string(REPLACE ";" " " ANDROID_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL}")
if(ANDROID_CCACHE)
set(CMAKE_C_COMPILER_LAUNCHER "${ANDROID_CCACHE}")
set(CMAKE_CXX_COMPILER_LAUNCHER "${ANDROID_CCACHE}")
endif()
set(CMAKE_C_COMPILER "${ANDROID_C_COMPILER}")
set(CMAKE_CXX_COMPILER "${ANDROID_CXX_COMPILER}")
set(CMAKE_AR "${ANDROID_AR}" CACHE FILEPATH "Archiver")
set(CMAKE_RANLIB "${ANDROID_RANLIB}" CACHE FILEPATH "Ranlib")
set(CMAKE_STRIP "${ANDROID_STRIP}" CACHE FILEPATH "Strip")
if(ANDROID_ABI STREQUAL "x86" OR ANDROID_ABI STREQUAL "x86_64")
set(CMAKE_ASM_NASM_COMPILER
"${ANDROID_TOOLCHAIN_ROOT}/bin/yasm${ANDROID_TOOLCHAIN_SUFFIX}")
set(CMAKE_ASM_NASM_COMPILER_ARG1 "-DELF")
endif()
# Set or retrieve the cached flags.
# This is necessary in case the user sets/changes flags in subsequent
# configures. If we included the Android flags in here, they would get
# overwritten.
set(CMAKE_C_FLAGS ""
CACHE STRING "Flags used by the compiler during all build types.")
set(CMAKE_CXX_FLAGS ""
CACHE STRING "Flags used by the compiler during all build types.")
set(CMAKE_ASM_FLAGS ""
CACHE STRING "Flags used by the compiler during all build types.")
set(CMAKE_C_FLAGS_DEBUG ""
CACHE STRING "Flags used by the compiler during debug builds.")
set(CMAKE_CXX_FLAGS_DEBUG ""
CACHE STRING "Flags used by the compiler during debug builds.")
set(CMAKE_ASM_FLAGS_DEBUG ""
CACHE STRING "Flags used by the compiler during debug builds.")
set(CMAKE_C_FLAGS_RELEASE ""
CACHE STRING "Flags used by the compiler during release builds.")
set(CMAKE_CXX_FLAGS_RELEASE ""
CACHE STRING "Flags used by the compiler during release builds.")
set(CMAKE_ASM_FLAGS_RELEASE ""
CACHE STRING "Flags used by the compiler during release builds.")
set(CMAKE_MODULE_LINKER_FLAGS ""
CACHE STRING "Flags used by the linker during the creation of modules.")
set(CMAKE_SHARED_LINKER_FLAGS ""
CACHE STRING "Flags used by the linker during the creation of dll's.")
set(CMAKE_EXE_LINKER_FLAGS ""
CACHE STRING "Flags used by the linker.")
set(CMAKE_C_FLAGS "${ANDROID_COMPILER_FLAGS} ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${ANDROID_COMPILER_FLAGS} ${ANDROID_COMPILER_FLAGS_CXX} ${CMAKE_CXX_FLAGS}")
set(CMAKE_ASM_FLAGS "${ANDROID_COMPILER_FLAGS} ${CMAKE_ASM_FLAGS}")
set(CMAKE_C_FLAGS_DEBUG "${ANDROID_COMPILER_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}")
set(CMAKE_CXX_FLAGS_DEBUG "${ANDROID_COMPILER_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}")
set(CMAKE_ASM_FLAGS_DEBUG "${ANDROID_COMPILER_FLAGS_DEBUG} ${CMAKE_ASM_FLAGS_DEBUG}")
set(CMAKE_C_FLAGS_RELEASE "${ANDROID_COMPILER_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_RELEASE "${ANDROID_COMPILER_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_ASM_FLAGS_RELEASE "${ANDROID_COMPILER_FLAGS_RELEASE} ${CMAKE_ASM_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${ANDROID_LINKER_FLAGS_EXE} ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE} ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE} ${CMAKE_MODULE_LINKER_FLAGS_RELEASE}")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE} ${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO} ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO} ${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO} ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL} ${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL}")
set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL} ${CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL}")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL} ${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}")
# Compatibility for read-only variables.
# Read-only variables for compatibility with the other toolchain file.
# We'll keep these around for the existing projects that still use them.
# TODO: All of the variables here have equivalents in our standard set of
# configurable variables, so we can remove these once most of our users migrate
# to those variables.
set(ANDROID_NATIVE_API_LEVEL ${ANDROID_PLATFORM_LEVEL})
if(ANDROID_ALLOW_UNDEFINED_SYMBOLS)
set(ANDROID_SO_UNDEFINED TRUE)
else()
set(ANDROID_NO_UNDEFINED TRUE)
endif()
set(ANDROID_FUNCTION_LEVEL_LINKING TRUE)
set(ANDROID_GOLD_LINKER TRUE)
set(ANDROID_NOEXECSTACK TRUE)
set(ANDROID_RELRO TRUE)
if(ANDROID_ARM_MODE STREQUAL arm)
set(ANDROID_FORCE_ARM_BUILD TRUE)
endif()
if(ANDROID_CPP_FEATURES MATCHES "rtti"
AND ANDROID_CPP_FEATURES MATCHES "exceptions")
set(ANDROID_STL_FORCE_FEATURES TRUE)
endif()
if(ANDROID_CCACHE)
set(NDK_CCACHE "${ANDROID_CCACHE}")
endif()
if(ANDROID_TOOLCHAIN STREQUAL clang)
set(ANDROID_TOOLCHAIN_NAME ${ANDROID_TOOLCHAIN_NAME}-clang)
else()
set(ANDROID_TOOLCHAIN_NAME ${ANDROID_TOOLCHAIN_NAME}-4.9)
endif()
set(ANDROID_NDK_HOST_X64 TRUE)
set(ANDROID_NDK_LAYOUT RELEASE)
if(ANDROID_ABI STREQUAL armeabi-v7a)
set(ARMEABI_V7A TRUE)
if(ANDROID_ARM_NEON)
set(NEON TRUE)
endif()
elseif(ANDROID_ABI STREQUAL arm64-v8a)
set(ARM64_V8A TRUE)
elseif(ANDROID_ABI STREQUAL x86)
set(X86 TRUE)
elseif(ANDROID_ABI STREQUAL x86_64)
set(X86_64 TRUE)
elseif(ANDROID_ABI STREQUAL riscv64)
set(RISCV64 TRUE)
endif()
set(ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_HOST_TAG})
set(ANDROID_NDK_ABI_NAME ${ANDROID_ABI})
set(ANDROID_NDK_RELEASE r${ANDROID_NDK_REVISION})
set(ANDROID_ARCH_NAME ${ANDROID_SYSROOT_ABI})
set(TOOL_OS_SUFFIX ${ANDROID_TOOLCHAIN_SUFFIX})
if(ANDROID_TOOLCHAIN STREQUAL clang)
set(ANDROID_COMPILER_IS_CLANG TRUE)
endif()
# CMake 3.7+ compatibility.
if (CMAKE_VERSION VERSION_GREATER 3.7.0)
set(CMAKE_ANDROID_NDK ${ANDROID_NDK})
set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)
set(CMAKE_ANDROID_STL_TYPE ${ANDROID_STL})
if(ANDROID_ABI MATCHES "^armeabi(-v7a)?$")
set(CMAKE_ANDROID_ARM_NEON ${ANDROID_ARM_NEON})
set(CMAKE_ANDROID_ARM_MODE ${ANDROID_ARM_MODE})
endif()
# https://github.com/android/ndk/issues/861
if(ANDROID_ABI STREQUAL armeabi-v7a)
set(CMAKE_ANDROID_ARCH arm)
elseif(ANDROID_ABI STREQUAL arm64-v8a)
set(CMAKE_ANDROID_ARCH arm64)
elseif(ANDROID_ABI STREQUAL x86)
set(CMAKE_ANDROID_ARCH x86)
elseif(ANDROID_ABI STREQUAL x86_64)
set(CMAKE_ANDROID_ARCH x86_64)
elseif(ANDROID_ABI STREQUAL riscv64)
set(CMAKE_ANDROID_ARCH riscv64)
endif()
# https://github.com/android/ndk/issues/1012
set(CMAKE_ASM_ANDROID_TOOLCHAIN_MACHINE "${ANDROID_TOOLCHAIN_NAME}")
set(CMAKE_C_ANDROID_TOOLCHAIN_MACHINE "${ANDROID_TOOLCHAIN_NAME}")
set(CMAKE_CXX_ANDROID_TOOLCHAIN_MACHINE "${ANDROID_TOOLCHAIN_NAME}")
set(CMAKE_ASM_ANDROID_TOOLCHAIN_SUFFIX "${ANDROID_TOOLCHAIN_SUFFIX}")
set(CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX "${ANDROID_TOOLCHAIN_SUFFIX}")
set(CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX "${ANDROID_TOOLCHAIN_SUFFIX}")
endif()

View File

@ -0,0 +1,291 @@
# Copyright (C) 2016 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.
# Configurable variables.
# Modeled after the ndk-build system.
# For any variables defined in:
# https://developer.android.com/ndk/guides/android_mk.html
# https://developer.android.com/ndk/guides/application_mk.html
# if it makes sense for CMake, then replace LOCAL, APP, or NDK with ANDROID, and
# we have that variable below.
#
# ANDROID_TOOLCHAIN
# ANDROID_ABI
# ANDROID_PLATFORM
# ANDROID_STL
# ANDROID_PIE
# ANDROID_CPP_FEATURES
# ANDROID_ALLOW_UNDEFINED_SYMBOLS
# ANDROID_ARM_MODE
# ANDROID_DISABLE_FORMAT_STRING_CHECKS
# ANDROID_CCACHE
# ANDROID_SANITIZE
cmake_minimum_required(VERSION 3.12.0)
# CMake invokes the toolchain file twice during the first build, but only once
# during subsequent rebuilds. This was causing the various flags to be added
# twice on the first build, and on a rebuild ninja would see only one set of the
# flags and rebuild the world.
# https://github.com/android-ndk/ndk/issues/323
if(ANDROID_NDK_TOOLCHAIN_INCLUDED)
return()
endif(ANDROID_NDK_TOOLCHAIN_INCLUDED)
set(ANDROID_NDK_TOOLCHAIN_INCLUDED true)
if(DEFINED ANDROID_USE_LEGACY_TOOLCHAIN_FILE)
set(_USE_LEGACY_TOOLCHAIN_FILE ${ANDROID_USE_LEGACY_TOOLCHAIN_FILE})
else()
# Default to the legacy toolchain file to avoid changing the behavior of
# CMAKE_CXX_FLAGS. See https://github.com/android/ndk/issues/1693.
set(_USE_LEGACY_TOOLCHAIN_FILE true)
endif()
if(_USE_LEGACY_TOOLCHAIN_FILE)
include("${CMAKE_CURRENT_LIST_DIR}/android-legacy.toolchain.cmake")
return()
endif()
# Android NDK path
get_filename_component(ANDROID_NDK_EXPECTED_PATH
"${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
if(NOT ANDROID_NDK)
set(CMAKE_ANDROID_NDK "${ANDROID_NDK_EXPECTED_PATH}")
else()
# Allow the user to specify their own NDK path, but emit a warning. This is an
# uncommon use case, but helpful if users want to use a bleeding edge
# toolchain file with a stable NDK.
# https://github.com/android-ndk/ndk/issues/473
get_filename_component(ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE)
if(NOT "${ANDROID_NDK}" STREQUAL "${ANDROID_NDK_EXPECTED_PATH}")
message(WARNING "Using custom NDK path (ANDROID_NDK is set): ${ANDROID_NDK}")
endif()
set(CMAKE_ANDROID_NDK ${ANDROID_NDK})
endif()
unset(ANDROID_NDK_EXPECTED_PATH)
file(TO_CMAKE_PATH "${CMAKE_ANDROID_NDK}" CMAKE_ANDROID_NDK)
# Android NDK revision
# Possible formats:
# * r16, build 1234: 16.0.1234
# * r16b, build 1234: 16.1.1234
# * r16 beta 1, build 1234: 16.0.1234-beta1
#
# Canary builds are not specially marked.
file(READ "${CMAKE_ANDROID_NDK}/source.properties" ANDROID_NDK_SOURCE_PROPERTIES)
set(ANDROID_NDK_REVISION_REGEX
"^Pkg\\.Desc = Android NDK\nPkg\\.Revision = ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-beta([0-9]+))?")
if(NOT ANDROID_NDK_SOURCE_PROPERTIES MATCHES "${ANDROID_NDK_REVISION_REGEX}")
message(SEND_ERROR "Failed to parse Android NDK revision: ${CMAKE_ANDROID_NDK}/source.properties.\n${ANDROID_NDK_SOURCE_PROPERTIES}")
endif()
set(ANDROID_NDK_MAJOR "${CMAKE_MATCH_1}")
set(ANDROID_NDK_MINOR "${CMAKE_MATCH_2}")
set(ANDROID_NDK_BUILD "${CMAKE_MATCH_3}")
set(ANDROID_NDK_BETA "${CMAKE_MATCH_5}")
if(ANDROID_NDK_BETA STREQUAL "")
set(ANDROID_NDK_BETA "0")
endif()
set(ANDROID_NDK_REVISION
"${ANDROID_NDK_MAJOR}.${ANDROID_NDK_MINOR}.${ANDROID_NDK_BUILD}${CMAKE_MATCH_4}")
# Touch toolchain variable to suppress "unused variable" warning.
# This happens if CMake is invoked with the same command line the second time.
if(CMAKE_TOOLCHAIN_FILE)
endif()
# Determine the ABI.
if(NOT CMAKE_ANDROID_ARCH_ABI)
if(ANDROID_ABI STREQUAL "armeabi-v7a with NEON")
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
elseif(ANDROID_ABI)
set(CMAKE_ANDROID_ARCH_ABI ${ANDROID_ABI})
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^arm-linux-androideabi-")
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^aarch64-linux-android-")
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^x86-")
set(CMAKE_ANDROID_ARCH_ABI x86)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^x86_64-")
set(CMAKE_ANDROID_ARCH_ABI x86_64)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^riscv64-")
set(CMAKE_ANDROID_ARCH_ABI riscv64)
else()
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
endif()
endif()
if(DEFINED ANDROID_ARM_NEON AND NOT ANDROID_ARM_NEON)
message(FATAL_ERROR "Disabling Neon is no longer supported")
endif()
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a")
set(CMAKE_ANDROID_ARM_NEON TRUE)
if(NOT DEFINED CMAKE_ANDROID_ARM_MODE)
if(DEFINED ANDROID_FORCE_ARM_BUILD)
set(CMAKE_ANDROID_ARM_MODE ${ANDROID_FORCE_ARM_BUILD})
elseif(DEFINED ANDROID_ARM_MODE)
if(ANDROID_ARM_MODE STREQUAL "arm")
set(CMAKE_ANDROID_ARM_MODE TRUE)
elseif(ANDROID_ARM_MODE STREQUAL "thumb")
set(CMAKE_ANDROID_ARM_MODE FALSE)
else()
message(FATAL_ERROR "Invalid Android ARM mode: ${ANDROID_ARM_MODE}.")
endif()
endif()
endif()
endif()
# PIE is supported on all currently supported Android releases, but it is not
# supported with static executables, so we still provide ANDROID_PIE as an
# escape hatch for those.
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
if(DEFINED ANDROID_PIE)
set(CMAKE_POSITION_INDEPENDENT_CODE ${ANDROID_PIE})
elseif(DEFINED ANDROID_APP_PIE)
set(CMAKE_POSITION_INDEPENDENT_CODE ${ANDROID_APP_PIE})
else()
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif()
endif()
# Default values for configurable variables.
if(NOT ANDROID_TOOLCHAIN)
set(ANDROID_TOOLCHAIN clang)
elseif(ANDROID_TOOLCHAIN STREQUAL gcc)
message(FATAL_ERROR "GCC is no longer supported. See "
"https://android.googlesource.com/platform/ndk/+/master/docs/ClangMigration.md.")
endif()
if(ANDROID_NATIVE_API_LEVEL AND NOT ANDROID_PLATFORM)
if(ANDROID_NATIVE_API_LEVEL MATCHES "^android-[0-9]+$")
set(ANDROID_PLATFORM ${ANDROID_NATIVE_API_LEVEL})
elseif(ANDROID_NATIVE_API_LEVEL MATCHES "^[0-9]+$")
set(ANDROID_PLATFORM android-${ANDROID_NATIVE_API_LEVEL})
endif()
endif()
include(${CMAKE_ANDROID_NDK}/build/cmake/adjust_api_level.cmake)
adjust_api_level("${ANDROID_PLATFORM}" CMAKE_SYSTEM_VERSION)
if(NOT DEFINED CMAKE_ANDROID_STL_TYPE AND DEFINED ANDROID_STL)
set(CMAKE_ANDROID_STL_TYPE ${ANDROID_STL})
endif()
if("hwaddress" IN_LIST ANDROID_SANITIZE AND "${CMAKE_ANDROID_STL_TYPE}" STREQUAL "c++_static")
message(FATAL_ERROR "\
hwaddress does not support c++_static. Use system or c++_shared.")
endif()
if("${CMAKE_ANDROID_STL_TYPE}" STREQUAL "gnustl_shared" OR
"${CMAKE_ANDROID_STL_TYPE}" STREQUAL "gnustl_static" OR
"${CMAKE_ANDROID_STL_TYPE}" STREQUAL "stlport_shared" OR
"${CMAKE_ANDROID_STL_TYPE}" STREQUAL "stlport_static")
message(FATAL_ERROR "\
${CMAKE_ANDROID_STL_TYPE} is no longer supported. Please switch to either c++_shared \
or c++_static. See https://developer.android.com/ndk/guides/cpp-support.html \
for more information.")
endif()
# Standard cross-compiling stuff.
set(CMAKE_SYSTEM_NAME Android)
# STL.
if(ANDROID_STL)
set(CMAKE_ANDROID_STL_TYPE ${ANDROID_STL})
endif()
if(NDK_CCACHE AND NOT ANDROID_CCACHE)
set(ANDROID_CCACHE "${NDK_CCACHE}")
endif()
if(ANDROID_CCACHE)
set(CMAKE_C_COMPILER_LAUNCHER "${ANDROID_CCACHE}")
set(CMAKE_CXX_COMPILER_LAUNCHER "${ANDROID_CCACHE}")
endif()
# Configuration specific flags.
if(ANDROID_STL_FORCE_FEATURES AND NOT DEFINED ANDROID_CPP_FEATURES)
set(ANDROID_CPP_FEATURES "rtti exceptions")
endif()
if(ANDROID_CPP_FEATURES)
separate_arguments(ANDROID_CPP_FEATURES)
foreach(feature ${ANDROID_CPP_FEATURES})
if(NOT ${feature} MATCHES "^(rtti|exceptions|no-rtti|no-exceptions)$")
message(FATAL_ERROR "Invalid Android C++ feature: ${feature}.")
endif()
if(${feature} STREQUAL "rtti")
set(CMAKE_ANDROID_RTTI TRUE)
endif()
if(${feature} STREQUAL "no-rtti")
set(CMAKE_ANDROID_RTTI FALSE)
endif()
if(${feature} STREQUAL "exceptions")
set(CMAKE_ANDROID_EXCEPTIONS TRUE)
endif()
if(${feature} STREQUAL "no-exceptions")
set(CMAKE_ANDROID_EXCEPTIONS FALSE)
endif()
endforeach()
string(REPLACE ";" " " ANDROID_CPP_FEATURES "${ANDROID_CPP_FEATURES}")
endif()
# Export configurable variables for the try_compile() command.
set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
ANDROID_ABI
ANDROID_ALLOW_UNDEFINED_SYMBOLS
ANDROID_ARM_MODE
ANDROID_ARM_NEON
ANDROID_CCACHE
ANDROID_CPP_FEATURES
ANDROID_DISABLE_FORMAT_STRING_CHECKS
ANDROID_PIE
ANDROID_PLATFORM
ANDROID_STL
ANDROID_TOOLCHAIN
ANDROID_USE_LEGACY_TOOLCHAIN_FILE
ANDROID_SANITIZE
)
if(DEFINED ANDROID_NO_UNDEFINED AND NOT DEFINED ANDROID_ALLOW_UNDEFINED_SYMBOLS)
if(ANDROID_NO_UNDEFINED)
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS FALSE)
else()
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS TRUE)
endif()
endif()
if(DEFINED ANDROID_SO_UNDEFINED AND NOT DEFINED ANDROID_ALLOW_UNDEFINED_SYMBOLS)
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS "${ANDROID_SO_UNDEFINED}")
endif()
# Exports compatible variables defined in exports.cmake.
set(_ANDROID_EXPORT_COMPATIBILITY_VARIABLES TRUE)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
set(ANDROID_HOST_TAG linux-x86_64)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
set(ANDROID_HOST_TAG darwin-x86_64)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(ANDROID_HOST_TAG windows-x86_64)
endif()
# Toolchain.
set(ANDROID_TOOLCHAIN_ROOT
"${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/${ANDROID_HOST_TAG}")
# NB: This variable causes CMake to automatically pass --sysroot to the
# toolchain. Studio currently relies on this to recognize Android builds. If
# this variable is removed, ensure that flag is still passed.
# TODO: Teach Studio to recognize Android builds based on --target.
set(CMAKE_SYSROOT "${ANDROID_TOOLCHAIN_ROOT}/sysroot")

View File

@ -0,0 +1,4 @@
# The file is automatically generated when the NDK is built.
set(CMAKE_ASM_COMPILER_VERSION 18.0.4)
set(CMAKE_C_COMPILER_VERSION 18.0.4)
set(CMAKE_CXX_COMPILER_VERSION 18.0.4)

View File

@ -0,0 +1,81 @@
# Copyright (C) 2020 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.
# Read-only variables for compatibility with the other toolchain file.
# We'll keep these around for the existing projects that still use them.
# TODO: All of the variables here have equivalents in the standard set of
# cmake configurable variables, so we can remove these once most of our
# users migrate to those variables.
# From legacy toolchain file.
set(ANDROID_NDK "${CMAKE_ANDROID_NDK}")
set(ANDROID_ABI "${CMAKE_ANDROID_ARCH_ABI}")
set(ANDROID_COMPILER_IS_CLANG TRUE)
set(ANDROID_PLATFORM "android-${CMAKE_SYSTEM_VERSION}")
set(ANDROID_PLATFORM_LEVEL "${CMAKE_SYSTEM_VERSION}")
set(ANDROID_ARM_NEON TRUE)
if(CMAKE_ANDROID_ARM_MODE)
set(ANDROID_ARM_MODE "arm")
set(ANDROID_FORCE_ARM_BUILD TRUE)
else()
set(ANDROID_ARM_MODE "thumb")
endif()
set(ANDROID_ARCH_NAME "${CMAKE_ANDROID_ARCH}")
set(ANDROID_LLVM_TRIPLE "${CMAKE_ANDROID_ARCH_LLVM_TRIPLE}${CMAKE_SYSTEM_VERSION}")
set(ANDROID_TOOLCHAIN_ROOT "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}")
set(ANDROID_HOST_TAG "${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}")
set(ANDROID_HOST_PREBUILTS "${CMAKE_ANDROID_NDK}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}")
set(ANDROID_AR "${CMAKE_AR}")
set(ANDROID_RANLIB "${CMAKE_RANLIB}")
set(ANDROID_STRIP "${CMAKE_STRIP}")
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(ANDROID_TOOLCHAIN_SUFFIX ".exe")
endif()
# From other toolchain file.
set(ANDROID_NATIVE_API_LEVEL "${ANDROID_PLATFORM_LEVEL}")
if(ANDROID_ALLOW_UNDEFINED_SYMBOLS)
set(ANDROID_SO_UNDEFINED TRUE)
else()
set(ANDROID_NO_UNDEFINED TRUE)
endif()
set(ANDROID_FUNCTION_LEVEL_LINKING TRUE)
set(ANDROID_GOLD_LINKER TRUE)
set(ANDROID_NOEXECSTACK TRUE)
set(ANDROID_RELRO TRUE)
if(ANDROID_CPP_FEATURES MATCHES "rtti"
AND ANDROID_CPP_FEATURES MATCHES "exceptions")
set(ANDROID_STL_FORCE_FEATURES TRUE)
endif()
if(ANDROID_CCACHE)
set(NDK_CCACHE "${ANDROID_CCACHE}")
endif()
set(ANDROID_NDK_HOST_X64 TRUE)
set(ANDROID_NDK_LAYOUT RELEASE)
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a")
set(ARMEABI_V7A TRUE)
set(NEON TRUE)
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
set(ARM64_V8A TRUE)
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86")
set(X86 TRUE)
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
set(X86_64 TRUE)
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "riscv64")
set(RISCV64 TRUE)
endif()
set(ANDROID_NDK_HOST_SYSTEM_NAME "${ANDROID_HOST_TAG}")
set(ANDROID_NDK_ABI_NAME "${CMAKE_ANDROID_ARCH_ABI}")
set(ANDROID_NDK_RELEASE "r${ANDROID_NDK_REVISION}")
set(TOOL_OS_SUFFIX "${ANDROID_TOOLCHAIN_SUFFIX}")

View File

@ -0,0 +1,121 @@
# Copyright (C) 2020 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.
# This file will be included directly by cmake. It is used to provide
# additional cflags / ldflags.
cmake_minimum_required(VERSION 3.12.0)
set(_ANDROID_NDK_INIT_CFLAGS)
set(_ANDROID_NDK_INIT_CFLAGS_DEBUG)
set(_ANDROID_NDK_INIT_CFLAGS_RELEASE)
set(_ANDROID_NDK_INIT_LDFLAGS)
set(_ANDROID_NDK_INIT_LDFLAGS_EXE)
# Generic flags.
string(APPEND _ANDROID_NDK_INIT_CFLAGS
" -DANDROID"
" -fdata-sections"
" -ffunction-sections"
" -funwind-tables"
" -fstack-protector-strong"
" -no-canonical-prefixes")
if(ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES)
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -D__BIONIC_NO_PAGE_SIZE_MACRO")
if(ANDROID_ABI STREQUAL arm64-v8a OR ANDROID_ABI STREQUAL x86_64)
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,-z,max-page-size=16384")
endif()
endif()
if(ANDROID_WEAK_API_DEFS)
string(APPEND _ANDROID_NDK_INIT_CFLAGS
" -D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__"
" -Werror=unguarded-availability")
endif()
if("hwaddress" IN_LIST ANDROID_SANITIZE)
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -fsanitize=hwaddress -fno-omit-frame-pointer")
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -fsanitize=hwaddress")
endif()
if("memtag" IN_LIST ANDROID_SANITIZE)
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -fsanitize=memtag-stack -fno-omit-frame-pointer")
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -fsanitize=memtag-stack,memtag-heap -fsanitize-memtag-mode=sync")
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -march=armv8-a+memtag")
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -march=armv8-a+memtag")
endif()
endif()
string(APPEND _ANDROID_NDK_INIT_CFLAGS_DEBUG " -fno-limit-debug-info")
# If we're using LLD we need to use a slower build-id algorithm to work around
# the old version of LLDB in Android Studio, which doesn't understand LLD's
# default hash ("fast").
#
# https://github.com/android/ndk/issues/885
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--build-id=sha1")
if(CMAKE_SYSTEM_VERSION LESS 30)
# https://github.com/android/ndk/issues/1196
# https://github.com/android/ndk/issues/1589
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--no-rosegment")
endif()
if (NOT ANDROID_ALLOW_UNDEFINED_VERSION_SCRIPT_SYMBOLS)
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--no-undefined-version")
endif()
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--fatal-warnings")
# This should only be set for release modes, but CMake doesn't provide a way for
# us to be that specific in the new toolchain file.
# https://github.com/android/ndk/issues/1813
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--gc-sections")
string(APPEND _ANDROID_NDK_INIT_LDFLAGS_EXE " -Wl,--gc-sections")
# Toolchain and ABI specific flags.
if(CMAKE_ANDROID_ARCH_ABI STREQUAL x86 AND CMAKE_SYSTEM_VERSION LESS 24)
# http://b.android.com/222239
# http://b.android.com/220159 (internal http://b/31809417)
# x86 devices have stack alignment issues.
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -mstackrealign")
endif()
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -D_FORTIFY_SOURCE=2")
if(CMAKE_ANDROID_ARCH_ABI MATCHES "armeabi")
# Clang does not set this up properly when using -fno-integrated-as.
# https://github.com/android-ndk/ndk/issues/906
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -march=armv7-a")
if(NOT CMAKE_ANDROID_ARM_MODE)
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -mthumb")
endif()
endif()
# CMake automatically forwards all compiler flags to the linker, and clang
# doesn't like having -Wa flags being used for linking. To prevent CMake from
# doing this would require meddling with the CMAKE_<LANG>_COMPILE_OBJECT rules,
# which would get quite messy.
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Qunused-arguments")
if(ANDROID_DISABLE_FORMAT_STRING_CHECKS)
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -Wno-error=format-security")
else()
string(APPEND _ANDROID_NDK_INIT_CFLAGS " -Wformat -Werror=format-security")
endif()
if(NOT ANDROID_ALLOW_UNDEFINED_SYMBOLS)
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--no-undefined")
endif()

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the end of
# Modules/Platform/Android-Clang.cmake.

View File

@ -0,0 +1,22 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the end of
# Modules/Platform/Android-Determine.cmake.
# android.toolchain.cmake may set this to export old variables.
if(_ANDROID_EXPORT_COMPATIBILITY_VARIABLES)
file(READ "${CMAKE_ANDROID_NDK}/build/cmake/exports.cmake" _EXPORTS)
string(APPEND CMAKE_SYSTEM_CUSTOM_CODE "\n${_EXPORTS}\n")
endif()

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the end of
# Modules/Platform/Android-Initialize.cmake.

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the end of
# Modules/Platform/Android.cmake.

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the end of
# Modules/Platform/Android/Determine-Compiler.cmake.

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the beginning of
# Modules/Platform/Android-Clang.cmake.

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the beginning of
# Modules/Platform/Android-Determine.cmake.

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the beginning of
# Modules/Platform/Android-Initialize.cmake.

View File

@ -0,0 +1,16 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the beginning of
# Modules/Platform/Android.cmake.

View File

@ -0,0 +1,42 @@
# Copyright (C) 2020 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.
# This is a hook file that will be included by cmake at the beginning of
# Modules/Platform/Android/Determine-Compiler.cmake.
# Skip hook for the legacy toolchain workflow.
if(CMAKE_SYSTEM_VERSION EQUAL 1)
return()
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.22.0")
# If we don't explicitly set the target CMake will ID the compiler using the
# default target, causing MINGW to be defined when a Windows host is used.
# https://github.com/android/ndk/issues/1581
# https://gitlab.kitware.com/cmake/cmake/-/issues/22647
if(CMAKE_ANDROID_ARCH_ABI STREQUAL armeabi-v7a)
set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL arm64-v8a)
set(ANDROID_LLVM_TRIPLE aarch64-none-linux-android)
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL x86)
set(ANDROID_LLVM_TRIPLE i686-none-linux-android)
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL x86_64)
set(ANDROID_LLVM_TRIPLE x86_64-none-linux-android)
else()
message(FATAL_ERROR "Invalid Android ABI: ${ANDROID_ABI}.")
endif()
set(CMAKE_ASM_COMPILER_TARGET "${ANDROID_LLVM_TRIPLE}${CMAKE_SYSTEM_VERSION}")
set(CMAKE_C_COMPILER_TARGET "${ANDROID_LLVM_TRIPLE}${CMAKE_SYSTEM_VERSION}")
set(CMAKE_CXX_COMPILER_TARGET "${ANDROID_LLVM_TRIPLE}${CMAKE_SYSTEM_VERSION}")
endif()

View File

@ -0,0 +1,23 @@
set(NDK_MIN_PLATFORM_LEVEL "21")
set(NDK_MAX_PLATFORM_LEVEL "35")
set(NDK_PLATFORM_ALIAS_20 "android-19")
set(NDK_PLATFORM_ALIAS_25 "android-24")
set(NDK_PLATFORM_ALIAS_J "android-16")
set(NDK_PLATFORM_ALIAS_J-MR1 "android-17")
set(NDK_PLATFORM_ALIAS_J-MR2 "android-18")
set(NDK_PLATFORM_ALIAS_K "android-19")
set(NDK_PLATFORM_ALIAS_L "android-21")
set(NDK_PLATFORM_ALIAS_L-MR1 "android-22")
set(NDK_PLATFORM_ALIAS_M "android-23")
set(NDK_PLATFORM_ALIAS_N "android-24")
set(NDK_PLATFORM_ALIAS_N-MR1 "android-24")
set(NDK_PLATFORM_ALIAS_O "android-26")
set(NDK_PLATFORM_ALIAS_O-MR1 "android-27")
set(NDK_PLATFORM_ALIAS_P "android-28")
set(NDK_PLATFORM_ALIAS_Q "android-29")
set(NDK_PLATFORM_ALIAS_R "android-30")
set(NDK_PLATFORM_ALIAS_S "android-31")
set(NDK_PLATFORM_ALIAS_Sv2 "android-32")
set(NDK_PLATFORM_ALIAS_Tiramisu "android-33")
set(NDK_PLATFORM_ALIAS_UpsideDownCake "android-34")
set(NDK_PLATFORM_ALIAS_VanillaIceCream "android-35")

View File

@ -0,0 +1 @@
set(NDK_SYSTEM_LIBS "libEGL.so;libGLESv1_CM.so;libGLESv2.so;libGLESv3.so;libOpenMAXAL.so;libOpenSLES.so;libaaudio.so;libamidi.so;libandroid.so;libbinder_ndk.so;libc.so;libcamera2ndk.so;libdl.so;libicu.so;libjnigraphics.so;liblog.so;libm.so;libmediandk.so;libnativehelper.so;libnativewindow.so;libneuralnetworks.so;libstdc++.so;libsync.so;libvulkan.so;libz.so")

View File

@ -0,0 +1,40 @@
NDK_DEFAULT_ABIS := arm64-v8a armeabi-v7a x86 x86_64
NDK_DEPRECATED_ABIS :=
NDK_KNOWN_DEVICE_ABI32S := armeabi-v7a x86
NDK_KNOWN_DEVICE_ABI64S := arm64-v8a riscv64 x86_64
NDK_KNOWN_DEVICE_ABIS := arm64-v8a armeabi-v7a riscv64 x86 x86_64
NDK_ABI_armeabi-v7a_PROC := armv7-a
NDK_ABI_armeabi-v7a_ARCH := arm
NDK_ABI_armeabi-v7a_TRIPLE := arm-linux-androideabi
NDK_ABI_armeabi-v7a_LLVM_TRIPLE := armv7-none-linux-androideabi
NDK_ABI_armeabi-v7a_MIN_OS_VERSION := 21
NDK_PROC_armv7-a_ABI := armeabi-v7a
NDK_ARCH_arm_ABI := armeabi-v7a
NDK_ABI_arm64-v8a_PROC := aarch64
NDK_ABI_arm64-v8a_ARCH := arm64
NDK_ABI_arm64-v8a_TRIPLE := aarch64-linux-android
NDK_ABI_arm64-v8a_LLVM_TRIPLE := aarch64-none-linux-android
NDK_ABI_arm64-v8a_MIN_OS_VERSION := 21
NDK_PROC_aarch64_ABI := arm64-v8a
NDK_ARCH_arm64_ABI := arm64-v8a
NDK_ABI_riscv64_PROC := riscv64
NDK_ABI_riscv64_ARCH := riscv64
NDK_ABI_riscv64_TRIPLE := riscv64-linux-android
NDK_ABI_riscv64_LLVM_TRIPLE := riscv64-none-linux-android
NDK_ABI_riscv64_MIN_OS_VERSION := 35
NDK_PROC_riscv64_ABI := riscv64
NDK_ARCH_riscv64_ABI := riscv64
NDK_ABI_x86_PROC := i686
NDK_ABI_x86_ARCH := x86
NDK_ABI_x86_TRIPLE := i686-linux-android
NDK_ABI_x86_LLVM_TRIPLE := i686-none-linux-android
NDK_ABI_x86_MIN_OS_VERSION := 21
NDK_PROC_i686_ABI := x86
NDK_ARCH_x86_ABI := x86
NDK_ABI_x86_64_PROC := x86_64
NDK_ABI_x86_64_ARCH := x86_64
NDK_ABI_x86_64_TRIPLE := x86_64-linux-android
NDK_ABI_x86_64_LLVM_TRIPLE := x86_64-none-linux-android
NDK_ABI_x86_64_MIN_OS_VERSION := 21
NDK_PROC_x86_64_ABI := x86_64
NDK_ARCH_x86_64_ABI := x86_64

View File

@ -0,0 +1,247 @@
# Copyright (C) 2009 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.
#
# this script is used to record an application definition in the
# NDK build system, before performing any build whatsoever.
#
# It is included repeatedly from build/core/main.mk and expects a
# variable named '_application_mk' which points to a given Application.mk
# file that will be included here. The latter must define a few variables
# to describe the application to the build system, and the rest of the
# code here will perform book-keeping and basic checks
#
$(call assert-defined, _application_mk _app)
$(call ndk_log,Parsing $(_application_mk))
$(call clear-vars, $(NDK_APP_VARS))
# Check that NDK_DEBUG is properly defined. If it is
# the only valid states are: undefined, 0, 1, false and true
#
# We set APP_DEBUG to <undefined>, 'true' or 'false'.
#
APP_DEBUG := $(strip $(NDK_DEBUG))
ifeq ($(APP_DEBUG),0)
APP_DEBUG:= false
endif
ifeq ($(APP_DEBUG),1)
APP_DEBUG := true
endif
ifdef APP_DEBUG
ifneq (,$(filter-out true false,$(APP_DEBUG)))
$(call __ndk_warning,NDK_DEBUG is defined to the unsupported value '$(NDK_DEBUG)', will be ignored!)
endif
endif
include $(_application_mk)
$(call check-required-vars,$(NDK_APP_VARS_REQUIRED),$(_application_mk))
_map := NDK_APP.$(_app)
# strip the 'lib' prefix in front of APP_MODULES modules
APP_MODULES := $(call strip-lib-prefix,$(APP_MODULES))
APP_PROJECT_PATH := $(strip $(APP_PROJECT_PATH))
ifndef APP_PROJECT_PATH
APP_PROJECT_PATH := $(NDK_PROJECT_PATH)
endif
include $(BUILD_SYSTEM)/setup-app-platform.mk
# Check that the value of APP_ABI corresponds to known ABIs
# 'all' is a special case that means 'all supported ABIs'
#
# It will be handled in setup-app.mk. We can't hope to change
# the value of APP_ABI is the user enforces it on the command-line
# with a call like: ndk-build APP_ABI=all
#
# Because GNU Make makes the APP_ABI variable read-only (any assignments
# to it will be ignored)
#
APP_ABI := $(subst $(comma),$(space),$(strip $(APP_ABI)))
ifndef APP_ABI
APP_ABI := $(NDK_DEFAULT_ABIS)
endif
# If APP_BUILD_SCRIPT is defined, check that the file exists.
# If undefined, look in $(APP_PROJECT_PATH)/jni/Android.mk
#
APP_BUILD_SCRIPT := $(strip $(APP_BUILD_SCRIPT))
ifdef APP_BUILD_SCRIPT
_build_script := $(strip $(wildcard $(APP_BUILD_SCRIPT)))
ifndef _build_script
$(call __ndk_info,Your APP_BUILD_SCRIPT points to an unknown file: $(APP_BUILD_SCRIPT))
$(call __ndk_error,Aborting...)
endif
APP_BUILD_SCRIPT := $(_build_script)
$(call ndk_log, Using build script $(APP_BUILD_SCRIPT))
else
ifeq (null,$(APP_PROJECT_PATH))
$(call __ndk_info,NDK_PROJECT_PATH==null. Please explicitly set APP_BUILD_SCRIPT.)
$(call __ndk_error,Aborting.)
endif
_build_script := $(strip $(wildcard $(APP_PROJECT_PATH)/jni/Android.mk))
ifndef _build_script
$(call __ndk_info,There is no Android.mk under $(APP_PROJECT_PATH)/jni)
$(call __ndk_info,If this is intentional, please define APP_BUILD_SCRIPT to point)
$(call __ndk_info,to a valid NDK build script.)
$(call __ndk_error,Aborting...)
endif
APP_BUILD_SCRIPT := $(_build_script)
$(call ndk_log, Defaulted to APP_BUILD_SCRIPT=$(APP_BUILD_SCRIPT))
endif
# Determine whether the application should be debuggable.
# - If APP_DEBUG is set to 'true', then it always should.
# - If APP_DEBUG is set to 'false', then it never should
# - Otherwise, extract the android:debuggable attribute from the manifest.
#
ifdef APP_DEBUG
APP_DEBUGGABLE := $(APP_DEBUG)
ifeq ($(NDK_LOG),1)
ifeq ($(APP_DEBUG),true)
$(call ndk_log,Application '$(_app)' forced debuggable through NDK_DEBUG)
else
$(call ndk_log,Application '$(_app)' forced *not* debuggable through NDK_DEBUG)
endif
endif
else
# NOTE: To make unit-testing simpler, handle the case where there is no manifest.
APP_DEBUGGABLE := false
ifdef APP_MANIFEST
APP_DEBUGGABLE := $(shell $(HOST_PYTHON) $(BUILD_PY)/extract_manifest.py debuggable $(call host-path,$(APP_MANIFEST)))
endif
ifeq ($(NDK_LOG),1)
ifeq ($(APP_DEBUGGABLE),true)
$(call ndk_log,Application '$(_app)' *is* debuggable)
else
$(call ndk_log,Application '$(_app)' is not debuggable)
endif
endif
endif
# LOCAL_BUILD_MODE will be either release or debug
#
# If APP_OPTIM is defined in the Application.mk, just use this.
#
# Otherwise, set to 'debug' if android:debuggable is set to TRUE,
# and to 'release' if not.
#
ifneq ($(APP_OPTIM),)
# check that APP_OPTIM, if defined, is either 'release' or 'debug'
$(if $(filter-out release debug,$(APP_OPTIM)),\
$(call __ndk_info, The APP_OPTIM defined in $(_application_mk) must only be 'release' or 'debug')\
$(call __ndk_error,Aborting)\
)
$(call ndk_log,Selecting optimization mode through Application.mk: $(APP_OPTIM))
else
ifeq ($(APP_DEBUGGABLE),true)
$(call ndk_log,Selecting debug optimization mode (app is debuggable))
APP_OPTIM := debug
else
$(call ndk_log,Selecting release optimization mode (app is not debuggable))
APP_OPTIM := release
endif
endif
APP_CFLAGS := $(strip $(APP_CFLAGS))
APP_CONLYFLAGS := $(strip $(APP_CONLYFLAGS))
APP_CPPFLAGS := $(strip $(APP_CPPFLAGS))
APP_CXXFLAGS := $(strip $(APP_CXXFLAGS))
APP_ASFLAGS := $(strip $(APP_ASFLAGS))
APP_ASMFLAGS := $(strip $(APP_ASMFLAGS))
APP_LDFLAGS := $(strip $(APP_LDFLAGS))
# Check that APP_STL is defined. If not, use the default value (system)
# otherwise, check that the name is correct.
APP_STL := $(strip $(APP_STL))
ifndef APP_STL
APP_STL := system
else
ifneq ($(filter $(APP_STL),gnustl_static gnustl_shared stlport_static stlport_shared),)
$(call __ndk_error,APP_STL $(APP_STL) is no longer supported. Please \
switch to either c++_static or c++_shared. See \
https://developer.android.com/ndk/guides/cpp-support.html for more \
information.)
endif
$(call ndk-stl-check,$(APP_STL))
endif
# wrap.sh files can be specified in the user's Application.mk in either an
# ABI-generic (APP_WRAP_SH) or ABI-specific (APP_WRAP_SH_x86, etc) fashion.
# These two approaches cannot be combined; if any ABI-specific wrap.sh files are
# specified then it is an error to also specify an ABI-generic one.
#
# After this block, only the ABI-specific values should be checked; if there is
# an ABI-generic script specified the ABI-specific variables will be populated
# with the generic script.
NDK_NO_USER_WRAP_SH := true
ifneq ($(APP_WRAP_SH),)
NDK_NO_USER_WRAP_SH := false
endif
NDK_HAVE_ABI_SPECIFIC_WRAP_SH := false
$(foreach _abi,$(NDK_ALL_ABIS),\
$(if $(APP_WRAP_SH_$(_abi)),\
$(eval NDK_HAVE_ABI_SPECIFIC_WRAP_SH := true)))
ifeq ($(NDK_HAVE_ABI_SPECIFIC_WRAP_SH),true)
# It is an error to have both ABI-specific and ABI-generic wrap.sh files
# specified.
ifneq ($(APP_WRAP_SH),)
$(call __ndk_error,Found both ABI-specific and ABI-generic APP_WRAP_SH \
directives. Must use either all ABI-specific or only ABI-generic.)
endif
NDK_NO_USER_WRAP_SH := false
else
# If we have no ABI-specific wrap.sh files but we *do* have an ABI-generic
# one, install the generic one for all ABIs.
$(foreach _abi,$(NDK_ALL_ABIS),\
$(eval APP_WRAP_SH_$(_abi) := $(APP_WRAP_SH)))
endif
# Stripping can be configured both at the app (APP_STRIP_MODE) and module level
# (LOCAL_STRIP_MODE). The module setting always overrides the application
# setting.
#
# This value is passed as-is as the flag to the strip command except when it is
# set to the special value "none". If set to "none", the binary will not be
# stripped at all.
ifeq ($(APP_STRIP_MODE),)
# The strip command is only used for shared libraries and executables. It is
# thus safe to use --strip-unneeded, which is only dangerous when applied to
# static libraries or object files.
APP_STRIP_MODE := --strip-unneeded
endif
$(if $(call get,$(_map),defined),\
$(call __ndk_info,Weird, the application $(_app) is already defined by $(call get,$(_map),defined))\
$(call __ndk_error,Aborting)\
)
$(call set,$(_map),defined,$(_application_mk))
# Record all app-specific variable definitions
$(foreach __name,$(NDK_APP_VARS),\
$(call set,$(_map),$(__name),$($(__name)))\
)
# Record the Application.mk for debugging
$(call set,$(_map),Application.mk,$(_application_mk))
NDK_ALL_APPS += $(_app)

View File

@ -0,0 +1,85 @@
# Copyright (C) 2009 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.
#
# this script is included repeatedly by main.mk to add a new toolchain
# definition to the NDK build system.
#
# '_config_mk' must be defined as the path of a toolchain
# configuration file (config.mk) that will be included here.
#
$(call assert-defined, _config_mk)
# The list of variables that must or may be defined
# by the toolchain configuration file
#
NDK_TOOLCHAIN_VARS_REQUIRED := TOOLCHAIN_ABIS TOOLCHAIN_ARCH
NDK_TOOLCHAIN_VARS_OPTIONAL :=
# Clear variables that are supposed to be defined by the config file
$(call clear-vars,$(NDK_TOOLCHAIN_VARS_REQUIRED))
$(call clear-vars,$(NDK_TOOLCHAIN_VARS_OPTIONAL))
# Include the config file
include $(_config_mk)
ifeq ($(TOOLCHAIN_ABIS)$(TOOLCHAIN_ARCH),)
# Ignore if both TOOLCHAIN_ABIS and TOOLCHAIN_ARCH are not defined
else
# Check that the proper variables were defined
$(call check-required-vars,$(NDK_TOOLCHAIN_VARS_REQUIRED),$(_config_mk))
# Check that the file didn't do something stupid
$(call assert-defined, _config_mk)
# Now record the toolchain-specific information
_dir := $(patsubst %/,%,$(dir $(_config_mk)))
_name := $(notdir $(_dir))
_arch := $(TOOLCHAIN_ARCH)
_abis := $(TOOLCHAIN_ABIS)
_toolchain := NDK_TOOLCHAIN.$(_name)
# check that the toolchain name is unique
$(if $(strip $($(_toolchain).defined)),\
$(call __ndk_error,Toolchain $(_name) defined in $(_parent) is\
already defined in $(NDK_TOOLCHAIN.$(_name).defined)))
$(_toolchain).defined := $(_toolchain_config)
$(_toolchain).arch := $(_arch)
$(_toolchain).abis := $(_abis)
$(_toolchain).setup := $(wildcard $(_dir)/setup.mk)
$(if $(strip $($(_toolchain).setup)),,\
$(call __ndk_error, Toolchain $(_name) lacks a setup.mk in $(_dir)))
NDK_ALL_TOOLCHAINS += $(_name)
NDK_ALL_ARCHS += $(_arch)
NDK_ALL_ABIS += $(_abis)
# NDK_ABI.<abi>.toolchains records the list of toolchains that support
# a given ABI
#
$(foreach _abi,$(_abis),\
$(eval NDK_ABI.$(_abi).toolchains += $(_name)) \
$(eval NDK_ABI.$(_abi).arch := $(sort $(NDK_ABI.$(_abi).arch) $(_arch)))\
)
NDK_ARCH.$(_arch).toolchains += $(_name)
NDK_ARCH.$(_arch).abis := $(sort $(NDK_ARCH.$(_arch).abis) $(_abis))
endif
# done

View File

@ -0,0 +1,125 @@
# Copyright (C) 2009-2010 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.
#
#
# This script is used to build all wanted NDK binaries. It is included
# by several scripts.
#
# ensure that the following variables are properly defined
$(call assert-defined,NDK_APPS NDK_APP_OUT)
# ====================================================================
#
# Prepare the build for parsing Android.mk files
#
# ====================================================================
# These phony targets are used to control various stages of the build
.PHONY: \
all \
host_libraries \
host_executables \
installed_modules \
executables libraries \
static_libraries \
shared_libraries \
clean clean-objs-dir \
clean-executables clean-libraries \
clean-installed-modules \
clean-installed-binaries \
clang_tidy_rules \
# These macros are used in Android.mk to include the corresponding
# build script that will parse the LOCAL_XXX variable definitions.
#
CLEAR_VARS := $(BUILD_SYSTEM)/clear-vars.mk
BUILD_HOST_EXECUTABLE := $(BUILD_SYSTEM)/build-host-executable.mk
BUILD_HOST_STATIC_LIBRARY := $(BUILD_SYSTEM)/build-host-static-library.mk
BUILD_STATIC_LIBRARY := $(BUILD_SYSTEM)/build-static-library.mk
BUILD_SHARED_LIBRARY := $(BUILD_SYSTEM)/build-shared-library.mk
BUILD_EXECUTABLE := $(BUILD_SYSTEM)/build-executable.mk
PREBUILT_SHARED_LIBRARY := $(BUILD_SYSTEM)/prebuilt-shared-library.mk
PREBUILT_STATIC_LIBRARY := $(BUILD_SYSTEM)/prebuilt-static-library.mk
# this is the list of directories containing dependency information
# generated during the build. It will be updated by build scripts
# when module definitions are parsed.
#
ALL_DEPENDENCY_DIRS :=
# this is the list of all generated files that we would need to clean
ALL_HOST_EXECUTABLES :=
ALL_HOST_STATIC_LIBRARIES :=
ALL_STATIC_LIBRARIES :=
ALL_SHARED_LIBRARIES :=
ALL_EXECUTABLES :=
WANTED_INSTALLED_MODULES :=
# the first rule
all: installed_modules host_libraries host_executables clang_tidy_rules
$(foreach _app,$(NDK_APPS),\
$(eval include $(BUILD_SYSTEM)/setup-app.mk)\
)
ifeq (,$(strip $(WANTED_INSTALLED_MODULES)))
ifneq (,$(strip $(NDK_APP_MODULES)))
$(call __ndk_warning,WARNING: No modules to build, your APP_MODULES definition is probably incorrect!)
else
$(call __ndk_warning,WARNING: There are no modules to build in this project!)
endif
endif
# ====================================================================
#
# Now finish the build preparation with a few rules that depend on
# what has been effectively parsed and recorded previously
#
# ====================================================================
clean: clean-intermediates clean-installed-binaries
distclean: clean
installed_modules: clean-installed-binaries libraries $(WANTED_INSTALLED_MODULES)
host_libraries: $(HOST_STATIC_LIBRARIES)
host_executables: $(HOST_EXECUTABLES)
# clang-tidy rules add themselves as dependencies of this phony rule in
# ev-clang-tidy.
clang_tidy_rules:
static_libraries: $(STATIC_LIBRARIES)
shared_libraries: $(SHARED_LIBRARIES)
executables: $(EXECUTABLES)
ifeq ($(GEN_COMPILE_COMMANDS_DB),true)
all: $(COMPILE_COMMANDS_JSON)
endif
libraries: static_libraries shared_libraries
clean-host-intermediates:
$(hide) $(call host-rm,$(HOST_EXECUTABLES) $(HOST_STATIC_LIBRARIES))
clean-intermediates: clean-host-intermediates
$(hide) $(call host-rm,$(EXECUTABLES) $(STATIC_LIBRARIES) $(SHARED_LIBRARIES))
# include dependency information
ALL_DEPENDENCY_DIRS := $(patsubst %/,%,$(sort $(ALL_DEPENDENCY_DIRS)))
-include $(wildcard $(ALL_DEPENDENCY_DIRS:%=%/*.d))

View File

@ -0,0 +1,714 @@
# Copyright (C) 2008 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.
#
# Check that LOCAL_MODULE is defined, then restore its LOCAL_XXXX values
$(call assert-defined,LOCAL_MODULE)
$(call module-restore-locals,$(LOCAL_MODULE))
# As in build-module.mk, eval sucks. Manually unstash the flags variations to
# preserve -Werror=#warnings.
LOCAL_ASFLAGS := $(__ndk_modules.$(LOCAL_MODULE).ASFLAGS)
LOCAL_ASMFLAGS := $(__ndk_modules.$(LOCAL_MODULE).ASMFLAGS)
LOCAL_CFLAGS := $(__ndk_modules.$(LOCAL_MODULE).CFLAGS)
LOCAL_CLANG_TIDY_FLAGS := $(__ndk_modules.$(LOCAL_MODULE).CLANG_TIDY_FLAGS)
LOCAL_CONLYFLAGS := $(__ndk_modules.$(LOCAL_MODULE).CONLYFLAGS)
LOCAL_CPPFLAGS := $(__ndk_modules.$(LOCAL_MODULE).CPPFLAGS)
LOCAL_CXXFLAGS := $(__ndk_modules.$(LOCAL_MODULE).CXXFLAGS)
LOCAL_LDFLAGS := $(__ndk_modules.$(LOCAL_MODULE).LDFLAGS)
# For now, only support target (device-specific modules).
# We may want to introduce support for host modules in the future
# but that is too experimental for now.
#
my := POISONED
# LOCAL_MAKEFILE must also exist and name the Android.mk that
# included the module build script.
#
$(call assert-defined,LOCAL_MAKEFILE LOCAL_BUILD_SCRIPT LOCAL_BUILT_MODULE)
# A list of LOCAL_XXX variables that are ignored for static libraries.
# Print a warning if they are present inside a module definition to let
# the user know this won't do what he/she expects.
not_in_static_libs := \
LOCAL_LDFLAGS \
LOCAL_LDLIBS \
LOCAL_ALLOW_UNDEFINED_SYMBOLS
ifeq ($(call module-get-class,$(LOCAL_MODULE)),STATIC_LIBRARY)
$(foreach _notvar,$(not_in_static_libs),\
$(if $(strip $($(_notvar))),\
$(call __ndk_info,WARNING:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): $(_notvar) is always ignored for static libraries)\
)\
)
endif
# Some developers like to add library names (e.g. -lfoo) to LOCAL_LDLIBS
# and LOCAL_LDFLAGS directly. This is very fragile and can lead to broken
# builds and other nasty surprises, because it doesn't tell ndk-build
# that the corresponding module depends on these files. Emit a warning
# when we detect this case.
libs_in_ldflags := $(filter -l% %.so %.a,$(LOCAL_LDLIBS) $(LOCAL_LDFLAGS))
# Since the above will glob anything ending in .so or .a, we need to filter out
# any cases of -Wl,--exclude-libs since we use that to hide symbols in STLs.
libs_in_ldflags := \
$(filter-out -Wl$(comma)--exclude-libs$(comma)%,$(libs_in_ldflags))
include $(BUILD_SYSTEM)/system_libs.mk
# The only way to statically link libomp.a is with
# `-Wl,-Bstatic -lomp -Wl,-Bdynamic`, so we need to accept `-lomp`.
# https://github.com/android-ndk/ndk/issues/1028
NDK_SYSTEM_LIBS += libomp.so
libs_in_ldflags := $(filter-out $(NDK_SYSTEM_LIBS:lib%.so=-l%),$(libs_in_ldflags))
ifneq (,$(strip $(libs_in_ldflags)))
$(call __ndk_info,WARNING:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): non-system libraries in linker flags: $(libs_in_ldflags))
$(call __ndk_info, This is likely to result in incorrect builds. Try using LOCAL_STATIC_LIBRARIES)
$(call __ndk_info, or LOCAL_SHARED_LIBRARIES instead to list the library dependencies of the)
$(call __ndk_info, current module)
endif
include $(BUILD_SYSTEM)/import-locals.mk
# Check for LOCAL_THIN_ARCHIVE / APP_THIN_ARCHIVE and print a warning if
# it is defined for non-static library modules.
thin_archive := $(strip $(LOCAL_THIN_ARCHIVE))
ifdef thin_archive
ifneq (STATIC_LIBRARY,$(call module-get-class,$(LOCAL_MODULE)))
$(call __ndk_info,WARNING:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): LOCAL_THIN_ARCHIVE is for building static libraries)
endif
endif
ifndef thin_archive
thin_archive := $(strip $(NDK_APP_THIN_ARCHIVE))
endif
# Print a warning if the value is not 'true', 'false' or empty.
ifneq (,$(filter-out true false,$(thin_archive)))
$(call __ndk_info,WARNING:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): Invalid LOCAL_THIN_ARCHIVE value '$(thin_archive)' ignored!)
thin_archive :=
endif
#
# Ensure that 'make <module>' and 'make clean-<module>' work
#
.PHONY: $(LOCAL_MODULE)
$(LOCAL_MODULE): $(LOCAL_BUILT_MODULE)
cleantarget := clean-$(LOCAL_MODULE)-$(TARGET_ARCH_ABI)
.PHONY: $(cleantarget)
clean: $(cleantarget)
$(cleantarget): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(cleantarget): PRIVATE_MODULE := $(LOCAL_MODULE)
ifneq ($(LOCAL_BUILT_MODULE_NOT_COPIED),true)
$(cleantarget): PRIVATE_CLEAN_FILES := $(LOCAL_BUILT_MODULE) \
$(LOCAL_OBJS_DIR)
else
$(cleantarget): PRIVATE_CLEAN_FILES := $(LOCAL_OBJS_DIR)
endif
$(cleantarget)::
$(call host-echo-build-step,$(PRIVATE_ABI),Clean) "$(PRIVATE_MODULE) [$(PRIVATE_ABI)]"
$(hide) $(call host-rmdir,$(PRIVATE_CLEAN_FILES))
# list of generated object files
LOCAL_OBJECTS :=
# always define ANDROID when building binaries
#
LOCAL_CFLAGS := -DANDROID $(LOCAL_CFLAGS)
ifeq ($(APP_SUPPORT_FLEXIBLE_PAGE_SIZES),true)
LOCAL_CFLAGS += -D__BIONIC_NO_PAGE_SIZE_MACRO
ifneq (,$(filter $(APP_ABI),arm64-v8a x86_64))
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384
endif
endif
#
# Add the default system shared libraries to the build
#
ifeq ($(LOCAL_SYSTEM_SHARED_LIBRARIES),none)
LOCAL_SHARED_LIBRARIES += $(TARGET_DEFAULT_SYSTEM_SHARED_LIBRARIES)
else
LOCAL_SHARED_LIBRARIES += $(LOCAL_SYSTEM_SHARED_LIBRARIES)
endif
#
# Check LOCAL_CPP_EXTENSION
#
bad_cpp_extensions := $(strip $(filter-out .%,$(LOCAL_CPP_EXTENSION)))
ifdef bad_cpp_extensions
$(call __ndk_info,WARNING: Invalid LOCAL_CPP_EXTENSION values: $(bad_cpp_extensions))
LOCAL_CPP_EXTENSION := $(filter $(bad_cpp_extensions),$(LOCAL_CPP_EXTENSIONS))
endif
LOCAL_CPP_EXTENSION := $(strip $(LOCAL_CPP_EXTENSION))
ifeq ($(LOCAL_CPP_EXTENSION),)
# Match the default GCC C++ extensions.
LOCAL_CPP_EXTENSION := $(default-c++-extensions)
endif
include $(BUILD_SYSTEM)/stl.mk
#
# If LOCAL_ALLOW_UNDEFINED_SYMBOLS is not true, the linker will allow the generation
# of a binary that uses undefined symbols.
#
ifneq ($(LOCAL_ALLOW_UNDEFINED_SYMBOLS),true)
LOCAL_LDFLAGS += $(TARGET_NO_UNDEFINED_LDFLAGS)
endif
# We enable fatal linker warnings by default.
# If LOCAL_DISABLE_FATAL_LINKER_WARNINGS is true, we don't enable this check.
ifneq ($(LOCAL_DISABLE_FATAL_LINKER_WARNINGS),true)
LOCAL_LDFLAGS += -Wl,--fatal-warnings
endif
# By default, we protect against format string vulnerabilities
# If LOCAL_DISABLE_FORMAT_STRING_CHECKS is true, we disable the protections.
ifeq ($(LOCAL_DISABLE_FORMAT_STRING_CHECKS),true)
LOCAL_CFLAGS += $(TARGET_DISABLE_FORMAT_STRING_CFLAGS)
else
LOCAL_CFLAGS += $(TARGET_FORMAT_STRING_CFLAGS)
endif
# Enable branch protection for arm64-v8a
LOCAL_BRANCH_PROTECTION := $(strip $(LOCAL_BRANCH_PROTECTION))
ifdef LOCAL_BRANCH_PROTECTION
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
LOCAL_CFLAGS += -mbranch-protection=$(LOCAL_BRANCH_PROTECTION)
endif
endif
# http://b.android.com/222239
# http://b.android.com/220159 (internal http://b/31809417)
# x86 devices have stack alignment issues.
ifeq ($(TARGET_ARCH_ABI),x86)
ifneq (,$(call lt,$(APP_PLATFORM_LEVEL),24))
LOCAL_CFLAGS += -mstackrealign
endif
endif
ifneq ($(LOCAL_ALLOW_UNDEFINED_VERSION_SCRIPT_SYMBOLS),true)
LOCAL_LDFLAGS += -Wl,--no-undefined-version
endif
#
# The original Android build system allows you to use the .arm prefix
# to a source file name to indicate that it should be defined in either
# 'thumb' or 'arm' mode, depending on the value of LOCAL_ARM_MODE
#
# First, check LOCAL_ARM_MODE, it should be empty, 'thumb' or 'arm'
# We make the default 'thumb'
#
LOCAL_ARM_MODE := $(strip $(LOCAL_ARM_MODE))
ifdef LOCAL_ARM_MODE
ifneq ($(words $(LOCAL_ARM_MODE)),1)
$(call __ndk_info, LOCAL_ARM_MODE in $(LOCAL_MAKEFILE) must be one word, not '$(LOCAL_ARM_MODE)')
$(call __ndk_error, Aborting)
endif
# check that LOCAL_ARM_MODE is defined to either 'arm' or 'thumb'
$(if $(filter-out thumb arm, $(LOCAL_ARM_MODE)),\
$(call __ndk_info, LOCAL_ARM_MODE must be defined to either 'arm' or 'thumb' in $(LOCAL_MAKEFILE) not '$(LOCAL_ARM_MODE)')\
$(call __ndk_error, Aborting)\
)
my_link_arm_mode := $(LOCAL_ARM_MODE)
else
my_link_arm_mode := thumb
endif
# As a special case, the original Android build system
# allows one to specify that certain source files can be
# forced to build in ARM mode by using a '.arm' suffix
# after the extension, e.g.
#
# LOCAL_SRC_FILES := foo.c.arm
#
# to build source file $(LOCAL_PATH)/foo.c as ARM
#
$(call clear-all-src-tags)
# Historically the NDK supported both Neon and non-Neon as variants of the
# armeabi-v7a ABI. These were practically two ABIs but the distinction was not
# official (APKs did not have separate libraries for Neon and non-Neon devices).
# As of NDK r24 non-Neon devices are no longer supported, so any options opting
# *in* to Neon are ignored, and options explicitly opting out of Neon are an
# error. Users that choose a non-Neon -mfpu in their CFLAGS will receive no
# diagnostic.
LOCAL_ARM_NEON := $(strip $(LOCAL_ARM_NEON))
ifeq ($(LOCAL_ARM_NEON),false)
$(call __ndk_error,Building non-Neon code is no longer supported.)
endif
LOCAL_SRC_FILES := $(LOCAL_SRC_FILES:%.neon=%)
# strip the .arm suffix from LOCAL_SRC_FILES
# and tag the relevant sources with the 'arm' tag
#
arm_sources := $(filter %.arm,$(LOCAL_SRC_FILES))
arm_sources := $(arm_sources:%.arm=%)
thumb_sources := $(filter-out %.arm,$(LOCAL_SRC_FILES))
LOCAL_SRC_FILES := $(LOCAL_SRC_FILES:%.arm=%)
ifeq ($(LOCAL_ARM_MODE),arm)
arm_sources := $(LOCAL_SRC_FILES)
# tag the precompiled header with 'arm' tag if it exists
ifneq (,$(LOCAL_PCH))
$(call tag-src-files,$(LOCAL_PCH),arm)
endif
endif
ifeq ($(LOCAL_ARM_MODE),thumb)
arm_sources := $(empty)
endif
$(call tag-src-files,$(arm_sources),arm)
# tag debug if APP_OPTIM is 'debug'
#
ifeq ($(APP_OPTIM),debug)
$(call tag-src-files,$(LOCAL_SRC_FILES),debug)
ifneq (,$(LOCAL_PCH))
$(call tag-src-files,$(LOCAL_PCH),debug)
endif
endif
# add PCH to LOCAL_SRC_FILES so that TARGET-process-src-files-tags could process it
ifneq (,$(LOCAL_PCH))
LOCAL_SRC_FILES += $(LOCAL_PCH)
endif
# Process all source file tags to determine toolchain-specific
# target compiler flags, and text.
#
$(call TARGET-process-src-files-tags)
# now remove PCH from LOCAL_SRC_FILES to prevent getting NDK warning about
# unsupported source file extensions
ifneq (,$(LOCAL_PCH))
LOCAL_SRC_FILES := $(filter-out $(LOCAL_PCH),$(LOCAL_SRC_FILES))
endif
# only call dump-src-file-tags during debugging
#$(dump-src-file-tags)
LOCAL_DEPENDENCY_DIRS :=
# all_source_patterns contains the list of filename patterns that correspond
# to source files recognized by our build system
ifneq ($(filter x86 x86_64, $(TARGET_ARCH_ABI)),)
all_source_extensions := .c .s .S .asm $(LOCAL_CPP_EXTENSION)
else
all_source_extensions := .c .s .S $(LOCAL_CPP_EXTENSION)
endif
all_source_patterns := $(foreach _ext,$(all_source_extensions),%$(_ext))
all_cpp_patterns := $(foreach _ext,$(LOCAL_CPP_EXTENSION),%$(_ext))
unknown_sources := $(strip $(filter-out $(all_source_patterns),$(LOCAL_SRC_FILES)))
ifdef unknown_sources
$(call __ndk_info,WARNING: Unsupported source file extensions in $(LOCAL_MAKEFILE) for module $(LOCAL_MODULE))
$(call __ndk_info, $(unknown_sources))
endif
# LOCAL_OBJECTS will list all object files corresponding to the sources
# listed in LOCAL_SRC_FILES, in the *same* order.
#
LOCAL_OBJECTS := $(LOCAL_SRC_FILES)
$(foreach _ext,$(all_source_extensions),\
$(eval LOCAL_OBJECTS := $$(LOCAL_OBJECTS:%$(_ext)=%$$(TARGET_OBJ_EXTENSION)))\
)
LOCAL_OBJECTS := $(filter %$(TARGET_OBJ_EXTENSION),$(LOCAL_OBJECTS))
LOCAL_OBJECTS := $(subst ../,__/,$(LOCAL_OBJECTS))
LOCAL_OBJECTS := $(subst :,_,$(LOCAL_OBJECTS))
LOCAL_OBJECTS := $(foreach _obj,$(LOCAL_OBJECTS),$(LOCAL_OBJS_DIR)/$(_obj))
# If the module has any kind of C++ features, enable them in LOCAL_CPPFLAGS
#
ifneq (,$(call module-has-c++-features,$(LOCAL_MODULE),rtti))
LOCAL_CPPFLAGS += -frtti
endif
ifneq (,$(call module-has-c++-features,$(LOCAL_MODULE),exceptions))
LOCAL_CPPFLAGS += -fexceptions
endif
# Build PCH
get-pch-name = $(strip \
$(subst ../,__/,\
$(eval __pch := $1)\
$(eval __pch := $(__pch:%.h=%.precompiled.h))\
$(__pch)\
))
ifneq (,$(LOCAL_PCH))
# Build PCH into obj directory
LOCAL_BUILT_PCH := $(call get-pch-name,$(LOCAL_PCH))
# Clang whines about a "c-header" (.h rather than .hpp) being used in C++
# mode (note that we use compile-cpp-source to build the header).
LOCAL_SRC_FILES_TARGET_CFLAGS.$(LOCAL_PCH) += -x c++-header
# Build PCH
$(call compile-cpp-source,$(LOCAL_PCH),$(LOCAL_BUILT_PCH).gch)
# The PCH must be compiled the same way as the sources (thumb vs arm must
# match). This means that we'd have to generate a PCH for both foo.c and
# foo.c.arm.
#
# Since files with those source tags should be the minority, precompiling
# that header might be a net loss compared to just using it normally. As
# such, we only use the PCH for the default compilation mode for the module.
#
# See https://github.com/android-ndk/ndk/issues/14
TAGS_TO_FILTER :=
# If we're building thumb, strip out .arm files.
ifneq (arm,$(LOCAL_ARM_MODE))
TAGS_TO_FILTER += arm
endif
# There is no .thumb. No need to filter them out if we're building ARM.
allowed_src := $(foreach src,$(filter $(all_cpp_patterns),$(LOCAL_SRC_FILES)),\
$(if $(filter $(TAGS_TO_FILTER),$(LOCAL_SRC_FILES_TAGS.$(src))),,$(src))\
)
# All files without tags depend on PCH
$(foreach src,$(allowed_src),\
$(eval $(LOCAL_OBJS_DIR)/$(call get-object-name,$(src)) : $(LOCAL_OBJS_DIR)/$(LOCAL_BUILT_PCH).gch)\
)
# Make sure those files are built with PCH
$(call add-src-files-target-cflags,$(allowed_src),-Winvalid-pch -include $(LOCAL_OBJS_DIR)/$(LOCAL_BUILT_PCH))
# Insert PCH dir at beginning of include search path
LOCAL_C_INCLUDES := \
$(LOCAL_OBJS_DIR) \
$(LOCAL_C_INCLUDES)
endif
# Build the sources to object files
#
do_tidy := $(NDK_APP_CLANG_TIDY)
ifdef LOCAL_CLANG_TIDY
do_tidy := $(LOCAL_CLANG_TIDY)
endif
ifeq ($(do_tidy),true)
$(foreach src,$(filter %.c,$(LOCAL_SRC_FILES)),\
$(call clang-tidy-c,$(src),$(call get-object-name,$(src))))
$(foreach src,$(filter $(all_cpp_patterns),$(LOCAL_SRC_FILES)),\
$(call clang-tidy-cpp,$(src),$(call get-object-name,$(src))))
endif
$(foreach src,$(filter %.c,$(LOCAL_SRC_FILES)), $(call compile-c-source,$(src),$(call get-object-name,$(src))))
$(foreach src,$(filter %.S %.s,$(LOCAL_SRC_FILES)), $(call compile-s-source,$(src),$(call get-object-name,$(src))))
$(foreach src,$(filter $(all_cpp_patterns),$(LOCAL_SRC_FILES)),\
$(call compile-cpp-source,$(src),$(call get-object-name,$(src)))\
)
ifneq ($(filter x86 x86_64, $(TARGET_ARCH_ABI)),)
$(foreach src,$(filter %.asm,$(LOCAL_SRC_FILES)), $(call compile-asm-source,$(src),$(call get-object-name,$(src))))
endif
#
# The compile-xxx-source calls updated LOCAL_OBJECTS and LOCAL_DEPENDENCY_DIRS
#
ALL_DEPENDENCY_DIRS += $(sort $(LOCAL_DEPENDENCY_DIRS))
CLEAN_OBJS_DIRS += $(LOCAL_OBJS_DIR)
#
# Handle the static and shared libraries this module depends on
#
# https://github.com/android/ndk/issues/885
# If we're using LLD we need to use a slower build-id algorithm to work around
# the old version of LLDB in Android Studio, which doesn't understand LLD's
# default hash ("fast").
linker_ldflags := -Wl,--build-id=sha1
ifneq (,$(call lt,$(APP_PLATFORM_LEVEL),30))
# https://github.com/android/ndk/issues/1196
# https://github.com/android/ndk/issues/1589
linker_ldflags += -Wl,--no-rosegment
endif
my_ldflags := $(TARGET_LDFLAGS) $(linker_ldflags) $(NDK_APP_LDFLAGS) $(LOCAL_LDFLAGS)
# https://github.com/android/ndk/issues/1390
# Only a warning rather than an error because the API level cannot be configured
# on a per-module basis. If the user has an APP_PLATFORM that happens to be able
# to build the static executables there's no need to fail the build.
ifneq (,$(filter -static,$(my_ldflags)))
ifneq ($(APP_PLATFORM),$(NDK_MAX_PLATFORM))
$(call __ndk_info,WARNING: Building static executable but APP_PLATFORM \
$(APP_PLATFORM) is not the latest API level $(NDK_MAX_PLATFORM). \
Build may not succeed.)
endif
endif
# When LOCAL_SHORT_COMMANDS is defined to 'true' we are going to write the
# list of all object files and/or static/shared libraries that appear on the
# command line to a file, then use the @<listfile> syntax to invoke it.
#
# This allows us to link or archive a huge number of stuff even on Windows
# with its puny 8192 max character limit on its command-line.
#
LOCAL_SHORT_COMMANDS := $(strip $(LOCAL_SHORT_COMMANDS))
ifndef LOCAL_SHORT_COMMANDS
LOCAL_SHORT_COMMANDS := $(strip $(NDK_APP_SHORT_COMMANDS))
endif
$(call generate-file-dir,$(LOCAL_BUILT_MODULE))
$(LOCAL_BUILT_MODULE): PRIVATE_OBJECTS := $(LOCAL_OBJECTS)
$(LOCAL_BUILT_MODULE): PRIVATE_LIBATOMIC := $(TARGET_LIBATOMIC)
$(LOCAL_BUILT_MODULE): PRIVATE_LD := $(TARGET_LD)
$(LOCAL_BUILT_MODULE): PRIVATE_LDFLAGS := $(my_ldflags)
$(LOCAL_BUILT_MODULE): PRIVATE_LDLIBS := $(LOCAL_LDLIBS) $(TARGET_LDLIBS)
$(LOCAL_BUILT_MODULE): PRIVATE_NAME := $(notdir $(LOCAL_BUILT_MODULE))
$(LOCAL_BUILT_MODULE): PRIVATE_CXX := $(TARGET_CXX)
$(LOCAL_BUILT_MODULE): PRIVATE_CC := $(TARGET_CC)
$(LOCAL_BUILT_MODULE): PRIVATE_SYSROOT_API_LIB_DIR := $(SYSROOT_API_LIB_DIR)
ifeq (,$(call module_needs_clangxx,$(LOCAL_MODULE)))
$(LOCAL_BUILT_MODULE): PRIVATE_LD_DRIVER := $(TARGET_CC)
else
$(LOCAL_BUILT_MODULE): PRIVATE_LD_DRIVER := $(TARGET_CXX)
endif
ifeq ($(call module-get-class,$(LOCAL_MODULE)),STATIC_LIBRARY)
#
# This is a static library module, things are very easy. We only need
# to build the object files and archive them with 'ar'. Note that module
# dependencies can be ignored here, i.e. if the module depends on other
# static or shared libraries, there is no need to actually build them
# before, so don't add Make dependencies to them.
#
# In other words, consider the following graph:
#
# libfoo.so -> libA.a ->libB.a
#
# then libA.a and libB.a can be built in parallel, only linking libfoo.so
# depends on their completion.
#
ar_objects := $(call host-path,$(LOCAL_OBJECTS))
ifeq ($(LOCAL_SHORT_COMMANDS),true)
$(call ndk_log,Building static library module '$(LOCAL_MODULE)' with linker list file)
ar_list_file := $(LOCAL_OBJS_DIR)/archiver.list
$(call generate-list-file,\
$(call escape-backslashes,$(ar_objects)),$(ar_list_file))
ar_objects := @$(call host-path,$(ar_list_file))
$(LOCAL_BUILT_MODULE): $(ar_list_file)
endif
# Compute 'ar' flags. Thin archives simply require 'T' here.
ar_flags := $(TARGET_ARFLAGS)
ifeq (true,$(thin_archive))
$(call ndk_log,$(TARGET_ARCH_ABI):Building static library '$(LOCAL_MODULE)' as thin archive)
ar_flags := $(ar_flags)T
endif
$(LOCAL_BUILT_MODULE): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(LOCAL_BUILT_MODULE): PRIVATE_AR := $(TARGET_AR) $(ar_flags) $(TARGET_AR_FLAGS)
$(LOCAL_BUILT_MODULE): PRIVATE_AR_OBJECTS := $(ar_objects)
$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_STATIC_LIB := $(cmd-build-static-library)
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
$(call host-echo-build-step,$(PRIVATE_ABI),StaticLibrary) "$(PRIVATE_NAME)"
$(hide) $(call host-rm,$@)
$(hide) $(PRIVATE_BUILD_STATIC_LIB)
ALL_STATIC_LIBRARIES += $(LOCAL_BUILT_MODULE)
endif
ifneq (,$(filter SHARED_LIBRARY EXECUTABLE,$(call module-get-class,$(LOCAL_MODULE))))
#
# This is a shared library or an executable, so computing dependencies properly is
# crucial. The general rule to apply is the following:
#
# - collect the list of all static libraries that need to be part
# of the link, and in the right order. To do so, get the transitive
# closure of LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES
# and ensure they are ordered topologically.
#
# - collect the list of all shared libraries that need to be part of
# the link. This is the transitive closure of the list of
# LOCAL_SHARED_LIBRARIES for the module and all its dependent static
# libraries identified in the step above. Of course, need to be
# ordered topologically too.
#
# - add Make dependencies to ensure that all these libs are built
# before the module itself too.
#
# A few quick examples:
#
# main.exe -> libA.a -> libB.a -> libfoo.so -> libC.a
#
# static_libs(main.exe) = libA.a libB.a (i.e. no libC.a)
# shared_libs(main.exe) = libfoo.so
# static_libs(libfoo.so) = libC.a
#
# main.exe -> libA.a ---> libB.a
# | ^
# v |
# libC.a ------
#
# static_libs(main.exe) = libA.a libC.a libB.a
# (i.e. libB.a must appear after all libraries that depend on it).
#
all_libs := $(call module-get-link-libs,$(LOCAL_MODULE))
shared_libs := $(call module-filter-shared-libraries,$(all_libs))
static_libs := $(call module-filter-static-libraries,$(all_libs))
whole_static_libs := $(call module-extract-whole-static-libs,$(LOCAL_MODULE),$(static_libs))
static_libs := $(filter-out $(whole_static_libs),$(static_libs))
all_defined_libs := $(shared_libs) $(static_libs) $(whole_static_libs)
undefined_libs := $(filter-out $(all_defined_libs),$(all_libs))
ifdef undefined_libs
$(call __ndk_warning,Module $(LOCAL_MODULE) depends on undefined modules: $(undefined_libs))
# https://github.com/android-ndk/ndk/issues/208
# ndk-build didn't used to fail the build for a missing dependency. This
# seems to have always been the behavior, so there's a good chance that
# there are builds out there that depend on this behavior (as of right now,
# anything using libc++ on ARM has this problem because of libunwind).
#
# By default we will abort in this situation because this is so completely
# broken. A user may define APP_ALLOW_MISSING_DEPS to "true" in their
# Application.mk or on the command line to revert to the old, broken
# behavior.
ifneq ($(APP_ALLOW_MISSING_DEPS),true)
$(call __ndk_error,Note that old versions of ndk-build silently ignored \
this error case. If your project worked on those versions$(comma) \
the missing libraries were not needed and you can remove those \
dependencies from the module to fix your build. \
Alternatively$(comma) set APP_ALLOW_MISSING_DEPS=true to allow \
missing dependencies.)
$(call __ndk_error,Aborting.)
endif
endif
$(call -ndk-mod-debug,module $(LOCAL_MODULE) [$(LOCAL_BUILT_MODULE)])
$(call -ndk-mod-debug,. all_libs='$(all_libs)')
$(call -ndk-mod-debug,. shared_libs='$(shared_libs)')
$(call -ndk-mod-debug,. static_libs='$(static_libs)')
$(call -ndk-mod-debug,. whole_static_libs='$(whole_static_libs)')
shared_libs := $(call map,module-get-built,$(shared_libs))
static_libs := $(call map,module-get-built,$(static_libs))
whole_static_libs := $(call map,module-get-built,$(whole_static_libs))
$(call -ndk-mod-debug,. built_shared_libs='$(shared_libs)')
$(call -ndk-mod-debug,. built_static_libs='$(static_libs)')
$(call -ndk-mod-debug,. built_whole_static_libs='$(whole_static_libs)')
# The list of object/static/shared libraries passed to the linker when
# building shared libraries and executables. order is important.
linker_objects_and_libraries = $(strip $(call TARGET-get-linker-objects-and-libraries,\
$(LOCAL_OBJECTS), \
$(static_libs), \
$(whole_static_libs), \
$(shared_libs)))
ifeq ($(LOCAL_SHORT_COMMANDS),true)
$(call ndk_log,Building ELF binary module '$(LOCAL_MODULE)' with linker list file)
linker_options := $(linker_objects_and_libraries)
linker_list_file := $(LOCAL_OBJS_DIR)/linker.list
linker_objects_and_libraries := @$(call host-path,$(linker_list_file))
$(call generate-list-file,\
$(call escape-backslashes,$(linker_options)),$(linker_list_file))
$(LOCAL_BUILT_MODULE): $(linker_list_file)
endif
$(LOCAL_BUILT_MODULE): $(shared_libs) $(static_libs) $(whole_static_libs)
$(LOCAL_BUILT_MODULE): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(LOCAL_BUILT_MODULE): PRIVATE_LINKER_OBJECTS_AND_LIBRARIES := $(linker_objects_and_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_STATIC_LIBRARIES := $(static_libs)
$(LOCAL_BUILT_MODULE): PRIVATE_WHOLE_STATIC_LIBRARIES := $(whole_static_libs)
$(LOCAL_BUILT_MODULE): PRIVATE_SHARED_LIBRARIES := $(shared_libs)
endif
#
# If this is a shared library module
#
ifeq ($(call module-get-class,$(LOCAL_MODULE)),SHARED_LIBRARY)
$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_SHARED_LIB := $(cmd-build-shared-library)
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
$(call host-echo-build-step,$(PRIVATE_ABI),SharedLibrary) "$(PRIVATE_NAME)"
$(hide) $(PRIVATE_BUILD_SHARED_LIB)
ALL_SHARED_LIBRARIES += $(LOCAL_BUILT_MODULE)
endif
#
# If this is an executable module
#
ifeq ($(call module-get-class,$(LOCAL_MODULE)),EXECUTABLE)
$(LOCAL_BUILT_MODULE): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_EXECUTABLE := $(cmd-build-executable)
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
$(call host-echo-build-step,$(PRIVATE_ABI),Executable) "$(PRIVATE_NAME)"
$(hide) $(PRIVATE_BUILD_EXECUTABLE)
ALL_EXECUTABLES += $(LOCAL_BUILT_MODULE)
endif
#
# If this is a copyable prebuilt module
#
ifeq ($(call module-is-copyable,$(LOCAL_MODULE)),$(true))
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
$(call host-echo-build-step,$(PRIVATE_ABI),Prebuilt) "$(PRIVATE_NAME) <= $(call pretty-dir,$(dir $<))"
$(hide) $(call host-cp,$<,$@)
endif
ifeq ($(LOCAL_STRIP_MODE),)
NDK_STRIP_MODE := $(NDK_APP_STRIP_MODE)
else
NDK_STRIP_MODE := $(LOCAL_STRIP_MODE)
endif
#
# If this is an installable module
#
ifeq ($(call module-is-installable,$(LOCAL_MODULE)),$(true))
$(LOCAL_INSTALLED): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(LOCAL_INSTALLED): PRIVATE_NAME := $(notdir $(LOCAL_BUILT_MODULE))
$(LOCAL_INSTALLED): PRIVATE_SRC := $(LOCAL_BUILT_MODULE)
$(LOCAL_INSTALLED): PRIVATE_DST_DIR := $(NDK_APP_DST_DIR)
$(LOCAL_INSTALLED): PRIVATE_DST := $(LOCAL_INSTALLED)
$(LOCAL_INSTALLED): PRIVATE_STRIP := $(TARGET_STRIP)
$(LOCAL_INSTALLED): PRIVATE_STRIP_MODE := $(NDK_STRIP_MODE)
$(LOCAL_INSTALLED): PRIVATE_STRIP_CMD := $(call cmd-strip, $(PRIVATE_DST))
$(LOCAL_INSTALLED): $(LOCAL_BUILT_MODULE) clean-installed-binaries
$(call host-echo-build-step,$(PRIVATE_ABI),Install) "$(PRIVATE_NAME) => $(call pretty-dir,$(PRIVATE_DST))"
$(hide) $(call host-install,$(PRIVATE_SRC),$(PRIVATE_DST))
$(if $(filter none,$(PRIVATE_STRIP_MODE)),,$(hide) $(PRIVATE_STRIP_CMD))
$(call generate-file-dir,$(LOCAL_INSTALLED))
endif

View File

@ -0,0 +1,31 @@
# Copyright (C) 2009 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.
#
# this file is included from Android.mk files to build a target-specific
# executable program
#
LOCAL_BUILD_SCRIPT := BUILD_EXECUTABLE
LOCAL_MAKEFILE := $(local-makefile)
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
$(call check-LOCAL_MODULE_FILENAME)
$(call handle-module-filename,,)
$(call handle-module-built)
LOCAL_MODULE_CLASS := EXECUTABLE
include $(BUILD_SYSTEM)/build-module.mk

View File

@ -0,0 +1,225 @@
# Copyright (C) 2010 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.
#
# This file is designed to be called from the 'ndk-build' script
# or similar wrapper tool.
#
# Detect the NDK installation path by processing this Makefile's location.
# This assumes we are located under $NDK_ROOT/build/core/main.mk
#
# Don't output to stdout if we're being invoked to dump a variable
DUMP_VAR := $(patsubst DUMP_%,%,$(filter DUMP_%,$(MAKECMDGOALS)))
ifneq (,$(DUMP_VAR))
NDK_NO_INFO := 1
NDK_NO_WARNINGS := 1
endif
NDK_ROOT := $(dir $(lastword $(MAKEFILE_LIST)))
NDK_ROOT := $(subst \,/,$(NDK_ROOT))
NDK_ROOT := $(strip $(NDK_ROOT:%build/core/=%))
NDK_ROOT := $(NDK_ROOT:%/=%)
ifeq ($(NDK_ROOT),)
# for the case when we're invoked from the NDK install path
NDK_ROOT := .
endif
ifeq ($(NDK_LOG),1)
$(info Android NDK: NDK installation path auto-detected: '$(NDK_ROOT)')
endif
ifneq ($(words $(NDK_ROOT)),1)
$(info Android NDK: Your NDK installation path contains spaces.)
$(info Android NDK: Please re-install to a different location to fix the issue !)
$(error Aborting.)
endif
include $(NDK_ROOT)/build/core/init.mk
# ====================================================================
#
# If NDK_PROJECT_PATH is not defined, find the application's project
# path by looking at the manifest file in the current directory or
# any of its parents. If none is found, try again with 'jni/Android.mk'
#
# Note that we first look at the current directory to avoid using
# absolute NDK_PROJECT_PATH values. This reduces the length of all
# source, object and binary paths that are passed to build commands.
#
# It turns out that some people use ndk-build to generate static
# libraries without a full Android project tree.
#
# If NDK_PROJECT_PATH=null, ndk-build make no attempt to look for it, but does
# need the following variables depending on NDK_PROJECT_PATH to be explicitly
# specified (from the default, if any):
#
# NDK_OUT
# NDK_LIBS_OUT
# APP_BUILD_SCRIPT
# NDK_DEBUG (optional, default to 0)
# Other APP_* used to be in Application.mk
#
# This behavior may be useful in an integrated build system.
#
# ====================================================================
find-project-dir = $(strip $(call find-project-dir-inner,$(abspath $1),$2))
find-project-dir-inner = \
$(eval __found_project_path := )\
$(eval __find_project_path := $1)\
$(eval __find_project_file := $2)\
$(call find-project-dir-inner-2)\
$(__found_project_path)
find-project-dir-inner-2 = \
$(call ndk_log,Looking for $(__find_project_file) in $(__find_project_path))\
$(eval __find_project_manifest := $(strip $(wildcard $(__find_project_path)/$(__find_project_file))))\
$(if $(__find_project_manifest),\
$(call ndk_log, Found it !)\
$(eval __found_project_path := $(__find_project_path))\
,\
$(eval __find_project_parent := $(call parent-dir,$(__find_project_path)))\
$(if $(__find_project_parent),\
$(eval __find_project_path := $(__find_project_parent))\
$(call find-project-dir-inner-2)\
)\
)
NDK_PROJECT_PATH := $(strip $(NDK_PROJECT_PATH))
APP_PROJECT_PATH := $(strip $(APP_PROJECT_PATH))
ifneq (,$(APP_PROJECT_PATH))
ifeq (,$(NDK_PROJECT_PATH))
# If NDK_PROJECT_PATH isn't set and APP_PROJECT_PATH is present, use APP_PROJECT_PATH
$(call ndk_log,Use APP_PROJECT_PATH for NDK_PROJECT_PATH: $(APP_PROJECT_PATH))
NDK_PROJECT_PATH := $(APP_PROJECT_PATH)
else
# If both NDK_PROJECT_PATH and APP_PROJECT_PATH are present, check consistency
ifneq ($(NDK_PROJECT_PATH),$(APP_PROJECT_PATH))
$(call __ndk_info,WARNING: NDK_PROJECT_PATH and APP_PROJECT_PATH are both set but not equal literally)
$(call __ndk_info, NDK_PROJECT_PATH = $(NDK_PROJECT_PATH))
$(call __ndk_info, APP_PROJECT_PATH = $(APP_PROJECT_PATH))
endif
endif
endif
ifeq (null,$(NDK_PROJECT_PATH))
$(call ndk_log,Make no attempt to look for NDK_PROJECT_PATH.)
else
# To keep paths as short as possible during the build, we first look if the
# current directory is the top of our project path. If this is the case, we
# will define NDK_PROJECT_PATH to simply '.'
#
# Otherwise, we will use find-project-dir which will first get the absolute
# path of the current directory the climb back the hierarchy until we find
# something. The result will always be a much longer definition for
# NDK_PROJECT_PATH
#
ifndef NDK_PROJECT_PATH
ifneq (,$(strip $(wildcard AndroidManifest.xml)))
NDK_PROJECT_PATH := .
else
ifneq (,$(strip $(wildcard jni/Android.mk)))
NDK_PROJECT_PATH := .
endif
endif
endif
ifndef NDK_PROJECT_PATH
NDK_PROJECT_PATH := $(call find-project-dir,.,jni/Android.mk)
endif
ifndef NDK_PROJECT_PATH
NDK_PROJECT_PATH := $(call find-project-dir,.,AndroidManifest.xml)
endif
ifndef NDK_PROJECT_PATH
$(call __ndk_info,Could not find application project directory !)
$(call __ndk_info,Please define the NDK_PROJECT_PATH variable to point to it.)
$(call __ndk_error,Aborting)
endif
# Check that there are no spaces in the project path, or bad things will happen
ifneq ($(words $(NDK_PROJECT_PATH)),1)
$(call __ndk_info,Your Android application project path contains spaces: '$(NDK_PROJECT_PATH)')
$(call __ndk_info,The Android NDK build cannot work here. Please move your project to a different location.)
$(call __ndk_error,Aborting.)
endif
$(call ndk_log,Found project path: $(NDK_PROJECT_PATH))
NDK_APPLICATION_MK := $(strip $(wildcard $(NDK_PROJECT_PATH)/jni/Application.mk))
endif # NDK_PROJECT_PATH == null
ifndef NDK_APPLICATION_MK
NDK_APPLICATION_MK := $(NDK_ROOT)/build/core/default-application.mk
endif
# Place all generated intermediate files here
NDK_APP_OUT := $(strip $(NDK_OUT))
ifndef NDK_APP_OUT
ifeq (null,$(NDK_PROJECT_PATH))
$(call __ndk_info,NDK_PROJECT_PATH==null. Please explicitly set NDK_OUT to directory for all generated intermediate files.)
$(call __ndk_error,Aborting.)
endif
NDK_APP_OUT := $(NDK_PROJECT_PATH)/obj
endif
$(call ndk_log,Ouput path for intermediate files: $(NDK_APP_OUT))
# Place all generated library files here. This is rarely changed since aapt expects the default libs/
NDK_APP_LIBS_OUT := $(strip $(NDK_LIBS_OUT))
ifndef NDK_APP_LIBS_OUT
ifeq (null,$(NDK_PROJECT_PATH))
$(call __ndk_info,NDK_PROJECT_PATH==null. Please explicitly set NDK_LIBS_OUT to directory for generated library files.)
$(call __ndk_error,Aborting.)
endif
NDK_APP_LIBS_OUT := $(NDK_PROJECT_PATH)/libs
endif
$(call ndk_log,Ouput path for generated library files: $(NDK_APP_LIBS_OUT))
# Fake an application named 'local'
_app := local
_application_mk := $(NDK_APPLICATION_MK)
NDK_APPS := $(_app)
include $(BUILD_SYSTEM)/add-application.mk
# If a goal is DUMP_xxx then we dump a variable xxx instead
# of building anything
#
MAKECMDGOALS := $(filter-out DUMP_$(DUMP_VAR),$(MAKECMDGOALS))
include $(BUILD_SYSTEM)/setup-imports.mk
ifneq (,$(DUMP_VAR))
# We only support a single DUMP_XXX goal at a time for now.
ifneq ($(words $(DUMP_VAR)),1)
$(call __ndk_error,!!TOO-MANY-DUMP-VARIABLES!!)
endif
$(foreach _app,$(NDK_APPS),\
$(eval include $(BUILD_SYSTEM)/setup-app.mk)\
)
.PHONY : DUMP_$(DUMP_VAR)
DUMP_$(DUMP_VAR):
@echo $($(DUMP_VAR))
else
# Build it
include $(BUILD_SYSTEM)/build-all.mk
endif

View File

@ -0,0 +1,46 @@
# Copyright (C) 2010 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.
#
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
# This file is used to record the LOCAL_XXX definitions of a given
# module. It is included by BUILD_STATIC_LIBRARY, BUILD_SHARED_LIBRARY
# and others.
#
LOCAL_MODULE_CLASS := $(strip $(LOCAL_MODULE_CLASS))
ifndef LOCAL_MODULE_CLASS
$(call __ndk_info,$(LOCAL_MAKEFILE):$(LOCAL_MODULE): LOCAL_MODULE_CLASS definition is missing !)
$(call __ndk_error,Aborting)
endif
$(if $(call module-class-check,$(LOCAL_MODULE_CLASS)),,\
$(call __ndk_info,$(LOCAL_MAKEFILE):$(LOCAL_MODULE): Unknown LOCAL_MODULE_CLASS value: $(LOCAL_MODULE_CLASS))\
$(call __ndk_error,Aborting)\
)
$(call module-add,$(LOCAL_MODULE))
# Eval sucks. It's not possible to preserve even properly escaped # characters
# as far as I can tell, and we need that for -Werror=#warnings. Manually stash
# all the flags variations so we can preserve these.
__ndk_modules.$(LOCAL_MODULE).ASFLAGS := $(LOCAL_ASFLAGS)
__ndk_modules.$(LOCAL_MODULE).ASMFLAGS := $(LOCAL_ASMFLAGS)
__ndk_modules.$(LOCAL_MODULE).CFLAGS := $(LOCAL_CFLAGS)
__ndk_modules.$(LOCAL_MODULE).CLANG_TIDY_FLAGS := $(LOCAL_CLANG_TIDY_FLAGS)
__ndk_modules.$(LOCAL_MODULE).CONLYFLAGS := $(LOCAL_CONLYFLAGS)
__ndk_modules.$(LOCAL_MODULE).CPPFLAGS := $(LOCAL_CPPFLAGS)
__ndk_modules.$(LOCAL_MODULE).CXXFLAGS := $(LOCAL_CXXFLAGS)
__ndk_modules.$(LOCAL_MODULE).LDFLAGS := $(LOCAL_LDFLAGS)

View File

@ -0,0 +1,31 @@
# Copyright (C) 2009 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.
#
# this file is included from Android.mk files to build a target-specific
# shared library
#
LOCAL_BUILD_SCRIPT := BUILD_SHARED_LIBRARY
LOCAL_MAKEFILE := $(local-makefile)
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
$(call check-LOCAL_MODULE_FILENAME)
$(call handle-module-filename,lib,$(TARGET_SONAME_EXTENSION))
$(call handle-module-built)
LOCAL_MODULE_CLASS := SHARED_LIBRARY
include $(BUILD_SYSTEM)/build-module.mk

View File

@ -0,0 +1,31 @@
# Copyright (C) 2009 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.
#
# this file is included from Android.mk files to build a target-specific
# static library
#
LOCAL_BUILD_SCRIPT := BUILD_STATIC_LIBRARY
LOCAL_MAKEFILE := $(local-makefile)
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
$(call handle-module-filename,lib,$(TARGET_LIB_EXTENSION))
$(call handle-module-built)
LOCAL_MODULE_CLASS := STATIC_LIBRARY
include $(BUILD_SYSTEM)/build-module.mk

View File

@ -0,0 +1,43 @@
# Copyright (C) 2010 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.
#
# Check that we have a Cygwin-compatible make.
#
# For some reason, a lot of application developers on Windows
# have another GNU Make installed in their path, that fails
# miserably with our build scripts. If we can detect this use
# case, early, we will be able to dump a human-readable error
# message with some help to fix the issue.
#
.PHONY: all
all:
# Get the cygwin-specific path to the make executable
# (e.g. /cygdrive/c/cygwin/usr/bin/make), then strip the
# .exe suffix, if any.
#
CYGWIN_MAKE := $(shell cygpath --unix --absolute $(firstword $(MAKE)))
CYGWIN_MAKE := $(CYGWIN_MAKE:%.exe=%)
# Now try to find it on the file system, a non-cygwin compatible
# GNU Make, even if launched from a Cygwin shell, will not
#
SELF_MAKE := $(strip $(wildcard $(CYGWIN_MAKE).exe))
ifeq ($(SELF_MAKE),)
$(error Android NDK: $(firstword $(MAKE)) is not cygwin-compatible)
endif
# that's all

View File

@ -0,0 +1,23 @@
# Copyright (C) 2009 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.
#
# this file is included repeatedly from Android.mk files in order to clean
# the module-specific variables from the environment,
# Note: As a special exception, we don't want to clear LOCAL_PATH
$(call clear-vars, $(filter-out LOCAL_PATH,$(modules-LOCALS:%=LOCAL_%)))
# strip LOCAL_PATH
LOCAL_PATH := $(strip $(LOCAL_PATH))

View File

@ -0,0 +1,28 @@
# Copyright (C) 2010 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.
#
# This is the default Application.mk that is being used for applications
# that don't provide $PROJECT_PATH/jni/Application.mk
#
APP_PROJECT_PATH := $(NDK_PROJECT_PATH)
# We expect the build script to be located here
ifndef APP_BUILD_SCRIPT
ifeq (null,$(NDK_PROJECT_PATH))
$(call __ndk_info,NDK_PROJECT_PATH==null. Please explicitly set APP_BUILD_SCRIPT.)
$(call __ndk_error,Aborting.)
endif
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/Android.mk
endif

View File

@ -0,0 +1,155 @@
# The following definitions are the defaults used by all toolchains.
# This is included in setup-toolchain.mk just before the inclusion
# of the toolchain's specific setup.mk file which can then override
# these definitions.
#
# These flags are used to ensure that a binary doesn't reference undefined
# flags.
TARGET_NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined
# Return the list of object, static libraries and shared libraries as they
# must appear on the final static linker command (order is important).
#
# This can be over-ridden by a specific toolchain. Note that by default
# we always put libgcc _after_ all static libraries and _before_ shared
# libraries. This ensures that any libgcc function used by the final
# executable will be copied into it. Otherwise, it could contain
# symbol references to the same symbols as exported by shared libraries
# and this causes binary compatibility problems when they come from
# system libraries (e.g. libc.so and others).
#
# IMPORTANT: The result must use the host path convention.
#
# $1: object files
# $2: static libraries
# $3: whole static libraries
# $4: shared libraries
#
TARGET-get-linker-objects-and-libraries = \
$(call host-path, $1) \
$(call link-whole-archives,$3) \
$(call host-path, $2) \
$(PRIVATE_LIBATOMIC) \
$(call host-path, $4) \
# This flag are used to provide compiler protection against format
# string vulnerabilities.
TARGET_FORMAT_STRING_CFLAGS := -Wformat -Werror=format-security
# This flag disables the above security checks
TARGET_DISABLE_FORMAT_STRING_CFLAGS := -Wno-error=format-security
define cmd-build-shared-library
$(PRIVATE_LD_DRIVER) \
-Wl,-soname,$(notdir $(LOCAL_BUILT_MODULE)) \
-shared \
$(PRIVATE_LINKER_OBJECTS_AND_LIBRARIES) \
$(GLOBAL_LDFLAGS) \
$(PRIVATE_LDFLAGS) \
$(PRIVATE_LDLIBS) \
-o $(call host-path,$(LOCAL_BUILT_MODULE))
endef
# The following -rpath-link= are needed for ld.bfd (default for ARM64) when
# linking executables to supress warning about missing symbol from libraries not
# directly needed. ld.gold (default for all other architectures) doesn't emulate
# this buggy behavior.
define cmd-build-executable
$(PRIVATE_LD_DRIVER) \
-Wl,-rpath-link=$(call host-path,$(PRIVATE_SYSROOT_API_LIB_DIR)) \
-Wl,-rpath-link=$(call host-path,$(TARGET_OUT)) \
$(PRIVATE_LINKER_OBJECTS_AND_LIBRARIES) \
$(GLOBAL_LDFLAGS) \
$(PRIVATE_LDFLAGS) \
$(PRIVATE_LDLIBS) \
-o $(call host-path,$(LOCAL_BUILT_MODULE))
endef
define cmd-build-static-library
$(PRIVATE_AR) $(call host-path,$(LOCAL_BUILT_MODULE)) $(PRIVATE_AR_OBJECTS)
endef
cmd-strip = $(PRIVATE_STRIP) $(PRIVATE_STRIP_MODE) $(call host-path,$1)
# arm32 currently uses a linker script in place of libgcc to ensure that
# libunwind is linked in the correct order. --exclude-libs does not propagate to
# the contents of the linker script and can't be specified within the linker
# script. Hide both regardless of architecture to future-proof us in case we
# move other architectures to a linker script (which we may want to do so we
# automatically link libclangrt on other architectures).
TARGET_LIBATOMIC = -latomic
TARGET_LDLIBS := -lc -lm
LLVM_TOOLCHAIN_PREFIX := $(TOOLCHAIN_ROOT)/bin/
# IMPORTANT: The following definitions must use lazy assignment because
# the value of TOOLCHAIN_NAME or TARGET_CFLAGS can be changed later by
# the toolchain's setup.mk script.
TOOLCHAIN_PREFIX = $(TOOLCHAIN_ROOT)/bin/$(TOOLCHAIN_NAME)-
TARGET_CC = $(LLVM_TOOLCHAIN_PREFIX)clang$(HOST_EXEEXT)
TARGET_CXX = $(LLVM_TOOLCHAIN_PREFIX)clang++$(HOST_EXEEXT)
CLANG_TIDY = $(LLVM_TOOLCHAIN_PREFIX)clang-tidy$(HOST_EXEEXT)
GLOBAL_CFLAGS = \
-target $(LLVM_TRIPLE)$(TARGET_PLATFORM_LEVEL) \
-fdata-sections \
-ffunction-sections \
-fstack-protector-strong \
-funwind-tables \
-no-canonical-prefixes \
# This is unnecessary given the new toolchain layout, but Studio will not
# recognize this as an Android build if there is no --sysroot flag.
# TODO: Teach Studio to recognize Android builds based on --target.
GLOBAL_CFLAGS += --sysroot $(call host-path,$(NDK_UNIFIED_SYSROOT_PATH))
# Always enable debug info. We strip binaries when needed.
GLOBAL_CFLAGS += -g
# TODO: Remove.
GLOBAL_CFLAGS += \
-Wno-invalid-command-line-argument \
-Wno-unused-command-line-argument \
GLOBAL_CFLAGS += -D_FORTIFY_SOURCE=2
ifeq ($(APP_WEAK_API_DEFS), true)
GLOBAL_CFLAGS += \
-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__ \
-Werror=unguarded-availability \
endif
GLOBAL_LDFLAGS = \
-target $(LLVM_TRIPLE)$(TARGET_PLATFORM_LEVEL) \
-no-canonical-prefixes \
ifeq ($(APP_OPTIM),release)
GLOBAL_LDFLAGS += -Wl,--gc-sections
endif
GLOBAL_CXXFLAGS = $(GLOBAL_CFLAGS) -fno-exceptions -fno-rtti
TARGET_CFLAGS =
TARGET_CONLYFLAGS =
TARGET_CXXFLAGS = $(TARGET_CFLAGS)
TARGET_ASM = $(TOOLCHAIN_ROOT)/bin/yasm
TARGET_ASMFLAGS =
TARGET_LD = $(TOOLCHAIN_ROOT)/bin/ld
TARGET_LDFLAGS :=
TARGET_AR = $(LLVM_TOOLCHAIN_PREFIX)llvm-ar$(HOST_EXEEXT)
TARGET_ARFLAGS := crsD
TARGET_STRIP = $(LLVM_TOOLCHAIN_PREFIX)llvm-strip$(HOST_EXEEXT)
TARGET_OBJ_EXTENSION := .o
TARGET_LIB_EXTENSION := .a
TARGET_SONAME_EXTENSION := .so

View File

@ -0,0 +1,27 @@
#
# Copyright (C) 2021 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.
#
# https://github.com/android/ndk/issues/1559
#
# When LOCAL_ALLOW_MISSING_PREBUILT is true we avoid checking for missing
# prebuilt libraries early and instead let the copy rule fail. This leads to a
# worse diagnostic but supports the use case where AGP runs `ndk-build -n` to
# get the build commands during sync time and the "pre" built library is
# actually built by another module that hasn't been built yet.
#
# This phony target is only generated when the library actually is missing (see
# the callsite in prebuilt-library.mk).
.PHONY: $(prebuilt)

View File

@ -0,0 +1,538 @@
# Copyright (C) 2012 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.
#
# Definitions of various graph-related generic functions, used by
# ndk-build internally.
#
# Coding style note:
#
# All internal variables in this file begin with '_ndk_mod_'
# All internal functions in this file begin with '-ndk-mod-'
#
# Set this to true if you want to debug the functions here.
_ndk_mod_debug := $(if $(NDK_DEBUG_MODULES),true)
_ndk_topo_debug := $(if $(NDK_DEBUG_TOPO),true)
# Use $(call -ndk-mod-debug,<message>) to print a debug message only
# if _ndk_mod_debug is set to 'true'. Useful for debugging the functions
# available here.
#
ifeq (true,$(_ndk_mod_debug))
-ndk-mod-debug = $(info $1)
else
-ndk-mod-debug := $(empty)
endif
ifeq (true,$(_ndk_topo_debug))
-ndk-topo-debug = $(info $1)
else
-ndk-topo-debug = $(empty)
endif
#######################################################################
# Filter a list of module with a predicate function
# $1: list of module names.
# $2: predicate function, will be called with $(call $2,<name>), if the
# result is not empty, <name> will be added to the result.
# Out: subset of input list, where each item passes the predicate.
#######################################################################
-ndk-mod-filter = $(strip \
$(foreach _ndk_mod_filter_n,$1,\
$(if $(call $2,$(_ndk_mod_filter_n)),$(_ndk_mod_filter_n))\
))
-test-ndk-mod-filter = \
$(eval -local-func = $$(call seq,foo,$$1))\
$(call test-expect,,$(call -ndk-mod-filter,,-local-func))\
$(call test-expect,foo,$(call -ndk-mod-filter,foo,-local-func))\
$(call test-expect,foo,$(call -ndk-mod-filter,foo bar,-local-func))\
$(call test-expect,foo foo,$(call -ndk-mod-filter,aaa foo bar foo,-local-func))\
$(eval -local-func = $$(call sne,foo,$$1))\
$(call test-expect,,$(call -ndk-mod-filter,,-local-func))\
$(call test-expect,,$(call -ndk-mod-filter,foo,-local-func))\
$(call test-expect,bar,$(call -ndk-mod-filter,foo bar,-local-func))\
$(call test-expect,aaa bar,$(call -ndk-mod-filter,aaa foo bar,-local-func))
#######################################################################
# Filter out a list of modules with a predicate function
# $1: list of module names.
# $2: predicate function, will be called with $(call $2,<name>), if the
# result is not empty, <name> will be added to the result.
# Out: subset of input list, where each item doesn't pass the predicate.
#######################################################################
-ndk-mod-filter-out = $(strip \
$(foreach _ndk_mod_filter_n,$1,\
$(if $(call $2,$(_ndk_mod_filter_n)),,$(_ndk_mod_filter_n))\
))
-test-ndk-mod-filter-out = \
$(eval -local-func = $$(call seq,foo,$$1))\
$(call test-expect,,$(call -ndk-mod-filter-out,,-local-func))\
$(call test-expect,,$(call -ndk-mod-filter-out,foo,-local-func))\
$(call test-expect,bar,$(call -ndk-mod-filter-out,foo bar,-local-func))\
$(call test-expect,aaa bar,$(call -ndk-mod-filter-out,aaa foo bar foo,-local-func))\
$(eval -local-func = $$(call sne,foo,$$1))\
$(call test-expect,,$(call -ndk-mod-filter-out,,-local-func))\
$(call test-expect,foo,$(call -ndk-mod-filter-out,foo,-local-func))\
$(call test-expect,foo,$(call -ndk-mod-filter-out,foo bar,-local-func))\
$(call test-expect,foo foo,$(call -ndk-mod-filter-out,aaa foo bar foo,-local-func))
#######################################################################
# Find the first item in a list that checks a valid predicate.
# $1: list of names.
# $2: predicate function, will be called with $(call $2,<name>), if the
# result is not empty, <name> will be added to the result.
# Out: subset of input list.
#######################################################################
-ndk-mod-find-first = $(firstword $(call -ndk-mod-filter,$1,$2))
-test-ndk-mod-find-first.empty = \
$(eval -local-pred = $$(call seq,foo,$$1))\
$(call test-expect,,$(call -ndk-mod-find-first,,-local-pred))\
$(call test-expect,,$(call -ndk-mod-find-first,bar,-local-pred))
-test-ndk-mod-find-first.simple = \
$(eval -local-pred = $$(call seq,foo,$$1))\
$(call test-expect,foo,$(call -ndk-mod-find-first,foo,-local-pred))\
$(call test-expect,foo,$(call -ndk-mod-find-first,aaa foo bar,-local-pred))\
$(call test-expect,foo,$(call -ndk-mod-find-first,aaa foo foo bar,-local-pred))
########################################################################
# Many tree walking operations require setting a 'visited' flag on
# specific graph nodes. The following helper functions help implement
# this while hiding details to the callers.
#
# Technical note:
# _ndk_mod_tree_visited.<name> will be 'true' if the node was visited,
# or empty otherwise.
#
# _ndk_mod_tree_visitors lists all visited nodes, used to clean all
# _ndk_mod_tree_visited.<name> variables in -ndk-mod-tree-setup-visit.
#
#######################################################################
# Call this before tree traversal.
-ndk-mod-tree-setup-visit = \
$(foreach _ndk_mod_tree_visitor,$(_ndk_mod_tree_visitors),\
$(eval _ndk_mod_tree_visited.$$(_ndk_mod_tree_visitor) :=))\
$(eval _ndk_mod_tree_visitors :=)
# Returns non-empty if a node was visited.
-ndk-mod-tree-is-visited = \
$(_ndk_mod_tree_visited.$1)
# Set the visited state of a node to 'true'
-ndk-mod-tree-set-visited = \
$(eval _ndk_mod_tree_visited.$1 := true)\
$(eval _ndk_mod_tree_visitors += $1)
########################################################################
# Many graph walking operations require a work queue and computing
# dependencies / children nodes. Here are a few helper functions that
# can be used to make their code clearer. This uses a few global
# variables that should be defined as follows during the operation:
#
# _ndk_mod_module current graph node name.
# _ndk_mod_wq current node work queue.
# _ndk_mod_list current result (list of nodes).
# _ndk_mod_depends current graph node's children.
# you must call -ndk-mod-get-depends to set this.
#
#######################################################################
# Pop first item from work-queue into _ndk_mod_module.
-ndk-mod-pop-first = \
$(eval _ndk_mod_module := $$(call first,$$(_ndk_mod_wq)))\
$(eval _ndk_mod_wq := $$(call rest,$$(_ndk_mod_wq)))
-test-ndk-mod-pop-first = \
$(eval _ndk_mod_wq := A B C)\
$(call -ndk-mod-pop-first)\
$(call test-expect,A,$(_ndk_mod_module))\
$(call test-expect,B C,$(_ndk_mod_wq))\
# Push list of items at the back of the work-queue.
-ndk-mod-push-back = \
$(eval _ndk_mod_wq := $(strip $(_ndk_mod_wq) $1))
-test-ndk-mod-push-back = \
$(eval _ndk_mod_wq := A B C)\
$(call -ndk-mod-push-back, D E)\
$(call test-expect,A B C D E,$(_ndk_mod_wq))
# Set _ndk_mod_depends to the direct dependencies of _ndk_mod_module
-ndk-mod-get-depends = \
$(eval _ndk_mod_depends := $$(call $$(_ndk_mod_deps_func),$$(_ndk_mod_module)))
# Set _ndk_mod_depends to the direct dependencies of _ndk_mod_module that
# are not already in _ndk_mod_list.
-ndk-mod-get-new-depends = \
$(call -ndk-mod-get-depends)\
$(eval _ndk_mod_depends := $$(filter-out $$(_ndk_mod_list),$$(_ndk_mod_depends)))
##########################################################################
# Compute the transitive closure
# $1: list of modules.
# $2: dependency function, $(call $2,<module>) should return all the
# module that <module> depends on.
# Out: transitive closure of all modules from those in $1. Always includes
# the modules in $1. Order is random.
#
# Implementation note:
# we use the -ndk-mod-tree-xxx functions to flag 'visited' nodes
# in the graph. A node is visited once it has been put into the work
# queue. For each item in the work queue, get the dependencies and
# append all those that were not visited yet.
#######################################################################
-ndk-mod-get-closure = $(strip \
$(eval _ndk_mod_wq :=)\
$(eval _ndk_mod_list :=)\
$(eval _ndk_mod_deps_func := $2)\
$(call -ndk-mod-tree-setup-visit)\
$(foreach _ndk_mod_module,$1,\
$(call -ndk-mod-closure-visit,$(_ndk_mod_module))\
)\
$(call -ndk-mod-closure-recursive)\
$(eval _ndk_mod_deps :=)\
$(_ndk_mod_list)\
)
# Used internally to visit a new node during -ndk-mod-get-closure.
# This appends the node to the work queue, and set its 'visit' flag.
-ndk-mod-closure-visit = \
$(call -ndk-mod-push-back,$1)\
$(call -ndk-mod-tree-set-visited,$1)
-ndk-mod-closure-recursive = \
$(call -ndk-mod-pop-first)\
$(eval _ndk_mod_list += $$(_ndk_mod_module))\
$(call -ndk-mod-get-depends)\
$(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
$(if $(call -ndk-mod-tree-is-visited,$(_ndk_mod_dep)),,\
$(call -ndk-mod-closure-visit,$(_ndk_mod_dep))\
)\
)\
$(if $(_ndk_mod_wq),$(call -ndk-mod-closure-recursive))
-test-ndk-mod-get-closure.empty = \
$(eval -local-deps = $$($$1_depends))\
$(call test-expect,,$(call -ndk-mod-get-closure,,-local-deps))
-test-ndk-mod-get-closure.single = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends :=)\
$(call test-expect,A,$(call -ndk-mod-get-closure,A,-local-deps))
-test-ndk-mod-get-closure.double = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends :=)\
$(call test-expect,A B,$(call -ndk-mod-get-closure,A,-local-deps))
-test-ndk-mod-get-closure.circular-deps = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends := C)\
$(eval C_depends := A)\
$(call test-expect,A B C,$(call -ndk-mod-get-closure,A,-local-deps))
-test-ndk-mod-get-closure.ABCDE = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B C)\
$(eval B_depends := D)\
$(eval C_depends := D E)\
$(eval D_depends :=)\
$(eval E_depends :=)\
$(call test-expect,A B C D E,$(call -ndk-mod-get-closure,A,-local-deps))
#########################################################################
# For topological sort, we need to count the number of incoming edges
# in each graph node. The following helper functions implement this and
# hide implementation details.
#
# Count the number of incoming edges for each node during topological
# sort with a string of xxxxs. I.e.:
# 0 edge -> ''
# 1 edge -> 'x'
# 2 edges -> 'xx'
# 3 edges -> 'xxx'
# etc.
#########################################################################
# zero the incoming edge counter for module $1
-ndk-mod-topo-zero-incoming = \
$(eval _ndk_mod_topo_incoming.$1 :=)
# increment the incoming edge counter for module $1
-ndk-mod-topo-increment-incoming = \
$(eval _ndk_mod_topo_incoming.$1 := $$(_ndk_mod_topo_incoming.$1)x)
# decrement the incoming edge counter for module $1
-ndk-mod-topo-decrement-incoming = \
$(eval _ndk_mod_topo_incoming.$1 := $$(_ndk_mod_topo_incoming.$1:%x=%))
# return non-empty if the module $1's incoming edge counter is > 0
-ndk-mod-topo-has-incoming = $(_ndk_mod_topo_incoming.$1)
# Find first node in a list that has zero incoming edges.
# $1: list of nodes
# Out: first node that has zero incoming edges, or empty.
-ndk-mod-topo-find-first-zero-incoming = $(firstword $(call -ndk-mod-filter-out,$1,-ndk-mod-topo-has-incoming))
# Only use for debugging:
-ndk-mod-topo-dump-count = \
$(foreach _ndk_mod_module,$1,\
$(info .. $(_ndk_mod_module) incoming='$(_ndk_mod_topo_incoming.$(_ndk_mod_module))'))
#########################################################################
# Return the topologically ordered closure of all nodes from a top-level
# one. This means that a node A, in the result, will always appear after
# node B if A depends on B. Assumes that the graph is a DAG (if there are
# circular dependencies, this property cannot be guaranteed, but at least
# the function should not loop infinitely).
#
# $1: top-level node name.
# $2: dependency function, i.e. $(call $2,<name>) returns the children
# nodes for <name>.
# Return: list of nodes, include $1, which will always be the first.
#########################################################################
-ndk-mod-get-topo-list = $(strip \
$(eval _ndk_mod_top_module := $1)\
$(eval _ndk_mod_deps_func := $2)\
$(eval _ndk_mod_nodes := $(call -ndk-mod-get-closure,$1,$2))\
$(call -ndk-mod-topo-count,$(_ndk_mod_nodes))\
$(eval _ndk_mod_list :=)\
$(eval _ndk_mod_wq := $(call -ndk-mod-topo-find-first-zero-incoming,$(_ndk_mod_nodes)))\
$(call -ndk-mod-topo-sort)\
$(_ndk_mod_list) $(_ndk_mod_nodes)\
)
# Given a closure list of nodes, count their incoming edges.
# $1: list of nodes, must be a graph closure.
-ndk-mod-topo-count = \
$(foreach _ndk_mod_module,$1,\
$(call -ndk-mod-topo-zero-incoming,$(_ndk_mod_module)))\
$(foreach _ndk_mod_module,$1,\
$(call -ndk-mod-get-depends)\
$(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
$(call -ndk-mod-topo-increment-incoming,$(_ndk_mod_dep))\
)\
)
-ndk-mod-topo-sort = \
$(call -ndk-topo-debug,-ndk-mod-topo-sort: wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)')\
$(call -ndk-mod-pop-first)\
$(if $(_ndk_mod_module),\
$(eval _ndk_mod_list += $(_ndk_mod_module))\
$(eval _ndk_mod_nodes := $(filter-out $(_ndk_mod_module),$(_ndk_mod_nodes)))\
$(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_module))\
$(call -ndk-mod-get-depends)\
$(call -ndk-topo-debug,-ndk-mod-topo-sort: deps='$(_ndk_mod_depends)')\
$(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
$(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_dep))\
$(if $(call -ndk-mod-topo-has-incoming,$(_ndk_mod_dep)),,\
$(call -ndk-mod-push-back,$(_ndk_mod_dep))\
)\
)\
$(call -ndk-mod-topo-sort)\
)
-test-ndk-mod-get-topo-list.empty = \
$(eval -local-deps = $$($$1_depends))\
$(call test-expect,,$(call -ndk-mod-get-topo-list,,-local-deps))
-test-ndk-mod-get-topo-list.single = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends :=)\
$(call test-expect,A,$(call -ndk-mod-get-topo-list,A,-local-deps))
-test-ndk-mod-get-topo-list.no-infinite-loop = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends := C)\
$(eval C_depends := A)\
$(call test-expect,A B C,$(call -ndk-mod-get-topo-list,A,-local-deps))
-test-ndk-mod-get-topo-list.ABC = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B C)\
$(eval B_depends :=)\
$(eval C_depends := B)\
$(call test-expect,A C B,$(call -ndk-mod-get-topo-list,A,-local-deps))
-test-ndk-mod-get-topo-list.ABCD = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B C)\
$(eval B_depends := D)\
$(eval C_depends := B)\
$(eval D_depends :=)\
$(call test-expect,A C B D,$(call -ndk-mod-get-topo-list,A,-local-deps))
-test-ndk-mod-get-topo-list.ABC.circular = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends := C)\
$(eval C_depends := B)\
$(call test-expect,A B C,$(call -ndk-mod-get-topo-list,A,-local-deps))
#########################################################################
# Return the topologically ordered closure of all dependencies from a
# top-level node.
#
# $1: top-level node name.
# $2: dependency function, i.e. $(call $2,<name>) returns the children
# nodes for <name>.
# Return: list of nodes, include $1, which will never be included.
#########################################################################
-ndk-mod-get-topological-depends = $(call rest,$(call -ndk-mod-get-topo-list,$1,$2))
-test-ndk-mod-get-topological-depends.simple = \
$(eval -local-get-deps = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends :=)\
$(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\
$(call test-expect,B,$(topo_deps),topo dependencies)
-test-ndk-mod-get-topological-depends.ABC = \
$(eval -local-get-deps = $$($$1_depends))\
$(eval A_depends := B C)\
$(eval B_depends :=)\
$(eval C_depends := B)\
$(eval bfs_deps := $$(call -ndk-mod-get-bfs-depends,A,-local-get-deps))\
$(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\
$(call test-expect,B C,$(bfs_deps),dfs dependencies)\
$(call test-expect,C B,$(topo_deps),topo dependencies)
-test-ndk-mod-get-topological-depends.circular = \
$(eval -local-get-deps = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends := C)\
$(eval C_depends := B)\
$(eval bfs_deps := $$(call -ndk-mod-get-bfs-depends,A,-local-get-deps))\
$(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\
$(call test-expect,B C,$(bfs_deps),dfs dependencies)\
$(call test-expect,B C,$(topo_deps),topo dependencies)
#########################################################################
# Return breadth-first walk of a graph, starting from an arbitrary
# node.
#
# This performs a breadth-first walk of the graph and will return a
# list of nodes. Note that $1 will always be the first in the list.
#
# $1: root node name.
# $2: dependency function, i.e. $(call $2,<name>) returns the nodes
# that <name> depends on.
# Result: list of dependent modules, $1 will be part of it.
#########################################################################
-ndk-mod-get-bfs-list = $(strip \
$(eval _ndk_mod_wq := $(call strip-lib-prefix,$1)) \
$(eval _ndk_mod_deps_func := $2)\
$(eval _ndk_mod_list :=)\
$(call -ndk-mod-tree-setup-visit)\
$(call -ndk-mod-tree-set-visited,$(_ndk_mod_wq))\
$(call -ndk-mod-bfs-recursive) \
$(_ndk_mod_list))
# Recursive function used to perform a depth-first scan.
# Must initialize _ndk_mod_list, _ndk_mod_field, _ndk_mod_wq
# before calling this.
-ndk-mod-bfs-recursive = \
$(call -ndk-mod-debug,-ndk-mod-bfs-recursive wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)' visited='$(_ndk_mod_tree_visitors)')\
$(call -ndk-mod-pop-first)\
$(eval _ndk_mod_list += $$(_ndk_mod_module))\
$(call -ndk-mod-get-depends)\
$(call -ndk-mod-debug,. node='$(_ndk_mod_module)' deps='$(_ndk_mod_depends)')\
$(foreach _ndk_mod_child,$(_ndk_mod_depends),\
$(if $(call -ndk-mod-tree-is-visited,$(_ndk_mod_child)),,\
$(call -ndk-mod-tree-set-visited,$(_ndk_mod_child))\
$(call -ndk-mod-push-back,$(_ndk_mod_child))\
)\
)\
$(if $(_ndk_mod_wq),$(call -ndk-mod-bfs-recursive))
-test-ndk-mod-get-bfs-list.empty = \
$(eval -local-deps = $$($$1_depends))\
$(call test-expect,,$(call -ndk-mod-get-bfs-list,,-local-deps))
-test-ndk-mod-get-bfs-list.A = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends :=)\
$(call test-expect,A,$(call -ndk-mod-get-bfs-list,A,-local-deps))
-test-ndk-mod-get-bfs-list.ABCDEF = \
$(eval -local-deps = $$($$1_depends))\
$(eval A_depends := B C)\
$(eval B_depends := D E)\
$(eval C_depends := F E)\
$(eval D_depends :=)\
$(eval E_depends :=)\
$(eval F_depends :=)\
$(call test-expect,A B C D E F,$(call -ndk-mod-get-bfs-list,A,-local-deps))
#########################################################################
# Return breadth-first walk of a graph, starting from an arbitrary
# node.
#
# This performs a breadth-first walk of the graph and will return a
# list of nodes. Note that $1 will _not_ be part of the list.
#
# $1: root node name.
# $2: dependency function, i.e. $(call $2,<name>) returns the nodes
# that <name> depends on.
# Result: list of dependent modules, $1 will not be part of it.
#########################################################################
-ndk-mod-get-bfs-depends = $(call rest,$(call -ndk-mod-get-bfs-list,$1,$2))
-test-ndk-mod-get-bfs-depends.simple = \
$(eval -local-deps-func = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends :=)\
$(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
$(call test-expect,B,$(deps))
-test-ndk-mod-get-bfs-depends.ABC = \
$(eval -local-deps-func = $$($$1_depends))\
$(eval A_depends := B C)\
$(eval B_depends :=)\
$(eval C_depends := B)\
$(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
$(call test-expect,B C,$(deps))\
-test-ndk-mod-get-bfs-depends.ABCDE = \
$(eval -local-deps-func = $$($$1_depends))\
$(eval A_depends := B C)\
$(eval B_depends := D)\
$(eval C_depends := D E F)\
$(eval D_depends :=)\
$(eval E_depends :=)\
$(eval F_depends :=)\
$(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
$(call test-expect,B C D E F,$(deps))\
-test-ndk-mod-get-bfs-depends.loop = \
$(eval -local-deps-func = $$($$1_depends))\
$(eval A_depends := B)\
$(eval B_depends := A)\
$(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
$(call test-expect,B,$(deps))

View File

@ -0,0 +1,218 @@
# Copyright (C) 2009 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.
#
# These definitions contain a few host-specific functions. I.e. they are
# typically used to generate shell commands during the build and their
# implementation will depend on the value of the HOST_OS variable.
#
# -----------------------------------------------------------------------------
# Function : host-path
# Arguments: 1: file path
# Returns : file path, as understood by the host file system
# Usage : $(call host-path,<path>)
# Rationale: This function is used to translate Cygwin paths into
# Cygwin-specific ones. On other platforms, it will just
# return its argument.
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),cygwin)
host-path = $(if $(strip $1),$(call cygwin-to-host-path,$1))
else
host-path = $1
endif
# -----------------------------------------------------------------------------
# Function : host-rm
# Arguments: 1: list of files
# Usage : $(call host-rm,<files>)
# Rationale: This function expands to the host-specific shell command used
# to remove some files.
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
host-rm = \
$(eval __host_rm_files := $(foreach __host_rm_file,$1,$(subst /,\,$(wildcard $(__host_rm_file)))))\
$(if $(__host_rm_files),del /f/q $(__host_rm_files) >NUL 2>NUL)
else
host-rm = rm -f $1
endif
# -----------------------------------------------------------------------------
# Function : host-rmdir
# Arguments: 1: list of files or directories
# Usage : $(call host-rm,<files>)
# Rationale: This function expands to the host-specific shell command used
# to remove some files _and_ directories.
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
host-rmdir = \
$(eval __host_rmdir_files := $(foreach __host_rmdir_file,$1,$(subst /,\,$(wildcard $(__host_rmdir_file)))))\
$(if $(__host_rmdir_files),del /f/s/q $(__host_rmdir_files) >NUL 2>NUL)
else
host-rmdir = rm -rf $1
endif
# -----------------------------------------------------------------------------
# Function : host-mkdir
# Arguments: 1: directory path
# Usage : $(call host-mkdir,<path>
# Rationale: This function expands to the host-specific shell command used
# to create a path if it doesn't exist.
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
host-mkdir = md $(subst /,\,"$1") >NUL 2>NUL || rem
else
host-mkdir = mkdir -p $1
endif
# -----------------------------------------------------------------------------
# Function : host-cp
# Arguments: 1: source file
# 2: target file
# Usage : $(call host-cp,<src-file>,<dst-file>)
# Rationale: This function expands to the host-specific shell command used
# to copy a single file
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
host-cp = copy /b/y $(subst /,\,"$1" "$2") > NUL
else
host-cp = cp -f $1 $2
endif
# -----------------------------------------------------------------------------
# Function : host-mv
# Arguments: 1: source file
# 2: target file
# Usage : $(call host-mv,<src-file>,<dst-file>)
# Rationale: This function expands to the host-specific shell command used
# to move a single file
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
host-mv = move /y $(subst /,\,"$1" "$2") > NUL
else
host-mv = mv -f $1 $2
endif
# -----------------------------------------------------------------------------
# Function : host-install
# Arguments: 1: source file
# 2: target file
# Usage : $(call host-install,<src-file>,<dst-file>)
# Rationale: This function expands to the host-specific shell command used
# to install a file or directory, while preserving its timestamps
# (if possible).
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
host-install = copy /b/y $(subst /,\,"$1" "$2") > NUL
else
host-install = install -p $1 $2
endif
# -----------------------------------------------------------------------------
# Function : host-echo-build-step
# Arguments: 1: ABI
# 2: Step description (e.g. 'Compile C++', or 'StaticLibrary')
# Usage : ---->|$(call host-echo-build-step,Compile) ....other text...
# Rationale: This function expands to the host-specific shell command used
# to print the prefix of a given build step / command.
# -----------------------------------------------------------------------------
host-echo-build-step = @ $(HOST_ECHO) [$1] $(call left-justify-quoted-15,$2):
# -----------------------------------------------------------------------------
# Function : host-c-includes
# Arguments: 1: list of file paths (e.g. "foo bar")
# Returns : list of include compiler options (e.g. "-Ifoo -Ibar")
# Usage : $(call host-c-includes,<paths>)
# Rationale: This function is used to translate Cygwin paths into
# Cygwin-specific ones. On other platforms, it will just
# return its argument.
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),cygwin)
host-c-includes = $(patsubst %,-I%,$(call host-path,$1))
else
host-c-includes = $(1:%=-I%)
endif
# -----------------------------------------------------------------------------
# Function : host-copy-if-differ
# Arguments: 1: source file
# 2: destination file
# Usage : $(call host-copy-if-differ,<src-file>,<dst-file>)
# Rationale: This function copy source file to destination file if contents are
# different.
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
host-copy-if-differ = $(HOST_CMP) -s $1 $2 > NUL || copy /b/y $(subst /,\,"$1" "$2") > NUL
else
host-copy-if-differ = $(HOST_CMP) -s $1 $2 > /dev/null 2>&1 || cp -f $1 $2
endif
# -----------------------------------------------------------------------------
# Function : host-path-is-absolute
# Arguments: 1: file path
# Usage : $(call host-path-is-absolute,<path>)
# Rationale: This function returns a non-empty result if the input path is
# absolute on the host filesystem.
# -----------------------------------------------------------------------------
# On Windows, we need to take care drive prefix in file paths, e.g.:
# /foo -> top-level 'foo' directory on current drive.
# //bar/foo -> top-level 'foo' on network share 'bar'
# c:/foo -> top-level 'foo' directory on C drive.
# c:foo -> 'foo' subdirectory on C drive's current directory.
#
# Treat all of them as absolute. Filtering the first two cases is easy
# by simply looking at the first character. The other ones are more
# complicated and the simplest way is still to try all alphabet letters
# directly. Anything else involves very complicated GNU Make parsing
# voodoo.
ndk-windows-drive-letters := a b c d e f g h i j k l m n o p q r s t u v w x y z \
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
ndk-windows-drive-patterns := $(foreach _drive,$(ndk-windows-drive-letters),$(_drive):%)
windows-path-is-absolute = $(if $(filter /% $(ndk-windows-drive-patterns),$(subst \,/,$1)),true)
ifeq ($(HOST_OS),windows)
host-path-is-absolute = $(call windows-path-is-absolute,$1)
else
host-path-is-absolute = $(if $(filter /%,$1),true)
endif
-test-host-path-is-absolute.relative-paths = \
$(call test-expect,,$(call host-path-is-absolute,foo))\
$(call test-expect,,$(call host-path-is-absolute,foo/bar))\
$(call test-expect,,$(call host-path-is-absolute,.))\
$(call test-expect,,$(call host-path-is-absolute,..))
-test-host-path-is-absolute.absolute-paths = \
$(call test-expect,true,$(call host-path-is-absolute,/))\
$(call test-expect,true,$(call host-path-is-absolute,/foo))\
$(call test-expect,true,$(call host-path-is-absolute,/foo/bar))\
$(call test-expect,true,$(call host-path-is-absolute,//foo))\
$(call test-expect,true,$(call host-path-is-absolute,/.))
-test-host-path-is-asbolute.windows-relative-paths = \
$(call test-expect,$(call windows-path-is-absolute,foo))\
$(call test-expect,$(call windows-path-is-absolute,foo/bar))\
$(call test-expect,$(call windows-path-is-absolute,.))\
$(call test-expect,$(call windows-path-is-absolute,..))
-test-host-path-is-asbolute.windows-absolute-paths = \
$(call test-expect,true,$(call windows-path-is-absolute,c:/))\
$(call test-expect,true,$(call windows-path-is-absolute,x:))\
$(call test-expect,true,$(call windows-path-is-absolute,K:foo))\
$(call test-expect,true,$(call windows-path-is-absolute,C:\Foo\Bar))\
$(call test-expect,true,$(call windows-path-is-absolute,\Foo))

View File

@ -0,0 +1,106 @@
# Copyright (C) 2012 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.
#
# Definitions for the Android NDK build system's internal unit tests.
#
#
# A function which names begin with -test- (e.g. -test-foo) is assumed
# to be an internal unit test. It will be run automatically by ndk-build
# if NDK_UNIT_TESTS is defined in your environment.
#
# Each test should call one of the following functions that will
# register a failure:
#
# $(call test-expect,<expected-value>,<actual-value>)
#
# This will check that <actual-value> is equal to <expected-value>.
# If not, this will print an error message and increment the failure
# counter.
#
# $(call test-assert,<expected-value>,<actual-value>)
#
# This is similar to test-expect, though it will abort the program
# immediately after displaying an error message.
#
# Here's an example that checks that the 'filter' function works correctly:
#
# -test-filter = \
# $(call test-expect,foo,$(filter bar,foo bar))
#
#
-ndk-test-start = \
$(eval _test_name := $1)\
$(eval _test_list += $1)\
$(eval _test_failed :=)\
$(info [$1 RUN])
# End current unit test.
#
-ndk-test-end = \
$(if $(_test_failed),\
$(info [$(_test_name) FAIL])$(error Aborting)\
$(eval _test_failures += $$(_test_name))\
,\
$(info [$(_test_name) OK])\
)
# Define NDK_UNIT_TESTS to 2 to dump each test-expect/assert check.
#
ifeq (2,$(NDK_UNIT_TESTS))
-ndk-test-log = $(info . $(_test_name): $1)
else
-ndk-test-log = $(empty)
endif
test-expect = \
$(call -ndk-test-log,expect '$2' == '$1')\
$(if $(call sne,$1,$2),\
$(info ERROR <$(_test_name)>:$3)\
$(info . expected value:'$1')\
$(info . actual value: '$2')\
$(eval _test_failed := true)\
)
test-assert = \
$(call -ndk-test-log,assert '$2' == '$1')\
$(if $(call sne,$1,$2),\
$(info ASSERT <$(_test_name)>:$3)\
$(info . expected value:'$1')\
$(info . actual value: '$2')\
$(eval _test_failed := true)\
$(error Aborting.)\
)
# Run all the tests, i.e. all functions that are defined with a -test-
# prefix will be called now in succession.
ndk-run-all-tests = \
$(info ================= STARTING NDK-BUILD UNIT TESTS =================)\
$(eval _test_list :=)\
$(eval _test_failures :=)\
$(foreach _test,$(filter -test-%,$(.VARIABLES)),\
$(call -ndk-test-start,$(_test))\
$(call $(_test))\
$(call -ndk-test-end)\
)\
$(eval _test_count := $$(words $$(_test_list)))\
$(eval _test_fail_count := $$(words $$(_test_failures)))\
$(if $(_test_failures),\
$(info @@@@@@@@@@@ FAILED $(_test_fail_count) of $(_test_count) NDK-BUILD UNIT TESTS @@@@@@@)\
$(foreach _test_name,$(_test_failures),\
$(info . $(_test_name)))\
,\
$(info =================== PASSED $(_test_count) NDK-BUILD UNIT TESTS =================)\
)

View File

@ -0,0 +1,272 @@
# Copyright (C) 2009 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.
#
# Common utility functions.
#
# NOTE: All the functions here should be purely functional, i.e. avoid
# using global variables or depend on the file system / environment
# variables. This makes testing easier.
# -----------------------------------------------------------------------------
# Macro : empty
# Returns : an empty macro
# Usage : $(empty)
# -----------------------------------------------------------------------------
empty :=
# -----------------------------------------------------------------------------
# Macro : space
# Returns : a single space
# Usage : $(space)
# -----------------------------------------------------------------------------
space := $(empty) $(empty)
space4 := $(space)$(space)$(space)$(space)
# -----------------------------------------------------------------------------
# Macro : comma
# Returns : a single comma
# Usage : $(comma)
# -----------------------------------------------------------------------------
comma := ,
# -----------------------------------------------------------------------------
# Macro : colon
# Returns : a single colon
# Usage : $(colon)
# -----------------------------------------------------------------------------
colon := :
define newline
endef
# -----------------------------------------------------------------------------
# Function : remove-duplicates
# Arguments: a list
# Returns : the list with duplicate items removed, order is preserved.
# Usage : $(call remove-duplicates, <LIST>)
# Note : This is equivalent to the 'uniq' function provided by GMSL,
# however this implementation is non-recursive and *much*
# faster. It will also not explode the stack with a lot of
# items like 'uniq' does.
# -----------------------------------------------------------------------------
remove-duplicates = $(strip \
$(eval __uniq_ret :=) \
$(foreach __uniq_item,$1,\
$(if $(findstring $(__uniq_item),$(__uniq_ret)),,\
$(eval __uniq_ret += $(__uniq_item))\
)\
)\
$(__uniq_ret))
-test-remove-duplicates = \
$(call test-expect,,$(call remove-duplicates))\
$(call test-expect,foo bar,$(call remove-duplicates,foo bar))\
$(call test-expect,foo bar,$(call remove-duplicates,foo bar foo bar))\
$(call test-expect,foo bar,$(call remove-duplicates,foo foo bar bar bar))
# -----------------------------------------------------------------------------
# Function : clear-vars
# Arguments: 1: list of variable names
# 2: file where the variable should be defined
# Returns : None
# Usage : $(call clear-vars, VAR1 VAR2 VAR3...)
# Rationale: Clears/undefines all variables in argument list
# -----------------------------------------------------------------------------
clear-vars = $(foreach __varname,$1,$(eval $(__varname) := $(empty)))
# -----------------------------------------------------------------------------
# Function : filter-by
# Arguments: 1: list
# 2: predicate function, will be called as $(call $2,<name>)
# and it this returns a non-empty value, then <name>
# will be appended to the result.
# Returns : elements of $1 that satisfy the predicate function $2
# -----------------------------------------------------------------------------
filter-by = $(strip \
$(foreach __filter_by_n,$1,\
$(if $(call $2,$(__filter_by_n)),$(__filter_by_n))))
-test-filter-by = \
$(eval -local-func = $$(call seq,foo,$$1))\
$(call test-expect,,$(call filter-by,,-local-func))\
$(call test-expect,foo,$(call filter-by,foo,-local-func))\
$(call test-expect,foo,$(call filter-by,foo bar,-local-func))\
$(call test-expect,foo foo,$(call filter-by,aaa foo bar foo,-local-func))\
$(eval -local-func = $$(call sne,foo,$$1))\
$(call test-expect,,$(call filter-by,,-local-func))\
$(call test-expect,,$(call filter-by,foo,-local-func))\
$(call test-expect,bar,$(call filter-by,foo bar,-local-func))\
$(call test-expect,aaa bar,$(call filter-by,aaa foo bar,-local-func))
# -----------------------------------------------------------------------------
# Function : filter-out-by
# Arguments: 1: list
# 2: predicate function, will be called as $(call $2,<name>)
# and it this returns an empty value, then <name>
# will be appended to the result.
# Returns : elements of $1 that do not satisfy the predicate function $2
# -----------------------------------------------------------------------------
filter-out-by = $(strip \
$(foreach __filter_out_by_n,$1,\
$(if $(call $2,$(__filter_out_by_n)),,$(__filter_out_by_n))))
-test-filter-out-by = \
$(eval -local-func = $$(call seq,foo,$$1))\
$(call test-expect,,$(call filter-out-by,,-local-func))\
$(call test-expect,,$(call filter-out-by,foo,-local-func))\
$(call test-expect,bar,$(call filter-out-by,foo bar,-local-func))\
$(call test-expect,aaa bar,$(call filter-out-by,aaa foo bar foo,-local-func))\
$(eval -local-func = $$(call sne,foo,$$1))\
$(call test-expect,,$(call filter-out-by,,-local-func))\
$(call test-expect,foo,$(call filter-out-by,foo,-local-func))\
$(call test-expect,foo,$(call filter-out-by,foo bar,-local-func))\
$(call test-expect,foo foo,$(call filter-out-by,aaa foo bar foo,-local-func))
# -----------------------------------------------------------------------------
# Function : find-first
# Arguments: 1: list
# 2: predicate function, will be called as $(call $2,<name>).
# Returns : the first item of $1 that satisfies the predicate.
# -----------------------------------------------------------------------------
find-first = $(firstword $(call filter-by,$1,$2))
-test-find-first.empty = \
$(eval -local-pred = $$(call seq,foo,$$1))\
$(call test-expect,,$(call find-first,,-local-pred))\
$(call test-expect,,$(call find-first,bar,-local-pred))
-test-find-first.simple = \
$(eval -local-pred = $$(call seq,foo,$$1))\
$(call test-expect,foo,$(call find-first,foo,-local-pred))\
$(call test-expect,foo,$(call find-first,aaa foo bar,-local-pred))\
$(call test-expect,foo,$(call find-first,aaa foo foo bar,-local-pred))
# -----------------------------------------------------------------------------
# Function : parent-dir
# Arguments: 1: path
# Returns : Parent dir or path of $1, with final separator removed.
# -----------------------------------------------------------------------------
ifeq ($(HOST_OS),windows)
# On Windows, defining parent-dir is a bit more tricky because the
# GNU Make $(dir ...) function doesn't return an empty string when it
# reaches the top of the directory tree, and we want to enforce this to
# avoid infinite loops.
#
# $(dir C:) -> C: (empty expected)
# $(dir C:/) -> C:/ (empty expected)
# $(dir C:\) -> C:\ (empty expected)
# $(dir C:/foo) -> C:/ (correct)
# $(dir C:\foo) -> C:\ (correct)
#
parent-dir = $(patsubst %/,%,$(strip \
$(eval __dir_node := $(patsubst %/,%,$(subst \,/,$1)))\
$(eval __dir_parent := $(dir $(__dir_node)))\
$(filter-out $1,$(__dir_parent))\
))
else
parent-dir = $(patsubst %/,%,$(dir $(1:%/=%)))
endif
-test-parent-dir = \
$(call test-expect,,$(call parent-dir))\
$(call test-expect,.,$(call parent-dir,foo))\
$(call test-expect,foo,$(call parent-dir,foo/bar))\
$(call test-expect,foo,$(call parent-dir,foo/bar/))
# -----------------------------------------------------------------------------
# Strip any 'lib' prefix in front of a given string.
#
# Function : strip-lib-prefix
# Arguments: 1: module name
# Returns : module name, without any 'lib' prefix if any
# Usage : $(call strip-lib-prefix,$(LOCAL_MODULE))
# -----------------------------------------------------------------------------
strip-lib-prefix = $(1:lib%=%)
-test-strip-lib-prefix = \
$(call test-expect,,$(call strip-lib-prefix,))\
$(call test-expect,foo,$(call strip-lib-prefix,foo))\
$(call test-expect,foo,$(call strip-lib-prefix,libfoo))\
$(call test-expect,nolibfoo,$(call strip-lib-prefix,nolibfoo))\
$(call test-expect,foolib,$(call strip-lib-prefix,foolib))\
$(call test-expect,foo bar,$(call strip-lib-prefix,libfoo libbar))
# -----------------------------------------------------------------------------
# Left-justify input string with spaces to fill a width of 15.
# Function: left-justify-quoted-15
# Arguments: 1: Input text
# Returns: A quoted string that can be used in command scripts to print
# the left-justified input with host-echo.
#
# Usage: ---->@$(call host-echo, $(call left-justify-quoted-15,$(_TEXT)): Do stuff)
# Where ----> is a TAB character.
# -----------------------------------------------------------------------------
left-justify-quoted-15 = $(call -left-justify,$1,xxxxxxxxxxxxxxx)
-test-left-justify-quoted-15 = \
$(call test-expect," ",$(call left-justify-quoted-15,))\
$(call test-expect,"Foo Bar ",$(call left-justify-quoted-15,Foo Bar))\
$(call test-expect,"Very long string over 15 characters wide",$(strip \
$(call left-justify-quoted-15,Very long string over 15 characters wide)))
# Used internally to compute a quoted left-justified text string.
# $1: Input string.
# $2: A series of contiguous x's, its length determines the full width to justify to.
# Return: A quoted string with the input text left-justified appropriately.
-left-justify = $(strip \
$(eval __lj_temp := $(subst $(space),x,$1))\
$(foreach __lj_a,$(__gmsl_characters),$(eval __lj_temp := $$(subst $$(__lj_a),x,$(__lj_temp))))\
$(eval __lj_margin := $$(call -justification-margin,$(__lj_temp),$2)))"$1$(subst x,$(space),$(__lj_margin))"
-test-left-justify = \
$(call test-expect,"",$(call -left-justify,,))\
$(call test-expect,"foo",$(call -left-justify,foo,xxx))\
$(call test-expect,"foo ",$(call -left-justify,foo,xxxx))\
$(call test-expect,"foo ",$(call -left-justify,foo,xxxxxx))\
$(call test-expect,"foo ",$(call -left-justify,foo,xxxxxxxxxxxx))\
$(call test-expect,"very long string",$(call -left-justify,very long string,xxx))\
# Used internally to compute a justification margin.
# Expects $1 to be defined to a string of consecutive x's (e.g. 'xxxx')
# Expects $2 to be defined to a maximum string of x's (e.g. 'xxxxxxxxx')
# Returns a string of x's such as $1 + $(result) is equal to $2
# If $1 is larger than $2, return empty string..
-justification-margin = $(strip \
$(if $2,\
$(if $1,\
$(call -justification-margin-inner,$1,$2),\
$2\
),\
$1))
-justification-margin-inner = $(if $(findstring $2,$1),,x$(call -justification-margin-inner,x$1,$2))
-test-justification-margin = \
$(call test-expect,,$(call -justification-margin,,))\
$(call test-expect,,$(call -justification-margin,xxx,xxx))\
$(call test-expect,xxxxxx,$(call -justification-margin,,xxxxxx))\
$(call test-expect,xxxxx,$(call -justification-margin,x,xxxxxx))\
$(call test-expect,xxxx,$(call -justification-margin,xx,xxxxxx))\
$(call test-expect,xxx,$(call -justification-margin,xxx,xxxxxx))\
$(call test-expect,xx,$(call -justification-margin,xxxx,xxxxxx))\
$(call test-expect,x,$(call -justification-margin,xxxxx,xxxxxx))\
$(call test-expect,,$(call -justification-margin,xxxxxx,xxxxxx))\
$(call test-expect,,$(call -justification-margin,xxxxxxxxxxx,xxxxxx))\
# Escapes \ to \\. Useful for escaping Windows paths.
escape-backslashes = $(subst \,\\,$1)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
# Copyright (C) 2009 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.
#
# Handle local variable expor/import during the build
#
$(call assert-defined,LOCAL_MODULE)
# For LOCAL_CFLAGS, LOCAL_CONLYFLAGS, LOCAL_CPPFLAGS and LOCAL_C_INCLUDES, etc,
# we need to use the exported definitions of the closure of all modules
# we depend on.
#
# I.e. If module 'foo' depends on 'bar' which depends on 'zoo',
# then 'foo' will get the CFLAGS/CONLYFLAGS/CPPFLAGS/C_INCLUDES/... of both 'bar'
# and 'zoo'
#
all_depends := $(call module-get-all-dependencies-topo,$(LOCAL_MODULE))
all_depends := $(filter-out $(LOCAL_MODULE),$(all_depends))
imported_CFLAGS := $(call module-get-listed-export,$(all_depends),CFLAGS)
imported_CONLYFLAGS := $(call module-get-listed-export,$(all_depends),CONLYFLAGS)
imported_CPPFLAGS := $(call module-get-listed-export,$(all_depends),CPPFLAGS)
imported_ASMFLAGS := $(call module-get-listed-export,$(all_depends),ASMFLAGS)
imported_C_INCLUDES := $(call module-get-listed-export,$(all_depends),C_INCLUDES)
imported_LDFLAGS := $(call module-get-listed-export,$(all_depends),LDFLAGS)
imported_SHARED_LIBRARIES := $(call module-get-listed-export,$(all_depends),SHARED_LIBRARIES)
imported_STATIC_LIBRARIES := $(call module-get-listed-export,$(all_depends),STATIC_LIBRARIES)
ifdef NDK_DEBUG_IMPORTS
$(info Imports for module $(LOCAL_MODULE):)
$(info CFLAGS='$(imported_CFLAGS)')
$(info CONLYFLAGS='$(imported_CONLYFLAGS)')
$(info CPPFLAGS='$(imported_CPPFLAGS)')
$(info ASMFLAGS='$(imported_ASMFLAGS)')
$(info C_INCLUDES='$(imported_C_INCLUDES)')
$(info LDFLAGS='$(imported_LDFLAGS)')
$(info SHARED_LIBRARIES='$(imported_SHARED_LIBRARIES)')
$(info STATIC_LIBRARIES='$(imported_STATIC_LIBRARIES)')
$(info All depends='$(all_depends)')
endif
#
# The imported compiler flags are prepended to their LOCAL_XXXX value
# (this allows the module to override them).
#
LOCAL_CFLAGS := $(strip $(imported_CFLAGS) $(LOCAL_CFLAGS))
LOCAL_CONLYFLAGS := $(strip $(imported_CONLYFLAGS) $(LOCAL_CONLYFLAGS))
LOCAL_CPPFLAGS := $(strip $(imported_CPPFLAGS) $(LOCAL_CPPFLAGS))
LOCAL_ASMFLAGS := $(strip $(imported_ASMFLAGS) $(LOCAL_ASMFLAGS))
LOCAL_LDFLAGS := $(strip $(imported_LDFLAGS) $(LOCAL_LDFLAGS))
__ndk_modules.$(LOCAL_MODULE).STATIC_LIBRARIES += \
$(strip $(call strip-lib-prefix,$(imported_STATIC_LIBRARIES)))
__ndk_modules.$(LOCAL_MODULE).SHARED_LIBRARIES += \
$(strip $(call strip-lib-prefix,$(imported_SHARED_LIBRARIES)))
$(call module-add-static-depends,$(LOCAL_MODULE),$(imported_STATIC_LIBRARIES))
$(call module-add-shared-depends,$(LOCAL_MODULE),$(imported_SHARED_LIBRARIES))
#
# The imported include directories are appended to their LOCAL_XXX value
# (this allows the module to override them)
#
LOCAL_C_INCLUDES := $(strip $(LOCAL_C_INCLUDES) $(imported_C_INCLUDES))
# Similarly, you want the imported flags to appear _after_ the LOCAL_LDLIBS
# due to the way Unix linkers work (depending libraries must appear before
# dependees on final link command).
#
imported_LDLIBS := $(call module-get-listed-export,$(all_depends),LDLIBS)
LOCAL_LDLIBS := $(strip $(LOCAL_LDLIBS) $(imported_LDLIBS))
# We're done here

View File

@ -0,0 +1,492 @@
# Copyright (C) 2009-2010 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.
#
# Initialization of the NDK build system. This file is included by
# several build scripts.
#
# Disable GNU Make implicit rules
# this turns off the suffix rules built into make
.SUFFIXES:
# this turns off the RCS / SCCS implicit rules of GNU Make
% : RCS/%,v
% : RCS/%
% : %,v
% : s.%
% : SCCS/s.%
# If a rule fails, delete $@.
.DELETE_ON_ERROR:
# Define NDK_LOG=1 in your environment to display log traces when
# using the build scripts. See also the definition of ndk_log below.
#
NDK_LOG := $(strip $(NDK_LOG))
ifeq ($(NDK_LOG),true)
override NDK_LOG := 1
endif
# Check that we have at least GNU Make 3.81
# We do this by detecting whether 'lastword' is supported
#
MAKE_TEST := $(lastword a b c d e f)
ifneq ($(MAKE_TEST),f)
$(error Android NDK: GNU Make version $(MAKE_VERSION) is too low (should be >= 3.81))
endif
ifeq ($(NDK_LOG),1)
$(info Android NDK: GNU Make version $(MAKE_VERSION) detected)
endif
# NDK_ROOT *must* be defined and point to the root of the NDK installation
NDK_ROOT := $(strip $(NDK_ROOT))
ifndef NDK_ROOT
$(error ERROR while including init.mk: NDK_ROOT must be defined !)
endif
ifneq ($(words $(NDK_ROOT)),1)
$(info,The Android NDK installation path contains spaces: '$(NDK_ROOT)')
$(error,Please fix the problem by reinstalling to a different location.)
endif
# ====================================================================
#
# Define a few useful variables and functions.
# More stuff will follow in definitions.mk.
#
# ====================================================================
# Used to output warnings and error from the library, it's possible to
# disable any warnings or errors by overriding these definitions
# manually or by setting NDK_NO_WARNINGS or NDK_NO_ERRORS
__ndk_name := Android NDK
__ndk_info = $(info $(__ndk_name): $1 $2 $3 $4 $5)
__ndk_warning = $(warning $(__ndk_name): $1 $2 $3 $4 $5)
__ndk_error = $(error $(__ndk_name): $1 $2 $3 $4 $5)
ifdef NDK_NO_INFO
__ndk_info :=
endif
ifdef NDK_NO_WARNINGS
__ndk_warning :=
endif
ifdef NDK_NO_ERRORS
__ndk_error :=
endif
# -----------------------------------------------------------------------------
# Function : ndk_log
# Arguments: 1: text to print when NDK_LOG is defined to 1
# Returns : None
# Usage : $(call ndk_log,<some text>)
# -----------------------------------------------------------------------------
ifeq ($(NDK_LOG),1)
ndk_log = $(info $(__ndk_name): $1)
else
ndk_log :=
endif
# -----------------------------------------------------------------------------
# Function : host-toolchain-path
# Arguments: 1: NDK root
# 2: Toolchain name
# Returns : The parent path of all toolchains for this host. Note that
# HOST_TAG64 == HOST_TAG for 32-bit systems.
# -----------------------------------------------------------------------------
ifeq ($(NDK_NEW_TOOLCHAINS_LAYOUT),true)
host-toolchain-path = $1/$(HOST_TAG64)/$2
else
host-toolchain-path = $1/$2/prebuilt/$(HOST_TAG64)
endif
# -----------------------------------------------------------------------------
# Function : get-gcclibs-path
# Arguments: 1: NDK root
# 2: Toolchain name (no version number)
# Returns : Path to the given prebuilt gcclibs.
# -----------------------------------------------------------------------------
get-gcclibs-path = $1/gcclibs/$2
# ====================================================================
#
# Host system auto-detection.
#
# ====================================================================
#
# Determine host system and architecture from the environment
#
HOST_OS := $(strip $(HOST_OS))
ifndef HOST_OS
# On all modern variants of Windows (including Cygwin and Wine)
# the OS environment variable is defined to 'Windows_NT'
#
# The value of PROCESSOR_ARCHITECTURE will be x86 or AMD64
#
ifeq ($(OS),Windows_NT)
HOST_OS := windows
else
# For other systems, use the `uname` output
UNAME := $(shell uname -s)
ifneq (,$(findstring Linux,$(UNAME)))
HOST_OS := linux
endif
ifneq (,$(findstring Darwin,$(UNAME)))
HOST_OS := darwin
endif
# We should not be there, but just in case !
ifneq (,$(findstring CYGWIN,$(UNAME)))
$(call __ndk_warning,Unsupported build environment CYGWIN.)
HOST_OS := windows
endif
ifneq (,$(findstring MINGW64,$(UNAME)))
$(call __ndk_warning,Unsupported build environment MSYS.)
HOST_OS := windows
endif
ifeq ($(HOST_OS),)
$(call __ndk_info,Unable to determine HOST_OS from uname -s: $(UNAME))
$(call __ndk_info,Please define HOST_OS in your environment.)
$(call __ndk_error,Aborting.)
endif
endif
$(call ndk_log,Host OS was auto-detected: $(HOST_OS))
else
$(call ndk_log,Host OS from environment: $(HOST_OS))
endif
# For all systems, we will have HOST_OS_BASE defined as
# $(HOST_OS), except on Cygwin where we will have:
#
# HOST_OS == cygwin
# HOST_OS_BASE == windows
#
# Trying to detect that we're running from Cygwin is tricky
# because we can't use $(OSTYPE): It's a Bash shell variable
# that is not exported to sub-processes, and isn't defined by
# other shells (for those with really weird setups).
#
# Instead, we assume that a program named /bin/uname.exe
# that can be invoked and returns a valid value corresponds
# to a Cygwin installation.
#
HOST_OS_BASE := $(HOST_OS)
ifeq ($(HOST_OS),windows)
ifneq (,$(strip $(wildcard /bin/uname.exe)))
$(call ndk_log,Found /bin/uname.exe on Windows host, checking for Cygwin)
# NOTE: The 2>NUL here is for the case where we're running inside the
# native Windows shell. On cygwin, this will create an empty NUL file
# that we're going to remove later (see below).
UNAME := $(shell /bin/uname.exe -s 2>NUL)
$(call ndk_log,uname -s returned: $(UNAME))
ifneq (,$(filter CYGWIN%,$(UNAME)))
$(call ndk_log,Cygwin detected: $(shell uname -a))
HOST_OS := cygwin
_ := $(shell rm -f NUL) # Cleaning up
else
ifneq (,$(filter MINGW32%,$(UNAME)))
$(call ndk_log,MSys detected: $(shell uname -a))
HOST_OS := cygwin
else
$(call ndk_log,Cygwin *not* detected!)
endif
endif
endif
endif
ifneq ($(HOST_OS),$(HOST_OS_BASE))
$(call ndk_log, Host operating system detected: $(HOST_OS), base OS: $(HOST_OS_BASE))
else
$(call ndk_log, Host operating system detected: $(HOST_OS))
endif
HOST_ARCH := $(strip $(HOST_ARCH))
HOST_ARCH64 :=
ifndef HOST_ARCH
ifeq ($(HOST_OS_BASE),windows)
# In the case that we're a 32-bit make (shouldn't be the case, but maybe
# the user is using their own make binary rather than the NDK's), on a
# 64-bit OS, PROCESSOR_ARCHITECTURE will be x86 but
# PROCESSOR_ARCHITEW6432 will be AMD64. If PROCESSOR_ARCHITECTURE is x86
# and PROCESSOR_ARCHITEW6432 is empty, this is a 32-bit OS.
# https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/
ifeq ($(PROCESSOR_ARCHITECTURE)$(PROCESSOR_ARCHITEW6432),x86)
$(call __ndk_error,32-bit Windows is supported.)
endif
endif
HOST_ARCH := x86
HOST_ARCH64 := x86_64
else
$(call ndk_log,Host CPU from environment: $(HOST_ARCH))
endif
ifeq (,$(HOST_ARCH64))
HOST_ARCH64 := $(HOST_ARCH)
endif
HOST_TAG := $(HOST_OS_BASE)-$(HOST_ARCH)
HOST_TAG64 := $(HOST_OS_BASE)-$(HOST_ARCH64)
# The directory separator used on this host
HOST_DIRSEP := :
ifeq ($(HOST_OS),windows)
HOST_DIRSEP := ;
endif
# The host executable extension
HOST_EXEEXT :=
ifeq ($(HOST_OS),windows)
HOST_EXEEXT := .exe
endif
ifeq ($(HOST_TAG),windows-x86)
# If we are on Windows, we need to check that we are not running Cygwin 1.5,
# which is deprecated and won't run our toolchain binaries properly.
ifeq ($(HOST_OS),cygwin)
# On cygwin, 'uname -r' returns something like 1.5.23(0.225/5/3)
# We recognize 1.5. as the prefix to look for then.
CYGWIN_VERSION := $(shell uname -r)
ifneq ($(filter XX1.5.%,XX$(CYGWIN_VERSION)),)
$(call __ndk_info,You seem to be running Cygwin 1.5, which is not supported.)
$(call __ndk_info,Please upgrade to Cygwin 1.7 or higher.)
$(call __ndk_error,Aborting.)
endif
endif
# special-case the host-tag
HOST_TAG := windows
endif
$(call ndk_log,HOST_TAG set to $(HOST_TAG))
# Check for NDK-specific versions of our host tools
HOST_TOOLS_ROOT := $(NDK_ROOT)/prebuilt/$(HOST_TAG64)
HOST_PREBUILT := $(strip $(wildcard $(HOST_TOOLS_ROOT)/bin))
HOST_MAKE := $(strip $(NDK_HOST_MAKE))
HOST_PYTHON := $(strip $(NDK_HOST_PYTHON))
TOOLCHAIN_ROOT := $(NDK_ROOT)/toolchains/llvm/prebuilt/$(HOST_TAG64)
ifdef HOST_PREBUILT
$(call ndk_log,Host tools prebuilt directory: $(HOST_PREBUILT))
# The windows prebuilt binaries are for ndk-build.cmd
# On cygwin, we must use the Cygwin version of these tools instead.
ifneq ($(HOST_OS),cygwin)
ifndef HOST_MAKE
HOST_MAKE := $(wildcard $(HOST_PREBUILT)/make$(HOST_EXEEXT))
endif
ifndef HOST_PYTHON
ifeq ($(HOST_OS),windows)
HOST_PYTHON := $(wildcard $(TOOLCHAIN_ROOT)/python3/python$(HOST_EXEEXT))
else
HOST_PYTHON := $(wildcard $(TOOLCHAIN_ROOT)/python3/bin/python3$(HOST_EXEEXT))
endif
endif
endif
else
$(call ndk_log,Host tools prebuilt directory not found, using system tools)
endif
ifndef HOST_PYTHON
HOST_PYTHON := python
endif
HOST_ECHO := $(strip $(NDK_HOST_ECHO))
ifdef HOST_PREBUILT
ifndef HOST_ECHO
# Special case, on Cygwin, always use the host echo, not our prebuilt one
# which adds \r\n at the end of lines.
ifneq ($(HOST_OS),cygwin)
HOST_ECHO := $(strip $(wildcard $(HOST_PREBUILT)/echo$(HOST_EXEEXT)))
endif
endif
endif
ifndef HOST_ECHO
HOST_ECHO := echo
endif
$(call ndk_log,Host 'echo' tool: $(HOST_ECHO))
# Define HOST_ECHO_N to perform the equivalent of 'echo -n' on all platforms.
ifeq ($(HOST_OS),windows)
# Our custom toolbox echo binary supports -n.
HOST_ECHO_N := $(HOST_ECHO) -n
else
# On Posix, just use bare printf.
HOST_ECHO_N := printf %s
endif
$(call ndk_log,Host 'echo -n' tool: $(HOST_ECHO_N))
HOST_CMP := $(strip $(NDK_HOST_CMP))
ifdef HOST_PREBUILT
ifndef HOST_CMP
HOST_CMP := $(strip $(wildcard $(HOST_PREBUILT)/cmp$(HOST_EXEEXT)))
endif
endif
ifndef HOST_CMP
HOST_CMP := cmp
endif
$(call ndk_log,Host 'cmp' tool: $(HOST_CMP))
# Location of python build helpers.
BUILD_PY := $(NDK_ROOT)/build
#
# On Cygwin/MSys, define the 'cygwin-to-host-path' function here depending on the
# environment. The rules are the following:
#
# 1/ If NDK_USE_CYGPATH=1 and cygpath does exist in your path, cygwin-to-host-path
# calls "cygpath -m" for each host path. Since invoking 'cygpath -m' from GNU
# Make for each source file is _very_ slow, this is only a backup plan in
# case our automatic substitution function (described below) doesn't work.
#
# 2/ Generate a Make function that performs the mapping from cygwin/msys to host
# paths through simple substitutions. It's really a series of nested patsubst
# calls, that loo like:
#
# cygwin-to-host-path = $(patsubst /cygdrive/c/%,c:/%,\
# $(patsusbt /cygdrive/d/%,d:/%, \
# $1)
# or in MSys:
# cygwin-to-host-path = $(patsubst /c/%,c:/%,\
# $(patsusbt /d/%,d:/%, \
# $1)
#
# except that the actual definition is built from the list of mounted
# drives as reported by "mount" and deals with drive letter cases (i.e.
# '/cygdrive/c' and '/cygdrive/C')
#
ifeq ($(HOST_OS),cygwin)
CYGPATH := $(strip $(HOST_CYGPATH))
ifndef CYGPATH
$(call ndk_log, Probing for 'cygpath' program)
CYGPATH := $(strip $(shell which cygpath 2>/dev/null))
ifndef CYGPATH
$(call ndk_log, 'cygpath' was *not* found in your path)
else
$(call ndk_log, 'cygpath' found as: $(CYGPATH))
endif
endif
ifeq ($(NDK_USE_CYGPATH),1)
ifndef CYGPATH
$(call __ndk_info,No cygpath)
$(call __ndk_error,Aborting)
endif
$(call ndk_log, Forced usage of 'cygpath -m' through NDK_USE_CYGPATH=1)
cygwin-to-host-path = $(strip $(shell $(CYGPATH) -m $1))
else
# Call a Python script to generate a Makefile function that approximates
# cygpath.
WINDOWS_HOST_PATH_FRAGMENT := $(shell mount | $(HOST_PYTHON) $(BUILD_PY)/gen_cygpath.py)
$(eval cygwin-to-host-path = $(WINDOWS_HOST_PATH_FRAGMENT))
endif
endif # HOST_OS == cygwin
# The location of the build system files
BUILD_SYSTEM := $(NDK_ROOT)/build/core
# Include common definitions
include $(BUILD_SYSTEM)/definitions.mk
# ====================================================================
#
# Read all platform-specific configuration files.
#
# Each platform must be located in build/platforms/android-<apilevel>
# where <apilevel> corresponds to an API level number, with:
# 3 -> Android 1.5
# 4 -> next platform release
#
# ====================================================================
# ====================================================================
#
# Read all toolchain-specific configuration files.
#
# Each toolchain must have a corresponding config.mk file located
# in build/toolchains/<name>/ that will be included here.
#
# Each one of these files should define the following variables:
# TOOLCHAIN_NAME toolchain name (e.g. arm-linux-androideabi-4.9)
# TOOLCHAIN_ABIS list of target ABIs supported by the toolchain.
#
# Then, it should include $(ADD_TOOLCHAIN) which will perform
# book-keeping for the build system.
#
# ====================================================================
# the build script to include in each toolchain config.mk
ADD_TOOLCHAIN := $(BUILD_SYSTEM)/add-toolchain.mk
# checkbuild.py generates these two files from the files in $NDK/meta.
include $(BUILD_SYSTEM)/abis.mk
include $(BUILD_SYSTEM)/platforms.mk
NDK_KNOWN_DEVICE_ABIS := $(NDK_KNOWN_DEVICE_ABI64S) $(NDK_KNOWN_DEVICE_ABI32S)
NDK_APP_ABI_ALL_EXPANDED := $(NDK_KNOWN_DEVICE_ABIS)
NDK_APP_ABI_ALL32_EXPANDED := $(NDK_KNOWN_DEVICE_ABI32S)
NDK_APP_ABI_ALL64_EXPANDED := $(NDK_KNOWN_DEVICE_ABI64S)
NDK_MIN_PLATFORM := android-$(NDK_MIN_PLATFORM_LEVEL)
NDK_MAX_PLATFORM := android-$(NDK_MAX_PLATFORM_LEVEL)
$(call ndk_log,Found max platform level: $(NDK_MAX_PLATFORM_LEVEL))
# the list of all toolchains in this NDK
NDK_ALL_TOOLCHAINS :=
NDK_ALL_ABIS :=
NDK_ALL_ARCHS :=
TOOLCHAIN_CONFIGS := $(wildcard $(NDK_ROOT)/build/core/toolchains/*/config.mk)
$(foreach _config_mk,$(TOOLCHAIN_CONFIGS),\
$(eval include $(BUILD_SYSTEM)/add-toolchain.mk)\
)
NDK_ALL_TOOLCHAINS := $(sort $(NDK_ALL_TOOLCHAINS))
NDK_ALL_ABIS := $(sort $(NDK_ALL_ABIS))
NDK_ALL_ARCHS := $(sort $(NDK_ALL_ARCHS))
# Check that each ABI has a single architecture definition
$(foreach _abi,$(strip $(NDK_ALL_ABIS)),\
$(if $(filter-out 1,$(words $(NDK_ABI.$(_abi).arch))),\
$(call __ndk_info,INTERNAL ERROR: The $(_abi) ABI should have exactly one architecture definitions. Found: '$(NDK_ABI.$(_abi).arch)')\
$(call __ndk_error,Aborting...)\
)\
)
# Allow the user to define NDK_TOOLCHAIN to a custom toolchain name.
# This is normally used when the NDK release comes with several toolchains
# for the same architecture (generally for backwards-compatibility).
#
NDK_TOOLCHAIN := $(strip $(NDK_TOOLCHAIN))
ifdef NDK_TOOLCHAIN
# check that the toolchain name is supported
$(if $(filter-out $(NDK_ALL_TOOLCHAINS),$(NDK_TOOLCHAIN)),\
$(call __ndk_info,NDK_TOOLCHAIN is defined to the unsupported value $(NDK_TOOLCHAIN)) \
$(call __ndk_info,Please use one of the following values: $(NDK_ALL_TOOLCHAINS))\
$(call __ndk_error,Aborting)\
,)
$(call ndk_log, Using specific toolchain $(NDK_TOOLCHAIN))
endif
$(call ndk_log, This NDK supports the following target architectures and ABIS:)
$(foreach arch,$(NDK_ALL_ARCHS),\
$(call ndk_log, $(space)$(space)$(arch): $(NDK_ARCH.$(arch).abis))\
)
$(call ndk_log, This NDK supports the following toolchains and target ABIs:)
$(foreach tc,$(NDK_ALL_TOOLCHAINS),\
$(call ndk_log, $(space)$(space)$(tc): $(NDK_TOOLCHAIN.$(tc).abis))\
)

View File

@ -0,0 +1,56 @@
#
# Copyright (C) 2018 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.
#
# Generates rules to install sanitizer runtime libraries to the out directory if
# the sanitizer is requested in the app's ldflags.
#
# Args:
# NDK_SANTIZER_NAME:
# Sanitizer name used as the variable name component to find the library.
# i.e. $(TARGET_$(2)_BASENAME) is the name of the library to install. This
# is also used as the name printed to the terminal for the build step.
# NDK_SANITIZER_FSANITIZE_ARGS:
# -fsanitize= arguments that require this runtime library.
# NDK_SANITIZER_EXCLUDE_FSANITIZE_ARGS:
# -fsanitize= arguments that exclude this runtime library. For example,
# the UBSan runtime is included in the ASan runtime, so if we have both
# the address and undefined sanitizers enabled, we only need to install
# the ASan runtime.
#
# Example usage:
# NDK_SANITIZER_NAME := UBSAN
# NDK_SANITIZER_FSANITIZE_ARGS := undefined
# include $(BUILD_SYSTEM)/install_sanitizer.mk
ifneq (,$(filter $(NDK_SANITIZER_FSANITIZE_ARGS),$(NDK_SANITIZERS)))
ifeq (,$(filter $(NDK_SANITIZER_EXCLUDE_FSANITIZE_ARGS),$(NDK_SANITIZERS)))
installed_modules: $(NDK_APP_$(NDK_SANITIZER_NAME))
NDK_SANITIZER_TARGET := $(NDK_APP_$(NDK_SANITIZER_NAME))
NDK_SANITIZER_LIB_PATH := $(NDK_TOOLCHAIN_LIB_DIR)/$(TARGET_$(NDK_SANITIZER_NAME)_BASENAME)
$(NDK_SANITIZER_TARGET): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(NDK_SANITIZER_TARGET): PRIVATE_NAME := $(NDK_SANITIZER_NAME)
$(NDK_SANITIZER_TARGET): PRIVATE_SRC := $(NDK_SANITIZER_LIB_PATH)
$(NDK_SANITIZER_TARGET): PRIVATE_DST := $(NDK_APP_$(NDK_SANITIZER_NAME))
$(call generate-file-dir,$(NDK_APP_$(NDK_SANITIZER_NAME)))
$(NDK_SANITIZER_TARGET): clean-installed-binaries
$(call host-echo-build-step,$(PRIVATE_ABI),$(PRIVATE_NAME) "$(call pretty-dir,$(PRIVATE_DST))")
$(hide) $(call host-install,$(PRIVATE_SRC),$(PRIVATE_DST))
endif
endif

View File

@ -0,0 +1,22 @@
# Not bothering to check if there's actually any C++ code in the app. c++_shared
# is not the default, so if someone has set it explicitly we might as well do
# what they say.
ifeq ($(APP_STL),c++_shared)
NDK_LIBCXX_TARGET := $(NDK_APP_DST_DIR)/libc++_shared.so
NDK_LIBCXX_LIB_PATH := $(SYSROOT_LIB_DIR)/libc++_shared.so
installed_modules: $(NDK_LIBCXX_TARGET)
$(NDK_LIBCXX_TARGET): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(NDK_LIBCXX_TARGET): PRIVATE_NAME := Install
$(NDK_LIBCXX_TARGET): PRIVATE_SRC := $(NDK_LIBCXX_LIB_PATH)
$(NDK_LIBCXX_TARGET): PRIVATE_DST := $(NDK_LIBCXX_TARGET)
$(call generate-file-dir,$(NDK_LIBCXX_TARGET))
$(NDK_LIBCXX_TARGET): clean-installed-binaries
$(call host-echo-build-step,$(PRIVATE_ABI),$(PRIVATE_NAME) "$(call pretty-dir,$(PRIVATE_DST))")
$(hide) $(call host-install,$(PRIVATE_SRC),$(PRIVATE_DST))
endif

View File

@ -0,0 +1,29 @@
#
# Copyright (C) 2018 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.
#
# Generates rules to install wrap.sh files to the app's out directory.
NDK_WRAP_SH := $(NDK_APP_DST_DIR)/wrap.sh
$(call generate-file-dir,$(NDK_WRAP_SH))
installed_modules: $(NDK_WRAP_SH)
WRAP_SH_SRC := $(call local-source-file-path,$(NDK_APP_WRAP_SH_$(TARGET_ARCH_ABI)))
$(NDK_WRAP_SH): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(NDK_WRAP_SH): $(WRAP_SH_SRC) clean-installed-binaries
$(call host-echo-build-step,$(PRIVATE_ABI),wrap.sh "$(call pretty-dir,$@)")
$(hide) $(call host-install,$<,$@)

View File

@ -0,0 +1,47 @@
#
# Copyright (C) 2019 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.
#
# Generates rules to install the dynamic OpenMP runtime libraries to the out
# directory if the runtime is requested by the app's ldflags.
NDK_APP_NEEDS_DYNAMIC_OMP := false
$(foreach __module,$(__ndk_modules),\
$(eval __module_ldflags := \
$(NDK_APP_LDFLAGS) $(__ndk_modules.$(__module).LDFLAGS))\
$(if $(filter -fopenmp,$(__module_ldflags)),\
$(if $(filter -static-openmp,$(__module_ldflags)),,\
$(eval NDK_APP_NEEDS_DYNAMIC_OMP := true)\
)\
)\
)
ifeq ($(NDK_APP_NEEDS_DYNAMIC_OMP),true)
NDK_APP_OMP := $(NDK_APP_DST_DIR)/libomp.so
installed_modules: $(NDK_APP_OMP)
NDK_OMP_LIB_PATH := \
$(NDK_TOOLCHAIN_LIB_DIR)/$(TARGET_TOOLCHAIN_ARCH_LIB_DIR)/libomp.so
$(NDK_APP_OMP): PRIVATE_ABI := $(TARGET_ARCH_ABI)
$(NDK_APP_OMP): PRIVATE_SRC := $(NDK_OMP_LIB_PATH)
$(NDK_APP_OMP): PRIVATE_DST := $(NDK_APP_OMP)
$(call generate-file-dir,$(NDK_APP_OMP))
$(NDK_APP_OMP): clean-installed-binaries
$(call host-echo-build-step,$(PRIVATE_ABI),OpenMP "$(call pretty-dir,$(PRIVATE_DST))")
$(hide) $(call host-install,$(PRIVATE_SRC),$(PRIVATE_DST))
endif

View File

@ -0,0 +1,23 @@
NDK_MIN_PLATFORM_LEVEL := 21
NDK_MAX_PLATFORM_LEVEL := 35
NDK_PLATFORM_ALIAS_20 := android-19
NDK_PLATFORM_ALIAS_25 := android-24
NDK_PLATFORM_ALIAS_J := android-16
NDK_PLATFORM_ALIAS_J-MR1 := android-17
NDK_PLATFORM_ALIAS_J-MR2 := android-18
NDK_PLATFORM_ALIAS_K := android-19
NDK_PLATFORM_ALIAS_L := android-21
NDK_PLATFORM_ALIAS_L-MR1 := android-22
NDK_PLATFORM_ALIAS_M := android-23
NDK_PLATFORM_ALIAS_N := android-24
NDK_PLATFORM_ALIAS_N-MR1 := android-24
NDK_PLATFORM_ALIAS_O := android-26
NDK_PLATFORM_ALIAS_O-MR1 := android-27
NDK_PLATFORM_ALIAS_P := android-28
NDK_PLATFORM_ALIAS_Q := android-29
NDK_PLATFORM_ALIAS_R := android-30
NDK_PLATFORM_ALIAS_S := android-31
NDK_PLATFORM_ALIAS_Sv2 := android-32
NDK_PLATFORM_ALIAS_Tiramisu := android-33
NDK_PLATFORM_ALIAS_UpsideDownCake := android-34
NDK_PLATFORM_ALIAS_VanillaIceCream := android-35

View File

@ -0,0 +1,81 @@
# Copyright (C) 2010 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.
#
# this file is included from prebuilt-shared-library.mk or
# prebuilt-static-library.mk to declare prebuilt library binaries.
#
$(call assert-defined, LOCAL_BUILD_SCRIPT LOCAL_MAKEFILE LOCAL_PREBUILT_PREFIX LOCAL_PREBUILT_SUFFIX)
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
$(call check-LOCAL_MODULE_FILENAME)
# Check that LOCAL_SRC_FILES contains only the path to one library
ifneq ($(words $(LOCAL_SRC_FILES)),1)
$(call __ndk_info,ERROR:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): The LOCAL_SRC_FILES for a prebuilt library should only contain one item))
$(call __ndk_error,Aborting)
endif
bad_prebuilts := $(filter-out %$(LOCAL_PREBUILT_SUFFIX),$(LOCAL_SRC_FILES))
ifdef bad_prebuilts
$(call __ndk_info,ERROR:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): LOCAL_SRC_FILES should point to a file ending with "$(LOCAL_PREBUILT_SUFFIX)")
$(call __ndk_info,The following file is unsupported: $(bad_prebuilts))
$(call __ndk_error,Aborting)
endif
prebuilt_path := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
prebuilt := $(strip $(wildcard $(prebuilt_path)))
ifndef prebuilt
ifeq ($(LOCAL_ALLOW_MISSING_PREBUILT),true)
prebuilt := $(prebuilt_path)
include $(BUILD_SYSTEM)/define-missing-prebuilt.mk
else
$(call __ndk_info,ERROR:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): \
LOCAL_SRC_FILES points to a missing file)
$(call __ndk_info,Check that $(prebuilt_path) exists, or that its path \
is correct)
$(call __ndk_error,Aborting)
endif
endif
# If LOCAL_MODULE_FILENAME is defined, it will be used to name the file
# in the TARGET_OUT directory, and then the installation one. Note that
# it shouldn't have an .a or .so extension nor contain directory separators.
#
# If the variable is not defined, we determine its value from LOCAL_SRC_FILES
#
LOCAL_MODULE_FILENAME := $(strip $(LOCAL_MODULE_FILENAME))
ifndef LOCAL_MODULE_FILENAME
LOCAL_MODULE_FILENAME := $(notdir $(LOCAL_SRC_FILES))
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME:%$(LOCAL_PREBUILT_SUFFIX)=%)
endif
$(eval $(call ev-check-module-filename))
# If LOCAL_BUILT_MODULE is not defined, then ensure that the prebuilt is
# copied to TARGET_OUT during the build.
LOCAL_BUILT_MODULE := $(strip $(LOCAL_BUILT_MODULE))
ifndef LOCAL_BUILT_MODULE
LOCAL_BUILT_MODULE := $(TARGET_OUT)/$(LOCAL_MODULE_FILENAME)$(LOCAL_PREBUILT_SUFFIX)
LOCAL_OBJECTS := $(prebuilt)
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
endif
LOCAL_OBJS_DIR := $(TARGET_OBJS)/$(LOCAL_MODULE)
LOCAL_SRC_FILES :=
include $(BUILD_SYSTEM)/build-module.mk

View File

@ -0,0 +1,27 @@
# Copyright (C) 2010 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.
#
# this file is included from Android.mk files to build a target-specific
# shared library
#
LOCAL_BUILD_SCRIPT := PREBUILT_SHARED_LIBRARY
LOCAL_MODULE_CLASS := PREBUILT_SHARED_LIBRARY
LOCAL_MAKEFILE := $(local-makefile)
LOCAL_PREBUILT_PREFIX := lib
LOCAL_PREBUILT_SUFFIX := $(TARGET_SONAME_EXTENSION)
include $(BUILD_SYSTEM)/prebuilt-library.mk

View File

@ -0,0 +1,33 @@
# Copyright (C) 2010 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.
#
# this file is included from Android.mk files to build a target-specific
# shared library
#
LOCAL_BUILD_SCRIPT := PREBUILT_STATIC_LIBRARY
LOCAL_MODULE_CLASS := PREBUILT_STATIC_LIBRARY
LOCAL_MAKEFILE := $(local-makefile)
LOCAL_PREBUILT_PREFIX := lib
LOCAL_PREBUILT_SUFFIX := $(TARGET_LIB_EXTENSION)
# Prebuilt static libraries don't need to be copied to TARGET_OUT
# to facilitate debugging, so use the prebuilt version directly
# at link time.
LOCAL_BUILT_MODULE := $(call local-prebuilt-path,$(LOCAL_SRC_FILES))
LOCAL_BUILT_MODULE_NOT_COPIED := true
include $(BUILD_SYSTEM)/prebuilt-library.mk

View File

@ -0,0 +1,57 @@
#
# Copyright (C) 2018 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.
#
NDK_APP_ASAN := $(NDK_APP_DST_DIR)/$(TARGET_ASAN_BASENAME)
NDK_APP_TSAN := $(NDK_APP_DST_DIR)/$(TARGET_TSAN_BASENAME)
NDK_APP_UBSAN := $(NDK_APP_DST_DIR)/$(TARGET_UBSAN_BASENAME)
NDK_MODULES_LDFLAGS :=
$(foreach __module,$(__ndk_modules),\
$(eval NDK_MODULES_LDFLAGS += --module $(__ndk_modules.$(__module).LDFLAGS)))
NDK_SANITIZERS := $(strip \
$(shell $(HOST_PYTHON) $(BUILD_PY)/ldflags_to_sanitizers.py \
$(NDK_APP_LDFLAGS) $(NDK_MODULES_LDFLAGS)))
NDK_SANITIZER_NAME := UBSAN
NDK_SANITIZER_FSANITIZE_ARGS := fuzzer undefined
NDK_SANITIZER_EXCLUDE_FSANITIZE_ARGS := address
include $(BUILD_SYSTEM)/install_sanitizer.mk
NDK_SANITIZER_NAME := ASAN
NDK_SANITIZER_FSANITIZE_ARGS := address
NDK_SANITIZER_EXCLUDE_FSANITIZE_ARGS :=
include $(BUILD_SYSTEM)/install_sanitizer.mk
NDK_SANITIZER_NAME := TSAN
NDK_SANITIZER_FSANITIZE_ARGS := thread
NDK_SANITIZER_EXCLUDE_FSANITIZE_ARGS :=
include $(BUILD_SYSTEM)/install_sanitizer.mk
# If the user has not specified their own wrap.sh and is using ASAN, install a
# default ASAN wrap.sh for them.
ifneq (,$(filter address,$(NDK_SANITIZERS)))
ifeq ($(NDK_NO_USER_WRAP_SH),true)
NDK_APP_WRAP_SH_$(TARGET_ARCH_ABI) := $(NDK_ROOT)/wrap.sh/asan.sh
endif
endif
# If the user has not specified their own wrap.sh and is using HWASAN, install a
# default HWASAN wrap.sh for them.
ifneq (,$(filter hwaddress,$(NDK_SANITIZERS)))
ifeq ($(NDK_NO_USER_WRAP_SH),true)
NDK_APP_WRAP_SH_$(TARGET_ARCH_ABI) := $(NDK_ROOT)/wrap.sh/hwasan.sh
endif
endif

View File

@ -0,0 +1,52 @@
# Copyright (C) 2009 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.
#
# this file is included multiple times by build/core/setup-app.mk
#
$(call ndk_log,Building application '$(NDK_APP_NAME)' for ABI '$(TARGET_ARCH_ABI)')
TARGET_ARCH := $(strip $(NDK_ABI.$(TARGET_ARCH_ABI).arch))
ifndef TARGET_ARCH
$(call __ndk_info,ERROR: The $(TARGET_ARCH_ABI) ABI has no associated architecture!)
$(call __ndk_error,Aborting...)
endif
TARGET_OUT := $(NDK_APP_OUT)/$(_app)/$(TARGET_ARCH_ABI)
TARGET_PLATFORM_LEVEL := $(APP_PLATFORM_LEVEL)
# Pull up the minSdkVersion for this ABI if it is higher than the user's
# APP_PLATFORM. A warning will be separately emitted in setup-app-platform.mk if
# the user's APP_PLATFORM is too low for the NDK overall.
MIN_OS_FOR_TARGET := $(NDK_ABI_${TARGET_ARCH_ABI}_MIN_OS_VERSION)
ifneq ($(call lt,$(TARGET_PLATFORM_LEVEL),$(MIN_OS_FOR_TARGET)),)
TARGET_PLATFORM_LEVEL := $(MIN_OS_FOR_TARGET)
endif
# Not used by ndk-build, but are documented for use by Android.mk files.
TARGET_PLATFORM := android-$(TARGET_PLATFORM_LEVEL)
TARGET_ABI := $(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)
# 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.
ifeq ($(NDK_APP_OPTIM),debug)
TARGET_OBJS := $(TARGET_OUT)/objs-debug
else
TARGET_OBJS := $(TARGET_OUT)/objs
endif
include $(BUILD_SYSTEM)/setup-toolchain.mk

View File

@ -0,0 +1,130 @@
#
# Copyright (C) 2017 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.
#
# Included from add-application.mk to configure the APP_PLATFORM setting.
ifeq (null,$(APP_PROJECT_PATH))
ifndef APP_PLATFORM
$(call __ndk_info,APP_PLATFORM not set. Defaulting to minimum supported \
version $(NDK_MIN_PLATFORM).)
APP_PLATFORM := $(NDK_MIN_PLATFORM)
endif
else
# Set APP_PLATFORM with the following precedence:
#
# 1. APP_PLATFORM setting from the user.
# 2. Value in project.properties.
# 3. Minimum supported platform level.
APP_PLATFORM := $(strip $(APP_PLATFORM))
ifndef APP_PLATFORM
_local_props := $(strip $(wildcard $(APP_PROJECT_PATH)/project.properties))
ifndef _local_props
# NOTE: project.properties was called default.properties before
_local_props := $(strip \
$(wildcard $(APP_PROJECT_PATH)/default.properties))
endif
ifdef _local_props
APP_PLATFORM := $(strip \
$(shell $(HOST_PYTHON) $(BUILD_PY)/extract_platform.py \
$(call host-path,$(_local_props))))
$(call __ndk_info,Found platform level in $(_local_props). Setting \
APP_PLATFORM to $(APP_PLATFORM).)
else
$(call __ndk_info,APP_PLATFORM not set. Defaulting to minimum \
supported version $(NDK_MIN_PLATFORM).)
APP_PLATFORM := $(NDK_MIN_PLATFORM)
endif
endif
endif # APP_PROJECT_PATH == null
ifeq ($(APP_PLATFORM),latest)
$(call __ndk_info,Using latest available APP_PLATFORM: $(NDK_MAX_PLATFORM).)
override APP_PLATFORM := $(NDK_MAX_PLATFORM)
endif
# Aliases defined by meta/platforms.json include codename aliases for platform
# API levels as well as cover any gaps in platforms that may not have had NDK
# APIs.
APP_PLATFORM_LEVEL := $(strip $(subst android-,,$(APP_PLATFORM)))
ifdef NDK_PLATFORM_ALIAS_$(APP_PLATFORM_LEVEL)
_alias_target := $(NDK_PLATFORM_ALIAS_$(APP_PLATFORM_LEVEL))
$(call __ndk_info,$(APP_PLATFORM) is an alias for $(_alias_target). \
Adjusting APP_PLATFORM to match.)
override APP_PLATFORM := $(_alias_target)
endif
# For APP_PLATFORM values set below the minimum supported version, we could
# either pull up or error out. Since it's very unlikely that someone actually
# *needs* a lower platform level to build their app, we'll emit a warning and
# pull up.
APP_PLATFORM_LEVEL := $(strip $(subst android-,,$(APP_PLATFORM)))
ifneq ($(call lt,$(APP_PLATFORM_LEVEL),$(NDK_MIN_PLATFORM_LEVEL)),)
$(call __ndk_info,$(APP_PLATFORM) is unsupported. Using minimum supported \
version $(NDK_MIN_PLATFORM).)
override APP_PLATFORM := $(NDK_MIN_PLATFORM)
endif
# There are two reasons (aside from user error) a user might have picked an API
# level that is higher than what we support:
#
# 1. To get a pseudo "latest" version that will raise with each new version.
# 2. Their using an old NDK that doesn't support the required API level.
#
# For 1, we now support `APP_PLATFORM := latest`, and users should just switch
# to that.
#
# For 2, clamping to the maximum API level for the older NDK when a newer API
# level is in fact needed to compile the project will just present the user with
# a lot of unclear errors. We'll save them time by failing early.
ifneq ($(call gt,$(APP_PLATFORM_LEVEL),$(NDK_MAX_PLATFORM_LEVEL)),)
$(call __ndk_info,$(APP_PLATFORM) is above the maximum supported version \
$(NDK_MAX_PLATFORM). Choose a supported API level or set APP_PLATFORM \
to "latest".)
$(call __ndk_error,Aborting.)
endif
ifneq (null,$(APP_PROJECT_PATH))
# Check platform level (after adjustment) against android:minSdkVersion in AndroidManifest.xml
#
APP_MANIFEST := $(strip $(wildcard $(APP_PROJECT_PATH)/AndroidManifest.xml))
APP_PLATFORM_LEVEL := $(strip $(subst android-,,$(APP_PLATFORM)))
ifdef APP_MANIFEST
_minsdkversion := $(strip \
$(shell $(HOST_PYTHON) $(BUILD_PY)/extract_manifest.py \
minSdkVersion $(call host-path,$(APP_MANIFEST))))
ifndef _minsdkversion
# minSdkVersion defaults to 1.
# https://developer.android.com/guide/topics/manifest/uses-sdk-element.html
_minsdkversion := 1
endif
ifneq (,$(call gt,$(APP_PLATFORM_LEVEL),$(_minsdkversion)))
$(call __ndk_info,WARNING: APP_PLATFORM $(APP_PLATFORM) is higher than \
android:minSdkVersion $(_minsdkversion) in $(APP_MANIFEST). NDK \
binaries will *not* be compatible with devices older than \
$(APP_PLATFORM). See \
https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md \
for more information.)
endif
endif
endif # APP_PROJECT_PATH == null

View File

@ -0,0 +1,129 @@
# Copyright (C) 2009 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.
#
# this file is included repeatedly from build/core/main.mk
# and is used to prepare for app-specific build rules.
#
$(call assert-defined,_app)
_map := NDK_APP.$(_app)
# ok, let's parse all Android.mk source files in order to build
# the modules for this app.
#
# Restore the APP_XXX variables just for this pass as NDK_APP_XXX
#
NDK_APP_NAME := $(_app)
NDK_APP_APPLICATION_MK := $(call get,$(_map),Application.mk)
$(foreach __name,$(NDK_APP_VARS),\
$(eval NDK_$(__name) := $(call get,$(_map),$(__name)))\
)
# make the application depend on the modules it requires
.PHONY: ndk-app-$(_app)
ndk-app-$(_app): $(NDK_APP_MODULES)
all: ndk-app-$(_app)
# The ABI(s) to use
NDK_APP_ABI := $(subst $(comma),$(space),$(strip $(NDK_APP_ABI)))
ifndef NDK_APP_ABI
NDK_APP_ABI := $(NDK_DEFAULT_ABIS)
endif
NDK_ABI_FILTER := $(strip $(NDK_ABI_FILTER))
ifdef NDK_ABI_FILTER
$(eval $(NDK_ABI_FILTER))
endif
# If APP_ABI is 'all', then set it to all supported ABIs
# Otherwise, check that we don't have an invalid value here.
#
ifeq ($(NDK_APP_ABI),all)
NDK_APP_ABI := $(NDK_APP_ABI_ALL_EXPANDED)
else ifeq ($(NDK_APP_ABI),all32)
NDK_APP_ABI := $(NDK_APP_ABI_ALL32_EXPANDED)
else ifeq ($(NDK_APP_ABI),all64)
NDK_APP_ABI := $(NDK_APP_ABI_ALL64_EXPANDED)
else
# check the target ABIs for this application
_bad_abis = $(strip $(filter-out $(NDK_ALL_ABIS),$(NDK_APP_ABI)))
ifneq ($(_bad_abis),)
ifneq ($(filter $(_bad_abis),armeabi-v7a-hard),)
$(call __ndk_info,armeabi-v7a-hard is no longer supported. Use armeabi-v7a.)
$(call __ndk_info,See https://android.googlesource.com/platform/ndk/+/master/docs/HardFloatAbi.md)
else ifneq ($(filter $(_bad_abis),armeabi),)
$(call __ndk_info,The armeabi ABI is no longer supported. Use armeabi-v7a.)
else ifneq ($(filter $(_bad_abis),mips mips64),)
$(call __ndk_info,MIPS and MIPS64 are no longer supported.)
endif
$(call __ndk_info,NDK Application '$(_app)' targets unknown ABI(s): $(_bad_abis))
$(call __ndk_info,Please fix the APP_ABI definition in $(NDK_APP_APPLICATION_MK))
$(call __ndk_error,Aborting)
endif
endif
_deprecated_abis := $(filter $(NDK_DEPRECATED_ABIS),$(NDK_APP_ABI))
ifneq ($(_deprecated_abis),)
$(call __ndk_warning,Application targets deprecated ABI(s): $(_deprecated_abis))
$(call __ndk_warning,Support for these ABIs will be removed in a future NDK release.)
endif
# Clear all installed binaries for this application. This ensures that if the
# build fails or if you remove a module, you're not going to mistakenly package
# an obsolete version.
#
# Historically this would clear every ABI, meaning that the following workflow
# would leave only x86_64 present in the lib dir on completion:
#
# for abi in armeabi-v7a arm64-v8a x86 x86_64; do
# ndk-build APP_ABI=$abi
# done
#
# This is the workflow used by gradle. They currently override NDK_ALL_ABIS (an
# internal variable) to workaround this behavior. Changing this behavior allows
# them to remove their workaround and stop clobbering our implementation
# details.
ifeq ($(NDK_APP.$(_app).cleaned_binaries),)
NDK_APP.$(_app).cleaned_binaries := true
clean-installed-binaries::
$(hide) $(call host-rm,$(NDK_APP_ABI:%=$(NDK_APP_LIBS_OUT)/%/*))
endif
COMPILE_COMMANDS_JSON := $(call host-path,compile_commands.json)
sub_commands_json :=
# Each ABI
$(foreach _abi,$(NDK_APP_ABI),\
$(eval TARGET_ARCH_ABI := $(_abi))\
$(eval include $(BUILD_SYSTEM)/setup-abi.mk) \
)
_sub_commands_arg := $(sub_commands_json)
ifeq ($(LOCAL_SHORT_COMMANDS),true)
compile_commands_list_file := $(NDK_APP_OUT)/compile_commands.list
_sub_commands_arg := @$(compile_commands_list_file)
$(compile_commands_list_file): $(sub_commands_json)
$(call generate-list-file,$(sub_commands_json),$(compile_commands_list_file))
endif
$(COMPILE_COMMANDS_JSON): PRIVATE_SUB_COMMANDS := $(_sub_commands_arg)
$(COMPILE_COMMANDS_JSON): $(compile_commands_list_file) $(sub_commands_json)
$(hide) $(HOST_PYTHON) $(BUILD_PY)/gen_compile_db.py -o $@ \
$(PRIVATE_SUB_COMMANDS)

View File

@ -0,0 +1,42 @@
# Copyright (C) 2009-2010 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.
#
# ====================================================================
#
# Check the import path
#
# ====================================================================
NDK_MODULE_PATH := $(strip $(NDK_MODULE_PATH))
ifdef NDK_MODULE_PATH
ifneq ($(words $(NDK_MODULE_PATH)),1)
$(call __ndk_info,ERROR: You NDK_MODULE_PATH variable contains spaces)
$(call __ndk_info,Please fix the error and start again.)
$(call __ndk_error,Aborting)
endif
endif
$(call import-init)
$(foreach __path,$(subst $(HOST_DIRSEP),$(space),$(NDK_MODULE_PATH)),\
$(call import-add-path,$(__path))\
)
$(call import-add-path-optional,$(NDK_ROOT)/sources)
$(call import-add-path-optional,$(NDK_ROOT)/../development/ndk/sources)
# Gradle can inject its own import paths to expose other ndk-build modules to
# ndk-build (such as those generate by Prefab).
ifdef NDK_GRADLE_INJECTED_IMPORT_PATH
$(call import-add-path,$(NDK_GRADLE_INJECTED_IMPORT_PATH))
endif

View File

@ -0,0 +1,167 @@
# Copyright (C) 2009 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.
#
# this file is included repeatedly from build/core/setup-abi.mk and is used
# to setup the target toolchain for a given platform/abi combination.
#
$(call assert-defined,TARGET_PLATFORM_LEVEL TARGET_ARCH TARGET_ARCH_ABI)
$(call assert-defined,NDK_APPS NDK_APP_STL)
# Check that we have a toolchain that supports the current ABI.
# NOTE: If NDK_TOOLCHAIN is defined, we're going to use it.
ifndef NDK_TOOLCHAIN
# TODO: Remove all the multiple-toolchain configuration stuff. We only have
# Clang.
# This is a sorted list of toolchains that support the given ABI. For older
# NDKs this was a bit more complicated, but now we just have the GCC and the
# Clang toolchains with GCC being first (named "*-4.9", whereas clang is
# "*-clang").
TARGET_TOOLCHAIN_LIST := \
$(strip $(sort $(NDK_ABI.$(TARGET_ARCH_ABI).toolchains)))
ifneq ($(words $(TARGET_TOOLCHAIN_LIST)),1)
$(call __ndk_error,Expected two items in TARGET_TOOLCHAIN_LIST, \
found "$(TARGET_TOOLCHAIN_LIST)")
endif
ifndef TARGET_TOOLCHAIN_LIST
$(call __ndk_info,There is no toolchain that supports the $(TARGET_ARCH_ABI) ABI.)
$(call __ndk_info,Please modify the APP_ABI definition in $(NDK_APP_APPLICATION_MK) to use)
$(call __ndk_info,a set of the following values: $(NDK_ALL_ABIS))
$(call __ndk_error,Aborting)
endif
# We default to using Clang, which is the last item in the list.
TARGET_TOOLCHAIN := $(lastword $(TARGET_TOOLCHAIN_LIST))
$(call ndk_log,Using target toolchain '$(TARGET_TOOLCHAIN)' for '$(TARGET_ARCH_ABI)' ABI)
else # NDK_TOOLCHAIN is not empty
TARGET_TOOLCHAIN_LIST := $(strip $(filter $(NDK_TOOLCHAIN),$(NDK_ABI.$(TARGET_ARCH_ABI).toolchains)))
ifndef TARGET_TOOLCHAIN_LIST
$(call __ndk_info,The selected toolchain ($(NDK_TOOLCHAIN)) does not support the $(TARGET_ARCH_ABI) ABI.)
$(call __ndk_info,Please modify the APP_ABI definition in $(NDK_APP_APPLICATION_MK) to use)
$(call __ndk_info,a set of the following values: $(NDK_TOOLCHAIN.$(NDK_TOOLCHAIN).abis))
$(call __ndk_info,Or change your NDK_TOOLCHAIN definition.)
$(call __ndk_error,Aborting)
endif
TARGET_TOOLCHAIN := $(NDK_TOOLCHAIN)
endif # NDK_TOOLCHAIN is not empty
# Define default values for TOOLCHAIN_NAME, this can be overriden in
# the setup file.
TOOLCHAIN_NAME := $(TARGET_TOOLCHAIN)
TOOLCHAIN_VERSION := $(call last,$(subst -,$(space),$(TARGET_TOOLCHAIN)))
# compute NDK_APP_DST_DIR as the destination directory for the generated files
NDK_APP_DST_DIR := $(NDK_APP_LIBS_OUT)/$(TARGET_ARCH_ABI)
# Default build commands, can be overriden by the toolchain's setup script
include $(BUILD_SYSTEM)/default-build-commands.mk
# now call the toolchain-specific setup script
include $(NDK_TOOLCHAIN.$(TARGET_TOOLCHAIN).setup)
# Setup sysroot variables.
#
# Note that these are not needed for the typical case of invoking Clang, as
# Clang already knows where the sysroot is relative to itself. We still need to
# manually refer to these in some places because other tools such as yasm and
# don't have this knowledge.
# SYSROOT_INC points to a directory that contains all public header files for a
# given platform.
ifndef NDK_UNIFIED_SYSROOT_PATH
NDK_UNIFIED_SYSROOT_PATH := $(TOOLCHAIN_ROOT)/sysroot
endif
# TODO: Have the driver add the library path to -rpath-link.
SYSROOT_INC := $(NDK_UNIFIED_SYSROOT_PATH)
SYSROOT_LIB_DIR := $(NDK_UNIFIED_SYSROOT_PATH)/usr/lib/$(TOOLCHAIN_NAME)
SYSROOT_API_LIB_DIR := $(SYSROOT_LIB_DIR)/$(TARGET_PLATFORM_LEVEL)
# API-specific library directory comes first to make the linker prefer shared
# libs over static libs.
SYSROOT_LINK_ARG := -L $(SYSROOT_API_LIB_DIR) -L $(SYSROOT_LIB_DIR)
# Architecture specific headers like asm/ and machine/ are installed to an
# arch-$ARCH subdirectory of the sysroot.
SYSROOT_ARCH_INC_ARG := \
-isystem $(SYSROOT_INC)/usr/include/$(TOOLCHAIN_NAME)
NDK_TOOLCHAIN_RESOURCE_DIR := $(shell $(TARGET_CXX) -print-resource-dir)
NDK_TOOLCHAIN_LIB_DIR := $(strip $(NDK_TOOLCHAIN_RESOURCE_DIR))/lib/linux
clean-installed-binaries::
# free the dictionary of LOCAL_MODULE definitions
$(call modules-clear)
# now parse the Android.mk for the application, this records all
# module declarations, but does not populate the dependency graph yet.
include $(NDK_APP_BUILD_SCRIPT)
# Avoid computing sanitizer/wrap.sh things in the DUMP_VAR case because both of
# these will create build rules and we want to avoid that. The DUMP_VAR case
# also doesn't parse the module definitions, so we're missing a lot of the
# information we need.
ifeq (,$(DUMP_VAR))
# Comes after NDK_APP_BUILD_SCRIPT because we need to know if *any* module
# has -fsanitize in its ldflags.
include $(BUILD_SYSTEM)/sanitizers.mk
include $(BUILD_SYSTEM)/openmp.mk
include $(BUILD_SYSTEM)/install_stl.mk
ifneq ($(NDK_APP_WRAP_SH_$(TARGET_ARCH_ABI)),)
include $(BUILD_SYSTEM)/install_wrap_sh.mk
endif
endif
# recompute all dependencies between modules
$(call modules-compute-dependencies)
# for debugging purpose
ifdef NDK_DEBUG_MODULES
$(call modules-dump-database)
endif
# now, really build the modules, the second pass allows one to deal
# with exported values
$(foreach __pass2_module,$(__ndk_modules),\
$(eval LOCAL_MODULE := $(__pass2_module))\
$(eval include $(BUILD_SYSTEM)/build-binary.mk)\
)
# Now compute the closure of all module dependencies.
#
# If APP_MODULES is not defined in the Application.mk, we
# will build all modules that were listed from the top-level Android.mk
# and the installable imported ones they depend on
#
ifeq ($(strip $(NDK_APP_MODULES)),)
WANTED_MODULES := $(call modules-get-all-installable,$(modules-get-top-list))
ifeq (,$(strip $(WANTED_MODULES)))
WANTED_MODULES := $(modules-get-top-list)
$(call ndk_log,[$(TARGET_ARCH_ABI)] No installable modules in project - forcing static library build)
endif
else
WANTED_MODULES := $(call module-get-all-dependencies,$(NDK_APP_MODULES))
endif
$(call ndk_log,[$(TARGET_ARCH_ABI)] Modules to build: $(WANTED_MODULES))
WANTED_INSTALLED_MODULES += $(call map,module-get-installed,$(WANTED_MODULES))

View File

@ -0,0 +1,63 @@
#
# Copyright (C) 2023 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.
#
# Interprets APP_STL to configure default cflags/ldflags and install rules for
# libc++ runtime libraries as necessary.
ifneq (,$(call module_needs_clangxx,$(LOCAL_MODULE)))
ifeq ($(APP_STL),none)
LOCAL_CPPFLAGS += -nostdinc++
LOCAL_LDFLAGS += -nostdlib++
else ifeq ($(APP_STL),system)
# TODO: Actually use the system STL headers for that mode or remove.
#
# I'm not sure how long this has been broken, but released NDKs do not use the
# bionic C++ headers when APP_STL=system, they use the libc++ headers. That's
# almost certainly unintentional.
#
# There may not actually be any compatibility issues with this because bionic's
# libstdc++ only provides new and delete anyway (the rest of the behavior is
# just headers that re-expose C APIs in the std namespace). We could choose to
# delete bionic's headers and keep this "bug" instead.
# LOCAL_CPPFLAGS += -stdlib=libstdc++
# LOCAL_LDFLAGS += -stdlib=libstdc++
# TODO: Remove when https://reviews.llvm.org/D55856 is merged.
#
# The system STL Android.mk will export -lstdc++, but the Clang driver will
# helpfully rewrite -lstdc++ to whatever the default C++ stdlib linker
# arguments are, except in the presence of -nostdlib and -nodefaultlibs.
# That part of the driver does not account for -nostdlib++. We can fix the
# behavior by using -stdlib=libstdc++ so it rewrites -lstdc++ to -lstdc++
# instead of -lc++.
LOCAL_LDFLAGS += -stdlib=libstdc++
ifneq (,$(call module-has-c++-features,$(LOCAL_MODULE),rtti exceptions))
LOCAL_LDLIBS += -lc++abi
endif
else ifeq ($(APP_STL),c++_static)
LOCAL_LDFLAGS += -static-libstdc++
endif
# Else c++_shared, and no flags are needed. Shared libc++ is the default
# behavior for Android targets in Clang.
#
# Invalid values will be checked by ndk-stl-check.
endif

View File

@ -0,0 +1 @@
NDK_SYSTEM_LIBS := libEGL.so libGLESv1_CM.so libGLESv2.so libGLESv3.so libOpenMAXAL.so libOpenSLES.so libaaudio.so libamidi.so libandroid.so libbinder_ndk.so libc.so libcamera2ndk.so libdl.so libicu.so libjnigraphics.so liblog.so libm.so libmediandk.so libnativehelper.so libnativewindow.so libneuralnetworks.so libstdc++.so libsync.so libvulkan.so libz.so

View File

@ -0,0 +1,20 @@
# 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.
#
# config file for the arm64 llvm toolchain for the Android NDK
# the real meat is in the setup.mk file adjacent to this one
#
TOOLCHAIN_ARCH := arm64
TOOLCHAIN_ABIS := arm64-v8a

View File

@ -0,0 +1,42 @@
# 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.
#
TOOLCHAIN_NAME := aarch64-linux-android
LLVM_TRIPLE := aarch64-none-linux-android
TARGET_TOOLCHAIN_ARCH_LIB_DIR := aarch64
TARGET_ASAN_BASENAME := libclang_rt.asan-aarch64-android.so
TARGET_TSAN_BASENAME := libclang_rt.tsan-aarch64-android.so
TARGET_UBSAN_BASENAME := libclang_rt.ubsan_standalone-aarch64-android.so
TARGET_CFLAGS := -fpic
TARGET_arm64_release_CFLAGS := \
-O2 \
-DNDEBUG \
TARGET_arm64_debug_CFLAGS := \
-O0 \
-UNDEBUG \
-fno-limit-debug-info \
# This function will be called to determine the target CFLAGS used to build
# a C or Assembler source file, based on its tags.
#
TARGET-process-src-files-tags = \
$(eval __debug_sources := $(call get-src-files-with-tag,debug)) \
$(eval __release_sources := $(call get-src-files-without-tag,debug)) \
$(call set-src-files-target-cflags, $(__debug_sources), $(TARGET_arm64_debug_CFLAGS)) \
$(call set-src-files-target-cflags, $(__release_sources),$(TARGET_arm64_release_CFLAGS)) \

View File

@ -0,0 +1,20 @@
# 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.
#
# config file for the arm llvm toolchain for the Android NDK the real meat is in
# the setup.mk file adjacent to this one
#
TOOLCHAIN_ARCH := arm
TOOLCHAIN_ABIS := armeabi-v7a

View File

@ -0,0 +1,65 @@
# 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.
#
TOOLCHAIN_NAME := arm-linux-androideabi
LLVM_TRIPLE := armv7-none-linux-androideabi
TARGET_TOOLCHAIN_ARCH_LIB_DIR := arm
TARGET_ASAN_BASENAME := libclang_rt.asan-arm-android.so
TARGET_UBSAN_BASENAME := libclang_rt.ubsan_standalone-arm-android.so
TARGET_CFLAGS := -fpic
TARGET_arm_release_CFLAGS := \
-O2 \
-DNDEBUG \
TARGET_thumb_release_CFLAGS := \
-mthumb \
-Oz \
-DNDEBUG \
TARGET_arm_debug_CFLAGS := \
-O0 \
-UNDEBUG \
-fno-limit-debug-info \
TARGET_thumb_debug_CFLAGS := \
-mthumb \
-O0 \
-UNDEBUG \
-fno-limit-debug-info \
# This function will be called to determine the target CFLAGS used to build
# a C or Assembler source file, based on its tags.
TARGET-process-src-files-tags = \
$(eval __arm_sources := $(call get-src-files-with-tag,arm)) \
$(eval __thumb_sources := $(call get-src-files-without-tag,arm)) \
$(eval __debug_sources := $(call get-src-files-with-tag,debug)) \
$(eval __release_sources := $(call get-src-files-without-tag,debug)) \
$(call set-src-files-target-cflags, \
$(call set_intersection,$(__arm_sources),$(__debug_sources)), \
$(TARGET_arm_debug_CFLAGS)) \
$(call set-src-files-target-cflags,\
$(call set_intersection,$(__arm_sources),$(__release_sources)),\
$(TARGET_arm_release_CFLAGS)) \
$(call set-src-files-target-cflags,\
$(call set_intersection,$(__thumb_sources),$(__debug_sources)),\
$(TARGET_thumb_debug_CFLAGS)) \
$(call set-src-files-target-cflags,\
$(call set_intersection,$(__thumb_sources),$(__release_sources)),\
$(TARGET_thumb_release_CFLAGS)) \
$(call set-src-files-text,$(__arm_sources),arm) \
$(call set-src-files-text,$(__thumb_sources),thumb)

View File

@ -0,0 +1,20 @@
# Copyright (C) 2023 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.
#
# config file for the riscv64 clang toolchain for the Android NDK the real meat
# is in the setup.mk file adjacent to this one
#
TOOLCHAIN_ARCH := riscv64
TOOLCHAIN_ABIS := riscv64

View File

@ -0,0 +1,47 @@
# Copyright (C) 2023 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.
#
TOOLCHAIN_NAME := riscv64-linux-android
LLVM_TRIPLE := riscv64-none-linux-android
TARGET_TOOLCHAIN_ARCH_LIB_DIR := riscv64
TARGET_ASAN_BASENAME := libclang_rt.asan-riscv64-android.so
# TODO(https://github.com/android/ndk/issues/1041): Add TSAN when it builds for RISCV64.
# TARGET_TSAN_BASENAME := libclang_rt.tsan-riscv64-android.so
TARGET_UBSAN_BASENAME := libclang_rt.ubsan_standalone-riscv64-android.so
TARGET_CFLAGS := -fPIC
TARGET_riscv64_release_CFLAGS := \
-O2 \
-DNDEBUG \
TARGET_riscv64_debug_CFLAGS := \
-O0 \
-UNDEBUG \
-fno-limit-debug-info \
# This function will be called to determine the target CFLAGS used to build
# a C or Assembler source file, based on its tags.
#
TARGET-process-src-files-tags = \
$(eval __debug_sources := $(call get-src-files-with-tag,debug)) \
$(eval __release_sources := $(call get-src-files-without-tag,debug)) \
$(call set-src-files-target-cflags, $(__debug_sources), $(TARGET_riscv64_debug_CFLAGS)) \
$(call set-src-files-target-cflags, $(__release_sources),$(TARGET_riscv64_release_CFLAGS)) \
# The ABI-specific sub-directory that the SDK tools recognize for
# this toolchain's generated binaries
TARGET_ABI_SUBDIR := riscv64

View File

@ -0,0 +1,20 @@
# 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.
#
# config file for the x86 clang toolchain for the Android NDK the real meat is
# in the setup.mk file adjacent to this one
#
TOOLCHAIN_ARCH := x86
TOOLCHAIN_ABIS := x86

View File

@ -0,0 +1,46 @@
# 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.
#
TOOLCHAIN_NAME := i686-linux-android
LLVM_TRIPLE := i686-none-linux-android
TARGET_TOOLCHAIN_ARCH_LIB_DIR := i386
TARGET_ASAN_BASENAME := libclang_rt.asan-i686-android.so
TARGET_UBSAN_BASENAME := libclang_rt.ubsan_standalone-i686-android.so
TARGET_CFLAGS := -fPIC
TARGET_x86_release_CFLAGS := \
-O2 \
-DNDEBUG \
# When building for debug, compile everything as x86.
TARGET_x86_debug_CFLAGS := \
-O0 \
-UNDEBUG \
-fno-limit-debug-info \
# This function will be called to determine the target CFLAGS used to build
# a C or Assembler source file, based on its tags.
#
TARGET-process-src-files-tags = \
$(eval __debug_sources := $(call get-src-files-with-tag,debug)) \
$(eval __release_sources := $(call get-src-files-without-tag,debug)) \
$(call set-src-files-target-cflags, $(__debug_sources), $(TARGET_x86_debug_CFLAGS)) \
$(call set-src-files-target-cflags, $(__release_sources),$(TARGET_x86_release_CFLAGS)) \
# The ABI-specific sub-directory that the SDK tools recognize for
# this toolchain's generated binaries
TARGET_ABI_SUBDIR := x86

View File

@ -0,0 +1,20 @@
# 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.
#
# config file for the x86_64 clang toolchain for the Android NDK the real meat
# is in the setup.mk file adjacent to this one
#
TOOLCHAIN_ARCH := x86_64
TOOLCHAIN_ABIS := x86_64

View File

@ -0,0 +1,46 @@
# 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.
#
TOOLCHAIN_NAME := x86_64-linux-android
LLVM_TRIPLE := x86_64-none-linux-android
TARGET_TOOLCHAIN_ARCH_LIB_DIR := x86_64
TARGET_ASAN_BASENAME := libclang_rt.asan-x86_64-android.so
TARGET_TSAN_BASENAME := libclang_rt.tsan-x86_64-android.so
TARGET_UBSAN_BASENAME := libclang_rt.ubsan_standalone-x86_64-android.so
TARGET_CFLAGS := -fPIC
TARGET_x86_64_release_CFLAGS := \
-O2 \
-DNDEBUG \
TARGET_x86_64_debug_CFLAGS := \
-O0 \
-UNDEBUG \
-fno-limit-debug-info \
# This function will be called to determine the target CFLAGS used to build
# a C or Assembler source file, based on its tags.
#
TARGET-process-src-files-tags = \
$(eval __debug_sources := $(call get-src-files-with-tag,debug)) \
$(eval __release_sources := $(call get-src-files-without-tag,debug)) \
$(call set-src-files-target-cflags, $(__debug_sources), $(TARGET_x86_64_debug_CFLAGS)) \
$(call set-src-files-target-cflags, $(__release_sources),$(TARGET_x86_64_release_CFLAGS)) \
# The ABI-specific sub-directory that the SDK tools recognize for
# this toolchain's generated binaries
TARGET_ABI_SUBDIR := x86_64

View File

@ -0,0 +1,4 @@
NDK_MAJOR := 27
NDK_MINOR := 3
NDK_BETA := 0
NDK_CANARY := false

View File

@ -0,0 +1,97 @@
#
# Copyright (C) 2018 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.
#
"""Generates a intermediate file for using in making a compilation database.
The intermediate file is also a JSON file, but only encodes the data for a
single output.
"""
from __future__ import print_function
import argparse
import json
import os
from pathlib import Path
from shlex import join
def get_argument_parser() -> argparse.ArgumentParser:
"""Parses and returns command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument(
"-o",
"--output",
type=os.path.realpath, # type: ignore
required=True,
help="Path to output file",
)
parser.add_argument(
"-d",
"--directory",
type=os.path.realpath, # type: ignore
help="Working directory for the compile command.",
)
parser.add_argument("-f", "--file", help="Source file.")
parser.add_argument("--object-file", help="Object file.")
parser.add_argument(
"--command-file",
type=os.path.realpath, # type: ignore
help="Compilation command list file.",
)
parser.add_argument(
"compile_command",
metavar="COMPILE_COMMAND",
nargs=argparse.REMAINDER,
help="Compilation command.",
)
return parser
def main() -> None:
"""Program entry point."""
parser = get_argument_parser()
args = parser.parse_args()
if args.command_file and args.compile_command:
parser.error("--command-file and COMPILE_COMMAND are mutually exclusive")
if not args.command_file and not args.compile_command:
parser.error("Either --command-file or COMPILE_COMMAND is required.")
command = join(args.compile_command)
if args.command_file:
command = Path(args.command_file).read_text(encoding="utf-8").strip()
with open(args.output, "w", encoding="utf-8") as out_file:
json.dump(
{
"directory": args.directory,
"file": args.file,
"output": args.object_file,
"command": command,
},
out_file,
)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,117 @@
#
# Copyright (C) 2017 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.
#
"""Extracts values from the AndroidManifest.xml file."""
from __future__ import print_function
import argparse
import os.path
import xml.etree.ElementTree
def parse_args() -> argparse.Namespace:
"""Parse and return command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument(
"property",
metavar="PROPERTY",
choices=("minSdkVersion", "debuggable"),
help="Property to extract from the manifest file.",
)
parser.add_argument(
"manifest_file",
metavar="MANIFEST_FILE",
type=os.path.abspath, # type: ignore
help="Path to the AndroidManifest.xml file.",
)
return parser.parse_args()
def get_rpath_attribute(
root: xml.etree.ElementTree.Element,
element_path: str,
attribute: str,
default: str = "",
) -> str:
"""Returns the value of an attribute at an rpath.
If more than one element exists with the same name, only the first is
checked.
Args:
root: The XML element to search from.
path: The path to the element.
attribute: The name of the attribute to fetch.
Returns:
The attribute's value as a string if found, else the value of
`default`.
"""
ns_url = "http://schemas.android.com/apk/res/android"
ns = {
"android": ns_url,
}
elem = root.find(element_path, ns)
if elem is None:
return ""
# ElementTree elements don't have the same helpful namespace parameter that
# the find family does :(
attrib_name = attribute.replace("android:", "{" + ns_url + "}")
return str(elem.get(attrib_name, default))
def get_minsdkversion(root: xml.etree.ElementTree.Element) -> str:
"""Finds and returns the value of android:minSdkVersion in the manifest.
Returns:
String form of android:minSdkVersion if found, else the empty string.
"""
return get_rpath_attribute(root, "./uses-sdk", "android:minSdkVersion", "")
def get_debuggable(root: xml.etree.ElementTree.Element) -> str:
"""Finds and returns the value of android:debuggable in the manifest.
Returns:
String form of android:debuggable if found, else the empty string.
"""
debuggable = get_rpath_attribute(root, "./application", "android:debuggable", "")
# Though any such manifest would be invalid, the awk script rewrote bogus
# values to false. Missing attributes should also be false.
if debuggable != "true":
debuggable = "false"
return debuggable
def main() -> None:
args = parse_args()
tree = xml.etree.ElementTree.parse(args.manifest_file)
if args.property == "minSdkVersion":
print(get_minsdkversion(tree.getroot()))
elif args.property == "debuggable":
print(get_debuggable(tree.getroot()))
else:
raise ValueError
if __name__ == "__main__":
main()

View File

@ -0,0 +1,77 @@
#
# Copyright (C) 2017 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.
#
"""Extracts the platform version from the project.properties file."""
from __future__ import print_function
import argparse
import os.path
import re
from typing import TextIO
def parse_args() -> argparse.Namespace:
"""Parse and return command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument(
"properties_file",
metavar="PROPERTIES_FILE",
type=os.path.abspath, # type: ignore
help="Path to the project.properties file.",
)
return parser.parse_args()
def get_platform(properties_file: TextIO) -> str:
"""Finds and returns the platform version in the properties file.
Returns:
String form of the platform version if found, else "unknown".
"""
android_regex = re.compile(r"(android-\w+)")
vendor_regex = re.compile(r":(\d+)\s*$")
for line in properties_file:
match = android_regex.search(line)
if match is not None:
return match.group(1)
match = vendor_regex.search(line)
if match is not None:
return "android-{}".format(match.group(1))
return "unknown"
def main() -> None:
args = parse_args()
# Following the comment in the old awk script, we're trying to match:
#
# target=android-<api>
# target=<vendor>:<name>:<api>
#
# There unfortunately aren't any examples of what the vendor target
# specification actually looks like or where it might be used, so we'll
# just have to mirror the simplistic match that was in the awk script.
#
# android- may be followed by either the numeric API level or the named
# platform. Note that while we can parse any name, ndk-build only support a
# small handful.
with open(args.properties_file, encoding="utf-8") as properties_file:
print(get_platform(properties_file))
if __name__ == "__main__":
main()

View File

@ -0,0 +1,81 @@
#
# Copyright (C) 2018 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.
#
"""Generates a compile_commands.json file for the given ndk-build project.
The compilation commands for this file are read from the files passed as
arguments to this script.
"""
from __future__ import print_function
import argparse
import json
import os
from pathlib import Path
def parse_args() -> argparse.Namespace:
"""Parses and returns command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument(
"-o", "--output", type=os.path.realpath, help="Path to output file"
) # type: ignore
def maybe_list_file(arg: str) -> str:
if arg.startswith("@"):
return "@" + os.path.realpath(arg[1:])
return os.path.realpath(arg)
parser.add_argument(
"command_files",
metavar="FILE",
type=maybe_list_file,
nargs="+",
help=(
"Path to the compilation database for a single object. If the "
"argument begins with @ it will be treated as a list file "
"containing paths to the one or more JSON files."
),
)
return parser.parse_args()
def main() -> None:
"""Program entry point."""
args = parse_args()
all_commands = []
command_files = []
for command_file in args.command_files:
if command_file.startswith("@"):
list_file = Path(command_file[1:])
command_files.extend(list_file.read_text(encoding="utf-8").split())
else:
command_files.append(command_file)
for command_file_path in command_files:
with open(command_file_path, encoding="utf-8") as command_file:
all_commands.append(json.load(command_file))
with open(args.output, "w", encoding="utf-8") as out_file:
json.dump(
all_commands, out_file, sort_keys=True, indent=4, separators=(",", ": ")
)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,103 @@
#
# Copyright (C) 2017 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.
#
"""Generates a make function approximating cygpath.
We don't just call cygpath (unless directed by NDK_USE_CYGPATH=1) because we
have to call this very often and doing so would be very slow. By doing this in
make, we can be much faster.
"""
from __future__ import print_function
import posixpath
import re
import sys
def get_mounts(mount_output: str) -> list[tuple[str, str]]:
"""Parses the output of mount and returns a dict of mounts.
Args:
mount_output: The text output from mount(1).
Returns:
A list of tuples mapping cygwin paths to Windows paths.
"""
mount_regex = re.compile(r"^(\S+) on (\S+) .*$")
# We use a list of tuples rather than a dict because we want to recurse on
# the list later anyway.
mounts: list[tuple[str, str]] = []
for line in mount_output.splitlines():
# Cygwin's mount doesn't use backslashes even in Windows paths, so no
# need to replace here.
match = mount_regex.search(line)
if match is not None:
win_path = match.group(1)
cyg_path = match.group(2)
if cyg_path == "/":
# Since we're going to be using patsubst on these, we need to
# make sure that the rule for / is applied last, otherwise
# we'll replace all other cygwin paths with that one.
mounts.insert(0, (cyg_path, win_path))
elif cyg_path.startswith("/cygdrive/"):
# We need both /cygdrive/c and /cygdrive/C to point to C:.
letter = posixpath.basename(cyg_path)
lower_path = posixpath.join("/cygdrive", letter.lower())
upper_path = posixpath.join("/cygdrive", letter.upper())
mounts.append((lower_path, win_path))
mounts.append((upper_path, win_path))
else:
mounts.append((cyg_path, win_path))
return mounts
def make_cygpath_function(mounts: list[tuple[str, str]]) -> str:
"""Creates a make function that can be used in place of cygpath.
Args:
mounts: A list of tuples decribing filesystem mounts.
Returns:
The body of a function implementing cygpath in make as a string.
"""
# We're building a bunch of nested patsubst calls. Once we've written each
# of the calls, we pass the function input to the inner most call.
if not mounts:
return "$1"
cyg_path, win_path = mounts[0]
if not cyg_path.endswith("/"):
cyg_path += "/"
if not win_path.endswith("/"):
win_path += "/"
other_mounts = mounts[1:]
return "$(patsubst {}%,{}%,\n{})".format(
cyg_path, win_path, make_cygpath_function(other_mounts)
)
def main() -> None:
# We're invoked from make and piped the output of `mount` so we can
# determine what mappings to make.
mount_output = sys.stdin.read()
mounts = get_mounts(mount_output)
print(make_cygpath_function(mounts))
if __name__ == "__main__":
main()

View File

@ -0,0 +1,27 @@
GNU Make Standard Library
-------------------------
1. Visit http://gmsl.sf.net for more details
2. To use the GMSL in your Makefile make sure that you have the files
gmsl
__gmsl
Add
include gmsl
to your Makefile(s).
3. To run the GMSL test suite have
gmsl
__gmsl
gmsl-tests
And then run
make -f gmsl-tests

View File

@ -0,0 +1,854 @@
# ----------------------------------------------------------------------------
#
# GNU Make Standard Library (GMSL)
#
# A library of functions to be used with GNU Make's $(call) that
# provides functionality not available in standard GNU Make.
#
# Copyright (c) 2005-2007 John Graham-Cumming
#
# This file is part of GMSL
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of the John Graham-Cumming nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ----------------------------------------------------------------------------
# This is the GNU Make Standard Library version number as a list with
# three items: major, minor, revision
gmsl_version := 1 0 11
# Used to output warnings and error from the library, it's possible to
# disable any warnings or errors by overriding these definitions
# manually or by setting GMSL_NO_WARNINGS or GMSL_NO_ERRORS
__gmsl_name := GNU Make Standard Library
__gmsl_warning = $(warning $(__gmsl_name): $1)
__gmsl_error = $(error $(__gmsl_name): $1)
ifdef GMSL_NO_WARNINGS
__gmsl_warning :=
endif
ifdef GMSL_NO_ERRORS
__gmsl_error :=
endif
# If GMSL_TRACE is enabled then calls to the library functions are
# traced to stdout using warning messages with their arguments
ifdef GMSL_TRACE
__gmsl_tr1 = $(warning $0('$1'))
__gmsl_tr2 = $(warning $0('$1','$2'))
__gmsl_tr3 = $(warning $0('$1','$2','$3'))
else
__gmsl_tr1 :=
__gmsl_tr2 :=
__gmsl_tr3 :=
endif
# Figure out whether we have $(eval) or not (GNU Make 3.80 and above)
# if we do not then output a warning message, if we do then some
# functions will be enabled.
__gmsl_have_eval := $(false)
__gmsl_ignore := $(eval __gmsl_have_eval := $(true))
# If this is being run with Electric Cloud's emake then warn that
# their $(eval) support is incomplete.
ifdef ECLOUD_BUILD_ID
$(warning You are using Electric Cloud's emake which has incomplete $$(eval) support)
__gmsl_have_eval := $(false)
endif
# See if we have $(lastword) (GNU Make 3.81 and above)
__gmsl_have_lastword := $(lastword $(false) $(true))
# See if we have native or and and (GNU Make 3.81 and above)
__gmsl_have_or := $(if $(filter-out undefined, \
$(origin or)),$(call or,$(true),$(false)))
__gmsl_have_and := $(if $(filter-out undefined, \
$(origin and)),$(call and,$(true),$(true)))
ifneq ($(__gmsl_have_eval),$(true))
$(call __gmsl_warning,GNU Make $(MAKE_VERSION) does not support $$$$(eval): some functions disabled)
endif
# ----------------------------------------------------------------------------
# Function: gmsl_compatible
# Arguments: List containing the desired library version number (maj min rev)
# Returns: $(true) if this version of the library is compatible
# with the requested version number, otherwise $(false)
# ----------------------------------------------------------------------------
gmsl_compatible = $(strip \
$(if $(call gt,$(word 1,$1),$(word 1,$(gmsl_version))), \
$(false), \
$(if $(call lt,$(word 1,$1),$(word 1,$(gmsl_version))), \
$(true), \
$(if $(call gt,$(word 2,$1),$(word 2,$(gmsl_version))), \
$(false), \
$(if $(call lt,$(word 2,$1),$(word 2,$(gmsl_version))), \
$(true), \
$(call lte,$(word 3,$1),$(word 3,$(gmsl_version))))))))
# ###########################################################################
# LOGICAL OPERATORS
# ###########################################################################
# not is defined in gmsl
# ----------------------------------------------------------------------------
# Function: and
# Arguments: Two boolean values
# Returns: Returns $(true) if both of the booleans are true
# ----------------------------------------------------------------------------
ifneq ($(__gmsl_have_and),$(true))
and = $(__gmsl_tr2)$(if $1,$(if $2,$(true),$(false)),$(false))
endif
# ----------------------------------------------------------------------------
# Function: or
# Arguments: Two boolean values
# Returns: Returns $(true) if either of the booleans is true
# ----------------------------------------------------------------------------
ifneq ($(__gmsl_have_or),$(true))
or = $(__gmsl_tr2)$(if $1$2,$(true),$(false))
endif
# ----------------------------------------------------------------------------
# Function: xor
# Arguments: Two boolean values
# Returns: Returns $(true) if exactly one of the booleans is true
# ----------------------------------------------------------------------------
xor = $(__gmsl_tr2)$(if $1,$(if $2,$(false),$(true)),$(if $2,$(true),$(false)))
# ----------------------------------------------------------------------------
# Function: nand
# Arguments: Two boolean values
# Returns: Returns value of 'not and'
# ----------------------------------------------------------------------------
nand = $(__gmsl_tr2)$(if $1,$(if $2,$(false),$(true)),$(true))
# ----------------------------------------------------------------------------
# Function: nor
# Arguments: Two boolean values
# Returns: Returns value of 'not or'
# ----------------------------------------------------------------------------
nor = $(__gmsl_tr2)$(if $1$2,$(false),$(true))
# ----------------------------------------------------------------------------
# Function: xnor
# Arguments: Two boolean values
# Returns: Returns value of 'not xor'
# ----------------------------------------------------------------------------
xnor =$(__gmsl_tr2)$(if $1,$(if $2,$(true),$(false)),$(if $2,$(false),$(true)))
# ###########################################################################
# LIST MANIPULATION FUNCTIONS
# ###########################################################################
# ----------------------------------------------------------------------------
# Function: first (same as LISP's car, or head)
# Arguments: 1: A list
# Returns: Returns the first element of a list
# ----------------------------------------------------------------------------
first = $(__gmsl_tr1)$(firstword $1)
# ----------------------------------------------------------------------------
# Function: last
# Arguments: 1: A list
# Returns: Returns the last element of a list
# ----------------------------------------------------------------------------
ifeq ($(__gmsl_have_lastword),$(true))
last = $(__gmsl_tr1)$(lastword $1)
else
last = $(__gmsl_tr1)$(if $1,$(word $(words $1),$1))
endif
# ----------------------------------------------------------------------------
# Function: rest (same as LISP's cdr, or tail)
# Arguments: 1: A list
# Returns: Returns the list with the first element removed
# ----------------------------------------------------------------------------
rest = $(__gmsl_tr1)$(wordlist 2,$(words $1),$1)
# ----------------------------------------------------------------------------
# Function: chop
# Arguments: 1: A list
# Returns: Returns the list with the last element removed
# ----------------------------------------------------------------------------
chop = $(__gmsl_tr1)$(wordlist 2,$(words $1),x $1)
# ----------------------------------------------------------------------------
# Function: map
# Arguments: 1: Name of function to $(call) for each element of list
# 2: List to iterate over calling the function in 1
# Returns: The list after calling the function on each element
# ----------------------------------------------------------------------------
map = $(__gmsl_tr2)$(strip $(foreach a,$2,$(call $1,$a)))
# ----------------------------------------------------------------------------
# Function: pairmap
# Arguments: 1: Name of function to $(call) for each pair of elements
# 2: List to iterate over calling the function in 1
# 3: Second list to iterate over calling the function in 1
# Returns: The list after calling the function on each pair of elements
# ----------------------------------------------------------------------------
pairmap = $(strip $(__gmsl_tr3)\
$(if $2$3,$(call $1,$(call first,$2),$(call first,$3)) \
$(call pairmap,$1,$(call rest,$2),$(call rest,$3))))
# ----------------------------------------------------------------------------
# Function: leq
# Arguments: 1: A list to compare against...
# 2: ...this list
# Returns: Returns $(true) if the two lists are identical
# ----------------------------------------------------------------------------
leq = $(__gmsl_tr2)$(strip $(if $(call seq,$(words $1),$(words $2)), \
$(call __gmsl_list_equal,$1,$2),$(false)))
__gmsl_list_equal = $(if $(strip $1), \
$(if $(call seq,$(call first,$1),$(call first,$2)), \
$(call __gmsl_list_equal, \
$(call rest,$1), \
$(call rest,$2)), \
$(false)), \
$(true))
# ----------------------------------------------------------------------------
# Function: lne
# Arguments: 1: A list to compare against...
# 2: ...this list
# Returns: Returns $(true) if the two lists are different
# ----------------------------------------------------------------------------
lne = $(__gmsl_tr2)$(call not,$(call leq,$1,$2))
# ----------------------------------------------------------------------------
# Function: reverse
# Arguments: 1: A list to reverse
# Returns: The list with its elements in reverse order
# ----------------------------------------------------------------------------
reverse =$(__gmsl_tr1)$(strip $(if $1,$(call reverse,$(call rest,$1)) \
$(call first,$1)))
# ----------------------------------------------------------------------------
# Function: uniq
# Arguments: 1: A list from which to remove repeated elements
# Returns: The list with duplicate elements removed without reordering
# ----------------------------------------------------------------------------
uniq = $(strip $(__gmsl_tr1)$(if $1,$(call uniq,$(call chop,$1)) \
$(if $(filter $(call last,$1),$(call chop,$1)),,$(call last,$1))))
# ----------------------------------------------------------------------------
# Function: length
# Arguments: 1: A list
# Returns: The number of elements in the list
# ----------------------------------------------------------------------------
length = $(__gmsl_tr1)$(words $1)
# ###########################################################################
# STRING MANIPULATION FUNCTIONS
# ###########################################################################
# Helper function that translates any GNU Make 'true' value (i.e. a
# non-empty string) to our $(true)
__gmsl_make_bool = $(if $(strip $1),$(true),$(false))
# ----------------------------------------------------------------------------
# Function: seq
# Arguments: 1: A string to compare against...
# 2: ...this string
# Returns: Returns $(true) if the two strings are identical
# ----------------------------------------------------------------------------
seq = $(__gmsl_tr2)$(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),$(false),$(true))
# ----------------------------------------------------------------------------
# Function: sne
# Arguments: 1: A string to compare against...
# 2: ...this string
# Returns: Returns $(true) if the two strings are not the same
# ----------------------------------------------------------------------------
sne = $(__gmsl_tr2)$(call not,$(call seq,$1,$2))
# ----------------------------------------------------------------------------
# Function: split
# Arguments: 1: The character to split on
# 2: A string to split
# Returns: Splits a string into a list separated by spaces at the split
# character in the first argument
# ----------------------------------------------------------------------------
split = $(__gmsl_tr2)$(strip $(subst $1, ,$2))
# ----------------------------------------------------------------------------
# Function: merge
# Arguments: 1: The character to put between fields
# 2: A list to merge into a string
# Returns: Merges a list into a single string, list elements are separated
# by the character in the first argument
# ----------------------------------------------------------------------------
merge = $(__gmsl_tr2)$(strip $(if $2, \
$(if $(call seq,1,$(words $2)), \
$2,$(call first,$2)$1$(call merge,$1,$(call rest,$2)))))
ifdef __gmsl_have_eval
# ----------------------------------------------------------------------------
# Function: tr
# Arguments: 1: The list of characters to translate from
# 2: The list of characters to translate to
# 3: The text to translate
# Returns: Returns the text after translating characters
# ----------------------------------------------------------------------------
tr = $(strip $(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3) \
$(eval __gmsl_t := $3) \
$(foreach c, \
$(join $(addsuffix :,$1),$2), \
$(eval __gmsl_t := \
$(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)), \
$(__gmsl_t))))$(__gmsl_t))
# Common character classes for use with the tr function. Each of
# these is actually a variable declaration and must be wrapped with
# $() or ${} to be used.
[A-Z] := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z #
[a-z] := a b c d e f g h i j k l m n o p q r s t u v w x y z #
[0-9] := 0 1 2 3 4 5 6 7 8 9 #
[A-F] := A B C D E F #
# ----------------------------------------------------------------------------
# Function: uc
# Arguments: 1: Text to upper case
# Returns: Returns the text in upper case
# ----------------------------------------------------------------------------
uc = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call tr,$([a-z]),$([A-Z]),$1)
# ----------------------------------------------------------------------------
# Function: lc
# Arguments: 1: Text to lower case
# Returns: Returns the text in lower case
# ----------------------------------------------------------------------------
lc = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call tr,$([A-Z]),$([a-z]),$1)
# ----------------------------------------------------------------------------
# Function: strlen
# Arguments: 1: A string
# Returns: Returns the length of the string
# ----------------------------------------------------------------------------
__gmsl_characters := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
__gmsl_characters += a b c d e f g h i j k l m n o p q r s t u v w x y z
__gmsl_characters += 0 1 2 3 4 5 6 7 8 9
__gmsl_characters += ` ~ ! @ \# $$ % ^ & * ( ) - _ = +
__gmsl_characters += { } [ ] \ : ; ' " < > , . / ? |
# Aside: if you read the above you might think that the lower-case
# letter x is missing, and that that's an error. It is missing, but
# it's not an error. __gmsl_characters is used by the strlen
# function. strlen works by transforming every character and space
# into the letter x and then counting the x's. Since there's no need
# to transform x into x I omitted it.
# This results in __gmsl_space containing just a space
__gmsl_space :=
__gmsl_space +=
strlen = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(strip $(eval __temp := $(subst $(__gmsl_space),x,$1))$(foreach a,$(__gmsl_characters),$(eval __temp := $$(subst $$a,x,$(__temp))))$(eval __temp := $(subst x,x ,$(__temp)))$(words $(__temp)))
# This results in __gmsl_newline containing just a newline
define __gmsl_newline
endef
# This results in __gmsl_tab containing a tab
__gmsl_tab := #
# ----------------------------------------------------------------------------
# Function: substr
# Arguments: 1: A string
# 2: Start position (first character is 1)
# 3: End position (inclusive)
# Returns: A substring.
# Note: The string in $1 must not contain a <20>
# ----------------------------------------------------------------------------
substr = $(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3)$(strip $(eval __temp := $$(subst $$(__gmsl_space),<2C> ,$$1))$(foreach a,$(__gmsl_characters),$(eval __temp := $$(subst $$a,$$a$$(__gmsl_space),$(__temp))))$(eval __temp := $(wordlist $2,$3,$(__temp))))$(subst <20>,$(__gmsl_space),$(subst $(__gmsl_space),,$(__temp)))
endif # __gmsl_have_eval
# ###########################################################################
# SET MANIPULATION FUNCTIONS
# ###########################################################################
# Sets are represented by sorted, deduplicated lists. To create a set
# from a list use set_create, or start with the empty_set and
# set_insert individual elements
# This is the empty set
empty_set :=
# ----------------------------------------------------------------------------
# Function: set_create
# Arguments: 1: A list of set elements
# Returns: Returns the newly created set
# ----------------------------------------------------------------------------
set_create = $(__gmsl_tr1)$(sort $1)
# ----------------------------------------------------------------------------
# Function: set_insert
# Arguments: 1: A single element to add to a set
# 2: A set
# Returns: Returns the set with the element added
# ----------------------------------------------------------------------------
set_insert = $(__gmsl_tr2)$(sort $1 $2)
# ----------------------------------------------------------------------------
# Function: set_remove
# Arguments: 1: A single element to remove from a set
# 2: A set
# Returns: Returns the set with the element removed
# ----------------------------------------------------------------------------
set_remove = $(__gmsl_tr2)$(filter-out $1,$2)
# ----------------------------------------------------------------------------
# Function: set_is_member
# Arguments: 1: A single element
# 2: A set
# Returns: Returns $(true) if the element is in the set
# ----------------------------------------------------------------------------
set_is_member = $(__gmsl_tr2)$(if $(filter $1,$2),$(true),$(false))
# ----------------------------------------------------------------------------
# Function: set_union
# Arguments: 1: A set
# 2: Another set
# Returns: Returns the union of the two sets
# ----------------------------------------------------------------------------
set_union = $(__gmsl_tr2)$(sort $1 $2)
# ----------------------------------------------------------------------------
# Function: set_intersection
# Arguments: 1: A set
# 2: Another set
# Returns: Returns the intersection of the two sets
# ----------------------------------------------------------------------------
set_intersection = $(__gmsl_tr2)$(filter $1,$2)
# ----------------------------------------------------------------------------
# Function: set_is_subset
# Arguments: 1: A set
# 2: Another set
# Returns: Returns $(true) if the first set is a subset of the second
# ----------------------------------------------------------------------------
set_is_subset = $(__gmsl_tr2)$(call set_equal,$(call set_intersection,$1,$2),$1)
# ----------------------------------------------------------------------------
# Function: set_equal
# Arguments: 1: A set
# 2: Another set
# Returns: Returns $(true) if the two sets are identical
# ----------------------------------------------------------------------------
set_equal = $(__gmsl_tr2)$(call seq,$1,$2)
# ###########################################################################
# ARITHMETIC LIBRARY
# ###########################################################################
# Integers a represented by lists with the equivalent number of x's.
# For example the number 4 is x x x x. The maximum integer that the
# library can handle as _input_ is __gmsl_input_int which is defined
# here as 65536
__gmsl_sixteen := x x x x x x x x x x x x x x x x
__gmsl_input_int := $(foreach a,$(__gmsl_sixteen), \
$(foreach b,$(__gmsl_sixteen), \
$(foreach c,$(__gmsl_sixteen), \
$(__gmsl_sixteen)))))
# ----------------------------------------------------------------------------
# Function: int_decode
# Arguments: 1: A number of x's representation
# Returns: Returns the integer for human consumption that is represented
# by the string of x's
# ----------------------------------------------------------------------------
int_decode = $(__gmsl_tr1)$(words $1)
# ----------------------------------------------------------------------------
# Function: int_encode
# Arguments: 1: A number in human-readable integer form
# Returns: Returns the integer encoded as a string of x's
# ----------------------------------------------------------------------------
int_encode = $(__gmsl_tr1)$(wordlist 1,$1,$(__gmsl_input_int))
# The arithmetic library functions come in two forms: one form of each
# function takes integers as arguments and the other form takes the
# encoded form (x's created by a call to int_encode). For example,
# there are two plus functions:
#
# plus Called with integer arguments and returns an integer
# int_plus Called with encoded arguments and returns an encoded result
#
# plus will be slower than int_plus because its arguments and result
# have to be translated between the x's format and integers. If doing
# a complex calculation use the int_* forms with a single encoding of
# inputs and single decoding of the output. For simple calculations
# the direct forms can be used.
# Helper function used to wrap an int_* function into a function that
# takes a pair of integers, perhaps a function and returns an integer
# result
__gmsl_int_wrap = $(call int_decode,$(call $1,$(call int_encode,$2),$(call int_encode,$3)))
__gmsl_int_wrap1 = $(call int_decode,$(call $1,$(call int_encode,$2)))
__gmsl_int_wrap2 = $(call $1,$(call int_encode,$2),$(call int_encode,$3))
# ----------------------------------------------------------------------------
# Function: int_plus
# Arguments: 1: A number in x's representation
# 2: Another number in x's represntation
# Returns: Returns the sum of the two numbers in x's representation
# ----------------------------------------------------------------------------
int_plus = $(strip $(__gmsl_tr2)$1 $2)
# ----------------------------------------------------------------------------
# Function: plus (wrapped version of int_plus)
# Arguments: 1: An integer
# 2: Another integer
# Returns: Returns the sum of the two integers
# ----------------------------------------------------------------------------
plus = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_plus,$1,$2)
# ----------------------------------------------------------------------------
# Function: int_subtract
# Arguments: 1: A number in x's representation
# 2: Another number in x's represntation
# Returns: Returns the difference of the two numbers in x's representation,
# or outputs an error on a numeric underflow
# ----------------------------------------------------------------------------
int_subtract = $(strip $(__gmsl_tr2)$(if $(call int_gte,$1,$2), \
$(filter-out xx,$(join $1,$2)), \
$(call __gmsl_warning,Subtraction underflow)))
# ----------------------------------------------------------------------------
# Function: subtract (wrapped version of int_subtract)
# Arguments: 1: An integer
# 2: Another integer
# Returns: Returns the difference of the two integers,
# or outputs an error on a numeric underflow
# ----------------------------------------------------------------------------
subtract = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_subtract,$1,$2)
# ----------------------------------------------------------------------------
# Function: int_multiply
# Arguments: 1: A number in x's representation
# 2: Another number in x's represntation
# Returns: Returns the product of the two numbers in x's representation
# ----------------------------------------------------------------------------
int_multiply = $(strip $(__gmsl_tr2)$(foreach a,$1,$2))
# ----------------------------------------------------------------------------
# Function: multiply (wrapped version of int_multiply)
# Arguments: 1: An integer
# 2: Another integer
# Returns: Returns the product of the two integers
# ----------------------------------------------------------------------------
multiply = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_multiply,$1,$2)
# ----------------------------------------------------------------------------
# Function: int_divide
# Arguments: 1: A number in x's representation
# 2: Another number in x's represntation
# Returns: Returns the result of integer division of argument 1 divided
# by argument 2 in x's representation
# ----------------------------------------------------------------------------
int_divide = $(__gmsl_tr2)$(strip $(if $2, \
$(if $(call int_gte,$1,$2), \
x $(call int_divide,$(call int_subtract,$1,$2),$2),), \
$(call __gmsl_error,Division by zero)))
# ----------------------------------------------------------------------------
# Function: divide (wrapped version of int_divide)
# Arguments: 1: An integer
# 2: Another integer
# Returns: Returns the integer division of the first argument by the second
# ----------------------------------------------------------------------------
divide = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_divide,$1,$2)
# ----------------------------------------------------------------------------
# Function: int_max, int_min
# Arguments: 1: A number in x's representation
# 2: Another number in x's represntation
# Returns: Returns the maximum or minimum of its arguments in x's
# representation
# ----------------------------------------------------------------------------
int_max = $(__gmsl_tr2)$(subst xx,x,$(join $1,$2))
int_min = $(__gmsl_tr2)$(subst xx,x,$(filter xx,$(join $1,$2)))
# ----------------------------------------------------------------------------
# Function: max, min
# Arguments: 1: An integer
# 2: Another integer
# Returns: Returns the maximum or minimum of its integer arguments
# ----------------------------------------------------------------------------
max = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_max,$1,$2)
min = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_min,$1,$2)
# ----------------------------------------------------------------------------
# Function: int_gt, int_gte, int_lt, int_lte, int_eq, int_ne
# Arguments: Two x's representation numbers to be compared
# Returns: $(true) or $(false)
#
# int_gt First argument greater than second argument
# int_gte First argument greater than or equal to second argument
# int_lt First argument less than second argument
# int_lte First argument less than or equal to second argument
# int_eq First argument is numerically equal to the second argument
# int_ne First argument is not numerically equal to the second argument
# ----------------------------------------------------------------------------
int_gt = $(__gmsl_tr2)$(call __gmsl_make_bool, \
$(filter-out $(words $2), \
$(words $(call int_max,$1,$2))))
int_gte = $(__gmsl_tr2)$(call __gmsl_make_bool, \
$(call int_gt,$1,$2)$(call int_eq,$1,$2))
int_lt = $(__gmsl_tr2)$(call __gmsl_make_bool, \
$(filter-out $(words $1), \
$(words $(call int_max,$1,$2))))
int_lte = $(__gmsl_tr2)$(call __gmsl_make_bool, \
$(call int_lt,$1,$2)$(call int_eq,$1,$2))
int_eq = $(__gmsl_tr2)$(call __gmsl_make_bool, \
$(filter $(words $1),$(words $2)))
int_ne = $(__gmsl_tr2)$(call __gmsl_make_bool, \
$(filter-out $(words $1),$(words $2)))
# ----------------------------------------------------------------------------
# Function: gt, gte, lt, lte, eq, ne
# Arguments: Two integers to be compared
# Returns: $(true) or $(false)
#
# gt First argument greater than second argument
# gte First argument greater than or equal to second argument
# lt First argument less than second argument
# lte First argument less than or equal to second argument
# eq First argument is numerically equal to the second argument
# ne First argument is not numerically equal to the second argument
# ----------------------------------------------------------------------------
gt = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_gt,$1,$2)
gte = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_gte,$1,$2)
lt = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_lt,$1,$2)
lte = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_lte,$1,$2)
eq = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_eq,$1,$2)
ne = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_ne,$1,$2)
# increment adds 1 to its argument, decrement subtracts 1. Note that
# decrement does not range check and hence will not underflow, but
# will incorrectly say that 0 - 1 = 0
# ----------------------------------------------------------------------------
# Function: int_inc
# Arguments: 1: A number in x's representation
# Returns: The number incremented by 1 in x's representation
# ----------------------------------------------------------------------------
int_inc = $(strip $(__gmsl_tr1)$1 x)
# ----------------------------------------------------------------------------
# Function: inc
# Arguments: 1: An integer
# Returns: The argument incremented by 1
# ----------------------------------------------------------------------------
inc = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_inc,$1)
# ----------------------------------------------------------------------------
# Function: int_dec
# Arguments: 1: A number in x's representation
# Returns: The number decremented by 1 in x's representation
# ----------------------------------------------------------------------------
int_dec = $(__gmsl_tr1)$(strip $(if $(call sne,0,$(words $1)), \
$(wordlist 2,$(words $1),$1), \
$(call __gmsl_warning,Decrement underflow)))
# ----------------------------------------------------------------------------
# Function: dec
# Arguments: 1: An integer
# Returns: The argument decremented by 1
# ----------------------------------------------------------------------------
dec = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_dec,$1)
# double doubles its argument, and halve halves it
# ----------------------------------------------------------------------------
# Function: int_double
# Arguments: 1: A number in x's representation
# Returns: The number doubled (i.e. * 2) and returned in x's representation
# ----------------------------------------------------------------------------
int_double = $(strip $(__gmsl_tr1)$1 $1)
# ----------------------------------------------------------------------------
# Function: double
# Arguments: 1: An integer
# Returns: The integer times 2
# ----------------------------------------------------------------------------
double = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_double,$1)
# ----------------------------------------------------------------------------
# Function: int_halve
# Arguments: 1: A number in x's representation
# Returns: The number halved (i.e. / 2) and returned in x's representation
# ----------------------------------------------------------------------------
int_halve = $(__gmsl_tr1)$(strip $(subst xx,x,$(filter-out xy x y, \
$(join $1,$(foreach a,$1,y x)))))
# ----------------------------------------------------------------------------
# Function: halve
# Arguments: 1: An integer
# Returns: The integer divided by 2
# ----------------------------------------------------------------------------
halve = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_halve,$1)
ifdef __gmsl_have_eval
# ###########################################################################
# ASSOCIATIVE ARRAYS
# ###########################################################################
# ----------------------------------------------------------------------------
# Function: set
# Arguments: 1: Name of associative array
# 2: The key value to associate
# 3: The value associated with the key
# Returns: None
# ----------------------------------------------------------------------------
set = $(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3)$(eval __gmsl_aa_$1_$2 = $3)
# ----------------------------------------------------------------------------
# Function: get
# Arguments: 1: Name of associative array
# 2: The key to retrieve
# Returns: The value stored in the array for that key
# ----------------------------------------------------------------------------
get = $(strip $(__gmsl_tr2)$(call assert_no_dollar,$0,$1$2)$(if $(filter-out undefined,$(origin __gmsl_aa_$1_$2)), \
$(__gmsl_aa_$1_$2)))
# ----------------------------------------------------------------------------
# Function: keys
# Arguments: 1: Name of associative array
# Returns: Returns a list of all defined keys in the array
# ----------------------------------------------------------------------------
keys = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(sort $(patsubst __gmsl_aa_$1_%,%, \
$(filter __gmsl_aa_$1_%,$(.VARIABLES))))
# ----------------------------------------------------------------------------
# Function: defined
# Arguments: 1: Name of associative array
# 2: The key to test
# Returns: Returns true if the key is defined (i.e. not empty)
# ----------------------------------------------------------------------------
defined = $(__gmsl_tr2)$(call assert_no_dollar,$0,$1$2)$(call sne,$(call get,$1,$2),)
endif # __gmsl_have_eval
ifdef __gmsl_have_eval
# ###########################################################################
# NAMED STACKS
# ###########################################################################
# ----------------------------------------------------------------------------
# Function: push
# Arguments: 1: Name of stack
# 2: Value to push onto the top of the stack (must not contain
# a space)
# Returns: None
# ----------------------------------------------------------------------------
push = $(__gmsl_tr2)$(call assert_no_dollar,$0,$1$2)$(eval __gmsl_stack_$1 := $2 $(if $(filter-out undefined,\
$(origin __gmsl_stack_$1)),$(__gmsl_stack_$1)))
# ----------------------------------------------------------------------------
# Function: pop
# Arguments: 1: Name of stack
# Returns: Top element from the stack after removing it
# ----------------------------------------------------------------------------
pop = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(strip $(if $(filter-out undefined,$(origin __gmsl_stack_$1)), \
$(call first,$(__gmsl_stack_$1)) \
$(eval __gmsl_stack_$1 := $(call rest,$(__gmsl_stack_$1)))))
# ----------------------------------------------------------------------------
# Function: peek
# Arguments: 1: Name of stack
# Returns: Top element from the stack without removing it
# ----------------------------------------------------------------------------
peek = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call first,$(__gmsl_stack_$1))
# ----------------------------------------------------------------------------
# Function: depth
# Arguments: 1: Name of stack
# Returns: Number of items on the stack
# ----------------------------------------------------------------------------
depth = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(words $(__gmsl_stack_$1))
endif # __gmsl_have_eval
# ###########################################################################
# DEBUGGING FACILITIES
# ###########################################################################
# ----------------------------------------------------------------------------
# Target: gmsl-print-%
# Arguments: The % should be replaced by the name of a variable that you
# wish to print out.
# Action: Echos the name of the variable that matches the % and its value.
# For example, 'make gmsl-print-SHELL' will output the value of
# the SHELL variable
# ----------------------------------------------------------------------------
gmsl-print-%: ; @echo $* = $($*)
# ----------------------------------------------------------------------------
# Function: assert
# Arguments: 1: A boolean that must be true or the assertion will fail
# 2: The message to print with the assertion
# Returns: None
# ----------------------------------------------------------------------------
assert = $(if $1,,$(call __gmsl_error,Assertion failure: $2))
# ----------------------------------------------------------------------------
# Function: assert_exists
# Arguments: 1: Name of file that must exist, if it is missing an assertion
# will be generated
# Returns: None
# ----------------------------------------------------------------------------
assert_exists = $(call assert,$(wildcard $1),file '$1' missing)
# ----------------------------------------------------------------------------
# Function: assert_no_dollar
# Arguments: 1: Name of a function being executd
# 2: Arguments to check
# Returns: None
# ----------------------------------------------------------------------------
assert_no_dollar = $(call assert,$(call not,$(findstring $$,$2)),$1 called with a dollar sign in argument)

View File

@ -0,0 +1,89 @@
# ----------------------------------------------------------------------------
#
# GNU Make Standard Library (GMSL)
#
# A library of functions to be used with GNU Make's $(call) that
# provides functionality not available in standard GNU Make.
#
# Copyright (c) 2005-2008 John Graham-Cumming
#
# This file is part of GMSL
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of the John Graham-Cumming nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ----------------------------------------------------------------------------
# Determine if the library has already been included and if so don't
# bother including it again
ifndef __gmsl_included
# Standard definitions for true and false. true is any non-empty
# string, false is an empty string. These are intended for use with
# $(if).
true := T
false :=
# ----------------------------------------------------------------------------
# Function: not
# Arguments: 1: A boolean value
# Returns: Returns the opposite of the arg. (true -> false, false -> true)
# ----------------------------------------------------------------------------
not = $(if $1,$(false),$(true))
# Prevent reinclusion of the library
__gmsl_included := $(true)
# Try to determine where this file is located. If the caller did
# include /foo/gmsl then extract the /foo/ so that __gmsl gets
# included transparently
ifneq ($(MAKEFILE_LIST),)
__gmsl_root := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
# If there are any spaces in the path in __gmsl_root then give up
ifeq (1,$(words $(__gmsl_root)))
__gmsl_root := $(patsubst %gmsl,%,$(__gmsl_root))
else
__gmsl_root :=
endif
include $(__gmsl_root)__gmsl
else
include __gmsl
endif
endif # __gmsl_included

View File

@ -0,0 +1,647 @@
# ----------------------------------------------------------------------------
#
# GNU Make Standard Library (GMSL) Test Suite
#
# Test suite for the GMSL
#
# Copyright (c) 2005-2007 John Graham-Cumming
#
# This file is part of GMSL
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of the John Graham-Cumming nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ----------------------------------------------------------------------------
.PHONY: all
all:
@echo
@echo Test Summary
@echo ------------
@echo "$(call int_decode,$(passed)) tests passed; $(call int_decode,$(failed)) tests failed"
include gmsl
passed :=
failed :=
ECHO := /bin/echo
start_test = $(shell $(ECHO) -n "Testing '$1': " >&2)$(eval current_test := OK)
stop_test = $(shell $(ECHO) " $(current_test)" >&2)
test_pass = .$(eval passed := $(call int_inc,$(passed)))
test_fail = X$(eval failed := $(call int_inc,$(failed)))$(eval current_test := ERROR '$1' != '$2')
test_assert = $(if $(filter undefined,$(origin 2)),$(eval 2 :=))$(shell $(ECHO) -n $(if $(call seq,$1,$2),$(call test_pass,$1,$2),$(call test_fail,$1,$2)) >&2)
$(call start_test,not)
$(call test_assert,$(call not,$(true)),$(false))
$(call test_assert,$(call not,$(false)),$(true))
$(call stop_test)
$(call start_test,or)
$(call test_assert,$(call or,$(true),$(true)),$(true))
$(call test_assert,$(call or,$(true),$(false)),$(true))
$(call test_assert,$(call or,$(false),$(true)),$(true))
$(call test_assert,$(call or,$(false),$(false)),$(false))
$(call stop_test)
$(call start_test,and)
$(call test_assert,$(call and,$(true),$(true)),$(true))
$(call test_assert,$(call and,$(true),$(false)),$(false))
$(call test_assert,$(call and,$(false),$(true)),$(false))
$(call test_assert,$(call and,$(false),$(false)),$(false))
$(call stop_test)
$(call start_test,xor)
$(call test_assert,$(call xor,$(true),$(true)),$(false))
$(call test_assert,$(call xor,$(true),$(false)),$(true))
$(call test_assert,$(call xor,$(false),$(true)),$(true))
$(call test_assert,$(call xor,$(false),$(false)),$(false))
$(call stop_test)
$(call start_test,nand)
$(call test_assert,$(call nand,$(true),$(true)),$(false))
$(call test_assert,$(call nand,$(true),$(false)),$(true))
$(call test_assert,$(call nand,$(false),$(true)),$(true))
$(call test_assert,$(call nand,$(false),$(false)),$(true))
$(call stop_test)
$(call start_test,nor)
$(call test_assert,$(call nor,$(true),$(true)),$(false))
$(call test_assert,$(call nor,$(true),$(false)),$(false))
$(call test_assert,$(call nor,$(false),$(true)),$(false))
$(call test_assert,$(call nor,$(false),$(false)),$(true))
$(call stop_test)
$(call start_test,xnor)
$(call test_assert,$(call xnor,$(true),$(true)),$(true))
$(call test_assert,$(call xnor,$(true),$(false)),$(false))
$(call test_assert,$(call xnor,$(false),$(true)),$(false))
$(call test_assert,$(call xnor,$(false),$(false)),$(true))
$(call stop_test)
$(call start_test,first)
$(call test_assert,$(call first,1 2 3),1)
$(call test_assert,$(call first,1),1)
$(call test_assert,$(call first,),)
$(call stop_test)
$(call start_test,last)
$(call test_assert,$(call last,1 2 3),3)
$(call test_assert,$(call last,1),1)
$(call test_assert,$(call last,),)
$(call stop_test)
$(call start_test,rest)
$(call test_assert,$(call rest,1 2 3),2 3)
$(call test_assert,$(call rest,1),)
$(call test_assert,$(call rest,),)
$(call stop_test)
$(call start_test,chop)
$(call test_assert,$(call chop,1 2 3),1 2)
$(call test_assert,$(call chop,1 2 3 4),1 2 3)
$(call test_assert,$(call chop,1),)
$(call test_assert,$(call chop,),)
$(call stop_test)
$(call start_test,length)
$(call test_assert,$(call length,1 2 3),3)
$(call test_assert,$(call length,1 2 3 4),4)
$(call test_assert,$(call length,1),1)
$(call test_assert,$(call length,),0)
$(call stop_test)
$(call start_test,map)
$(call test_assert,$(call map,origin,__undefined map MAKE),undefined file default)
$(call test_assert,$(call map,origin,),)
$(call stop_test)
joinem = $1$2
$(call start_test,pairmap)
$(call test_assert,$(call pairmap,addsuffix,2 1 3,a b c),a2 b1 c3)
$(call test_assert,$(call pairmap,addprefix,2 1 3,a b c d),2a 1b 3c d)
$(call test_assert,$(call pairmap,addprefix,2 1 3 4,a b c),2a 1b 3c)
$(call test_assert,$(call pairmap,joinem,2 1 3 4,a b c),2a 1b 3c 4)
$(call stop_test)
$(call start_test,seq)
$(call test_assert,$(call seq,abc,abc),T)
$(call test_assert,$(call seq,x,),)
$(call test_assert,$(call seq,,x),)
$(call test_assert,$(call seq,x,x),T)
$(call test_assert,$(call seq,a%c,abc),)
$(call test_assert,$(call seq,abc,a%c),)
$(call test_assert,$(call seq,abc,ABC),)
$(call test_assert,$(call seq,abc,),)
$(call test_assert,$(call seq,,),T)
$(call test_assert,$(call seq,a b c,a b c),T)
$(call test_assert,$(call seq,aa% bb% cc,aa% bb% cc),T)
$(call test_assert,$(call seq,aa% bb% cc,aa% bb cc),)
$(call test_assert,$(call seq,aa% bb% cc,xx yy zz),)
$(call stop_test)
$(call start_test,sne)
$(call test_assert,$(call sne,abc,abc),)
$(call test_assert,$(call sne,x,),T)
$(call test_assert,$(call sne,,x),T)
$(call test_assert,$(call sne,x,x),)
$(call test_assert,$(call sne,abc,ABC),T)
$(call test_assert,$(call sne,abc,),T)
$(call test_assert,$(call sne,,),)
$(call test_assert,$(call sne,a b c,a b c),)
$(call test_assert,$(call sne,aa% bb% cc,aa% bb% cc),)
$(call test_assert,$(call sne,aa% bb% cc,aa% bb cc),T)
$(call stop_test)
$(call start_test,strlen)
$(call test_assert,$(call strlen,),0)
$(call test_assert,$(call strlen,a),1)
$(call test_assert,$(call strlen,a b),3)
$(call test_assert,$(call strlen,a ),2)
$(call test_assert,$(call strlen, a),2)
$(call test_assert,$(call strlen, ),2)
$(call test_assert,$(call strlen, ),3)
$(call test_assert,$(call strlen, ),4)
$(call stop_test)
$(call start_test,substr)
$(call test_assert,$(call substr,xyz,1,1),x)
$(call test_assert,$(call substr,xyz,1,2),xy)
$(call test_assert,$(call substr,xyz,2,3),yz)
$(call test_assert,$(call substr,some string,1,1),s)
$(call test_assert,$(call substr,some string,1,2),so)
$(call test_assert,$(call substr,some string,1,3),som)
$(call test_assert,$(call substr,some string,1,4),some)
$(call test_assert,$(call substr,some string,1,5),some )
$(call test_assert,$(call substr,some string,1,6),some s)
$(call test_assert,$(call substr,some string,5,5), )
$(call test_assert,$(call substr,some string,5,6), s)
$(call test_assert,$(call substr,some string,5,7), st)
$(call test_assert,$(call substr,some string,5,8), str)
$(call test_assert,$(call substr,some string,1,100),some string)
$(call stop_test)
$(call start_test,lc)
$(call test_assert,$(call lc,The Quick Brown Fox),the quick brown fox)
$(call test_assert,$(call lc,the1 quick2 brown3 fox4),the1 quick2 brown3 fox4)
$(call test_assert,$(call lc,The_),the_)
$(call test_assert,$(call lc,),)
$(call stop_test)
$(call start_test,uc)
$(call test_assert,$(call uc,The Quick Brown Fox),THE QUICK BROWN FOX)
$(call test_assert,$(call uc,the1 quick2 brown3 fox4),THE1 QUICK2 BROWN3 FOX4)
$(call test_assert,$(call uc,The_),THE_)
$(call test_assert,$(call uc,),)
$(call stop_test)
$(call start_test,tr)
$(call test_assert,$(call tr,A B C,1 2 3,CAPITAL),31PIT1L)
$(call test_assert,$(call tr,a b c,1 2 3,CAPITAL),CAPITAL)
$(call test_assert,$(call tr,E L I,3 1 1,I AM ELITE),1 AM 311T3)
$(call stop_test)
$(call start_test,leq)
$(call test_assert,$(call leq,1 2 3,1 2 3),T)
$(call test_assert,$(call leq,1 2 3,1 2 3 4),)
$(call test_assert,$(call leq,1 2 3 4,1 2 3),)
$(call test_assert,$(call leq,1,1),T)
$(call test_assert,$(call leq,,),T)
$(call stop_test)
$(call start_test,lne)
$(call test_assert,$(call lne,1 2 3,1 2 3),)
$(call test_assert,$(call lne,1 2 3,1 2 3 4),T)
$(call test_assert,$(call lne,1 2 3 4,1 2 3),T)
$(call test_assert,$(call lne,1,1),)
$(call test_assert,$(call lne,,),)
$(call stop_test)
$(call start_test,empty_set)
$(call test_assert,$(empty_set),)
$(call test_assert,$(empty_set),$(call set_create,))
$(call stop_test)
$(call start_test,set_create)
$(call test_assert,$(call set_create,),)
$(call test_assert,$(call set_create,1 2 2 3),1 2 3)
$(call test_assert,$(call set_create,2 1 1 2 2 3),1 2 3)
$(call test_assert,$(call set_create,1),1)
$(call stop_test)
$(call start_test,set_insert)
$(call test_assert,$(call set_insert,1,$(empty_set)),1)
$(call test_assert,$(call set_insert,1,$(call set_create,1)),1)
$(call test_assert,$(call set_insert,1,$(call set_create,1 2)),1 2)
$(call test_assert,$(call set_insert,0,$(call set_create,1 2)),0 1 2)
$(call stop_test)
$(call start_test,set_remove)
$(call test_assert,$(call set_remove,1,$(empty_set)),$(empty_set))
$(call test_assert,$(call set_remove,1,$(call set_create,1 2)),2)
$(call test_assert,$(call set_remove,1,$(call set_create,1 11 2)),11 2)
$(call test_assert,$(call set_remove,0,$(call set_create,1 2)),1 2)
$(call stop_test)
$(call start_test,set_is_member)
$(call test_assert,$(call set_is_member,1,$(empty_set)),)
$(call test_assert,$(call set_is_member,1,$(call set_create,2 3)),)
$(call test_assert,$(call set_is_member,1,$(call set_create,1 2 3)),T)
$(call test_assert,$(call set_is_member,1,$(call set_create,1)),T)
$(call stop_test)
$(call start_test,set_union)
$(call test_assert,$(call set_union,,),)
$(call test_assert,$(call set_union,1 2,),1 2)
$(call test_assert,$(call set_union,,3 4),3 4)
$(call test_assert,$(call set_union,1 2,3 4),1 2 3 4)
$(call test_assert,$(call set_union,1 2 3,3 4 5),1 2 3 4 5)
$(call stop_test)
$(call start_test,set_intersection)
$(call test_assert,$(call set_intersection,,),)
$(call test_assert,$(call set_intersection,1 2,),)
$(call test_assert,$(call set_intersection,,3 4),)
$(call test_assert,$(call set_intersection,1 2,3 4),)
$(call test_assert,$(call set_intersection,1 2 3 4,3 4 5),3 4)
$(call stop_test)
$(call start_test,set_is_subset)
$(call test_assert,$(call set_is_subset,,),T)
$(call test_assert,$(call set_is_subset,1 2,),)
$(call test_assert,$(call set_is_subset,,3 4),T)
$(call test_assert,$(call set_is_subset,1 2,3 4),)
$(call test_assert,$(call set_is_subset,1 2,1 2 3 4 5),T)
$(call test_assert,$(call set_is_subset,1 2,1 2),T)
$(call test_assert,$(call set_is_subset,1 2,1 3 4 5),)
$(call stop_test)
$(call start_test,set_equal)
$(call test_assert,$(call set_equal,,),T)
$(call test_assert,$(call set_equal,1,),)
$(call test_assert,$(call set_equal,,1),)
$(call test_assert,$(call set_equal,1,1),T)
$(call test_assert,$(call set_equal,1 2,),)
$(call test_assert,$(call set_equal,,1 2),)
$(call test_assert,$(call set_equal,1 2,1 2 3),)
$(call stop_test)
$(call start_test,int_encode)
$(call test_assert,$(call int_encode,0),)
$(call test_assert,$(call int_encode,1),x)
$(call test_assert,$(call int_encode,2),x x)
$(call test_assert,$(call int_encode,10),x x x x x x x x x x)
$(call stop_test)
$(call start_test,int_decode)
$(call test_assert,$(call int_decode,),0)
$(call test_assert,$(call int_decode,x),1)
$(call test_assert,$(call int_decode,x x),2)
$(call test_assert,$(call int_decode,x x x x x x x x x x),10)
$(call stop_test)
$(call start_test,int_plus)
$(call test_assert,$(call int_plus,$(call int_encode,3),$(call int_encode,4)),$(call int_encode,7))
$(call test_assert,$(call int_plus,$(call int_encode,0),$(call int_encode,4)),$(call int_encode,4))
$(call test_assert,$(call int_plus,$(call int_encode,3),$(call int_encode,0)),$(call int_encode,3))
$(call test_assert,$(call int_plus,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0))
$(call test_assert,$(call int_plus,$(call int_encode,1),$(call int_encode,0)),$(call int_encode,1))
$(call stop_test)
$(call start_test,plus)
$(call test_assert,$(call plus,3,4),7)
$(call test_assert,$(call plus,4,3),7)
$(call test_assert,$(call plus,0,4),4)
$(call test_assert,$(call plus,3,0),3)
$(call test_assert,$(call plus,0,0),0)
$(call stop_test)
__gmsl_warning = $1
$(call start_test,int_subtract)
$(call test_assert,$(call int_subtract,$(call int_encode,3),$(call int_encode,4)),Subtraction underflow)
$(call test_assert,$(call int_subtract,$(call int_encode,4),$(call int_encode,3)),$(call int_encode,1))
$(call test_assert,$(call int_subtract,$(call int_encode,3),$(call int_encode,0)),$(call int_encode,3))
$(call test_assert,$(call int_subtract,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0))
$(call test_assert,$(call int_subtract,$(call int_encode,1),$(call int_encode,0)),$(call int_encode,1))
$(call stop_test)
__gmsl_warning = x x x x x x x x x x
$(call start_test,subtract)
$(call test_assert,$(call subtract,3,4),10)
$(call test_assert,$(call subtract,4,3),1)
$(call test_assert,$(call subtract,3,0),3)
$(call test_assert,$(call subtract,0,0),0)
$(call stop_test)
$(call start_test,int_multiply)
$(call test_assert,$(call int_multiply,$(call int_encode,3),$(call int_encode,4)),$(call int_encode,12))
$(call test_assert,$(call int_multiply,$(call int_encode,4),$(call int_encode,3)),$(call int_encode,12))
$(call test_assert,$(call int_multiply,$(call int_encode,3),$(call int_encode,0)),$(call int_encode,0))
$(call test_assert,$(call int_multiply,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0))
$(call test_assert,$(call int_multiply,$(call int_encode,1),$(call int_encode,0)),$(call int_encode,0))
$(call stop_test)
$(call start_test,multiply)
$(call test_assert,$(call multiply,3,4),12)
$(call test_assert,$(call multiply,4,3),12)
$(call test_assert,$(call multiply,3,0),0)
$(call test_assert,$(call multiply,0,3),0)
$(call test_assert,$(call multiply,0,0),0)
$(call stop_test)
__gmsl_error = $1
$(call start_test,int_divide)
$(call test_assert,$(call int_divide,$(call int_encode,3),$(call int_encode,4)),$(call int_encode,0))
$(call test_assert,$(call int_divide,$(call int_encode,4),$(call int_encode,3)),$(call int_encode,1))
$(call test_assert,$(call int_divide,$(call int_encode,31),$(call int_encode,3)),$(call int_encode,10))
$(call test_assert,$(call int_divide,$(call int_encode,30),$(call int_encode,3)),$(call int_encode,10))
$(call test_assert,$(call int_divide,$(call int_encode,29),$(call int_encode,3)),$(call int_encode,9))
$(call test_assert,$(call int_divide,$(call int_encode,0),$(call int_encode,1)),$(call int_encode,0))
$(call test_assert,$(call int_divide,$(call int_encode,1),$(call int_encode,0)),Division by zero)
$(call stop_test)
__gmsl_error = x x x x x x x x x x
$(call start_test,divide)
$(call test_assert,$(call divide,3,4),0)
$(call test_assert,$(call divide,4,3),1)
$(call test_assert,$(call divide,21,2),10)
$(call test_assert,$(call divide,20,2),10)
$(call test_assert,$(call divide,19,2),9)
$(call test_assert,$(call divide,1,0),10)
$(call stop_test)
$(call start_test,associative array)
$(call test_assert,$(call get,myarray,key1),)
$(call set,myarray,key1,value1)
$(call test_assert,$(call get,myarray,key1),value1)
$(call test_assert,$(call get,myarray,key2),)
$(call test_assert,$(call get,myarray1,key1),)
$(call test_assert,$(call defined,myarray,key1),T)
$(call test_assert,$(call defined,myarray,key2),)
$(call test_assert,$(call defined,myarray1,key1),)
$(call set,myarray,key2,value2)
$(call test_assert,$(call keys,myarray),key1 key2)
$(call test_assert,$(call keys,myarray1),)
$(call stop_test)
$(call start_test,named stack)
$(call test_assert,$(call pop,mystack),)
$(call test_assert,$(call push,mystack,e2))
$(call push,mystack,e1)
$(call test_assert,$(call pop,mystack),e1)
$(call test_assert,$(call pop,mystack),e2)
$(call push,mystack,f3)
$(call push,mystack,f1)
$(call test_assert,$(call pop,mystack),f1)
$(call push,mystack,f2)
$(call test_assert,$(call peek,mystack),f2)
$(call test_assert,$(call depth,mystack),2)
$(call test_assert,$(call pop,mystack),f2)
$(call test_assert,$(call depth,mystack),1)
$(call test_assert,$(call pop,myotherstack),)
$(call stop_test)
$(call start_test,reverse)
$(call test_assert,$(call reverse,),)
$(call test_assert,$(call reverse,1),1)
$(call test_assert,$(call reverse,1 2),2 1)
$(call test_assert,$(call reverse,1 2 3),3 2 1)
$(call stop_test)
$(call start_test,uniq)
$(call test_assert,$(call uniq,),)
$(call test_assert,$(call uniq,a),a)
$(call test_assert,$(call uniq,a a),a)
$(call test_assert,$(call uniq,a aa),a aa)
$(call test_assert,$(call uniq,a aa a),a aa)
$(call test_assert,$(call uniq,a b ba ab b a a ba a),a b ba ab)
$(call stop_test)
c:=,
$(call start_test,split)
$(call test_assert,$(call split,$c,comma$cseparated$cstring),comma separated string)
$(call test_assert,$(call split,*,star*field*record),star field record)
$(call test_assert,$(call split,*,star*),star)
$(call test_assert,$(call split,*,star*field),star field)
$(call test_assert,$(call split,*,star****field),star field)
$(call test_assert,$(call split,*,),)
$(call stop_test)
$(call start_test,merge)
$(call test_assert,$(call merge,$c,list of things),list$cof$cthings)
$(call test_assert,$(call merge,*,list of things),list*of*things)
$(call test_assert,$(call merge,*,list),list)
$(call test_assert,$(call merge,*,),)
$(call stop_test)
$(call start_test,int_max)
$(call test_assert,$(call int_max,$(call int_encode,2),$(call int_encode,1)),$(call int_encode,2))
$(call test_assert,$(call int_max,$(call int_encode,1),$(call int_encode,2)),$(call int_encode,2))
$(call test_assert,$(call int_max,$(call int_encode,2),$(call int_encode,0)),$(call int_encode,2))
$(call test_assert,$(call int_max,$(call int_encode,0),$(call int_encode,2)),$(call int_encode,2))
$(call test_assert,$(call int_max,$(call int_encode,2),$(call int_encode,2)),$(call int_encode,2))
$(call test_assert,$(call int_max,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0))
$(call stop_test)
$(call start_test,max)
$(call test_assert,$(call max,2,1),2)
$(call test_assert,$(call max,1,2),2)
$(call test_assert,$(call max,2,0),2)
$(call test_assert,$(call max,0,2),2)
$(call test_assert,$(call max,2,2),2)
$(call test_assert,$(call max,0,0),0)
$(call stop_test)
$(call start_test,int_min)
$(call test_assert,$(call int_min,$(call int_encode,2),$(call int_encode,1)),$(call int_encode,1))
$(call test_assert,$(call int_min,$(call int_encode,1),$(call int_encode,2)),$(call int_encode,1))
$(call test_assert,$(call int_min,$(call int_encode,2),$(call int_encode,0)),$(call int_encode,0))
$(call test_assert,$(call int_min,$(call int_encode,0),$(call int_encode,2)),$(call int_encode,0))
$(call test_assert,$(call int_min,$(call int_encode,2),$(call int_encode,2)),$(call int_encode,2))
$(call test_assert,$(call int_min,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0))
$(call stop_test)
$(call start_test,min)
$(call test_assert,$(call min,2,1),1)
$(call test_assert,$(call min,1,2),1)
$(call test_assert,$(call min,2,0),0)
$(call test_assert,$(call min,0,2),0)
$(call test_assert,$(call min,2,2),2)
$(call test_assert,$(call min,0,0),0)
$(call stop_test)
__gmsl_error = $1
$(call start_test,assert functions)
$(call test_assert,$(call assert,$(true),ignore),)
$(call test_assert,$(call assert,$(false),failed),Assertion failure: failed)
$(call test_assert,$(call assert_exists,gmsl-tests),)
$(call test_assert,$(call assert_exists,MISSING-gmsl-tests),Assertion failure: file 'MISSING-gmsl-tests' missing)
$(call stop_test)
$(call start_test,int_inc)
$(call test_assert,$(call int_inc,$(call int_encode,0)),$(call int_encode,1))
$(call test_assert,$(call int_inc,$(call int_encode,1)),$(call int_encode,2))
$(call test_assert,$(call int_inc,$(call int_encode,4)),$(call int_encode,5))
$(call test_assert,$(call int_inc,$(call int_encode,10)),$(call int_encode,11))
$(call stop_test)
$(call start_test,inc)
$(call test_assert,$(call inc,0),1)
$(call test_assert,$(call inc,1),2)
$(call test_assert,$(call inc,4),5)
$(call test_assert,$(call inc,10),11)
$(call stop_test)
__gmsl_warning = $1
$(call start_test,int_dec)
$(call test_assert,$(call int_dec,$(call int_encode,0)),Decrement underflow)
$(call test_assert,$(call int_dec,$(call int_encode,1)),$(call int_encode,0))
$(call test_assert,$(call int_dec,$(call int_encode,4)),$(call int_encode,3))
$(call test_assert,$(call int_dec,$(call int_encode,10)),$(call int_encode,9))
$(call stop_test)
__gmsl_warning = x x x x x x x x x x
$(call start_test,dec)
$(call test_assert,$(call dec,0),10)
$(call test_assert,$(call dec,1),0)
$(call test_assert,$(call dec,4),3)
$(call test_assert,$(call dec,10),9)
$(call stop_test)
$(call start_test,int_double)
$(call test_assert,$(call int_double,$(call int_encode,0)),$(call int_encode,0))
$(call test_assert,$(call int_double,$(call int_encode,1)),$(call int_encode,2))
$(call test_assert,$(call int_double,$(call int_encode,4)),$(call int_encode,8))
$(call stop_test)
$(call start_test,double)
$(call test_assert,$(call double,0),0)
$(call test_assert,$(call double,1),2)
$(call test_assert,$(call double,4),8)
$(call stop_test)
$(call start_test,int_halve)
$(call test_assert,$(call int_halve,$(call int_encode,0)),$(call int_encode,0))
$(call test_assert,$(call int_halve,$(call int_encode,2)),$(call int_encode,1))
$(call test_assert,$(call int_halve,$(call int_encode,8)),$(call int_encode,4))
$(call test_assert,$(call int_halve,$(call int_encode,7)),$(call int_encode,3))
$(call stop_test)
$(call start_test,halve)
$(call test_assert,$(call halve,0),0)
$(call test_assert,$(call halve,2),1)
$(call test_assert,$(call halve,8),4)
$(call test_assert,$(call halve,7),3)
$(call stop_test)
$(call start_test,gt)
$(call test_assert,$(call gt,2,3),)
$(call test_assert,$(call gt,3,2),$(true))
$(call test_assert,$(call gt,2,2),)
$(call stop_test)
$(call start_test,gte)
$(call test_assert,$(call gte,2,3),)
$(call test_assert,$(call gte,3,2),$(true))
$(call test_assert,$(call gte,2,2),$(true))
$(call stop_test)
$(call start_test,lt)
$(call test_assert,$(call lt,2,3),$(true))
$(call test_assert,$(call lt,3,2),)
$(call test_assert,$(call lt,2,2),)
$(call stop_test)
$(call start_test,lte)
$(call test_assert,$(call lte,2,3),$(true))
$(call test_assert,$(call lte,3,2),)
$(call test_assert,$(call lte,2,2),$(true))
$(call stop_test)
$(call start_test,eq)
$(call test_assert,$(call eq,2,3),)
$(call test_assert,$(call eq,3,2),)
$(call test_assert,$(call eq,2,2),$(true))
$(call stop_test)
$(call start_test,ne)
$(call test_assert,$(call ne,2,3),$(true))
$(call test_assert,$(call ne,3,2),$(true))
$(call test_assert,$(call ne,2,2),)
$(call stop_test)
$(call start_test,int_gt)
$(call test_assert,$(call int_gt,$(call int_encode,2),$(call int_encode,3)),)
$(call test_assert,$(call int_gt,$(call int_encode,3),$(call int_encode,2)),$(true))
$(call test_assert,$(call int_gt,$(call int_encode,2),$(call int_encode,2)),)
$(call stop_test)
$(call start_test,int_gte)
$(call test_assert,$(call int_gte,$(call int_encode,2),$(call int_encode,3)),)
$(call test_assert,$(call int_gte,$(call int_encode,3),$(call int_encode,2)),$(true))
$(call test_assert,$(call int_gte,$(call int_encode,2),$(call int_encode,2)),$(true))
$(call stop_test)
$(call start_test,int_lt)
$(call test_assert,$(call int_lt,$(call int_encode,2),$(call int_encode,3)),$(true))
$(call test_assert,$(call int_lt,$(call int_encode,3),$(call int_encode,2)),)
$(call test_assert,$(call int_lt,$(call int_encode,2),$(call int_encode,2)),)
$(call stop_test)
$(call start_test,int_lte)
$(call test_assert,$(call int_lte,$(call int_encode,2),$(call int_encode,3)),$(true))
$(call test_assert,$(call int_lte,$(call int_encode,3),$(call int_encode,2)),)
$(call test_assert,$(call int_lte,$(call int_encode,2),$(call int_encode,2)),$(true))
$(call stop_test)
$(call start_test,int_eq)
$(call test_assert,$(call int_eq,$(call int_encode,2),$(call int_encode,3)),)
$(call test_assert,$(call int_eq,$(call int_encode,3),$(call int_encode,2)),)
$(call test_assert,$(call int_eq,$(call int_encode,2),$(call int_encode,2)),$(true))
$(call stop_test)
$(call start_test,int_ne)
$(call test_assert,$(call int_ne,$(call int_encode,2),$(call int_encode,3)),$(true))
$(call test_assert,$(call int_ne,$(call int_encode,3),$(call int_encode,2)),$(true))
$(call test_assert,$(call int_ne,$(call int_encode,2),$(call int_encode,2)),)
$(call stop_test)
$(call start_test,gmsl_compatible)
$(call test_assert,$(call gmsl_compatible,$(gmsl_version)),$(true))
$(call test_assert,$(call gmsl_compatible,0 9 0),$(true))
$(call test_assert,$(call gmsl_compatible,0 0 1),$(true))
$(call test_assert,$(call gmsl_compatible,0 0 0),$(true))
$(call test_assert,$(call gmsl_compatible,2 0 0),)
$(call test_assert,$(call gmsl_compatible,1 1 0),)
$(call test_assert,$(call gmsl_compatible,1 0 8),$(true))
$(call test_assert,$(call gmsl_compatible,1 0 8),$(true))
$(call test_assert,$(call gmsl_compatible,1 0 10),$(true))
$(call test_assert,$(call gmsl_compatible,1 0 11),$(true))
$(call test_assert,$(call gmsl_compatible,1 0 12),)
$(call stop_test)

View File

@ -0,0 +1,687 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
<title>GNU Make Standard Library</title></head>
<body>
<h1>GNU Make Standard Library</h1>
The GNU Make Standard Library (GMSL) is a collection of functions
implemented using native GNU Make functionality that provide list and
string manipulation, integer arithmetic, associative arrays, stacks,
and debugging facilities.&nbsp; The GMSL is released under the BSD License.<br>
<br>
<a href="http://sourceforge.net/projects/gmsl/">[Project Page]</a> <a href="http://sourceforge.net/project/showfiles.php?group_id=129887">[Download]</a>
<a href="http://sourceforge.net/forum/forum.php?forum_id=443916">[Discussion
Forum]</a><br>
<h2>Using GMSL</h2>
The two files needed are <span style="font-family: monospace;">gmsl</span>
and <span style="font-family: monospace;">__gmsl</span>.&nbsp; To
include the GMSL in your Makefile do<br>
<pre style="margin-left: 40px;">include gmsl</pre>
<span style="font-family: monospace;">gmsl</span> automatically includes<span style="font-family: monospace;"> __gmsl</span>.&nbsp; To check that
you have the right version of <span style="font-family: monospace;">gmsl</span>
use the <span style="font-family: monospace;">gmsl_compatible</span>
function (see
below). The current version is <span style="font-family: monospace;">1
0 11</span>.<br>
<br>
The GMSL package also includes a test suite for GMSL.&nbsp; Just run <span style="font-family: monospace;">make -f gmsl-tests</span>.<br>
<h2>Logical Operators</h2>GMSL has boolean $(true) (a non-empty string)
and $(false) (an empty string).&nbsp; The following operators can be
used with those variables.<br>
<br>
<hr style="width: 100%; height: 2px;"><span style="font-weight: bold;">not</span><br>
<br>
<span style="font-family: monospace;">Arguments: A boolean value</span><br style="font-family: monospace;">
<span style="font-family: monospace;">Returns:&nbsp;&nbsp; Returns $(true) if the boolean is $(false) and vice versa</span><br style="font-family: monospace;">
<hr style="width: 100%; height: 2px; font-family: monospace;"><span style="font-weight: bold;"></span><span style="font-weight: bold;">and</span><br>
<br>
<span style="font-family: monospace;">Arguments: Two boolean values</span><br style="font-family: monospace;">
<span style="font-family: monospace;">Returns:&nbsp;&nbsp; Returns $(true) if both of the booleans are true</span><br style="font-family: monospace;">
<hr style="width: 100%; height: 2px; font-family: monospace;"><span style="font-weight: bold;">or</span><br>
<br>
<span style="font-family: monospace;">Arguments: Two boolean values</span><br style="font-family: monospace;">
<span style="font-family: monospace;">Returns:&nbsp;&nbsp; Returns $(true) if either of the booleans is true</span><br style="font-family: monospace;">
<hr style="width: 100%; height: 2px; font-family: monospace;"><span style="font-weight: bold;">xor</span><br style="font-weight: bold;">
<br>
<span style="font-family: monospace;">Arguments: Two boolean values</span><br style="font-family: monospace;">
<span style="font-family: monospace;">Returns:&nbsp;&nbsp; Returns $(true) if exactly one of the booleans is true</span><br style="font-family: monospace;">
<hr style="width: 100%; height: 2px; font-family: monospace;"><span style="font-weight: bold;">nand</span><br>
<br>
<span style="font-family: monospace;">Arguments: Two boolean values</span><br style="font-family: monospace;">
<span style="font-family: monospace;">Returns:&nbsp;&nbsp; Returns value of 'not and'</span><br style="font-family: monospace;">
<hr style="width: 100%; height: 2px; font-family: monospace;"><span style="font-weight: bold;">nor</span><br>
<br>
<span style="font-family: monospace;">Arguments: Two boolean values</span><br style="font-family: monospace;">
<span style="font-family: monospace;">Returns:&nbsp;&nbsp; Returns value of 'not or'</span><br style="font-family: monospace;">
<hr style="width: 100%; height: 2px; font-family: monospace;"><span style="font-weight: bold;">xnor</span><br>
<br>
<span style="font-family: monospace;">Arguments: Two boolean values</span><br style="font-family: monospace;">
<span style="font-family: monospace;">Returns:&nbsp;&nbsp; Returns value of 'not xor'</span><br style="font-family: monospace;">
<hr style="width: 100%; height: 2px; font-family: monospace;">
<h2>List Manipulation Functions</h2>
&nbsp;A list is a string of characters; the list separator is a space.<br>
<br>
<hr style="width: 100%; height: 2px;"><b>first</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the first element of a list<br>
</span>
<hr><b>last</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the last element of a list<br>
</span>
<hr><b>rest</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the list with the first element
removed<br>
</span>
<hr><b>chop</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the list with the last element removed<br>
</span>
<hr><b>map</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of function to
$(call) for each element of list<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: List to
iterate over calling the function in 1<br>
Returns:&nbsp;&nbsp;&nbsp;The list after calling the function on each
element<br>
</span>
<hr><b>pairmap</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of function to
$(call) for each pair of elements<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: List to
iterate over calling the function in 1<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3: Second
list to iterate over calling the function in 1<br>
Returns:&nbsp;&nbsp;&nbsp;The list after calling the function on each
pair of elements<br>
</span>
<hr><b>leq</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list to compare
against...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: ...this
list<br>
Returns:&nbsp;&nbsp;&nbsp;Returns $(true) if the two lists are identical<br>
</span>
<hr><b>lne</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list to compare
against...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: ...this
list<br>
Returns:&nbsp;&nbsp;&nbsp;Returns $(true) if the two lists are different<br>
</span>
<hr><b>reverse</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list to reverse<br>
Returns:&nbsp;&nbsp;&nbsp;The list with its elements in reverse order<br>
</span>
<hr><b>uniq</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list to deduplicate<br>
Returns:&nbsp;&nbsp;&nbsp;The list with elements in order without duplicates<br>
</span>
<hr><b>length</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list<br>
Returns:&nbsp;&nbsp;&nbsp;The number of elements in the list<br>
</span>
<hr style="width: 100%; height: 2px;"><span style="font-family: monospace;"></span>
<h2>String Manipulation Functions</h2>
A string is any sequence of characters.<br>
<br>
<hr style="width: 100%; height: 2px;"><b>seq</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A string to compare
against...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: ...this
string<br>
Returns:&nbsp;&nbsp;&nbsp;Returns $(true) if the two strings are
identical<br>
</span>
<hr><b>sne</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A string to compare
against...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: ...this
string<br>
Returns:&nbsp;&nbsp;&nbsp;Returns $(true) if the two strings are not
the same<br>
</span>
<hr><b>strlen</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A string<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the length of the string<br>
</span>
<hr><b>substr</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A string<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Start offset (first character is 1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3: Ending offset (inclusive)<br>Returns:&nbsp;&nbsp;&nbsp;Returns a substring<br>
</span>
<hr><b>split</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: The character to
split on<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: A
string to split<br>
Returns:&nbsp;&nbsp;&nbsp;Splits a string into a list separated by
spaces at the split<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; character
in the first argument<br>
</span>
<hr><b>merge</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: The character to
put between fields<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: A list
to merge into a string<br>
Returns:&nbsp;&nbsp;&nbsp;Merges a list into a single string, list
elements are separated<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by the
character in the first argument<br>
</span>
<hr><b>tr</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: The list of
characters to translate from <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: The
list of characters to translate to<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3: The
text to translate<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the text after translating characters<br>
</span>
<hr><b>uc</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Text to upper case<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the text in upper case<br>
</span>
<hr><b>lc</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Text to lower case<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the text in lower case<br>
</span>
<hr style="width: 100%; height: 2px;"><span style="font-family: monospace;"></span>
<h2>Set Manipulation Functions</h2>
Sets are represented by sorted, deduplicated lists. To create a set
from a list use <span style="font-family:
monospace;">set_create</span>, or start with the <span
style="font-family: monospace;">empty_set</span> and <span
style="font-family: monospace;">set_insert</span> individual elements.
The empty set is defined as <span style="font-family:
monospace;">empty_set</span>.<p>
<hr><b>set_create</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A list of set elements<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the newly created set<br>
</span>
<hr><b>set_insert</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A single element to add to a set<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2: A set<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the set with the element added<br>
</span>
<hr><b>set_remove</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A single element to remove from a set<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2: A set<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the set with the element removed<br>
</span>
<hr><b>set_is_member</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A single element<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2: A set<br>
Returns:&nbsp;&nbsp;&nbsp;Returns $(true) if the element is in the set<br>
</span>
<hr><b>set_union</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A set<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2: Another set<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the union of the two sets<br>
</span>
<hr><b>set_intersection</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A set<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2: Another set<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the intersection of the two sets<br>
</span>
<hr><b>set_is_subset</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A set<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2: Another set<br>
Returns:&nbsp;&nbsp;&nbsp;Returns $(true) if the first set is a subset of the second<br>
</span>
<hr><b>set_equal</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A set<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2: Another set<br>
Returns:&nbsp;&nbsp;&nbsp;Returns $(true) if the two sets are identical<br>
</span>
<hr style="width: 100%; height: 2px;"><span style="font-family: monospace;"></span>
<h2>Integer Arithmetic Functions</h2>
Integers are represented by lists with the equivalent number of
x's.&nbsp; For example the number 4 is x x x x.&nbsp; The maximum
integer that the library can handle as <span style="font-style: italic;">input</span> (i.e. as the argument to a
call to <span style="font-family: monospace;">int_encode</span>) is
65536. There is no limit on integer size for internal computations or
output.<br>
<br>
The arithmetic library functions come in two forms: one form of each
function takes integers as arguments and the other form takes the
encoded form (x's created by a call to <span style="font-family: monospace;">int_encode</span>).&nbsp; For example,
there are two plus functions: <span style="font-family: monospace;">plus</span>
(called with integer arguments and returns an integer) and <span style="font-family: monospace;">int_plus</span> (called with encoded
arguments and returns an encoded result).<br>
<br>
<span style="font-family: monospace;">plus</span> will be slower than <span style="font-family: monospace;">int_plus</span> because its arguments
and result have to be translated between the x's format and
integers.&nbsp; If doing a complex calculation use the <span style="font-family: monospace;">int_*</span> forms with a single
encoding of inputs and single decoding of the output.&nbsp; For simple
calculations the direct forms can be used.<br>
<br>
<hr style="width: 100%; height: 2px;"><b>int_decode</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number of x's
representation<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the integer for human consumption
that is represented<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by the
string of x's<br>
</span>
<hr><b>int_encode</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in
human-readable integer form<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the integer encoded as a string of x's<br>
</span>
<hr><b>int_plus</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
number in x's represntation<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the sum of the two numbers in x's
representation<br>
</span>
<hr><b>plus (wrapped version of int_plus)</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
integer<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the sum of the two integers<br>
</span>
<hr><b>int_subtract</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
number in x's represntation<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the difference of the two numbers in
x's representation,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; or outputs
an error on a numeric underflow<br>
</span>
<hr><b>subtract (wrapped version of int_subtract)</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
integer<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the difference of the two integers,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; or outputs
an error on a numeric underflow<br>
</span>
<hr><b>int_multiply</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
number in x's represntation<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the product of the two numbers in x's
representation<br>
</span>
<hr><b>multiply (wrapped version of int_multiply)</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
integer<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the product of the two integers<br>
</span>
<hr><b>int_divide</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
number in x's represntation<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the result of integer division of
argument 1 divided<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by
argument 2 in x's representation<br>
</span>
<hr><b>divide (wrapped version of int_divide)</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
integer<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the integer division of the first
argument by the second<br>
</span>
<hr><b>int_max, int_min</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
number in x's represntation<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the maximum or minimum of its
arguments in x's<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
representation<br>
</span>
<hr><b>max, min</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Another
integer<br>
Returns:&nbsp;&nbsp;&nbsp;Returns the maximum or minimum of its integer
arguments<br>
</span>
<hr><b>int_gt, int_gte, int_lt, int_lte, int_eq, int_ne</b><br>
<br>
<span style="font-family: monospace;">Arguments: Two x's representation
numbers to be compared<br>
Returns:&nbsp;&nbsp;&nbsp;$(true) or $(false)<br>
<br>
int_gt First argument greater than second argument<br>
int_gte First argument greater than or equal to second argument<br>
int_lt First argument less than second argument <br>
int_lte First argument less than or equal to second argument<br>
int_eq First argument is numerically equal to the second argument<br>
int_ne First argument is not numerically equal to the second argument<br>
</span>
<hr><b>gt, gte, lt, lte, eq, ne</b><br>
<br>
<span style="font-family: monospace;">Arguments: Two integers to be
compared<br>
Returns:&nbsp;&nbsp;&nbsp;$(true) or $(false)<br>
<br>
gt First argument greater than second argument<br>
gte First argument greater than or equal to second argument<br>
lt First argument less than second argument <br>
lte First argument less than or equal to second argument<br>
eq First argument is numerically equal to the second argument<br>
ne First argument is not numerically equal to the second argument<br>
</span>
increment adds 1 to its argument, decrement subtracts 1. Note that<br>
decrement does not range check and hence will not underflow, but<br>
will incorrectly say that 0 - 1 = 0<br>
<hr><b>int_inc</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
Returns:&nbsp;&nbsp;&nbsp;The number incremented by 1 in x's
representation<br>
</span>
<hr><b>inc</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
Returns:&nbsp;&nbsp;&nbsp;The argument incremented by 1<br>
</span>
<hr><b>int_dec</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
Returns:&nbsp;&nbsp;&nbsp;The number decremented by 1 in x's
representation<br>
</span>
<hr><b>dec</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
Returns:&nbsp;&nbsp;&nbsp;The argument decremented by 1<br>
</span>
<hr><b>int_double</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
Returns:&nbsp;&nbsp;&nbsp;The number doubled (i.e. * 2) and returned in
x's representation<br>
</span>
<hr><b>double</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
Returns:&nbsp;&nbsp;&nbsp;The integer times 2<br>
</span>
<hr><b>int_halve</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A number in x's
representation<br>
Returns:&nbsp;&nbsp;&nbsp;The number halved (i.e. / 2) and returned in
x's representation<br>
</span>
<hr><b>halve</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: An integer<br>
Returns:&nbsp;&nbsp;&nbsp;The integer divided by 2<br>
</span>
<hr style="width: 100%; height: 2px;"><span style="font-family: monospace;"></span>
<h2>Associative Arrays</h2>
An associate array maps a key value (a string with no spaces in it) to
a single value (any string).&nbsp;&nbsp;&nbsp; <br>
<b><br>
</b>
<hr style="width: 100%; height: 2px;"><b>set</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of associative
array<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: The key
value to associate<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3: The
value associated with the key<br>
Returns:&nbsp;&nbsp;&nbsp;None<br>
</span>
<hr><b>get</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of associative
array<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: The key
to retrieve<br>
Returns:&nbsp;&nbsp;&nbsp;The value stored in the array for that key<br>
</span>
<hr><b>keys</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of associative
array<br>
Returns:&nbsp;&nbsp;&nbsp;Returns a list of all defined keys in the
array<br>
</span>
<hr><b>defined</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of associative
array<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: The key
to test<br>
Returns:&nbsp;&nbsp;&nbsp;Returns true if the key is defined (i.e. not
empty)<br>
</span>
<hr style="width: 100%; height: 2px;"><span style="font-family: monospace;"></span>
<h2>Named Stacks</h2>
A stack is an ordered list of strings (with no spaces in them).<br>
<br>
<hr style="width: 100%; height: 2px;"><b>push</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of stack<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Value
to push onto the top of the stack (must not contain<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a space)<br>
Returns:&nbsp;&nbsp;&nbsp;None<br>
</span>
<hr><b>pop</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of stack<br>
Returns:&nbsp;&nbsp;&nbsp;Top element from the stack after removing it<br>
</span>
<hr><b>peek</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of stack<br>
Returns:&nbsp;&nbsp;&nbsp;Top element from the stack without removing it<br>
</span>
<hr><b>depth</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of stack<br>
Returns:&nbsp;&nbsp;&nbsp;Number of items on the stack<br>
</span>
<hr style="width: 100%; height: 2px;"><span style="font-family: monospace;"></span>
<h2>Miscellaneous and Debugging Facilities</h2>
GMSL defines the following constants; all are accessed as normal GNU
Make variables by wrapping them in <span style="font-family: monospace;">$()</span> or <span style="font-family: monospace;">${}</span>.<br>
<br>
<table style="text-align: left;" border="1" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td><span style="font-style: italic;">Constant</span><br>
</td>
<td><span style="font-style: italic;">Value</span><br>
</td>
<td><span style="font-style: italic;">Purpose</span><br>
</td>
</tr>
<tr>
<td><span style="font-family: monospace;">true</span><br>
</td>
<td><span style="font-family: monospace;">T</span><br>
</td>
<td>Boolean for <span style="font-family: monospace;">$(if)</span>
and return from&nbsp; GMSL functions<br>
</td>
</tr>
<tr>
<td><span style="font-family: monospace;">false</span><br>
</td>
<td><br>
</td>
<td>Boolean for <span style="font-family: monospace;">$(if)</span>
and return from GMSL functions<br>
</td>
</tr>
<tr>
<td><span style="font-family: monospace;">gmsl_version</span><br>
</td>
<td><span style="font-family: monospace;">1 0 0</span><br>
</td>
<td>GMSL version number as list: major minor revision<br>
</td>
</tr>
</tbody>
</table>
<span style="font-weight: bold;"><br>
gmsl_compatible</span><span style="font-family: monospace;"><br>
<br>
Arguments: List containing the desired library version number (maj min
rev)<br>
</span><span style="font-family: monospace;">Returns:&nbsp;&nbsp;
$(true) if this version of the library is compatible<br>
</span><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
with the requested version number, otherwise $(false)</span>
<hr><b>gmsl-print-% (target not a function)</b><br>
<br>
<span style="font-family: monospace;">Arguments: The % should be
replaced by the name of a variable that you<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wish to
print out.<br>
Action:&nbsp;&nbsp;&nbsp; Echos the name of the variable that matches
the % and its value.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For
example, 'make gmsl-print-SHELL' will output the value of<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the SHELL
variable<br>
</span>
<hr><b>assert</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: A boolean that must
be true or the assertion will fail<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: The
message to print with the assertion<br>
Returns:&nbsp;&nbsp;&nbsp;None<br>
</span>
<hr><b>assert_exists</b><br>
<br>
<span style="font-family: monospace;">Arguments: 1: Name of file that
must exist, if it is missing an assertion<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; will be
generated<br>
Returns:&nbsp;&nbsp;&nbsp;None<br>
</span>
<hr style="width: 100%; height: 2px;"><br>
GMSL has a number of environment variables (or command-line overrides)
that control various bits of functionality:<br>
<br>
<table style="text-align: left;" border="1" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td><span style="font-style: italic;">Variable</span><br>
</td>
<td><span style="font-style: italic;">Purpose</span><br>
</td>
</tr>
<tr>
<td><span style="font-family: monospace;">GMSL_NO_WARNINGS</span><br>
</td>
<td>If set prevents GMSL from outputting warning messages:
artithmetic functions generate underflow warnings.<br>
</td>
</tr>
<tr>
<td><span style="font-family: monospace;">GMSL_NO_ERRORS</span><br>
</td>
<td>If set prevents GMSL from generating fatal errors: division
by zero or failed assertions are fatal.<br>
</td>
</tr>
<tr>
<td><span style="font-family: monospace;">GMSL_TRACE</span><br>
</td>
<td>Enables function tracing.&nbsp; Calls to GMSL functions will
result in name and arguments being traced.<br>
</td>
</tr>
</tbody>
</table>
<span style="font-family: monospace;"></span><br>
<hr>
Copyright (c) 2005-2006 <a href="http://www.jgc.org/">John Graham-Cumming</a>.<br>
<hr style="width: 100%; height: 2px;">
<table style="width: 100%; text-align: left;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="width: 50%;">John Graham-Cumming's work on this
project was sponsored by <a href="http://www.electric-cloud.com/">Electric
Cloud, Inc</a>.<br>
<a href="http://www.electric-cloud.com/"><img alt="" src="http://gmsl.sf.net/ec_logo.gif" style="border: 0px solid ; width: 223px; height: 47px;"></a><br>
</td>
<td align="right">
<p><a href="http://sourceforge.net/"><img src="http://sourceforge.net/sflogo.php?group_id=129887&amp;type=1" alt="SourceForge.net Logo" border="0" height="31" width="88"></a></p>
</td>
</tr>
</tbody>
</table>
</body></html>

View File

@ -0,0 +1,75 @@
#!/usr/bin/env python3
#
# Copyright (C) 2018 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.
#
"""Determines which sanitizers should be linked based on ldflags."""
from __future__ import print_function
import sys
from typing import TextIO
def sanitizers_from_args(args: list[str]) -> list[str]:
"""Returns the sanitizers enabled by a given set of ldflags."""
sanitizers = set()
for arg in args:
if arg.startswith("-fsanitize="):
sanitizer_list = arg.partition("=")[2]
sanitizers |= set(sanitizer_list.split(","))
elif arg.startswith("-fno-sanitize="):
sanitizer_list = arg.partition("=")[2]
sanitizers -= set(sanitizer_list.split(","))
return sorted(list(sanitizers))
def argv_to_module_arg_lists(args: list[str]) -> tuple[list[str], list[list[str]]]:
"""Converts module ldflags from argv format to per-module lists.
Flags are passed to us in the following format:
['global flag', '--module', 'flag1', 'flag2', '--module', 'flag 3']
These should be returned as a list for the global flags and a list of
per-module lists, i.e.:
['global flag'], [['flag1', 'flag2'], ['flag1', 'flag3']]
"""
modules: list[list[str]] = [[]]
for arg in args:
if arg == "--module":
modules.append([])
else:
modules[-1].append(arg)
return modules[0], modules[1:]
def main(argv: list[str], stream: TextIO = sys.stdout) -> None:
"""Program entry point."""
# The only args we're guaranteed to see are the program name and at least
# one --module. GLOBAL_FLAGS might be empty, as might any of the
# MODULE_FLAGS sections.
if len(argv) < 2:
sys.exit(
"usage: ldflags_to_sanitizers.py [GLOBAL_FLAGS] "
"--module [MODULE_FLAGS] [--module [MODULE_FLAGS]...]"
)
global_flags, modules_flags = argv_to_module_arg_lists(argv[1:])
all_sanitizers = list(sanitizers_from_args(global_flags))
for module_flags in modules_flags:
all_sanitizers.extend(sanitizers_from_args(module_flags))
print(" ".join(sorted(set(all_sanitizers))), file=stream)
if __name__ == "__main__":
main(sys.argv)

View File

@ -0,0 +1,181 @@
#!/usr/bin/env bash
#
# Copyright (C) 2010 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.
#
# This shell script is a wrapper to launch the NDK build from the
# command-line inside an application project path.
#
# Typical usage is:
#
# cd $PROJECT_PATH
# ndk-build
#
# Assuming that the Android NDK root path is in your PATH. However,
# you can also invoke it directly as:
#
# $NDK_ROOT/ndk-build
#
# This really is a tiny wrapper around GNU Make.
#
# Ensure we get the full path of this script's directory
# this is needed if the caller uses the -C <path> GNU Make
# option, as in:
#
# cd ndk
# ./ndk-build -C <project-path>
#
PROGDIR=$(dirname "$0")
PROGDIR=$(cd "$PROGDIR" && pwd -P)
ANDROID_NDK_ROOT=$PROGDIR/..
# Unset PYTHONPATH and PYTHONHOME to prevent the user's environment from
# affecting the Python that we invoke.
# See https://github.com/googlesamples/vulkan-basic-samples/issues/25
unset PYTHONHOME
unset PYTHONPATH
# Check if absolute NDK path contain space
#
case "$PROGDIR" in
*\ *) echo "ERROR: NDK path cannot contain space"
exit 1
;;
esac
# If NDK_LOG is set to 1 or true in the environment, or the command-line
# then enable log messages below
if [ -z "$NDK_LOG" ]; then
NDK_LOG=0
fi
if [ -z "$NDK_ANALYZE" ]; then
NDK_ANALYZE=0
fi
PROJECT_PATH=
PROJECT_PATH_NEXT=
for opt; do
if [ -z "$PROJECT_PATH" ] && [ "$PROJECT_PATH_NEXT" = "yes" ] ; then
PROJECT_PATH=$opt
PROJECT_PATH_NEXT=
else
case $opt in
NDK_LOG=1|NDK_LOG=true)
NDK_LOG=1
;;
NDK_LOG=*)
NDK_LOG=0
;;
NDK_ANALYZE=1|NDK_ANALYZE=true)
NDK_ANALYZE=1
;;
NDK_ANALYZE=*)
NDK_ANALYZE=0
;;
-C)
PROJECT_PATH_NEXT="yes"
;;
esac
fi
done
if [ "$NDK_LOG" = "true" ]; then
NDK_LOG=1
fi
if [ "$NDK_ANALYZE" = "true" ]; then
NDK_ANALYZE=1
fi
if [ "$NDK_LOG" = "1" ]; then
log () {
echo "$@"
}
else
log () {
: # nothing
}
fi
# Detect host operating system and architecture
. "$ANDROID_NDK_ROOT/build/tools/ndk_bin_common.sh"
log "HOST_OS=$HOST_OS"
log "HOST_ARCH=$HOST_ARCH"
log "HOST_TAG=$HOST_TAG"
# If GNUMAKE is defined, check that it points to a valid file
if [ -n "$GNUMAKE" ] ; then
if ! ABS_GNUMAKE=$(which "$GNUMAKE" 2> /dev/null); then
echo "ERROR: Your GNUMAKE variable is defined to an invalid name: $GNUMAKE"
echo "Please fix it to point to a valid make executable (e.g. /usr/bin/make)"
exit 1
fi
GNUMAKE="$ABS_GNUMAKE"
log "GNUMAKE=$GNUMAKE (from environment variable)"
else
# Otherwise use the prebuilt version for our host tag, if it exists
# Note: we intentionally do not provide prebuilt make binaries for Cygwin
# or MSys.
GNUMAKE=$ANDROID_NDK_ROOT/prebuilt/$HOST_TAG/bin/make
if [ ! -f "$GNUMAKE" ]; then
# Otherwise, use 'make' and check that it is available
if ! GNUMAKE=$(which make 2> /dev/null); then
echo "ERROR: Cannot find 'make' program. Please install Cygwin make package"
echo "or define the GNUMAKE variable to point to it."
exit 1
fi
log "GNUMAKE=$GNUMAKE (system path)"
else
log "GNUMAKE=$GNUMAKE (NDK prebuilt)"
fi
fi
# On Windows, when running under cygwin, check that we are
# invoking a cygwin-compatible GNU Make binary. It is unfortunately
# common for app developers to have another non cygwin-compatible
# 'make' program in their PATH.
#
if [ "$OSTYPE" = "cygwin" ] ; then
GNUMAKE=$(cygpath -u "$GNUMAKE")
PROGDIR_MIXED=$(cygpath -m "$PROGDIR")
if ! ("$GNUMAKE" -f "$PROGDIR_MIXED/core/check-cygwin-make.mk" >/dev/null 2>&1); then
echo "ERROR: You are using a non-Cygwin compatible Make program."
echo "Currently using: $(cygpath -m "$GNUMAKE")"
echo ""
echo "To solve the issue, follow these steps:"
echo ""
echo "1. Ensure that the Cygwin 'make' package is installed."
echo " NOTE: You will need GNU Make 3.81 or later!"
echo ""
echo "2. Define the GNUMAKE environment variable to point to it, as in:"
echo ""
echo " export GNUMAKE=/usr/bin/make"
echo ""
echo "3. Call 'ndk-build' again."
echo ""
exit 1
fi
log "Cygwin-compatible GNU make detected"
fi
NDK_ANALYZER_FLAGS=
if [ "$NDK_ANALYZE" = 1 ]; then
# Continue supporting the old interface to the static analyzer. clang-tidy
# does all the same checks by default (and some new ones).
NDK_ANALYZER_FLAGS=APP_CLANG_TIDY=true
fi
"$GNUMAKE" -O -f "$PROGDIR/core/build-local.mk" $NDK_ANALYZER_FLAGS "$@"

View File

@ -0,0 +1,21 @@
@echo off
setlocal
rem This is checked in build-local.mk... but make on windows doesn't handle
rem LAST_MAKEFILE correctly when the makefile is in a directory with spaces
rem anyway, so that defense doesn't work either.
rem https://github.com/android/ndk/issues/1400
rem https://stackoverflow.com/a/29057742/632035
for /f "tokens=2" %%a in ("%~dp0") do (
echo ERROR: NDK path cannot contain spaces
exit /b 1
)
rem Unset PYTHONPATH and PYTHONHOME to prevent the user's environment from
rem affecting the Python that we invoke.
rem See https://github.com/googlesamples/vulkan-basic-samples/issues/25
set PYTHONHOME=
set PYTHONPATH=
set NDK_ROOT=%~dp0..
set PREBUILT_PATH=%NDK_ROOT%\prebuilt\windows-x86_64
"%PREBUILT_PATH%\bin\make.exe" -O -f "%NDK_ROOT%\build\core\build-local.mk" SHELL=cmd %*

View File

@ -0,0 +1,183 @@
#
# Copyright (C) 2017 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.
#
from __future__ import print_function
import textwrap
import unittest
import xml.etree.ElementPath
import build.extract_manifest
class ExtractMinSdkVersionTest(unittest.TestCase):
def testMinSdkVersion(self) -> None:
xml_str = textwrap.dedent(
"""\
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="@string/app_name"
android:debuggable="true">
<activity
android:name=".Test"
android:label="@string/app_name">
</activity>
</application>
<uses-sdk android:minSdkVersion="9"/>
</manifest>
"""
)
root = xml.etree.ElementTree.fromstring(xml_str)
self.assertEqual("9", build.extract_manifest.get_minsdkversion(root))
def testUsesSdkMissingMinSdkVersion(self) -> None:
xml_str = textwrap.dedent(
"""\
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="@string/app_name"
android:debuggable="true">
<activity
android:name=".Test"
android:label="@string/app_name">
</activity>
</application>
<uses-sdk android:maxSdkVersion="21"/>
</manifest>
"""
)
root = xml.etree.ElementTree.fromstring(xml_str)
self.assertEqual("", build.extract_manifest.get_minsdkversion(root))
def testNoUsesSdk(self) -> None:
xml_str = textwrap.dedent(
"""\
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="@string/app_name"
android:debuggable="true">
<activity
android:name=".Test"
android:label="@string/app_name">
</activity>
</application>
</manifest>
"""
)
root = xml.etree.ElementTree.fromstring(xml_str)
self.assertEqual("", build.extract_manifest.get_minsdkversion(root))
class ExtractDebuggableTest(unittest.TestCase):
def testIsDebuggable(self) -> None:
xml_str = textwrap.dedent(
"""\
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="@string/app_name"
android:debuggable="true">
</application>
</manifest>
"""
)
root = xml.etree.ElementTree.fromstring(xml_str)
self.assertEqual("true", build.extract_manifest.get_debuggable(root))
def testIsNotDebuggable(self) -> None:
xml_str = textwrap.dedent(
"""\
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="@string/app_name"
android:debuggable="false">
</application>
</manifest>
"""
)
root = xml.etree.ElementTree.fromstring(xml_str)
self.assertEqual("false", build.extract_manifest.get_debuggable(root))
def testBogusValue(self) -> None:
xml_str = textwrap.dedent(
"""\
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="@string/app_name"
android:debuggable="bogus">
</application>
</manifest>
"""
)
root = xml.etree.ElementTree.fromstring(xml_str)
self.assertEqual("false", build.extract_manifest.get_debuggable(root))
def testNotSet(self) -> None:
xml_str = textwrap.dedent(
"""\
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0">
<application android:label="@string/app_name">
<activity
android:name=".Test"
android:label="@string/app_name">
</activity>
</application>
<uses-sdk android:maxSdkVersion="21"/>
</manifest>
"""
)
root = xml.etree.ElementTree.fromstring(xml_str)
self.assertEqual("false", build.extract_manifest.get_debuggable(root))

View File

@ -0,0 +1,74 @@
#
# Copyright (C) 2017 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.
#
from __future__ import print_function
from io import StringIO
import textwrap
import unittest
import build.extract_platform
class ExtractPlatformTest(unittest.TestCase):
def testNumericVersion(self) -> None:
props_file = StringIO(
textwrap.dedent(
"""\
some
# other
junk
target=android-9
foo
"""
)
)
self.assertEqual("android-9", build.extract_platform.get_platform(props_file))
def testNamedVersion(self) -> None:
props_file = StringIO(
textwrap.dedent(
"""\
some
# other
junk
target=android-nougat
foo
"""
)
)
self.assertEqual(
"android-nougat", build.extract_platform.get_platform(props_file)
)
def testVendorVersion(self) -> None:
props_file = StringIO(
textwrap.dedent(
"""\
some
# other
junk
target=vendor:something:21
foo
"""
)
)
self.assertEqual("android-21", build.extract_platform.get_platform(props_file))
def testNoVersion(self) -> None:
self.assertEqual("unknown", build.extract_platform.get_platform(StringIO("")))

View File

@ -0,0 +1,98 @@
#
# Copyright (C) 2017 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.
#
from __future__ import print_function
import textwrap
import unittest
import build.gen_cygpath
class GetMountsTest(unittest.TestCase):
def testSingleMount(self) -> None:
mount_output = "C:/cygwin on / type ntfs (binary,auto)"
self.assertEqual(
[("/", "C:/cygwin")], build.gen_cygpath.get_mounts(mount_output)
)
def testCaseInsensitiveMount(self) -> None:
mount_output = "C: on /cygdrive/c type ntfs"
expected_output = [
("/cygdrive/c", "C:"),
("/cygdrive/C", "C:"),
]
self.assertEqual(expected_output, build.gen_cygpath.get_mounts(mount_output))
def testManyMounts(self) -> None:
mount_output = textwrap.dedent(
"""\
C:/cygwin/bin on /usr/bin type ntfs (binary,auto)
C:/cygwin/lib on /usr/lib type ntfs (binary,auto)
C:/cygwin on / type ntfs (binary,auto)
C: on /cygdrive/c type ntfs (binary,posix=0,user,noumount,auto)
D: on /cygdrive/d type udf (binary,posix=0,user,noumount,auto)
"""
)
expected_output = [
("/", "C:/cygwin"),
("/usr/bin", "C:/cygwin/bin"),
("/usr/lib", "C:/cygwin/lib"),
("/cygdrive/c", "C:"),
("/cygdrive/C", "C:"),
("/cygdrive/d", "D:"),
("/cygdrive/D", "D:"),
]
self.assertEqual(expected_output, build.gen_cygpath.get_mounts(mount_output))
class MakeCygpathFunctionTest(unittest.TestCase):
def testSingleMount(self) -> None:
mounts = [("/", "C:/cygwin")]
expected_output = "$(patsubst /%,C:/cygwin/%,\n$1)"
self.assertEqual(
expected_output, build.gen_cygpath.make_cygpath_function(mounts)
)
def testManyMounts(self) -> None:
mounts = [
("/", "C:/cygwin"),
("/usr/bin", "C:/cygwin/bin"),
("/usr/lib", "C:/cygwin/lib"),
("/cygdrive/c", "C:"),
("/cygdrive/C", "C:"),
("/cygdrive/d", "D:"),
("/cygdrive/D", "D:"),
]
expected_output = textwrap.dedent(
"""\
$(patsubst /%,C:/cygwin/%,
$(patsubst /usr/bin/%,C:/cygwin/bin/%,
$(patsubst /usr/lib/%,C:/cygwin/lib/%,
$(patsubst /cygdrive/c/%,C:/%,
$(patsubst /cygdrive/C/%,C:/%,
$(patsubst /cygdrive/d/%,D:/%,
$(patsubst /cygdrive/D/%,D:/%,
$1)))))))"""
)
self.assertEqual(
expected_output, build.gen_cygpath.make_cygpath_function(mounts)
)

View File

@ -0,0 +1,136 @@
#!/usr/bin/env python3
#
# Copyright (C) 2018 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.
#
"""Does test_ldflags_to_sanitizers stuff."""
from __future__ import absolute_import
import unittest
try:
from StringIO import StringIO # type: ignore
except ImportError:
from io import StringIO
from build.ldflags_to_sanitizers import argv_to_module_arg_lists
from build.ldflags_to_sanitizers import main as ldflags_main
from build.ldflags_to_sanitizers import sanitizers_from_args
class LdflagsToSanitizersTest(unittest.TestCase):
def test_sanitizers_from_args_no_sanitize_args(self) -> None:
"""Tests that we don't identify sanitizers when there are none."""
self.assertListEqual([], sanitizers_from_args([]))
self.assertListEqual([], sanitizers_from_args(["foo", "bar"]))
def test_sanitizers_from_args_enabled_sanitizers(self) -> None:
"""Tests that we find enabled sanitizers."""
self.assertListEqual(["address"], sanitizers_from_args(["-fsanitize=address"]))
self.assertListEqual(
["address"], sanitizers_from_args(["-fsanitize=address", "foo"])
)
self.assertListEqual(
["address", "undefined"],
sanitizers_from_args(["-fsanitize=address", "-fsanitize=undefined"]),
)
self.assertListEqual(
["address", "undefined"],
sanitizers_from_args(["-fsanitize=address,undefined"]),
)
self.assertListEqual(
["address", "undefined"],
sanitizers_from_args(["-fsanitize=address,undefined", "foo"]),
)
def test_sanitizers_from_args_disabled_sanitizers(self) -> None:
"""Tests that we don't find disabled sanitizers."""
self.assertListEqual([], sanitizers_from_args(["-fno-sanitize=address"]))
self.assertListEqual([], sanitizers_from_args(["-fno-sanitize=address", "foo"]))
self.assertListEqual(
[],
sanitizers_from_args(["-fno-sanitize=address", "-fno-sanitize=undefined"]),
)
self.assertListEqual(
[], sanitizers_from_args(["-fno-sanitize=address,undefined"])
)
self.assertListEqual(
[], sanitizers_from_args(["-fno-sanitize=address,undefined", "foo"])
)
def test_sanitizers_from_args_enabled_disabled_sanitizers(self) -> None:
"""Tests that we correctly identify only enabled sanitizers."""
self.assertListEqual(
[], sanitizers_from_args(["-fsanitize=address", "-fno-sanitize=address"])
)
self.assertListEqual(
["address"],
sanitizers_from_args(
["-fsanitize=address", "-fno-sanitize=address", "-fsanitize=address"]
),
)
self.assertListEqual(
[],
sanitizers_from_args(
[
"-fsanitize=address",
"-fno-sanitize=address",
"-fsanitize=address",
"-fno-sanitize=address",
]
),
)
self.assertListEqual(
["undefined"],
sanitizers_from_args(
["-fsanitize=address,undefined", "-fno-sanitize=address"]
),
)
self.assertListEqual(
["undefined"],
sanitizers_from_args(
["-fsanitize=address", "-fsanitize=undefined", "-fno-sanitize=address"]
),
)
def test_argv_to_module_arg_lists(self) -> None:
"""Tests that modules' arguments are properly identified."""
self.assertTupleEqual(([], []), argv_to_module_arg_lists([]))
self.assertTupleEqual((["foo"], []), argv_to_module_arg_lists(["foo"]))
self.assertTupleEqual(
([], [["foo", "bar"], ["baz"]]),
argv_to_module_arg_lists(["--module", "foo", "bar", "--module", "baz"]),
)
self.assertTupleEqual(
(["foo", "bar"], [["baz"]]),
argv_to_module_arg_lists(["foo", "bar", "--module", "baz"]),
)
def test_main(self) -> None:
"""Test that the program itself works."""
sio = StringIO()
ldflags_main(
[
"ldflags_to_sanitizers.py",
"-fsanitize=undefined",
"--module",
"-fsanitize=address,thread",
"-fno-sanitize=thread",
"--module",
"-fsanitize=undefined",
],
sio,
)
self.assertEqual("address undefined", sio.getvalue().strip())

View File

@ -0,0 +1,463 @@
#!/usr/bin/env python3
#
# Copyright (C) 2016 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.
#
"""Creates a toolchain installation for a given Android target.
THIS TOOL IS OBSOLETE. It is no longer necessary to create a separate toolchain for use
with build systems that lack explicit NDK support. The compiler installed to
<NDK>/toolchains/llvm/prebuilt/<host>/bin can be used directly. See
https://developer.android.com/ndk/guides/other_build_systems for more details.
"""
import argparse
import atexit
import inspect
import json
import logging
import os
import shutil
import stat
import sys
import tempfile
import textwrap
from pathlib import Path
THIS_DIR = os.path.realpath(os.path.dirname(__file__))
NDK_DIR = os.path.realpath(os.path.join(THIS_DIR, "../.."))
def logger():
"""Return the main logger for this module."""
return logging.getLogger(__name__)
def check_ndk_or_die():
"""Verify that our NDK installation is somewhat present or die."""
checks = [
"build/core",
"prebuilt",
"toolchains",
]
for check in checks:
check_path = os.path.join(NDK_DIR, check)
if not os.path.exists(check_path):
sys.exit("Missing {}".format(check_path))
def get_triple(arch):
"""Return the triple for the given architecture."""
return {
"arm": "arm-linux-androideabi",
"arm64": "aarch64-linux-android",
"riscv64": "riscv64-linux-android",
"x86": "i686-linux-android",
"x86_64": "x86_64-linux-android",
}[arch]
def arch_to_abi(arch: str) -> str:
"""Return the ABI name for the given architecture."""
return {
"arm": "armeabi-v7a",
"arm64": "arm64-v8a",
"riscv64": "riscv64",
"x86": "x86",
"x86_64": "x86_64",
}[arch]
def get_host_tag_or_die():
"""Return the host tag for this platform. Die if not supported."""
if sys.platform.startswith("linux"):
return "linux-x86_64"
elif sys.platform == "darwin":
return "darwin-x86_64"
elif sys.platform == "win32" or sys.platform == "cygwin":
return "windows-x86_64"
sys.exit("Unsupported platform: " + sys.platform)
def get_toolchain_path_or_die(host_tag):
"""Return the toolchain path or die."""
toolchain_path = os.path.join(NDK_DIR, "toolchains/llvm/prebuilt", host_tag)
if not os.path.exists(toolchain_path):
sys.exit("Could not find toolchain: {}".format(toolchain_path))
return toolchain_path
def make_clang_target(triple, api):
"""Returns the Clang target for the given GNU triple and API combo."""
arch, os_name, env = triple.split("-")
if arch == "arm":
arch = "armv7a" # Target armv7, not armv5.
return "{}-{}-{}{}".format(arch, os_name, env, api)
def make_clang_scripts(install_dir, arch, api, windows):
"""Creates Clang wrapper scripts.
The Clang in standalone toolchains historically was designed to be used as
a drop-in replacement for GCC for better compatibility with existing
projects. Since a large number of projects are not set up for cross
compiling (and those that are expect the GCC style), our Clang should
already know what target it is building for.
Create wrapper scripts that invoke Clang with `-target` and `--sysroot`
preset.
"""
with open(os.path.join(install_dir, "AndroidVersion.txt")) as version_file:
first_line = version_file.read().strip().splitlines()[0]
major, minor, _build = first_line.split(".")
version_number = major + minor
exe = ""
if windows:
exe = ".exe"
bin_dir = os.path.join(install_dir, "bin")
shutil.move(
os.path.join(bin_dir, "clang" + exe),
os.path.join(bin_dir, "clang{}".format(version_number) + exe),
)
shutil.move(
os.path.join(bin_dir, "clang++" + exe),
os.path.join(bin_dir, "clang{}++".format(version_number) + exe),
)
triple = get_triple(arch)
target = make_clang_target(triple, api)
flags = "-target {}".format(target)
# We only need mstackrealign to fix issues on 32-bit x86 pre-24. After 24,
# this consumes an extra register unnecessarily, which can cause issues for
# inline asm.
# https://github.com/android-ndk/ndk/issues/693
if arch == "i686" and api < 24:
flags += " -mstackrealign"
cxx_flags = str(flags)
clang_path = os.path.join(install_dir, "bin/clang")
with open(clang_path, "w") as clang:
clang.write(
textwrap.dedent(
"""\
#!/usr/bin/env bash
bin_dir=`dirname "$0"`
if [ "$1" != "-cc1" ]; then
"$bin_dir/clang{version}" {flags} "$@"
else
# target/triple already spelled out.
"$bin_dir/clang{version}" "$@"
fi
""".format(
version=version_number, flags=flags
)
)
)
mode = os.stat(clang_path).st_mode
os.chmod(clang_path, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
clangpp_path = os.path.join(install_dir, "bin/clang++")
with open(clangpp_path, "w") as clangpp:
clangpp.write(
textwrap.dedent(
"""\
#!/usr/bin/env bash
bin_dir=`dirname "$0"`
if [ "$1" != "-cc1" ]; then
"$bin_dir/clang{version}++" {flags} "$@"
else
# target/triple already spelled out.
"$bin_dir/clang{version}++" "$@"
fi
""".format(
version=version_number, flags=cxx_flags
)
)
)
mode = os.stat(clangpp_path).st_mode
os.chmod(clangpp_path, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
shutil.copy2(
os.path.join(install_dir, "bin/clang"),
os.path.join(install_dir, "bin", triple + "-clang"),
)
shutil.copy2(
os.path.join(install_dir, "bin/clang++"),
os.path.join(install_dir, "bin", triple + "-clang++"),
)
if windows:
for pp_suffix in ("", "++"):
is_cpp = pp_suffix == "++"
exe_name = "clang{}{}.exe".format(version_number, pp_suffix)
clangbat_text = textwrap.dedent(
"""\
@echo off
setlocal
call :find_bin
if "%1" == "-cc1" goto :L
set "_BIN_DIR=" && "%_BIN_DIR%{exe}" {flags} %*
if ERRORLEVEL 1 exit /b 1
goto :done
:L
rem target/triple already spelled out.
set "_BIN_DIR=" && "%_BIN_DIR%{exe}" %*
if ERRORLEVEL 1 exit /b 1
goto :done
:find_bin
rem Accommodate a quoted arg0, e.g.: "clang"
rem https://github.com/android-ndk/ndk/issues/616
set _BIN_DIR=%~dp0
exit /b
:done
""".format(
exe=exe_name, flags=cxx_flags if is_cpp else flags
)
)
for triple_prefix in ("", triple + "-"):
clangbat_path = os.path.join(
install_dir, "bin", "{}clang{}.cmd".format(triple_prefix, pp_suffix)
)
with open(clangbat_path, "w") as clangbat:
clangbat.write(clangbat_text)
def replace_gcc_wrappers(install_path, triple, is_windows):
cmd = ".cmd" if is_windows else ""
gcc = os.path.join(install_path, "bin", triple + "-gcc" + cmd)
clang = os.path.join(install_path, "bin", "clang" + cmd)
shutil.copy2(clang, gcc)
gpp = os.path.join(install_path, "bin", triple + "-g++" + cmd)
clangpp = os.path.join(install_path, "bin", "clang++" + cmd)
shutil.copy2(clangpp, gpp)
def copytree(src, dst):
# A Python invocation running concurrently with make_standalone_toolchain.py
# can create a __pycache__ directory inside the src dir. Avoid copying it,
# because it can be in an inconsistent state.
shutil.copytree(
src, dst, ignore=shutil.ignore_patterns("__pycache__"), dirs_exist_ok=True
)
def create_toolchain(install_path, arch, api, toolchain_path, host_tag):
"""Create a standalone toolchain."""
copytree(toolchain_path, install_path)
triple = get_triple(arch)
make_clang_scripts(install_path, arch, api, host_tag == "windows-x86_64")
replace_gcc_wrappers(install_path, triple, host_tag == "windows-x86_64")
prebuilt_path = os.path.join(NDK_DIR, "prebuilt", host_tag)
copytree(prebuilt_path, install_path)
def warn_unnecessary(arch, api, host_tag):
"""Emits a warning that this script is no longer needed."""
if host_tag == "windows-x86_64":
ndk_var = "%NDK%"
prompt = "C:\\>"
else:
ndk_var = "$NDK"
prompt = "$ "
target = make_clang_target(get_triple(arch), api)
standalone_toolchain = os.path.join(
ndk_var, "build", "tools", "make_standalone_toolchain.py"
)
toolchain_dir = os.path.join(
ndk_var, "toolchains", "llvm", "prebuilt", host_tag, "bin"
)
old_clang = os.path.join("toolchain", "bin", "clang++")
new_clang = os.path.join(toolchain_dir, target + "-clang++")
logger().warning(
textwrap.dedent(
"""\
THIS TOOL IS OBSOLETE. The {toolchain_dir} directory contains
target-specific scripts that perform the same task. For example,
instead of:
{prompt}python {standalone_toolchain} \\
--arch {arch} --api {api} --install-dir toolchain
{prompt}{old_clang} src.cpp
Instead use:
{prompt}{new_clang} src.cpp
See https://developer.android.com/ndk/guides/other_build_systems for more
details.
""".format(
toolchain_dir=toolchain_dir,
prompt=prompt,
standalone_toolchain=standalone_toolchain,
arch=arch,
api=api,
old_clang=old_clang,
new_clang=new_clang,
)
)
)
def get_min_supported_api_level(arch: str) -> int:
abis_json = Path(NDK_DIR) / "meta/abis.json"
with abis_json.open(encoding="utf-8") as abis_file:
data = json.load(abis_file)
return int(data[arch_to_abi(arch)]["min_os_version"])
def parse_args():
"""Parse command line arguments from sys.argv."""
parser = argparse.ArgumentParser(
description=inspect.getdoc(sys.modules[__name__]),
# Even when there are invalid arguments, we want to emit the deprecation
# warning. We usually wait until after argument parsing to emit that warning so
# that we can use the --abi and --api inputs to provide a more complete
# replacement example, so to do that in the case of an argument error we need to
# catch the error rather than allow it to exit immediately.
exit_on_error=False,
)
parser.add_argument(
"--arch", required=True, choices=("arm", "arm64", "riscv64", "x86", "x86_64")
)
parser.add_argument(
"--api", type=int, help='Target the given API version (example: "--api 24").'
)
parser.add_argument(
"--stl", help="Ignored. Retained for compatibility until NDK r19."
)
parser.add_argument(
"--force",
action="store_true",
help="Remove existing installation directory if it exists.",
)
parser.add_argument(
"-v", "--verbose", action="count", help="Increase output verbosity."
)
def path_arg(arg):
return os.path.realpath(os.path.expanduser(arg))
output_group = parser.add_mutually_exclusive_group()
output_group.add_argument(
"--package-dir",
type=path_arg,
default=os.getcwd(),
help=(
"Build a tarball and install it to the given directory. If "
"neither --package-dir nor --install-dir is specified, a "
"tarball will be created and installed to the current "
"directory."
),
)
output_group.add_argument(
"--install-dir",
type=path_arg,
help="Install toolchain to the given directory instead of packaging.",
)
return parser.parse_args()
def main():
"""Program entry point."""
try:
args = parse_args()
except argparse.ArgumentError as ex:
warn_unnecessary("arm64", "21", get_host_tag_or_die())
sys.exit(ex)
if args.verbose is None:
logging.basicConfig(level=logging.WARNING)
elif args.verbose == 1:
logging.basicConfig(level=logging.INFO)
elif args.verbose >= 2:
logging.basicConfig(level=logging.DEBUG)
host_tag = get_host_tag_or_die()
warn_unnecessary(args.arch, args.api, host_tag)
check_ndk_or_die()
min_api = get_min_supported_api_level(args.arch)
api = args.api
if api is None:
logger().warning(
"Defaulting to target API %d (minimum supported target for %s)",
min_api,
args.arch,
)
api = min_api
elif api < min_api:
sys.exit(
"{} is less than minimum platform for {} ({})".format(
api, args.arch, min_api
)
)
triple = get_triple(args.arch)
toolchain_path = get_toolchain_path_or_die(host_tag)
if args.install_dir is not None:
install_path = args.install_dir
if os.path.exists(install_path):
if args.force:
logger().info("Cleaning installation directory %s", install_path)
shutil.rmtree(install_path)
else:
sys.exit("Installation directory already exists. Use --force.")
else:
tempdir = tempfile.mkdtemp()
atexit.register(shutil.rmtree, tempdir)
install_path = os.path.join(tempdir, triple)
create_toolchain(install_path, args.arch, api, toolchain_path, host_tag)
if args.install_dir is None:
if host_tag == "windows-x86_64":
package_format = "zip"
else:
package_format = "bztar"
package_basename = os.path.join(args.package_dir, triple)
shutil.make_archive(
package_basename,
package_format,
root_dir=os.path.dirname(install_path),
base_dir=os.path.basename(install_path),
)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,49 @@
#!/usr/bin/env bash
#
# Copyright (C) 2022 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.
#
HOST_OS=$(uname -s)
case $HOST_OS in
Darwin) HOST_OS=darwin;;
Linux) HOST_OS=linux;;
FreeBsd) HOST_OS=freebsd;;
CYGWIN*|*_NT-*) HOST_OS=cygwin;;
*) echo "ERROR: Unknown host operating system: $HOST_OS"
exit 1
esac
HOST_ARCH=$(uname -m)
case $HOST_ARCH in
arm64) HOST_ARCH=arm64;;
i?86) HOST_ARCH=x86;;
x86_64|amd64) HOST_ARCH=x86_64;;
*) echo "ERROR: Unknown host CPU architecture: $HOST_ARCH"
exit 1
esac
HOST_TAG=$HOST_OS-$HOST_ARCH
if [ $HOST_TAG = darwin-arm64 ]; then
# The NDK ships universal arm64+x86_64 binaries in the darwin-x86_64
# directory.
HOST_TAG=darwin-x86_64
fi
if [ $HOST_OS = cygwin ]; then
ANDROID_NDK_PYTHON=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/windows-x86_64/python3/python.exe
else
ANDROID_NDK_PYTHON=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAG/python3/bin/python3
fi