Android.mk文件编写

news2024/12/24 9:20:28

来源:https://www.jianshu.com/p/9aab51f4cd6f

1. Android.mk 介绍

Android.mk 是Android 提供的一种makefile 文件,注意用来编译生成 exe(二进制可执行文件)、so(动态库文件)、a(静态库文件)、jar(jar包) 和 apk 等文件。Android.mk和一个或多个.c的源文件放在同一目录下做为一个模块,通过mm或者mmm命令来编译该模块,生成自己所需的文件,如:二进制的可执行文件、动态库、静态库、jar包和apk。可参考原生的Android.mk文件进行修改来编写适合自己的Android.mk文件,故需要掌握Android.mk的基本语法。

通过make命令可以编译整个android源码;mm指令编译当前目录(单独模块的编译);mmm指令就是用来编译指定目录(单独模块的编译)。

2. Android.mk 基本语法

2.1 Android.mk 基本语法格式示例:

  • 配置环境变量:定义当前模块的相对路径
    LOCAL_PATH := $(call my-dir)
  • 清空当前环境变量:除 LOCAL_PATH 外的所有环境变量
    include $(CLEAR_VARS)
  • 编译所生成的目标文件的文件名
    LOCAL_MODULE := test
  • 编译该模块所需的源文件:使用连接符“\”连接多个源文件
    LOCAL_SRC_FILES := test.c
  • 编译所生成的目标文件的格式(类型):
    include $(BUILD_EXECUTABLE)

2.2 编译生成的目标文件类型:

  • EXECUTABLES:二进制可执行文件
  • SHARED_LIBRARIES:动态库文件
  • STATIC_LIBRARY:静态库文件
  • JAVA_LIBRARIES:jar包
  • PACKAGE:apk

2.3 Android.mk 中引用资源:

  • 引用系统静态库 —> LOCAL_STATIC_LIBRARIES += libxxx
  • 引用系统动态库 —> LOCAL_SHARED_LIBRARIES += libxxx

如引用系统动态库:LOCAL_SHARED_LIBRARIES += liblog

  • 引用第三方库文件 —> LOCAL_LDFLAGS := -L/PATH -lxxx

如引用第三方动态库:LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3

如引用第三方静态库:LOCAL_LDFLAGS := $(LOCAL_PATH)/lib/libtest2.a

  • 引用第三方头文件 —> LOCAL_C_INCLUDES := path

如:LOCAL_C_INCLUDES = $(INCLUDES)

  • 引入头文件等 —> LOCAL_xxx := xxx
  • 引入jar包等 —> LOCAL_xxx := xxx

如引入共享(动态)jar包:LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava

3 Android.mk管理源码文件(指定编译所需的源码文件)

3.1 编译多个源码文件

问题:一个工程下有多个源码文件,怎么统一管理进行编译?

 

 

工程目录结构.png

 

解答:将工程下的多个源码文件添加到Android.mk的变量LOCAL_SRC_FILES中
(1)方法一: 使用连接符“\”将每个源文件添加到Android.mk中 (2) 方法一: 使用系统提供的函数处理

 

编译多个源码文件的方法.png

 

编译生成目标文件.png

 

3.2 一个Android.mk 文件编译生成多个目标文件

问题:如何在一个Android.mk 文件编译生成多个目标文件?如同时生成多个 bin 文件(二进制可执行文件)、.so 文件(动态库文件)和 .a 文件(静态库文件)。
解答:LOCAL_PATH变量不变,其他变量复制并重新进行配置

一个Android.mk 文件编译生成多个目标文件的方法.png

 

一个Android.mk 文件编译生成多个目标文件.png

4 Android.mk 管理编译所生成的目标文件类型

4.1 编译生成 exe、so 或 a 文件 —> 源文件为 C/C++ 文件

  • 如何编译生成二进制可执行文件exe->修改编译类型为:BULID_EXECUTABLE
  • 如何编译生成动态库文件so->修改编译类型为:BULID_SHARED_LIBRARY
  • 如何编译生成静态库文件a->修改编译类型为:BULID_STATIC_LIBRARY

(1) 指定编译生成的文件类型

指定编译生成的文件类型.png

(2) 编译生成各类目标文件

编译生成各类目标文件.png

4.2 编译生成 jar 包或 apk文件 —> 源文件为 java 文件

(1) 编译生成 jar 包

  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_SRC_FILES := $(call all-subdir-java-files)
  LOCAL_MODULE := com.test.myjar
  include $(BUILD_JAVA_LIBRARY)
  • 静态jar包:include $(BUILD_STATIC_JAVA_LIBRARY)
    使用.class文件打包而成的JAR文件,可以在任何java虚拟机运行
  • 动态jar包:include $(BUILD_JAVA_LIBRARY)
    在静态jar包基础之上使用.dex打包而成的jar文件,.dex是android系统使用的文件格式。

