This page introduces the syntax of the Android.mk compiled file used by ndk-build.
Overview
Android.mk The file is located in a subdirectory of the project’s jni/ directory, and is used to describe source files and shared libraries to the build system. It is actually a tiny GNU makefile fragment that the build system parses one or more times. The Android.mk file is used to define the project scope settings that are not defined by Application.mk, the compilation system, and environment variables. It can also replace the project scope setting of a specific module.
The syntax of Android.mk supports grouping source files into modules. Modules are static libraries, shared libraries, or stand-alone executable files. You can define one or more modules in each Android.mk file, or you can use the same source file in multiple modules. The build system only puts the shared library into your application package. In addition, static libraries can generate shared libraries.
In addition to the package library, the compilation system can also handle various other things for you. For example, you do not need to list explicit dependencies between header files or generated files in the Android.mk file. The NDK compilation system automatically calculates these relationships. Therefore, you should be able to enjoy the benefits of new toolchain/platform support in future NDK versions without having to process the Android.mk file.
The syntax of this file is very similar to the syntax used in the Android.mk file distributed with the entire Android open source project. Although the implementation of the compilation system using these grammars is not the same, by deliberately designing the grammars to be similar, application developers can more easily reuse source code for external libraries.
Basic knowledge
Before learning the syntax in detail, it is best to understand the basic information of the content contained in the Android.mk file. To this end, this section uses the Android.mk file in the Hello-JNI example to explain the role of each line in the file.
Android.mk The file must first define LOCAL_PATH Variables:
LOCAL_PATH := $(call my -dir)
This variable represents the location of the source file in the development tree. In this line of code, the macro function my-dir provided by the compilation system will return the path of the current directory (Android.mk where the file itself is located).
The next line declares the CLEAR_VARS variable, the value of which is provided by the compilation system.
include $(CLEAR_VARS )
CLEAR_VARS The variable points to a special GNU Makefile, which will clear many LOCAL_XXX variables, such as LOCAL_MODULE, LOCAL_SRC_FILES and LOCAL_STATIC_LIBRARIES. Please note that GNU Makefile will not clear LOCAL_PATH. This variable must retain its value, because the system parses all compilation control files in a single GNU Make execution environment (all variables in which are global variables). Before describing each module, this variable must be declared (redeclared).
Next, the LOCAL_MODULE variable stores the name of the module you want to compile. Please use this variable once in each module of your application.
LOCAL_MODULE := hello -jni
Each module name must be unique without any spaces. When the compilation system generates the final shared library file, it will automatically add the correct prefix and suffix to the name you assigned to LOCAL_MODULE. For example, the above example will generate a library named libhello-jni.so.
Note: If the module name already starts with lib, the compilation system will not append an additional lib prefix; Instead, the module name is used as is, and the extension .so is added. Therefore, for example, the original source file named libfoo.c will still generate a shared object file named libfoo.so. This behavior is to support the libraries generated by the Android platform source files based on the Android.mk file; the names of all these libraries begin with lib.
The next line will list the source files, separating multiple files with spaces:
LOCAL_SRC_FILES := hello-jni.c< br>
div>
LOCAL_SRC_FILES The variable must contain a list of C and/or C++ source files to be compiled into the module.
The last line of the help system connects everything together:
include $ (BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY The variable points to a GNU Makefile script, which will collect your most recent include all the information defined in the LOCAL_XXX variable. This script determines what to compile and how to compile.
There are more complex examples in the example directory, including the annotated Android.mk file for your reference. In addition, example: native-activity details the Android.mk file of this example. Finally, variables and macros provide more information about the variables in this section.
Variables and macros
The compilation system provides many variables that can be used in the Android.mk file. Many of these variables are pre-assigned. Other variables are assigned by you.
In addition to these variables, you can also define any variables yourself. When defining variables, please note that the NDK compilation system reserves the following variable names:
Names beginning with LOCAL_, such as LOCAL_MODULE.
Names beginning with PRIVATE_, NDK_ or APP. The compilation system uses these variable names internally.
Lower case name, such as my-dir. The compilation system also uses these variable names internally.
If you need to define your own variables in the Android.mk file for convenience, it is recommended to add MY_ before the name.
NDK-defined include variables
This section discusses the GNU Make variables defined by the compilation system before parsing the Android.mk file. In some cases, the NDK may parse the Android.mk file multiple times, each time using different definitions of some of the variables.
CLEAR_VARS
The compiled script pointed to by this variable is used to undefine almost all LOCAL_XXX variables listed in the “Variables Defined by Developers” section below. Before describing the new module, use this variable to include this script. The syntax for using it is:
include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY
The compilation script pointed to by this variable is used to collect all the relevant information of the module you provided in the LOCAL_XXX variable, and to determine how to compile the target based on the source file you listed Shared library. Please note that using this script requires that you have at least assigned values for LOCAL_MODULE and LOCAL_SRC_FILES (for details about these variables, please refer to the module description variables).
The syntax for using this variable is:
include $(BUILD_SHARED_LIBRARY)
Shared library variables will cause the compilation system to generate library files with the extension .so.
BUILD_STATIC_LIBRARY
The variant of BUILD_SHARED_LIBRARY used to compile static libraries. The build system will not copy static libraries into your project/package, but you can use static libraries to compile shared libraries (see LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES below). The syntax for using this variable is:
include $(BUILD_STATIC_LIBRARY< span class="pun">)
Static library variables will cause the compilation system to generate a library with the extension .a.
PREBUILT_SHARED_LIBRARY
Point to the compilation script used to specify the pre-compiled shared library. Unlike the cases of BUILD_SHARED_LIBRARY and BUILD_STATIC_LIBRARY, the value of LOCAL_SRC_FILES here cannot be a source file, but must be a path to a precompiled shared library. For example, foo/libfoo.so. The syntax for using this variable is:
include $(PREBUILT_SHARED_LIBRARY< span class="pun">)
You can also use the LOCAL_PREBUILTS variable to refer to a pre-compiled library in another module. To learn more about how to use precompiled libraries, see Using precompiled libraries.
PREBUILT_STATIC_LIBRARY
Same as PREBUILT_SHARED_LIBRARY, but used to precompile static libraries. To learn more about how to use precompiled libraries, see Using precompiled libraries.
Target information variable h3>
The compilation system will parse each ABI specified by the APP_ABI variable once Android.mk. The variable is usually in the Defined in the >Application.mk file. If APP_ABI is all, the compilation system will parse Android.mk once according to each ABI supported by the NDK. This section introduces the variables defined every time the compilation system parses Android.mk.
TARGET_ARCH
The CPU series for which the compilation system parses this Android.mk file. This variable is one of arm, arm64, x86 or x86_64.
TARGET_PLATFORM
The Android API level number for which the compilation system parses this Android.mk file. For example, the Android 5.1 system image corresponds to Android API level 22: android-22. For a complete list of platform names and corresponding Android system images, please refer to Android NDK Native API. The following example demonstrates the syntax for using this variable:
ifeq ( $(TARGET_PLATFORM),android-22) # ... do something ... endif span>
TARGET_ARCH_ABI
The compilation system parses this Android.mk code> The ABI for the file. Table 1 shows the ABI settings for each supported CPU and architecture.
Table 1. ABI settings for different CPUs and architectures.
CPU and architecture
Settings
ARMv7
armeabi-v7a
ARMv8 AArch64
arm64-v8a
i686
x86
< tr>
x86-64
x86_64
The following example demonstrates How to check whether ARMv8 AArch64 is a combination of target CPU and ABI:
ifeq ($(TARGET_ARCH_ABI),arm64- v8a) # ... do something ... endif
To learn more about the architecture ABI and related compatibility issues, please refer to ABI Management.
The new target ABI in the future will use a different value.
TARGET_ABI
The connection between the target Android API level and the ABI is especially suitable for situations where a specific target system image needs to be tested against actual devices. For example, to check 64-bit ARM devices with Android API level 22:
ifeq ($(TARGET_ABI),android-22-arm64-v8a) # ... do something ... endif /span>
module Descriptive variables
This The variables in the section describe your module to the build system. Each module description should follow the following basic process:
Use CLEAR_VARS to initialize or undefine variables related to the module.
Assign values to variables used to describe the module.
Use BUILD_XXX variables to set the NDK compilation system to use the appropriate compilation script for the module.
LOCAL_PATH
This variable is used to specify the path of the current file. This variable must be defined at the beginning of the Android.mk file. The following example demonstrates how to define this variable:
LOCAL_PATH := $(call my-dir) span>
CLEAR_VARS The pointed script will not clear this variable. Therefore, even if the Android.mk file describes multiple modules, you only need to define it once.
LOCAL_MODULE
This variable is used to store the module name. The specified name must be unique and must not contain any spaces. This variable must be defined before any scripts (except the scripts of CLEAR_VARS) are included. There is no need to add the lib prefix or the .so or .a file extension; the compilation system will automatically make these changes. In the entire Android.mk and Application.mk files, please refer to the module by its unmodified name. For example, the following line will cause a shared library module named libfoo.so to be generated:
LOCAL_MODULE :="foo" < /span>
If you want the generated module to use "lib + < For names other than the value of code>LOCAL_MODULE, you can use the LOCAL_MODULE_FILENAME variable to specify the name of your choice for the generated module.
LOCAL_MODULE_FILENAME
This optional variable allows you to replace the default name used by the compilation system for the files it generates. For example, if the name of LOCAL_MODULE is foo, you can force the system to name the file it generates as libnewfoo. The following example demonstrates how to accomplish this:
For shared library modules, this example will generate a file named libnewfoo.so.
Note: You cannot substitute file paths or file extensions.
LOCAL_SRC_FILES
This variable contains a list of source files used by the compilation system to generate the module. Only the files actually passed by the compilation system to the compiler are listed, because the compilation system automatically calculates all related dependencies. Please note that you can use relative (relative to LOCAL_PATH) and absolute file paths.
It is recommended to avoid using absolute file paths; relative paths can improve the portability of Android.mk files.
Note: Be sure to use Unix-style forward slashes (/) in the compiled file. The compilation system cannot handle Windows-style backslashes (\) correctly.
LOCAL_CPP_EXTENSION
You can use this optional variable to specify a file extension other than .cpp for the C++ source file. For example, the following line changes the extension to .cxx. (The setting must contain dots.)
LOCAL_CPP_EXTENSION :=.cxx
You can use this variable to specify multiple extensions. For example:
LOCAL_CPP_EXTENSION :=.cxx .cpp .cc
LOCAL_CPP_FEATURES
You can use this optional variable to indicate that your code depends on specific C++ features. It will enable the correct compiler flags and linker flags during the compilation process. For pre-compiled binary files, this variable also declares which functions the binary file depends on to ensure that the final link runs normally. It is recommended that you use this variable instead of directly enabling -frtti and -fexceptions in the definition of LOCAL_CPPFLAGS.
Using this variable allows the compilation system to use the appropriate tags for each module. Using LOCAL_CPPFLAGS will cause the compiler to use all specified tags for all modules, regardless of actual requirements.
For example, to indicate that your code uses RTTI (Runtime Type Information), enter:
LOCAL_CPP_FEATURES < span class="pun">:= rtti
To indicate that your code uses C++ exceptions, please enter:
LOCAL_CPP_FEATURES := exceptions
< p>You can also specify multiple values for this variable. For example:
LOCAL_CPP_FEATURES := rtti features span>
The order in which the values are described does not matter.
LOCAL_C_INCLUDES
You can use this optional variable to specify a path list relative to the NDK root directory, so that it can be added to the include search path when compiling all source files (C, C++, and Assembly). For example:
Please set any corresponding Define this variable before including the tag.
When using ndk-gdb to start native debugging, the compilation system will also automatically use the LOCAL_C_INCLUDES path.
LOCAL_CFLAGS
This optional variable is used to set the compiler flags to be passed by the compilation system when compiling C and C++ source files. In this way, you can specify additional macro definitions or compilation options. You can use LOCAL_CPPFLAGS to specify tags only for C++.
Don’t try to change the optimization/debugging level in the Android.mk file. The compilation system can use the relevant information in the [pplication.mk] file to automatically handle this setting. In this way, the compilation system can generate useful data files for use during debugging.
You can specify additional include paths by entering the following code:
LOCAL_CFLAGS +=-I,
However, it is better to use LOCAL_C_INCLUDES, because this can also use the path that can be used for ndk-gdb native debugging.
LOCAL_CPPFLAGS
A set of optional compiler flags that will be passed when compiling only C++ source files. They will appear after LOCAL_CFLAGS in the compiler command line. Use LOCAL_CFLAGS to specify tags for C and C++.
LOCAL_STATIC_LIBRARIES
This variable is used to store the list of static library modules that the current module depends on.
If the current module is a shared library or executable file, this variable will force these libraries to be linked to the generated binary file.
If the current module is a static library, this variable just indicates that other modules that depend on the current module will also depend on the listed libraries.
LOCAL_SHARED_LIBRARIES
This variable will list the shared library modules that this module depends on at runtime. This information is necessary for linking and is used to embed the corresponding information in the generated file.
LOCAL_WHOLE_STATIC_LIBRARIES
This variable is a variant of LOCAL_STATIC_LIBRARIES, which means that the linker should treat the related library module as a complete archive. To learn more about the complete archive, please refer to the --whole-archive tag section of the GNU ld documentation.
This variable is useful when there are circular dependencies between multiple static libraries. When using this variable to compile a shared library, it will force the compilation system to add all object files in the static library to the final binary file. However, this does not happen when generating executable files.
LOCAL_LDLIBS
This variable lists additional linker tags used when compiling shared libraries or executable files. With this variable, you can use the -l prefix to pass the name of a specific system library. For example, the following example instructs the linker to generate a module that links to /system/lib/libz.so at load time:
LOCAL_LDLIBS :=-lz
If you need to understand the public systems that can be linked in this NDK version For the list of libraries, please refer to Android NDK Native API.
Note: If you define this variable for a static library, the compilation system will ignore this variable, and ndk-build will display a warning.
LOCAL_LDFLAGS
This variable lists other linker tags used by the build system when compiling shared libraries or executable files. For example, to use the ld.bfd linker on ARM/X86:
Note: If this variable is defined for a static library, the compilation system This variable will be ignored, and ndk-build will display a warning.
LOCAL_ALLOW_UNDEFINED_SYMBOLS
By default, if the compilation system encounters an undefined reference when trying to compile a shared library, it will throw an “undefined symbol” error. This error can help you catch errors in the source code.
To disable this check, set this variable to true. Please note that this setting may cause shared libraries to be loaded at runtime.
Note: If you define this variable for a static library, the build system will ignore this variable, and ndk-build will display a warning.
LOCAL_ARM_MODE
By default, the compilation system will generate an ARM target binary file in thumb mode, where each instruction is 16 bits wide and is associated with the STL library in the thumb/ directory. Defining this variable as arm will force the compilation system to generate the object file of the module in 32-bit arm mode. The following example demonstrates how to do this:
LOCAL_ARM_MODE := arm
You can also append the source file name< The code>.arm suffix indicates that the compilation system only compiles specific source files in arm mode. For example, the following example instructs the compilation system to always compile bar.c in ARM mode, but compile foo.c according to the value of LOCAL_ARM_MODE.
LOCAL_SRC_FILES := foo.c bar.c.arm
注意:您也可以在 Application.mk 文件中将 APP_OPTIM 设置为 debug,以强制编译系统生成 ARM 二进制文件。指定 debug会强制执行 ARM 编译,因为工具链调试程序无法正确处理 Thumb 代码。
LOCAL_ARM_NEON
此变量仅在以 armeabi-v7a ABI 为目标时才有意义。它允许在 C 和 C++ 源代码中使用 ARM Advanced SIMD (NEON) 编译器内建函数,以及在 Assembly 文件中使用 NEON 指令。
include $(CLEAR_VARS) LOCAL_MODULE := foo LOCAL_SRC_FILES := foo/foo.c LOCAL_EXPORT_CFLAGS :=-DFOO=1 include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS) LOCAL_MODULE := bar LOCAL_SRC_FILES := bar.c LOCAL_CFLAGS :=-DBAR=2 LOCAL_STATIC_LIBRARIES := foo include $(BUILD_SHARED_LIBRARY)