在阅读android 源码时经常会有阅读native代码的场景,使用asfp有些代码跳转不是很准确,甚至有些无法跳转的情况,这篇文章将介绍如何配置vscode阅读native代码, 这里不介绍原理,直接介绍方法, 亲测有效,跳转准确
主要步骤
- 生成compile_commands.json
- 配置vscode
- 加载aosp项目native 代码
1. 生成compile_commands.json
在aosp工程中有对compile_commands.json生成方式进行介绍的文档。文档位置在:build/soong/docs/compdb.md
- 配置环境变量
ini
$ export SOONG_GEN_COMPDB=1
$ export SOONG_GEN_COMPDB_DEBUG=1
- 编译生成compile_commands.json命令
shell
$source build/envsetup.sh
$lunch xxxx
$make nothing
- 生成的compile_commands.json目录:
bash
out/soong/development/ide/compdb/compile_commands.json
注意:这种方式生成的compile_commands.json包含了所有使用Android.bp定义的模块的编译数据库,使用Android.mk编译的模块并不包含在内。
Android16新方式: 在Android16工程中使用上述方法则不会生成我们想要的compile_commands.json文件,在android16需要使用下面方法。
- 在android.bp中添加全局配置: 在文件
build/soong/cc/config/global.go中commonGlobalCflags中添加-v选项如下:
c
commonGlobalCflags = []string{
........,
"-v",
}
- clear之前的编译, 可以直接删除.out 目录
- 重新编译
bash
source build/envsetup.sh
lunch xxx
make -j32 | tee build_sys.log
这里把编译时,产生的日志输入到 build_sys.log 文件中。 或者不使用tee将编译的日志输入到 build_sys.log中也可以, 直接进行make 编译,编译完后也系统也会生成一个编译日志文件,使用这个文件也是可以的。 4. 使用编译日志文件生成compile_commands.json 使用下面脚本进行生成,创建文件build_cc_json_tools.py
css
import json
import sys
def build_compile_commands(input_file: 'str', output_file: 'str', android_top: 'str', compiler='clang'):
with open(input_file) as input:
target_lines = []
compile_command_list = []
for line in input:
if line.count(compiler) > 0 and ( line.count('.c') > 0 or line.count('.cpp') > 0 ):
target_lines.append(line.strip())
# print(len(target_lines))
for rule in target_lines:
if rule.count('"') >= 2:
compile_command = {}
compile_command['directory'] = android_top
compile_command['arguments'] = []
compile_command_file = ''
items = rule.split(' ')
for item in items:
item = item.replace('"', '')
if item.count(compiler) > 0:
item = android_top + '/' + item
compile_command['arguments'].append(item)
if item.count('.c') > 0 or item.count('.cpp') > 0:
if item.count('/') > 0:
compile_command_file = item
if compile_command_file != '':
compile_command['file'] = compile_command_file
compile_command_list.append(compile_command)
with open(output_file, 'w') as output:
print(json.dumps(compile_command_list, indent=4), file=output)
if __name__ == '__main__':
if len(sys.argv) < 4:
print("Usage: python3 {} <input_file> <output_file> <android_top> [compiler]".format(sys.argv[0]))
exit(1)
else:
input_file = sys.argv[1]
output_file = sys.argv[2]
android_top = sys.argv[3]
compiler = 'clang'
if len(sys.argv) > 4:
compiler = sys.argv[4]
build_compile_commands(input_file, output_file, android_top, compiler)
执行命令,这里需要注意使用python3 进行生成
bash
python3 build_cc_json_tools.py build_sys.log compile_commands.json /home/cuckoo/Adisk/aosp16
第一个参数:编译生成日志文件 第二个参数:生成的compile_commands.json名字 第三个参数:存放路径
2. 精简compile_commands.json
你可能会发现,编译后生成的compile_commands.json很大,如果打开整个Android目录会非常慢,一般来说,我们只会打开一个或几个仓库就可以,如frameworks,hardware 等几个仓库,所以我们需要精简compile_commands.json,然后打开特定仓库进行索引,以加快vscode的响应速度。
可以使用下面脚本精简compile_commands.json, 复制脚本创建文件streamline_project.py,
python
#!/usr/bin/python3
import json
import sys
from typing import *
def simply_compile_commands_json(completed_json_file: 'str', simplified_json_file: 'str', repositories: 'List[str]'):
with open(completed_json_file) as input_file:
command_content = input_file.read()
command_json = json.loads(command_content)
target_command_list = []
for command in command_json:
file: 'str' = command['file']
if any((file.startswith(repository) for repository in repositories)):
target_command_list.append(command)
with open(simplified_json_file, "w") as output_file:
output_file.write(json.dumps(target_command_list, indent=4))
if __name__ == '__main__':
if len(sys.argv) != 4:
print('Usage: python3 {} <complete.json> <simply.json> <repo[,repo[,repo]...]>'.format(sys.argv[0]))
print('Eg: python3 {} ./compile_commands.json.big ./compile_commands.json system,hardware,frameworks'.format(sys.argv[0]))
exit(1)
else:
input_compile_commands = sys.argv[1]
output_compile_commands = sys.argv[2]
repositories = sys.argv[3].split(',')
simply_compile_commands_json(input_compile_commands, output_compile_commands, repositories)
执行命令,这里需要注意使用python3 进行精简操作
bash
$python3 streamline_project.py out/soong/development/ide/compdb/compile_commands.json ./compile_commands.json frameworks,hardware,kernel
第一个参数:生成的完整的compile_commands.json 第二个参数:精简后的compile_commands.json文件 第三个参数:需要保留的模块,用,隔开
到这里我们需要的compile_commands.json文件就制作好了
最后把生成的compile_commands.json文件放到aosp工程的根目录。
3. vscode 配置
clangd插件
- clangd插件能根据提供的配置文件(compile_commands.json),来分析代码中每个函数在哪个头文件声明,在哪个文件中实现,十分准确
- clangd插件和C/C++ IntelliSense 有些冲突,需要先禁掉这个插件,或者把C/C++ 插件卸载掉 参考:vscode c工程中抛弃C/C++ IntelliSense实现函数跳转
clangd插件分为两部分。
- vscode 中clangd 插件
- 你的电脑上需要安装
ubuntu 系统可以使用下面命令进行安装:
ruby
$ sudo apt install clangd
打开vscode加载aosp项目。 clangd默认会在打开文件的当前目录下找compile_commands.json。等待扫描完成即可。 到这里导入的时候需要注意一点, 在vscode可能提示需要使用java17, 可能需要手动安装一下。