(2) 编译生成 apk
语法:

  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_SRC_FILES := $(call all-subdir-java-files)
  LOCAL_PACKAGE_NAME := LocalPackage
  include $(BUILD_PACKAGE)
  • LOCAL_SRC_FILES := $(call all-subdir-java-files) —> 获取当前目录下所有的java文件作为源文件
  • LOCAL_PACKAGE_NAME := LocalPackage —> 编译生成的目标文件名为LocalPackage
  • include $(BUILD_PACKAGE) —> 编译生成的目标文件类型为apk

:若apk依赖于jar包,即在apk中导入jar包和库文件的语法为

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_JAVA_LIBRARIES := share-library
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := LocalPackage
include $(BUILD_PACKAGE)

  • apk中导入静态jar包 —> LOCAL_STATIC_JAVA_LIBRARIES := static-library
  • apk中导入动态(系统/共享)jar包 —> LOCAL_JAVA_LIBRARIES := share-library
    如:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_SDK_VERSION := current

LOCAL_PACKAGE_NAME := Calculator

include $(BUILD_PACKAGE)

5. Android.mk 引入各种库和头文件

5.1 在工程引入系统库

工程如何引入系统库:将源文件中使用的系统库添加到Android.mk中,即LOCAL_SHARED_LIBRARIES += libxxx。libxxx 代表系统库名称。
(1) 如:新建源文件main.cpp中使用了系统函数 ALOGE("")

#include <stdio.h>
#define LOG_TAG "Main"
#include <utils/Log.h>
int main(void)
{
   ALOGE("test");
   return 0;
}

(2) 将源文件main.cpp添加至Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= test3
LOCAL_C_ALL_FILES := src/main.cpp
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/bin
include $(BUILD_EXECUTABLE)

(3) 直接编译报错:没用将源码中使用的系统库文件引入工程

编译报错.png

 

(4) 修改Android.mk:将源文件main.cpp中使用的系统函数对应的库liblog加入,即添加LOCAL_SHARED_LIBRARIES += liblog

引入系统库文件.png


(5) 重新编译成功

编译成功.png

5.2 在工程引入第三方库

说明1:新建源文件test1.cpp

#include <stdio.h>
void call_test(void)
{
   printf("test1\n");
   return;
}

说明2:Android.mk文件如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= libtest3
LOCAL_C_ALL_FILES := src/test1.cpp
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/lib
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE:= test3
LOCAL_C_ALL_FILES := src/main.cpp
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/bin
include $(BUILD_EXECUTABLE)

备注:test1.cpp编译生成了动态库libtest3.so文件(相当于第三方库文件),main.cpp编译生成了二进制可执行test3文件。

5.2.1 引入第三方动态库

工程如何引入第三方动态库:将源文件中使用的第三方库添加到Android.mk中,即LOCAL_LDFLAGS := -L/Path -lxxx。Path 代表第三方库路径,xxx代表第三方库名称 or 编译生成的目标文件名
(1) 如:工程源文件main.cpp调用了test1.cpp中的函数,通过extern的方式

调用其他文件中的函数.png


(2) 直接编译则会报错:

编译报错.png


(3) 需修改Android.mk:引入第三方库libtest3.so文件,即添加:LOCAL_LDFLAGS := -L ./lib/ -ltest3 或LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3

引入第三方库文件.png


(4) 重新编译成功

编译成功.png

5.2.2 引入第三方头文件

说明1:头文件test1.h 文件如下

#ifndef TEST1 H
#define TEST1 H
extern void call_test(void);
#endif

说明2:Android.mk文件如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= libtest3
LOCAL_C_ALL_FILES := src/test1.cpp
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/lib
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE:= test3
LOCAL_LDFLAGS := -L ./lib/ -ltest3
#LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3
LOCAL_C_ALL_FILES := src/main.cpp
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/bin
include $(BUILD_EXECUTABLE)

工程如何引入第三方头文件:在Android.mk文件中配置头文件路径LOCAL_C_INCLUDES := Path 。Path 代表头文件的路径。
(1) 如:工程源文件main.cpp调用了test1.cpp中的函数,通过头文件的方式

main.cpp.png
(2) 当头文件的路径和main.cpp的路径相差很多时,可通过以下方式来引入头文件

main.cpp.png

配置头文件路径.png

5.2.3 引入第三方静态库

工程如何引入第三方静态库:将源文件中使用的第三方库静态库添加到Android.mk中,即LOCAL_LDFLAGS := Path。Path 代表第三方库静态库的路径。

