Article Directory
When we use third-party libraries, many of which are provided makefile, we need to understand them and their appropriate modifications, although another google now recommended cmake, but if you meet Android.mk still need to be able to read.
1. What is the Makefile
Whether it is c, c ++ source files should first be compiled into intermediate code file in Windows is .obj files, .o files under UNIX is that Object File, this action is called 编译(compile)
, and then perform a large number of synthetic Object File static or dynamic library files, this action is called 链接(link)
.
A source file project does not count, according to its type, function modules were placed in several directories, makefile defines a set of rules to specify which files need to be compiled, which files need compiled, how links and other operations.
makefile is "automatic compilation", tells how to make command to compile and link that configuration scripts make tools.
By default, gun make command in order to find the file in the current directory
"GNUmakefile”、“makefile”、“Makefile”
Best not to use "GNUmakefile", this document is make recognizes the GNU (Windows Nmake not identify)
Of course, you can also use another file name to write Makefile, such as: "Make.Linux", "Make.android". So when you need to usemake -f XX 或者 make --file XX。
2. Makefile rules
Basic Usage
Command in the Makefile, you must start with [Tab] key.
在Makefile中的命令,必须要以[Tab]键开始。
target : prerequisites ...(预备知识,先决条件)
command(指令)
-----------------------------------------------------------------------------------------
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签。
prerequisites 要生成那个target所需要的文件或是其他target。
command也就是make需要执行的命令。(任意的Shell命令)
The following example
# g++ -o 指定生成可执行文件的名称
# 下面的方法就是将main.o和test.o编译成test可执行程序test
test:main.o test1.o
g++ -o test main.o test1.o
Of course, you can also directly compile cpp
# \ 是换行连接符 便于Makefile的易读,不用都挤在一行
test2:
g++ -o test2 main.cpp \
test1.cpp
clean
clean:
rm test main.o test.o
Print data
print:
echo "hello world"
variable
If more complex cases, such as document number, target goal more, if we modify, such as adding a .cpp file,
It may be necessary in many places to write about, but also prone to error. For ease of maintenance, you can use variables in the makefile.
#声明变量
objects=main.o T1.o
#mac上自动编译 main.o
test:${objects}
g++ -o test ${objects}
clean:
rm test ${objects}
#======================================
# *.c 表示所有后缀为c的文件。
# 让通配符在变量中(当前目录下所有 .c 文件)
objects = $(wildcard *.c)
test : ${objects}
gcc -o test ${objects}
clean :
rm test ${obects}
include
include make.clean
#或者
mk=make.clean
include ${mk}
File Search
In some large projects, a large number of source files stored in different directories, the best way to tell is to make a path, let go to make automatic.
Makefile file the special variable VPATH
is to complete this function
#默认先查找当前目录再查找当前目录下的a、b、c目录
VPATH = a:b:c
OBJ=a.o b.o c.o main.o
test : $(OBJ)
gcc -o test $(OBJ)
clean :
rm test $(OBJ)
Predefined variables
Command variable | meaning |
---|---|
WITH | Library packaged program, the default is "ar" |
AS | Assembly language compiler, the default is "as" |
CC | C language compiler, the default command is "cc" |
CXX | C ++ language compiler, the default command is "g ++" |
RM | Delete the file name of the program, the default value rm -f |
ARFLAGS | Library file maintenance options for the program, with no default |
ASFLAGS | Options assembly program, with no default |
CFLAGS | C compiler options, with no default |
CPPFLAGS | C pre-compiler option, no default |
CXXFLAGS | C ++ compiler options, with no default |
Automatic variables
$@
target的名字
main.o:main.c
gcc -c main.c -o main.o
#使用 $@ 代替 main.o
main.o:main.c
gcc -c main.c -o $@
$<
target依赖的第一个依赖文件名
main.o:main.c a.h b.h
gcc -c main.c -o main.o
#使用 $< 代替 main.c
main.o:main.c a.h b.h
gcc -c $< -o main.o
variable | Explanation |
---|---|
$* | target file name does not include an extension of |
$+ | All dependent files, separated by spaces, and to have appeared for the order, dependent files may contain duplicate |
$? | All timestamps later than the target file dependency files, and separated by spaces |
$^ | All non-repetition of the dependent files, separated by spaces |
Conditional statements
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
Output
AAA=123456
#输出变量AAA
$(warning $(AAA))
$(info $(AAA))
3. Android.mk
GNU makefile tiny fragments.
Source files grouped into modules . Module is a static library, shared library or stand-alone executable file. May each Android.mk
define one or more modules files may also be used with a plurality of modules in a source file.
#源文件在的位置。宏函数 my-dir 返回当前目录
LOCAL_PATH := $(call my-dir)
#可为您清除变量
#不会清理 LOCAL_PATH 变量
include $(CLEAR_VARS)
#存储您要构建的模块的名称 每个模块名称必须唯一,且不含任何空格
#如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。
LOCAL_MODULE := hello-jni
#包含要构建到模块中的 C 和/或 C++ 源文件列表 以空格分开
LOCAL_SRC_FILES := hello-jni.c
#构建动态库
include $(BUILD_SHARED_LIBRARY)
Variables and macros
Define your own arbitrary variables. Please note that the definition of variables, NDK build system will reserve the following variable names:
- With
LOCAL_
names that begin, for exampleLOCAL_MODULE
. - To
PRIVATE_
,NDK_
orAPP
names that begin with. The system uses these variables to build internally. - Lowercase names, for example
my-dir
. Construction of the system is the use of these variables internally.
If you needed in order to facilitate Android.mk
the definition of their variable documents, additional recommendations before the name MY_
.
Common built-in variables
variable name | meaning | Examples |
---|---|---|
BUILD_STATIC_LIBRARY | Makefile script to build the static library | include $(BUILD_STATIC_LIBRARY) |
PREBUILT_SHARED_LIBRARY | Precompiled script Makeifle shared libraries | include $(PREBUILT_SHARED_LIBRARY) |
PREBUILT_STATIC_LIBRARY | Static library of pre-compiled script Makeifle | include $(PREBUILT_STATIC_LIBRARY) |
TARGET_PLATFORM | Android API level number | TARGET_PLATFORM := android-22 |
TARGET_ARCH | CUP architecture | arm arm64 x86 x86_64 |
TARGET_ARCH_ABI | CPU architecture | armeabi armeabi-v7a arm64-v8a |
Module Description variables
variable name | description | Case |
---|---|---|
LOCAL_MODULE_FILENAME | Construction covering system which generates a default name for the file | LOCAL_MODULE := foo LOCAL_MODULE_FILENAME := libnewfoo |
LOCAL_CPP_FEATURES | C ++ specific features | Support exception: LOCAL_CPP_FEATURES: = exceptions |
LOCAL_C_INCLUDES | Header files directory search path | LOCAL_C_INCLUDES := $(LOCAL_PATH)/include |
LOCAL_CFLAGS | C building and build parameters of C ++ | |
LOCAL_CPPFLAGS | c++ | |
LOCAL_STATIC_LIBRARIES | The current module depends static library modules list | |
LOCAL_SHARED_LIBRARIES | ||
LOCAL_WHOLE_STATIC_LIBRARIES | –whole-archive | 将未使用的函数符号也加入编译进入这个模块 |
LOCAL_LDLIBS | 依赖 系统库 | LOCAL_LDLIBS := -lz |
导出给引入模块的模块使用
LOCAL_EXPORT_CFLAGS
LOCAL_EXPORT_CPPFLAGS
LOCAL_EXPORT_C_INCLUDES
LOCAL_EXPORT_LDLIBS
引入其他模块
#将一个新的路径加入NDK_MODULE_PATH变量
#NDK_MODULE_PATH 变量是系统环境变量
$(call import-add-path,$(LOCAL_PATH)/platform/third_party/android/prebuilt)
#包含CocosDenshion/android目录下的mk文件
$(call import-module,CocosDenshion/android)
#这里即为 我需要引入 CocosDenshion/android 下面的Android.mk
#CocosDenshion/android 的路径会从 $(LOCAL_PATH)/platform/third_party/android/prebuilt 去查找
4. Application.mk
配置
同样是GNU Makefile 片段,在Application.mk中定义一些全局(整个项目)的配置
APP_OPTIM
将此可选变量定义为 release
或 debug
。在构建应用的模块时可使用它来更改优化级别。发行模式是默认模式,可生成高度优化的二进制文件。调试模式会生成未优化的二进制文件,更容易调试。
APP_CFLAGS
为任何模块编译任何 C 或 C++ 源代码时传递到编译器的一组 C 编译器标志
APP_CPPFLAGS
构建 C++ 源文件时传递到编译器的一组 C++ 编译器标志。
APP_ABI
需要生成的cpu架构(ndk r17之上 只支持:armeabi-v7a, arm64-v8a, x86, x86_64)
APP_PLATFORM
此变量包含目标 Android 平台的名称。例如,android-3
指定 Android 1.5 系统映像
APP_STL
默认情况下,NDK 构建系统为 Android 系统提供的最小 C++ 运行时库 (system/lib/libstdc++.so
) 提供 C++ 功能。
APP_ABI架构
不同 Android 手机使用不同的 CPU,因此支持不同的指令集。
armeabi
此 ABI 适用于基于 ARM、至少支持 ARMv5TE 指令集的 CPU。此 ABI 不支持硬件辅助的浮点计算。 相反,所有浮点运算都使用编译器 libgcc.a
静态库中的软件帮助程序函数。
armeabi-v7a
armeabi-v7a
ABI 使用 -mfloat-abi=softfp
开关强制实施规则,要求编译器在函数调用时必须传递核心寄存器对中的所有双精度值,而不是专用浮点值。 系统可以使用 FP 寄存器执行所有内部计算。 这样可极大地加速计算。
如果要以 armeabi-v7a ABI 为目标,则必须设置下列标志:
CFLAGS= -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
arm64-v8a
此 ABI 适用于基于 ARMv8、支持 AArch64 的 CPU。它还包含 NEON 和 VFPv4 指令集。
x86
此 ABI 适用于支持通常称为“x86”或“IA-32”的指令集的 CPU。设置的标志如:
-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32
x86_64
-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel
现在手机主要是armeabi-v7a。查看手机cpu:
adb shell cat /proc/cpuinfo
adb shell getprop ro.product.cpu.abi
apk在安装的时候,如果手机是armeabi-v7a的,则会首先查看apk中是否存在armeabi-v7a目录,如果没有就会查找armeabi。
保证cpu目录下so数量一致。
如果目标是armeabi-v7a,但是拥有一个armeabi的,也可以把它放到armeabi-v7a目录下。但是反过来不行
ABI(横 so)/CPU(竖 手机) | armeabi | armeabi-v7a | arm64-v8a | x86 | x86_64 |
---|---|---|---|---|---|
ARMV5 | 支持 | ||||
ARMV7 | 支持 | 支持 | |||
ARMV8 | 支持 | 支持 | 支持 | ||
X86 | 支持 | ||||
X86_64 | 支持 | 支持 |