Android 编译脚本 mk & bp

IT疑难杂症诊疗室 10w+人浏览 847人参与

Android 编译脚本

平常写在android 里面的业务代码,java 还是c++ 都需要靠android 编译脚本来进行编译;在android 的高版本,13,14,谷歌其实是比较推荐我们使用bp 文件来进行编译,但是旧版本的业务还是存在的,所以需要两者都掌握。

Android.mk 基本概念和结构

Android.mk 文件是 Android 构建系统中定义编译规则的配置文件,主要用于描述哪些源文件需要编译,以及如何编译它们。
常见的 Android.mk 文件结构:
在这里插入图片描述

  • LOCAL_PATH:表示当前模块的路径,通常使用 $(call my-dir)。
  • include $(CLEAR_VARS):清除之前定义的所有 LOCAL_ 变量,确保不会影响当前模块。
  • LOCAL_MODULE:定义模块名称。
  • LOCAL_SRC_FILES:定义模块的源文件。
  • include $(BUILD_SHARED_LIBRARY):表示编译为动态库(共享库)。

常用变量

  • LOCAL_MODULE:定义模块的名称,即生成的目标文件名(例如 .so 文件或可执行文件)。
  • LOCAL_SRC_FILES:指定模块的源代码文件列表,支持 .c、.cpp、.java 等文件。
  • LOCAL_C_INCLUDES:指定 C/C++ 头文件路径(包括目录)。
  • LOCAL_LDLIBS:指定链接时使用的库(例如 -llog 表示链接 liblog.so)。
  • LOCAL_STATIC_LIBRARIES:指定静态链接的库。

编译可执行文件
Android.mk 中除了编译库文件外,还可以编译可执行文件。使用 include $(BUILD_EXECUTABLE) 而不是 BUILD_SHARED_LIBRARY。
在这里插入图片描述
静态库和动态库
静态库使用 include $(BUILD_STATIC_LIBRARY),动态库使用 include $(BUILD_SHARED_LIBRARY)。
示例编译静态库:
在这里插入图片描述
模块间依赖
模块间的依赖关系可以通过 LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 实现。例如,一个模块可以依赖另一个库:
在这里插入图片描述
常见的编译目标

  • include $(BUILD_SHARED_LIBRARY):编译为共享库(.so)。
  • include $(BUILD_STATIC_LIBRARY):编译为静态库(.a)。
  • include $(BUILD_EXECUTABLE):编译为可执行文件。

编译预处理
可以通过 LOCAL_CFLAGS 和 LOCAL_CPPFLAGS 添加编译时的预处理宏、优化选项或警告级别等。例如:
LOCAL_CFLAGS := -Wall -O2
LOCAL_CPPFLAGS := -DDEBUG=1

多文件编译
在 LOCAL_SRC_FILES 中可以指定多个源文件,分行书写或者以空格隔开:
LOCAL_SRC_FILES := file1.c file2.c file3.c

子目录中的 Android.mk
如果你的项目有多个子目录,可以在顶级 Android.mk 文件中使用 $(call all-subdir-makefiles) 来包含子目录中的 Android.mk:
include $(call all-subdir-makefiles)

Android.mk 实战

目录结构:
在这里插入图片描述

在这里插入图片描述

  1. 生成 C++ 静态库
    static_lib/hello_static.cpp
#include <iostream>

void print_static_hello(){

        std::cout << "Hello from static library!" << std::endl;
}

static_lib/Android.mk

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

LOCAL_MODULE := libhello_static #定义静态库名称
LOCAL_SRC_FILES := hello_static.cpp #指定源文件

include $(BUILD_STATIC_LIBRARY) #编译目标为静态库
  1. 生成 C++ 动态库
    shared_lib/hello_shared.cpp
#include <iostream>

void print_shared_hello(){
    std::cout << "Hello from shared library!" << std::endl;

}
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libhello_shared
LOCAL_SRC_FILES := hello_shared.cpp
include $(BUILD_SHARED_LIBRARY)
  1. 生成可执行文件并依赖静态库和动态库
    executable/main.cpp

#include <iostream>

extern void print_static_hello();
extern void print_shared_hello();

int main(){
        print_static_hello();
        print_shared_hello();

        return 0;

}

executable/Android.mk


LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello_executable
LOCAL_SRC_FILES := main.cpp

LOCAL_STATIC_LIBRARIES := libhello_static
LOCAL_SHARED_LIBRARIES := libhello_shared