引入第三方静态库.png 

6. Android.mk 中使用判断语句

语法:

ifeq($(VALUE), x)  
  do_yes
else
  do_no
endif

ifneq($(VALUE), x)  
  do_yes
else
  do_no
endif

如:

静态库与动态库的区别
首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。
什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件。另外一种情况是,对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库,因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间。
上面提到库在使用的时候需要 Link,Link 的方式有两种,静态和动态,于是便产生了静态库和动态库。
静态库
静态库即静态链接库(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做静态,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了。
静态库的好处很明显,编译完成之后,库文件实际上就没有作用了。目标程序没有外部依赖,直接就可以运行。当然其缺点也很明显,就是会使用目标程序的体积增大。
动态库
动态库即动态链接库(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib)。与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来。
动态库的优点是,不需要拷贝到目标程序中,不会影响目标程序的体积,而且同一份库可以被多个程序使用(因为这个原因,动态库也被称作共享库)。同时,编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码。动态库带来的问题主要是,动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境。如果环境缺少动态库或者库的版本不正确,就会导致程序无法运行(Linux 下喜闻乐见的 lib not found 错误)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/194775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PWN入门程序装载与虚拟内存 小白笔记

1.源代码到执行源代码test.c从磁盘中&#xff0c;通过gcc编译成a.out&#xff08;可执行文件&#xff09;。执行的时候&#xff0c;是将磁盘中的可执行文件&#xff08;a.out&#xff09;映像到内存中。2.节视图和段视图节视图&#xff08;磁盘中的可执行文件&#xff09;不同的…

采用消息中间件实现最终一致性的分布式事务

基于可靠消息服务的方案是通过消息中间件保证上下游应用数据操作的一致性。假设有A和B两个系统&#xff0c;分别可以处理任务A和任务B。此时存在一个业务流程&#xff0c;需要将任务A和任务B在同一个事务中处理。就可以使用消息中间件来实现这种分布式事务。 第一步&#xff…

一篇文章带你了解KendoReact DateRangePicker,让日期选择变得更酷炫!

Kendo UI致力于新的开发&#xff0c;来满足不断变化的需求。现在我们非常自豪地宣布&#xff0c;通过React框架的Kendo UI JavaScript封装来支持React Javascript框架。KendoReact能够为客户提供更好的用户体验&#xff0c;并且能够更快地构建更好的应用程序。理想情况下&#…

python中有哪些运算符,python里的运算符号

大家好&#xff0c;给大家分享一下python中有哪些运算符&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 1、Python中的算术运算符有哪些呢&#xff1f; 1. 比较运算符&#xff1a; 如果比较式成立&#xff0c;返回True&#xff1b;不成立…

[Linux系列]linux bond详解

目录 背景 简介 bond分类 1. mode0(balance-rr) 2. mode1 (active-backup) 3. mode2&#xff08;balance-xor&#xff09; 4. mode3&#xff08;broadcast&#xff09; 5. mode4&#xff08;802.3ad&#xff09; 6. mode5&#xff08;balance-tlb&#xff09;…

STL模拟实现——stack、queue和priority_queue(适配器、仿函数、反向迭代器)

适配器 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总 结)&#xff0c;该种模式是将一个类的接口转换成客户希望的另外一个接口。下列的这些stack、queue和priority_queue以及反向迭代器都是适配器。 stack介绍 1. sta…

数据结构-第八期——树状数组-原理区间和

目录 1、树状数组 2、基本应用 2.1、前缀和&#xff1a;不修改&#xff0c;只查询 2.2、树状数组&#xff1a;动态修改&#xff0c;求区间和 3、实现数组树状 3.1、神奇的lowbit (x)操作 3.2、tree[ ]数组 3.3、基于tree[ ]的计算 3.4 sum[]的计算 3.5、tree[]的更新…

CD3药物研发进展-销售数据-上市药品前景分析

CD3作为近几年的双抗热门靶点之一&#xff0c;目前在全球登记的CD3相关药物就有470个&#xff0c;上市的CD3药物有8款&#xff0c;Ⅰ期临床到Ⅲ期临床有116种&#xff0c;临床前及药物发现达200多种&#xff0c;其火热程度可想而知&#xff0c;笔者为方便大家更加清晰了解CD3在…

ESP-IDF:冒泡排序和选择排序测试代码

