学习Android源码,如果电脑配置还不错,最好还是下载一套源码,经过编译后导入到Android Studio中来学习,这样会更加的直观,代码之间的跳转查看会更加方便。因此,笔者决定下载并编译一套源码,以利于源码的探索和学习。本文不介绍怎么下载的源码,主要是记录编译源码时踩过的坑,为自己同时也便于读者少走弯路。
为了方便读者做对比,这里简单介绍一下笔者的硬件和软件配置:
- 硬件:MAcBook Pro
- 处理器:2.6GHz 六核 Intel Core i7
- 内存:16GB 2667 MHz DDR4
- macOS:Sonoma 14.6.1
- 存储:外接 1T 的移动固态硬盘(希捷Seagate)
- 软件:
- XCode 16.0(16A242D)
- Mac sdk 15.0
1.不能找到一个支持的 mac sdk 错误
报错提示如下所示:
internal error: Could not find a supported mac sdk: ["10.10" "10.11" "10.12" "10.13" "10.14"]
internal error: Could not find a supported mac sdk: ["10.10" "10.11" "10.12" "10.13" "10.14"]
在执行编译过程中,如果出现不能找到一个支持的mac sdk错误(XCode 的 sdk),可以通过下面的命令行编辑以下文件:
vim build/soong/cc/config/x86_darwin_host.go
添加已安装的mac sdk版本号即可,笔者这里安装 XCode 自带的是:15和15.0,就都给添加上了
然后,重新编译,解决了该问题!!!
在继续编译的过程中,又出现了新的问题…
2.VNDK library list has been changed
报错提示如下所示:
error: VNDK library list has been changed.
Changing the VNDK library list is not allowed in API locked branches.
错误原因是:out/target/product/generic/obj/PACKAGING/vndk_intermediates/libs.txt 和 build/make/target/product/gsi/29.txt 文件内容不一致所导致,根据提示的差异内容和文本对比工具进行差异对比,笔者查到的解决方案有如下几种:
- 将 libs.txt 的内容完全复制到 29.txt 即可解决;(笔者试了几次并没有解决)
- 删除 libs.txt 文本文件;(笔者试了几次也没有解决)
- 将 29.txt 文本文件以及其所在同目录下的 current.txt 文本文件,与 libs.txt 的内容保持一致(即用 libs.txt 的内容覆盖其它两个文件的内容);(笔者试了几次依然没有解决)
- 使用下面的命令进行编译:
make target-files-package
使用上述命令解决了该问题!!!
在继续编译的过程中,又出现了新的问题,编译源码真的是不断摸索前进…
3.sprintf is deprecated
报错提示如下所示:
external/protobuf/src/google/protobuf/io/strtod.cc:62:14: error: 'sprintf' is deprecated: This function is provided
for compatibility reasons only. Due to security concerns inherent in the design of sprintf(3), it is highly
recommended that you use snprintf(3) instead. [-Werror,-Wdeprecated-declarations]
int size = sprintf(temp, "%.1f", 1.5);
^
sprintf 函数在某些版本的 C 或 C++ 标准库中已被标记为过时(deprecated)。这意味着,虽然在当前代码中它仍然可以使用,但是在未来的库版本中,它可能会被移除。使用这个函数可能会产生警告,并且建议使用其他更现代、更安全的函数。
报错的原因是:sprintf 函数被弃用,编译器认为使用 sprintf 函数不安全,按照提示将对应语法替换为 snprintf 函数即可:
下图为报错提示的 strtod.cc 文件的全路径,便于读者快速查找并修改:
strtod.cc 文件中将对应语法替换为 snprintf 函数:
解决方法:使用 snprintf 或 sprintf_s(取决于你使用的是 C 还是 C++ 以及你的编译器)来代替 sprintf。这两个函数是当前标准库中的替代函数,它们提供了类似的功能,但是更加安全,不会有过时的问题。代码修改后的前后对比如下:
// 旧的使用 sprintf 的代码
char temp[16];
int size = snprintf(temp, "%.1f", 1.5);
// 替换后新的使用 snprintf 的代码
char temp[16];
int size = snprintf(temp, sizeof(temp), "%.1f", 1.5);
替换后解决该问题,在继续编译的过程中,又出现了新的问题,编译源码真的是要有不断与报错抗争的耐心…
4.use of undeclared identifier ‘PAGE_SIZE’
报错提示如下所示:
system/core/base/cmsg.cpp:36:21: error: use of undeclared identifier 'PAGE_SIZE'
if (cmsg_space >= PAGE_SIZE) {
^
system/core/base/cmsg.cpp:78:21: error: use of undeclared identifier 'PAGE_SIZE'
if (cmsg_space >= PAGE_SIZE) {
^
2 errors generated.
17:46:11 ninja failed with: exit status 1
报错的原因是:使用未声明的标识符**‘PAGE_SIZE’**,即 PAGE_SIZE 这个变量未定义。
解决方法:
satckoverflow 上有人碰到类似的问题,看到下面有回复说是配置mac os sdk版本的问题,这里采用回答所给的第二个方案改了一下:
在 ~/system/core/base/include/android-base/cmsg.h 头文件中添加如下内容:
#ifndef PAGE_SIZE
#define PAGE_SIZE (size_t)(sysconf(_SC_PAGESIZE))
#endif
添加声明后该问题解决,继续编译…
5.error: unknown type name ‘AuthorizationRef’
报错提示如下所示:
/Applications/Xcode.app/Contents/Developer/.../SCPreferences.h:196:6:
error: unknown type name 'AuthorizationRef'
报错原因:编译器遇到一个未知的类型名称时,会抛出 “unknown type name ‘XXX’” 的错误。
解决方法:根据错误提示的文件路劲,找到对应文件中的 AuthorizationRef 的定义或声明,并确保它能被正确地识别和引用。
#if !TARGET_OS_IPHONE
#include <Security/Security.h>
#else // !TARGET_OS_IPHONE
typedef const struct AuthorizationOpaqueRef * AuthorizationRef;
#endif // !TARGET_OS_IPHONE
分析这里的代码,如果目标OS不是IPhone,则引入 Security/Security.h 头文件,否者定义 AuthorizationOpaqueRef 结构体。由于我们是编译的 Android 源码,也就满足 if 条件则引入文件,但是该头文件没有包含特定的头文件来定义 AuthorizationRef。
因此笔者做了如下修改,算是欺骗编译器,先让源码的编译能够正常通过,修改后的源码如下:
// #if !TARGET_OS_IPHONE
// #include <Security/Security.h>
// #else // !TARGET_OS_IPHONE
typedef const struct AuthorizationOpaqueRef * AuthorizationRef;
// #endif // !TARGET_OS_IPHONE
取消判断逻辑,直接定义所需的 AuthorizationRef,保存修改后继续编译,问题就这么被解决了,又可以愉快的编译源码了…
6.FAILED: out/target/product/generic/obj/ETC/sepolicy_tests_intermediates/sepolicy_tests
报错提示如下所示:
FAILED: out/target/product/generic/obj/ETC/sepolicy_tests_intermediates/sepolicy_tests
......//省略部分
FAILED: out/target/product/generic/obj/ETC/treble_sepolicy_tests_26.0_intermediates/treble_sepolicy_tests_26.0
报错原因:目前还未搞明白,看着是跟测试有关的…
查到的解决方案是:修改 system/sepolicy/tests/Android.bp 去掉stl: “libc++_static”;
cc_library_host_shared {
name: "libsepolwrap",
srcs: ["sepol_wrap.cpp"],
cflags: ["-Wall", "-Werror",],
export_include_dirs: ["include"],
// libsepolwrap gets loaded from the system python, which does not have the
// ASAN runtime. So turn off sanitization for ourself, and use static
// libraries, since the shared libraries will use ASAN.
static_libs: [
"libbase",
"libsepol",
],
// stl: "libc++_static", // 删掉这一行即可
sanitize: {
never: true,
},
}
保存修改后,重新编译源码,该问题得到解决,继续编译…
编译构建成功
等待编译完成后,如下图所示,则意味着构建完成啦!
终于大工完成了,不是编译了1个多小时哈!这是中断编译后,修改调整后重新继续编译的时间,如果没有遇到问题的情况下,依笔者的电脑配置,预估得5个小时左右吧!