include $(BUILD_EXECUTABLE)

编译:

mmm external/project/static_lib
mmm external/project/shared_lib 
mmm external/project/executable 

在这里插入图片描述
在这里插入图片描述

调试运行

adb push out/target/product/xxx/system/bin/hello_executable  /system/bin/
adb push out/target/product/xxx/system/lib64/libhello_shared.so  /system/lib64/
adb shell 
cd system/bin/
chmod +x hello_executable  
./hello_executable  
  1. emulator -verbose -writable-system 启动虚拟机
    writable-system 表示 system 分区可写
    在这里插入图片描述

adb root
adb remount
在这里插入图片描述
3. 把编译出来的可执行程序放到android 虚拟机上验证
adb push hello_executable /system/bin
adb push hello_executable /system/bin
adb shell

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ok,程序执行成功

注意点是,不需要把静态库push 到android 设备,因为静态库会在编译的时候合并到源码里面;但是动态库是运行时链接的

静态库 vs 动态库的主要区别

  1. 静态库(Static Library)
编译时合并:静态库的代码被完整地复制到最终的可执行文件中

独立性:生成的可执行文件独立,运行时不需要外部库文件

体积大:多个程序使用同一库时,每个程序都包含该库的完整副本

更新麻烦:库更新需要重新编译所有依赖它的程序
  1. 动态库 (Dynamic Library / Shared Library)
运行时链接:程序运行时才从系统中加载所需的库

共享性:多个程序可以共享同一个动态库实例

体积小:可执行文件体积小,只包含引用信息

更新方便:更新库文件,所有程序自动使用新版本

依赖环境:运行时需要确保系统中存在正确的库版本

Android.bp

  1. 什么是 Android.bp 文件?
    Android.bp 文件是 Android 构建系统的一部分,用于定义模块的构建逻辑。它采用 JSON 类似的语法,简单、结构化,可读性更强。构建系统会根据这些规则生成需要的目标文件。

主要功能:

  • 定义模块类型(例如应用程序、库、工具等)。
  • 描述模块依赖关系。
  • 指定源文件、标志和输出路径。
  1. Android.bp 文件的语法基础
    2.1. 基本结构
模块类型 {
    属性名1: "值1",
    属性名2: ["值2", "值3"],
}

2.2. 常见数据类型

  • 字符串: 用于表示路径或模块名称,使用双引号。
name: "MyModule"
  • 列表: 用于存储多个值,用方括号括起。
srcs: ["file1.c", "file2.c"]
  • 布尔值: true 或 false,用来表示开关。
enabled: true
  1. 常见模块类型
    定义共享库模块(.so 文件)。
cc_library_shared {
    name: "mylib",
    srcs: ["mylib.cpp"],
    shared_libs: ["liblog"],  # 依赖其他共享库
    include_dirs: ["include"], # 指定头文件目录
}

3.2. cc_library_static
定义静态库模块(.a 文件)。

cc_library_static {
    name: "mylib_static",
    srcs: ["mylib_static.cpp"],
}

3.3. cc_binary
定义可执行文件模块。

cc_binary {
    name: "mytool",
    srcs: ["main.cpp"],
    shared_libs: ["liblog"], # 依赖共享库
}

3.4. android_app
定义 APK 模块。

android_app {
    name: "MyApp",
    srcs: ["src/**/*.java"],
    manifest: "AndroidManifest.xml",
    static_libs: ["mylib"],
}
  1. 关键属性解析
    4.1. name
    模块的唯一名称,必须全局唯一。
name: "MyModule"

4.2. srcs
指定源文件列表,可以包含 C/C++ 文件、Java 文件等。

srcs: ["file1.cpp", "file2.c"]

4.3. shared_libs 和 static_libs

  • shared_libs: 声明依赖的共享库(.so 文件)。
  • static_libs: 声明依赖的静态库(.a 文件)。
shared_libs: ["liblog", "libc"],
static_libs: ["libmylib"],

4.4. include_dirs
指定头文件搜索路径。

include_dirs: ["include"],

4.5. cflags 和 ldflags

  • cflags: 传递给编译器的标志(如优化或警告标志)。
  • ldflags: 传递给链接器的标志。
cflags: ["-Wall", "-O2"],
ldflags: ["-lm"],

bp 实战

目录结构
在这里插入图片描述
编译和调试运行和上面mk 环节一样,这里就不写了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值