android Jni ndk-build 对应makefile执行过程


$(NDK)代表NDK的安装目录。

GNU make 快速参考

ndk-build命令

ndk-build命令执行的是\((NDK)/ndk-build.bat(windows)或者\)(NDK)/ndk-build(*nix)

$(NDK)/ndk-build.bat内容如下 bat @echo off rem This is a Windows cmd.exe script used to invoke the NDK-specific GNU Make executable call "%~dp0find-win-host.cmd" NDK_WIN_HOST if ERRORLEVEL 1 (exit /b 1) set NDK_ROOT=%~dp0 "%NDK_ROOT%prebuilt/%NDK_WIN_HOST%/bin/make.exe" -f "%NDK_ROOT%build/core/build-local.mk" SHELL=cmd %*

  • 第一行 @echo off 不显示后续命令行及当前命令行
  • 第二行 rem注释
  • 第三行 %~dp0表示当前路径,call 调用另一个批处理文件,因此这句表示调用当前路径下find-win-host.cmd批处理命令,该命令最终完成两个功能1. 判断NDK_ROOT 也就ndk的安装路径是否含有空格,空格会报错. 2. NDKWINHOST 根据当前电脑生成对应的值,windows为 windows.
  • 第四行 判断find-win-host.cmd批处理命令是否正确执行了
  • 第五行 执行make命令

最终是执行了make -f build/core/build-local.mk命令,所以整个jni的编译是在标准GNU make上执行的,下面分析执行ndk-build的makefile的执行过程.

makefile文件解析

build-local.mk作为执行入口分块解析代码如下

第一部分

NDK_ROOT := $(dir $(lastword $(MAKEFILE_LIST)))
NDK_ROOT := $(strip $(NDK_ROOT:%build/core/=%))
NDK_ROOT := $(subst \,/,$(NDK_ROOT))
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: You NDK installation path contains spaces.)
    $(info Android NDK: Please re-install to a different location to fix the issue !)
    $(error Aborting.)
endif

这一部分完成了NDK_ROOT变量的赋值. 几个关键点:

  • $(lastword $(MAKEFILE_LIST)) 当前makefile文件的路径
  • makefile中路径的处理,比如目录后是否带/的统一
  • ifneq (\((words \)(NDK_ROOT)),1) 如何判断路径中有空格

第二部分

include $(NDK_ROOT)/build/core/init.mk

禁用GNU make的一些默认规则.

build/core/init.mk

# 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:

在64位机器上是否使用32位编译

# Define NDK_HOST_32BIT=1 in your environment to always use toolchain in 32-bit
# even if 64-bit is present.  Note that toolchains in 64-bit still produce
# 32-bit binaries for Android
#
NDK_HOST_32BIT := $(strip $(NDK_HOST_32BIT))
ifeq ($(NDK_HOST_32BIT),true)
    override NDK_HOST_32BIT := 1
endif

测试makefile版本.

定义一些log的函数

# 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)

HOSTOS HOSTOSBASE(Cygwin)的判断,HOSTOS的可选值

  • windows
  • linux
  • darwin

只有对cygwin HOSTOSBASE有效,在这种情况下

  • HOST_OS == cygwin
  • HOSTOSBASE == windows
#
# Determine host system and architecture from the environment
#
HOST_OS := $(strip $(HOST_OS))

HOSTARCH HOSTARCH64的判断HOSTARCH64只可能是x8664 HOST_ARCH的可选值

  • x86
  • ppc
HOST_ARCH := $(strip $(HOST_ARCH))
HOST_ARCH64 :=
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
# Check for NDK-specific versions of our host tools
HOST_PREBUILT_ROOT := $(call host-prebuilt-tag, $(NDK_ROOT)) # D:\android-ndk-r10c\prebuilt\windows
HOST_PREBUILT := $(strip $(wildcard $(HOST_PREBUILT_ROOT)/bin)) #D:\android-ndk-r10c\prebuilt\windows\bin
HOST_AWK := $(strip $(NDK_HOST_AWK))   #HOST_AWK := $(wildcard $(HOST_PREBUILT)/awk$(HOST_EXEEXT))
HOST_SED  := $(strip $(NDK_HOST_SED))  #HOST_SED  := $(wildcard $(HOST_PREBUILT)/sed$(HOST_EXEEXT))
HOST_MAKE := $(strip $(NDK_HOST_MAKE)) #HOST_MAKE := $(wildcard $(HOST_PREBUILT)/make$(HOST_EXEEXT))
HOST_PYTHON := $(strip $(NDK_HOST_PYTHON)) #HOST_PYTHON := $(wildcard $(HOST_PREBUILT)/python$(HOST_EXEEXT))
HOST_ECHO := $(strip $(NDK_HOST_ECHO)) #HOST_ECHO := $(strip $(wildcard $(HOST_PREBUILT)/echo$(HOST_EXEEXT)))
# The location of the build system files
BUILD_SYSTEM := $(NDK_ROOT)/build/core
# Include common definitions
include $(BUILD_SYSTEM)/definitions.mk
NDK_PLATFORMS_ROOT := $(strip $(NDK_PLATFORMS_ROOT)) #NDK_PLATFORMS_ROOT := $(strip $(wildcard $(NDK_ROOT)/platforms))
# the list of known abis and archs
NDK_KNOWN_DEVICE_ABI64S := arm64-v8a x86_64 mips64
NDK_KNOWN_DEVICE_ABI32S := armeabi-v7a armeabi x86 mips
NDK_KNOWN_DEVICE_ABIS := $(NDK_KNOWN_DEVICE_ABI64S) $(NDK_KNOWN_DEVICE_ABI32S)
NDK_KNOWN_ABIS     := armeabi-v7a-hard $(NDK_KNOWN_DEVICE_ABIS)
NDK_KNOWN_ABI32S   := armeabi-v7a-hard $(NDK_KNOWN_DEVICE_ABI32S)
NDK_KNOWN_ARCHS    := arm x86 mips arm64 x86_64 mips64
_archs := $(sort $(strip $(notdir $(wildcard $(NDK_PLATFORMS_ROOT)/android-*/arch-*))))
NDK_FOUND_ARCHS    := $(_archs:arch-%=%)

Copyright © FengGuangtu 2017