ESP-IDF:冒泡排序和选择排序测试代码 /冒泡排序/ void printarry16 (int arr[],int length) { for(int i0;i<length;i) { cout<<arr[i]<<" “; } cout<<endl; } void test16() { int arr[] {9, 8, 7, 6, 5, 4, 3, 2, 1, 0,9, 8, 7, 6, 5, 4, 3, 2…

【笔记】容器基础-容器与虚拟机

杂记&#xff1a; 容器技术的兴起源于 PaaS 技术的普及Docker 公司发布的 Docker 项目具有里程碑式的意义Docker 项目通过“容器镜像”&#xff0c;解决了应用打包这个根本性难题容器本身没有价值&#xff0c;有价值的是“容器编排”进程&#xff1a; 静态表现&#xff1a;程序…

Java NIO同步非阻塞编程原理解析及案例

Java NIO同步非阻塞编程原理解析及案例 文章目录Java NIO同步非阻塞编程原理解析及案例NIO介绍NIO和 BIO的比较NIO 三大核心原理示意图缓冲区(Buffer)基本介绍Buffer常用API介绍Buffer 类及其子类缓冲区对象创建缓冲区对象添加数据缓冲区对象读取数据通道(Channel)基本介绍Chan…

生物医药校招这么难,怎么锁定高端人才?

“每年招聘压力大&#xff0c;进校太难。”“各个事业部人才选用要求高&#xff0c;很难达到要求。”“企业、事业单位、高校三方‘围剿’&#xff0c;人才竞争实在太大&#xff01;”……人才招聘内卷&#xff0c;在生物医药行业可以说是体现得淋漓尽致。生物医药岗位及学历要…

【小白课程】以openKylin看图软件为例,浅谈图片编解码库—FreeImage

看图软件是openKylin操作系统上一款开源的图像查看软件&#xff0c;支持对图片进行基本操作,如&#xff1a;缩放、翻转、详情查看、复制、打印、重命名等&#xff0c;同时还可以对图片进行裁剪、存储、标注和ocr&#xff08;文字识别&#xff09;。 图1 看图软件界面 作为图像…

信通院联合偶数科技等企业发布《云原生湖仓一体白皮书》

2023年1月9日&#xff0c;云原生产业联盟在今年年会上重磅发布了《云原生湖仓一体白皮书》。该白皮书由中国信通院牵头&#xff0c;偶数科技、中国人寿、中信建投、中国联通等单位共同编写。 本次白皮书从云原生湖仓的发展历程、技术方案、生态现状、实践案例等方面进行了全面深…

Linux C 捕捉 Ctrl+C 的SIGINT信号

kill -l可以看每个数字对应的信号信号值9和15的区别&#xff1a;kill命令默认是-15&#xff0c;代表的信号为SIGTERM&#xff0c;在结束此进程之前&#xff0c;允许此进程做一些清理工作kill -9会直接杀死目标进程&#xff0c;不给其机会做清理工作按键盘的 CtrlC时&#xff0c…

测试高薪必备

测试人员由于工作原因要经常检查数据库的数据是否正确&#xff0c;这个时候就需要频繁使用多表查询。 在多表查询中&#xff0c;应用最多的就是内连接&#xff0c;其次就是子查询。 为什么子查询是在工作中应用也有这么广泛的应用呢&#xff1f;原因在于子查询非常方便…

macOS下使用vscode+xdebug调试php

手动安装xdebug1、浏览器访问https://xdebug.org/wizard2、在本地终端输入php -i 命令&#xff0c;将输出的内容复制到指南中的输入框中并提交分析3、分析完后会给出分析概览&#xff0c;然后根据下面提示步骤进行手动安装即可第5步中的phpize 命令位置:/usr/local/Cellar/php7…

神经网络基础与原理

7.1 神经网络基础与原理 学习目标 目标 了解感知机结构、作用以及优缺点了解tensorflow playground的使用说明感知机与神经网络的联系说明神经网络的组成说明神经网络的分类原理说明softmax回归说明交叉熵损失应用 无 7.1.1 神经网络 人工神经网络&#xff08; Artificial N…

Oracle数据库卸载安装

卸载oracle步骤&#xff1a;1.首先关掉所有oracle的相关服务&#xff0c;然后找到oracle的卸载程序Universal Installer&#xff1a;2.卸载&#xff0c;删除所有应用然后继续点击卸载产品&#xff0c;然后点击展开全部&#xff0c;将主目录以外的所有应用全部卸载掉&#xff0c…

【C语言】C语言中a<b<c与a<bb<c的区别你注意到了嘛?

问题导入   今天碰到了一个if(a<b<c)逻辑一直成立&#xff0c;无论a,b,c三者的值如何&#xff0c;输出结果一直一样。&#x1f605;&#x1f605;&#x1f605;大家可以看看下图&#xff1a; 逻辑运算测试1 不过讲实话&#xff0c;在实际写代码过成中&#xff0c;小编一…