From 51f7d3ebb2cd80bb2ca2b68272dc6d980567f329 Mon Sep 17 00:00:00 2001 From: Daiva Naudziuniene Date: Tue, 7 Jun 2016 02:44:24 -0700 Subject: [PATCH] Integrating ndk-build with infer Reviewed By: jvillard Differential Revision: D3378660 fbshipit-source-id: 55b3017 --- infer/lib/ndk_capture/infer/config.mk | 2 + infer/lib/ndk_capture/infer/setup.mk | 159 ++++++++++++++++++ infer/lib/python/infer | 3 +- .../lib/python/inferlib/capture/ndk-build.py | 79 +++++++++ 4 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 infer/lib/ndk_capture/infer/config.mk create mode 100644 infer/lib/ndk_capture/infer/setup.mk create mode 100644 infer/lib/python/inferlib/capture/ndk-build.py diff --git a/infer/lib/ndk_capture/infer/config.mk b/infer/lib/ndk_capture/infer/config.mk new file mode 100644 index 000000000..0b11cb63b --- /dev/null +++ b/infer/lib/ndk_capture/infer/config.mk @@ -0,0 +1,2 @@ +TOOLCHAIN_ARCH := arm +TOOLCHAIN_ABIS := armeabi armeabi-v7a armeabi-v7a-hard \ No newline at end of file diff --git a/infer/lib/ndk_capture/infer/setup.mk b/infer/lib/ndk_capture/infer/setup.mk new file mode 100644 index 000000000..fb30af4ad --- /dev/null +++ b/infer/lib/ndk_capture/infer/setup.mk @@ -0,0 +1,159 @@ +# A custom toolchain for infer to intercept calls to clang +# This file is modified toochain/arm-linux-androideabi-clang3.6/setup.mk + + +# 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. +# + +# this file is used to prepare the NDK to build with the arm clang-3.6 +# toolchain any number of source files +# +# its purpose is to define (or re-define) templates used to build +# various sources into target object files, libraries or executables. +# +# Note that this file may end up being parsed several times in future +# revisions of the NDK. +# + +# +# Override the toolchain prefix +# + +TOOLCHAIN_VERSION := 4.8 +TOOLCHAIN_NAME := arm-linux-androideabi-$(TOOLCHAIN_VERSION) +TOOLCHAIN_ROOT := $(NDK_ROOT)/toolchains/$(TOOLCHAIN_NAME) +TOOLCHAIN_PREBUILT_ROOT := $(call host-prebuilt-tag,$(TOOLCHAIN_ROOT)) +TOOLCHAIN_PREFIX := $(TOOLCHAIN_PREBUILT_ROOT)/bin/arm-linux-androideabi- + +# empty path to clang +TARGET_CC := clang$(HOST_EXEEXT) +TARGET_CXX := clang++$(HOST_EXEEXT) + +# +# CFLAGS +# + +TARGET_CFLAGS := \ + -gcc-toolchain $(call host-path,$(TOOLCHAIN_PREBUILT_ROOT)) \ + -fpic \ + -ffunction-sections \ + -funwind-tables \ + -fstack-protector-strong \ + -Wno-invalid-command-line-argument \ + -Wno-unused-command-line-argument \ + -no-canonical-prefixes + +# Disable integrated-as for better compatibility +TARGET_CFLAGS += \ + -fno-integrated-as \ + -flto # to generate .o files in one clang call + + +TARGET_C_INCLUDES := \ + $(SYSROOT_INC)/usr/include + +ifneq ($(filter %armeabi-v7a,$(TARGET_ARCH_ABI)),) + LLVM_TRIPLE := armv7-none-linux-androideabi + + TARGET_CFLAGS += -target $(LLVM_TRIPLE) \ + -march=armv7-a \ + -mfloat-abi=softfp \ + -mfpu=vfpv3-d16 +else +ifneq ($(filter %armeabi-v7a-hard,$(TARGET_ARCH_ABI)),) + LLVM_TRIPLE := armv7-none-linux-androideabi + + TARGET_CFLAGS += -target $(LLVM_TRIPLE) \ + -march=armv7-a \ + -mfpu=vfpv3-d16 \ + -mhard-float \ + -D_NDK_MATH_NO_SOFTFP=1 +else + LLVM_TRIPLE := armv5te-none-linux-androideabi + + TARGET_CFLAGS += -target $(LLVM_TRIPLE) \ + -march=armv5te \ + -mtune=xscale \ + -msoft-float +endif +endif + +TARGET_CFLAGS.neon := -mfpu=neon + +TARGET_arm_release_CFLAGS := -O2 \ + -g \ + -DNDEBUG \ + -fomit-frame-pointer \ + -fstrict-aliasing + +TARGET_thumb_release_CFLAGS := -mthumb \ + -Os \ + -g \ + -DNDEBUG \ + -fomit-frame-pointer \ + -fno-strict-aliasing + +# When building for debug, compile everything as arm. +TARGET_arm_debug_CFLAGS := $(TARGET_arm_release_CFLAGS) \ + -O0 \ + -UNDEBUG \ + -fno-omit-frame-pointer \ + -fno-strict-aliasing + +TARGET_thumb_debug_CFLAGS := $(TARGET_thumb_release_CFLAGS) \ + -O0 \ + -UNDEBUG \ + -marm \ + -fno-omit-frame-pointer + +# 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,$(__arm_sources),$(__debug_sources)),\ + $(TARGET_arm_debug_CFLAGS)) \ +$(call set-src-files-target-cflags,\ + $(call set_intersection,$(__thumb_sources),$(__release_sources)),\ + $(TARGET_thumb_release_CFLAGS)) \ +$(call set-src-files-target-cflags,\ + $(call set_intersection,$(__thumb_sources),$(__debug_sources)),\ + $(TARGET_thumb_debug_CFLAGS)) \ +$(call add-src-files-target-cflags,\ + $(call get-src-files-with-tag,neon),\ + $(TARGET_CFLAGS.neon)) \ +$(call set-src-files-text,$(__arm_sources),arm) \ +$(call set-src-files-text,$(__thumb_sources),thumb) + +# Re-defining default build commands +# Link / install / strip as noop +define cmd-build-shared-library +endef + +define host-install +endef + +define cmd-strip +endef diff --git a/infer/lib/python/infer b/infer/lib/python/infer index a65bebef9..c65a7838e 100755 --- a/infer/lib/python/infer +++ b/infer/lib/python/infer @@ -36,7 +36,8 @@ MODULE_TO_COMMAND = { 'javac': ['javac'], 'make': make.SUPPORTED_COMMANDS, 'xcodebuild': ['xcodebuild'], - 'mvn': ['mvn'] + 'mvn': ['mvn'], + 'ndk-build': ['ndk-build'], } def get_commands(): diff --git a/infer/lib/python/inferlib/capture/ndk-build.py b/infer/lib/python/inferlib/capture/ndk-build.py new file mode 100644 index 000000000..232c1b33d --- /dev/null +++ b/infer/lib/python/inferlib/capture/ndk-build.py @@ -0,0 +1,79 @@ +# Copyright (c) 2016 - present Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. + +import os +import shutil + +import make +import util +from inferlib import config + +MODULE_NAME = 'ndk-build/clang' +MODULE_DESCRIPTION = '''Run analysis of code built with ndk-build + + Analysis examples: + infer -- ndk-build''' + + +def gen_instance(*args): + return NdkBuildCapture(*args) + + +create_argparser = \ + util.clang_frontend_argparser(MODULE_DESCRIPTION, MODULE_NAME) + + +class NdkBuildCapture(make.MakeCapture): + def __init__(self, args, cmd): + make.MakeCapture.__init__(self, args, cmd) + + def get_envvars(self): + env_vars = make.MakeCapture.get_envvars(self) + env_vars['NDK_TOOLCHAIN'] = 'infer' + return env_vars + + def _get_android_ndk_dir(self): + # TODO: other ways to get android_ndk + android_ndk = self.get_envvars()['ANDROID_NDK'] + if not os.path.exists(android_ndk): + raise Exception('Cannot find the location of the Android NDK. ' + 'Please set the ANDROID_NDK environment variable ' + 'to a path containing an installation of the ' + 'Android NDK.') + return android_ndk + + def _setup_infer_toolchain(self): + src_dir = os.path.join(config.LIB_DIRECTORY, 'ndk_capture', 'infer') + android_ndk = self._get_android_ndk_dir() + dest_dir = os.path.join(android_ndk, 'toolchains', 'infer') + if not os.path.exists(dest_dir): + try: + shutil.copytree(src_dir, dest_dir) + except shutil.Error: + raise Exception('An error occurred while setting up infer ' + 'toolchain in Android NDK. Please ensure ' + 'infer has write access to the ' + '$ANDROID_NDK/toolchains directory.') + + def _cleanup_infer_toolchain(self): + android_ndk = self._get_android_ndk_dir() + infer_toolchain = os.path.join(android_ndk, 'toolchains', 'infer') + if os.path.exists(infer_toolchain): + try: + shutil.rmtree(infer_toolchain) + except shutil.Error: + raise Exception('An error occurred while cleaning up infer ' + 'toolchain in Android NDK. Please ensure ' + 'infer has write access to the ' + '$ANDROID_NDK/toolchains directory.') + + def capture(self): + try: + self._setup_infer_toolchain() + return make.MakeCapture.capture(self) + finally: + self._cleanup_infer_toolchain()