模块编译与依赖:模块类型与依赖声明
大家好,我是你们的老朋友。今天我们来聊聊 Android Build 系统里最核心的一个概念——模块编译与依赖。
说实话,我刚接触 Android 源码那会儿,面对一堆 Android.mk 文件,整个人是懵的。什么 BUILD_SHARED_LIBRARY、BUILD_EXECUTABLE,看着像天书。后来踩了不少坑,才慢慢摸清门道。今天我就把这些经验分享给你。
模块类型:你写的代码到底要编成什么?
在 Android 的构建系统里,每个模块都要明确告诉系统:我是什么类型? 这就像你去餐厅点菜,你得说清楚要主食还是甜品,对吧?
常见的模块类型有这么几种:
| 模块类型宏 | 说明 | 典型输出 |
|---|---|---|
| BUILD_SHARED_LIBRARY | 编译成动态库(.so) | libxxx.so |
| BUILD_STATIC_LIBRARY | 编译成静态库(.a) | libxxx.a |
| BUILD_EXECUTABLE | 编译成可执行文件 | xxx(无后缀) |
| BUILD_JAVA_LIBRARY | 编译成 Java 库(.jar) | xxx.jar |
| BUILD_PACKAGE | 编译成 APK 包 | xxx.apk |
嗯,这里要注意:动态库和静态库的区别。动态库是运行时加载的,多个进程可以共享一份代码。静态库则是编译时直接打进可执行文件里。我个人习惯是:如果是公共组件,用动态库;如果是内部工具,用静态库更省心。
实战:写一个最简单的模块
光说不练假把式。我们来看一个实际的 Android.mk 文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello_world
LOCAL_SRC_FILES := hello.c
LOCAL_SHARED_LIBRARIES := libcutils libutils
include $(BUILD_EXECUTABLE)
这段代码什么意思?我拆开给你看:
LOCAL_PATH:当前路径,构建系统用它来找源文件LOCAL_MODULE:模块名字,编译出来的可执行文件就叫 hello_worldLOCAL_SRC_FILES:源文件列表,这里只有一个 hello.cLOCAL_SHARED_LIBRARIES:依赖的动态库include $(BUILD_EXECUTABLE):告诉系统,我要编译成可执行文件
我在项目中遇到过一个问题:有同事把 LOCAL_MODULE 名字写成了 hello-world(带横杠),结果编译出来的文件找不到。后来发现 Android 的模块名不支持横杠,得用下划线。这种小坑,你记住了就能省半天时间。
模块依赖声明:你的代码需要谁?
写代码就像搭积木,很少有模块能独立存在。你写的功能可能要用到别人写的库。这时候就需要声明依赖。
依赖声明有几种方式:
- LOCAL_SHARED_LIBRARIES:声明依赖的动态库
- LOCAL_STATIC_LIBRARIES:声明依赖的静态库
- LOCAL_HEADER_LIBRARIES:声明依赖的头文件库(Android 7.0 之后引入)
举个例子:
LOCAL_MODULE := my_app
LOCAL_SRC_FILES := main.c
LOCAL_SHARED_LIBRARIES := liblog libbinder
LOCAL_STATIC_LIBRARIES := libmystatic
LOCAL_HEADER_LIBRARIES := libmyheaders
你想想看,如果漏掉了某个依赖,编译时就会报 undefined reference 错误。我曾经因为少写了一个 liblog 依赖,排查了整整一个下午。最后发现就是一行代码的事。
依赖的传递性
这里有个概念很重要:依赖的传递性。说白了就是:
- 如果你依赖了一个动态库,这个动态库的依赖不会自动传递给你
- 但如果你依赖了一个静态库,这个静态库的依赖会被带进来
为什么会这样?因为动态库是运行时加载的,它自己会去找它的依赖。而静态库是编译时打进去的,所以它的依赖也得一起打进去。
知识体系总览
为了让你更直观地理解模块编译与依赖的整体结构,我画了一张图:
这张图把今天讲的内容串起来了。左边是模块类型,右边是依赖声明。你写 Android.mk 的时候,这两块就是核心。
核心要点回顾:
- 模块类型决定了输出文件格式(.so、.a、可执行文件、.jar、.apk)
- 依赖声明告诉构建系统你的代码需要哪些库
- 动态库依赖不会自动传递,静态库依赖会传递
- 依赖声明顺序很重要,要按依赖链排列
好了,今天的内容就到这里。模块编译和依赖是 Android 构建系统的基石,搞懂了这些,后面的路就好走了。下次我们聊聊更高级的话题——条件编译和多架构支持。
公众号:蓝海资料掘金营,微信deep3321