Project Icon

elixir

开源源代码索引和交叉引用系统

Elixir是一个开源的源代码交叉引用系统,专为C/C++项目设计。它使用Git和Berkeley DB存储代码及索引数据,可高效索引大型项目的所有版本。Elixir采用简洁的数据结构,提供快速查询,支持CGI和REST API接口。该系统特别适合Linux内核等大型开源项目的代码浏览和搜索。

= Elixir 交叉引用工具 :doctype: book :pp: {plus}{plus} :toc: :toc-placement!:

image::https://travis-ci.com/bootlin/elixir.svg?branch=master[构建状态,link=https://travis-ci.com/bootlin/elixir]

Elixir 是一个受 https://en.wikipedia.org/wiki/LXR_Cross_Referencer[LXR] 启发的源代码交叉引用工具。它用 Python 编写,主要目的是为了以最小的占用空间索引 C 或 C{pp} 项目(如 Linux 内核)的每个发布版本。

它使用 Git 作为源代码文件存储,使用 Berkeley DB 存储交叉引用数据。在内部,它索引 Git blobs 而不是文件树,以避免重复工作和数据。它具有简单直观的数据结构(类似于早期的 LXR 版本),以保持查询简单快速。

您可以在 https://elixir.bootlin.com/ 上看到它的运行效果

注意:本文档适用于 Elixir 2.0 版本。

toc::[]

= 要求

  • Python >= 3.6
  • Git >= 1.9
  • Jinja2 和 Pygments (>= 2.7) Python 库
  • Berkeley DB (及其 Python 绑定)
  • Universal Ctags
  • Perl (用于非贪婪正则表达式和自动化测试)
  • Falcon 和 mod_wsgi (用于 REST API)

= 架构

Elixir 具有以下架构:

.---------------.----------------. | CGI 接口 | REST 接口 | |---------------|----------------.

查询命令更新命令
Shell 脚本
'--------------------------------'

Shell 脚本 (script.sh) 是底层,提供与 Git 和其他 Unix 工具交互的命令。Python 命令使用 shell 脚本的服务来提供对带注释的源代码和标识符列表的访问 (query.py),或创建和更新数据库 (update.py)。最后,CGI 接口 (web.py) 和 REST 接口 (api.py) 使用查询接口来生成 HTML 页面和响应 REST 查询。

在安装系统时,您应该手动测试每一层,确保它正常工作后再继续下一层。

== 数据库设计

./update.py 存储 git 对象哈希("blobs")和顺序键之间的双向映射。 索引这些哈希的目的是减少它们的存储占用(SHA-1 哈希为 20 字节,而 32 位整数为 4 字节)。

将提供详细的数据库图表。在此之前,请直接查看源代码。

= 手动安装

== 安装依赖


对于 RedHat/Fedora/AlmaLinux



sudo dnf install python36-pip python36-pytest python36-jinja2 python36-bsddb3 python36-falcon python3-pygments git httpd perl perl-autodie jansson libyaml rh-python36-mod_wsgi


对于 Debian



sudo apt install python3-jinja2 python3-bsddb3 python3-falcon python3-pytest python3-pygments universal-ctags perl git apache2 libapache2-mod-wsgi-py3 libjansson4

要启用 REST API,请按照 https://github.com/GrahamDumpleton/mod_wsgi[`mod_wsgi`] 的安装说明进行操作,并按照 https://github.com/GrahamDumpleton/mod_wsgi#connecting-into-apache-installation 中的详细说明将其连接到 apache 安装。

要了解需要安装哪些软件包,您还可以阅读 docker/ 目录中的 Docker 文件,以了解 Elixir 在您喜欢的发行版中需要哪些软件包。

== 下载 Elixir 项目


git clone https://github.com/bootlin/elixir.git /usr/local/elixir/

== 创建目录


mkdir -p /path/elixir-data/linux/repo mkdir -p /path/elixir-data/linux/data

== 设置环境变量

使用两个环境变量来告诉 Elixir 在哪里找到项目的本地 git 仓库和数据库:

  • LXR_REPO_DIR (项目的 git 仓库目录)
  • LXR_DATA_DIR (项目的数据库目录)

现在打开 /etc/profile 并追加以下内容。


export LXR_REPO_DIR=/path/elixir-data/linux/repo export LXR_DATA_DIR=/path/elixir-data/linux/data

然后运行 source /etc/profile

== 克隆内核源代码

首先克隆 Linus Torvalds 发布的主分支:


cd /path/elixir-data/linux git clone --bare https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git repo

然后,您还应该声明一个对应于 stable 树的 stable 远程分支,以获取所有发布更新:


cd repo git remote add stable git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git git fetch stable

然后,您还可以声明一个对应于其他仓库中不存在的旧 Linux 版本的 history 远程分支,以获取所有仍然可用的旧版本:


cd repo git remote add history https://github.com/bootlin/linux-history.git git fetch history --tags

请随意以这种方式添加更多远程分支,因为 Elixir 将考虑所有远程分支的标签。

== 第一次测试


cd /usr/local/elixir/ ./script.sh list-tags

== 创建数据库


./update.py <线程数>


生成完整数据库可能需要很长时间:在 Xeon E3-1245 v5 上索引 Linux 内核的 1800 个标签大约需要 15 小时。因此,您可能想要调整脚本(例如,通过使用 "head" 限制标签数量)以测试更新和查询命令。您甚至可以创建一个新的 Git 仓库,只创建一个标签,而不使用非常大的官方内核仓库。


== 第二次测试

验证查询是否有效:

$ ./query.py v4.10 ident raw_spin_unlock_irq C $ ./query.py v4.10 file /kernel/sched/clock.c

注意: v4.10 可以替换为任何其他标签。

== 配置 httpd

CGI 接口 (web.py) 旨在由您的 Web 服务器调用。由于它包含对多个项目进行索引的支持,它需要一个不同的变量 (LXR_PROJ_DIR),该变量指向具有特定结构的目录:

  • <LXR_PROJ_DIR> ** <项目 1> *** data *** repo ** <项目 2> *** data *** repo ** <项目 3> *** data *** repo

然后它将在调用查询命令时生成其他两个变量。

现在打开 /etc/httpd/conf.d/elixir.conf 并写入以下内容。 注意:如果使用 apache2 (Ubuntu/Debian) 而不是 httpd (RedHat/Centos), 默认配置文件为: /etc/apache2/sites-enabled/000-default.conf


HTTP 所需

<Directory /usr/local/elixir/http/> Options +ExecCGI AllowOverride None Require all granted SetEnv PYTHONIOENCODING utf-8 SetEnv LXR_PROJ_DIR /path/elixir-data

REST API 所需

<Directory /usr/local/elixir/api/> SetHandler wsgi-script Require all granted SetEnv PYTHONIOENCODING utf-8 SetEnv LXR_PROJ_DIR /path/elixir-data

AddHandler cgi-script .py #Listen 80 <VirtualHost *:80> ServerName xxx DocumentRoot /usr/local/elixir/http

# 要在安装 mod_wsgi 后启用 REST api:填写路径并取消注释:
#WSGIScriptAlias /api /usr/local/elixir/api/api.py

AllowEncodedSlashes On

RewriteEngine on RewriteRule "^/$" "/linux/latest/source" [R] RewriteRule "^/(?!api|acp).*/(source|ident|search)" "/web.py" [PT] RewriteRule "^/acp" "/autocomplete.py" [PT]

RHEL/CentOS 默认已启用 cgi 和 rewrite 支持,但如果你使用的是 Debian/Ubuntu 发行版,则需要手动启用。


a2enmod cgi rewrite

最后,启动 httpd 服务器。


systemctl start httpd

== 配置 SELinux 策略

当使用启用了 SELinux 的 systemd 时,httpd 服务器只能访问有限的目录。 如果你的 /path/elixir-data/ 不在这些允许的目录中,你将收到 500 状态码的响应。

要允许 httpd 服务器访问 /path/elixir-data/,请运行以下命令:

chcon -R -t httpd_sys_rw_content_t /path/elixir-data/

要检查是否生效,请运行以下命令:

ls -Z /path/elixir-data/

如果你想查看与 httpd 相关的 SELinux 日志,请运行以下命令:

audit2why -a | grep httpd | less

== 配置 systemd 日志目录

默认情况下,elixir 的错误日志会放在 /tmp/elixir-errors。 然而,systemd 默认启用 PrivateTmp。 因此,最终的错误目录将类似于 /tmp/systemd-private-xxxxx-httpd.service-xxxx/tmp/elixir-errors。 如果你想禁用它,请使用以下属性配置 httpd.service:

PrivateTmp=false

== 配置 lighttpd

以下是 lighttpd 的示例配置:


server.document-root = server_root + "/elixir/http" url.redirect = ( "^/$" => "/linux/latest/source" ) url.rewrite = ( "^/(?!api|acp).*/(source|ident|search)" => "/web.py/$1") url.rewrite = ( "^/acp" => "/autocomplete.py") setenv.add-environment = ( "PYTHONIOENCODING" => "utf-8", "LXR_PROJ_DIR" => "/path/to/elixir-data" )

= REST API 使用

配置 httpd 后,你可以测试 API 的使用:

== ident 查询

/api/ident/<Project>/<Ident>?version=<version>&family=<family> 发送 GET 请求。 例如:

curl http://127.0.0.1/api/ident/barebox/cdev?version=latest&family=C

响应体的结构如下:


{ "definitions": [{"path": "commands/loadb.c", "line": 71, "type": "variable"}, ...], "references": [{"path": "arch/arm/boards/cm-fx6/board.c", "line": "64,64,71,72,75", "type": null}, ...] }

= 维护和增强

== 使用缓存提高性能

在 Bootlin,我们使用 https://varnish-cache.org/[Varnish http 缓存] 作为前端,以减少运行 Elixir 代码的服务器负载。

.-------------. .---------------. .-----------------------. | Http 客户端 | --------> | Varnish 缓存 | --------> | 运行 Elixir 的 Apache | '-------------' '---------------' '-----------------------'

== 保持 Elixir 数据库更新

为了保持 Elixir 数据库的更新并索引新发布的版本, 我们建议使用类似 utils/update-elixir-data 的脚本,通过每日 cron 任务调用。

你可以设置 $ELIXIR_THREADS 来更改 update.py 用于索引的线程数(默认为系统的 CPU 数量)。

== 控制 git 仓库的磁盘使用

随着不断更新 git 仓库,你可能会注意到某些仓库比原来大得多。这似乎发生在大型仓库中出现 gc.log 文件时, 导致 git 的垃圾收集器(git gc)失败,因此每次获取新对象时都会快速消耗磁盘空间。

当这种情况发生时,你可以通过打包 git 目录来节省磁盘空间,方法如下:


cd git prune rm gc.log git gc --aggressive

实际上,再次运行上述命令可以节省更多空间。

要在循环中处理多个 git 仓库,你可以使用我们提供的 utils/pack-repositories 脚本, 在所有仓库所在的目录中运行。

= 构建 Docker 镜像

Dockerfile 文件位于 docker/ 目录中。要构建镜像,请运行以下命令:

git clone https://github.com/bootlin/elixir.git ./elixir

docker build -t elixir -f ./elixir/docker/Dockerfile ./elixir

然后你可以使用 docker run 运行镜像。 建议将卷或主机目录挂载到 Elixir 数据目录。 这样可以轻松替换容器为新版本,而不会丢失索引数据。

mkdir ./elixir-data

docker run -v ./elixir-data/:/srv/elixir-data -d --name elixir-container elixir

Docker 镜像不包含任何仓库。要索引仓库,你可以使用实用脚本 index-repository。 例如,要添加 musl 仓库,请运行:

docker exec -it -e PYTHONUNBUFFERED=1 elixir-container /usr/local/elixir/utils/index-repository musl https://git.musl-libc.org/git/musl

没有 PYTHONUNBUFFERED 环境变量,更新日志可能会延迟显示。

或者,在单独的容器中运行索引:

docker run -e PYTHONUNBUFFERED=1 -v ./elixir-data/:/srv/elixir-data --entrypoint /usr/local/elixir/utils/index-repository elixir musl https://git.musl-libc.org/git/musl

你也可以使用 utils/index-all-repositories 开始索引所有官方支持的仓库。

索引完成后,Elixir 应该可以在主机上通过以下 URL 访问: http://172.17.0.2/musl/latest/source

如果 172.17.0.2 无响应,你可以通过运行以下命令检查容器的 IP 地址:

docker inspect elixir-container | grep IPAddress

== 自动仓库更新

Docker 镜像本身不会自动更新仓库。 你可以,例如,在容器中启动 utils/update-elixir-data(或在单独的容器中,挂载 Elixir 数据卷/目录) 通过主机上的 cron 定期更新仓库。

== 将 Docker 镜像用作开发服务器

你可以通过按照上述步骤轻松将 Docker 镜像用作开发服务器,但在运行 docker run elixir 时, 将主机上的 Elixir 源目录挂载到容器中的 /usr/local/elixir/

在主机上对代码所做的更改应该自动反映在容器中。 你可以使用 apache2ctl 重启 Apache。 错误日志可在容器内的 /var/log/apache2/error.log/tmp/elixir-errors 中找到。

= 硬件要求

性能要求主要取决于 Elixir 服务的流量。但是,快速的服务器对于项目的初始索引也有帮助。

强烈推荐使用 SSD 存储,因为需要频繁访问 git 仓库。

在 Bootlin,以下是我们使用的服务器的一些详细信息:

  • 截至 2019 年 7 月,我们的 Elixir 服务消耗 17 GB 数据(支持所有项目), 仅对于 Linux 内核(最新版本为 5.2),索引数据占用 12 GB, git 仓库占用 2 GB。
  • 我们在一个云服务器上使用 8 GB RAM 的 LXD 实例,该服务器有 8 个 CPU 核心, 运行频率为 3.1 GHz。

= 为 Elixir 做贡献

== 支持新项目 Elixir具有非常简单的模块化架构,只需在Elixir源码中添加一个新文件即可支持新的源代码项目。

Elixir的假设:

  • 项目源码必须存在于git仓库中
  • 所有项目发布都与特定的git标签关联。Elixir只考虑这些标签。

首先按照上述说明安装Elixir。查看projects子目录了解已支持的项目。

当Elixir至少能运行一个项目后,就可以克隆你想支持的项目的git仓库:

cd /srv/git git clone --bare https://github.com/zephyrproject-rtos/zephyr

完成后,你也可以引用和获取该项目的远程分支,例如对应Linux内核的stable树(参见本文档前面关于Linux的说明)。

现在,在你的LXR_PROJ_DIR目录中,为新项目创建一个新目录:

cd $LXR_PROJ_DIR mkdir -p zephyr/data ln -s /srv/git/zephyr.git repo export LXR_DATA_DIR=$LXR_PROJ_DIR/data export LXR_REPO_DIR=$LXR_PROJ_DIR/repo

然后,返回Elixir源码并测试标签是否正确提取:

./script.sh list-tags

根据你想在Elixir页面上展示可用版本的方式,你可能需要对每个标签字符串进行替换,例如添加缺失的v前缀,以与其他项目版本的显示方式保持一致。你也可以决定忽略特定标签。这些都可以通过在新的projects/<projectname>.sh文件中重新定义默认的list_tags()函数来实现。下面是一个例子(projects/zephyr.sh文件):

list_tags() { echo "$tags" | grep -v '^zephyr-v' }

注意<project_name>必须与你在LXR_PROJ_DIR下创建的目录名称匹配。

下一步是确保版本在版本菜单中按照你的意愿分类。这个分类工作是通过list_tags_h()函数完成的,该函数生成./scripts.sh list-tags -h命令的输出。以下是Linux项目的输出示例:

v4 v4.16 v4.16 v4 v4.16 v4.16-rc7 v4 v4.16 v4.16-rc6 v4 v4.16 v4.16-rc5 v4 v4.16 v4.16-rc4 v4 v4.16 v4.16-rc3 v4 v4.16 v4.16-rc2 v4 v4.16 v4.16-rc1 ...

第一列是版本的顶级菜单项。 第二列是下一级菜单项, 第三列是可以在菜单中选择的实际版本。 注意,这第三项必须与git中标签的确切名称相对应。

如果默认行为不符合你的需求,你需要自定义list_tags_h函数。

你还应确保Elixir正确识别最新版本:

./script.sh get-latest

如有必要,自定义get_latest()函数。

如果你想在设备树文件中启用对compatible属性的支持,在projects/<projectname>.sh的开头添加dts_comp_support=1

现在你可以为新项目生成Elixir的数据库:

./update.py <线程数>

然后你可以通过HTTP服务器检查Elixir是否正常工作。

== 编码风格

如果你希望为Elixir的Python代码做出贡献,请遵循Python的官方编码风格。

== 如何发送补丁

与我们分享贡献的最佳方式是在GitHub上提交拉取请求。

= 自动化测试

Elixir在t/目录中包含一个简单的测试套件。要运行它, 在Elixir的顶级目录中执行:

prove

测试套件使用t/tree中提取的Linux v5.4代码。

== t/tree中代码的许可

复制的代码按照Linux附带的COPYING文件中描述的方式许可。所有复制的文件都带有GPL-2.0+GPL-2.0-or-later的SPDX许可标识符。根据GNU的兼容性表,GPL 2.0+代码可以在GPLv3下使用,前提是组合在GPLv3下。此外,GNU对AGPLv3的概述表明,其条款"实际上包含GPLv3的条款"加上网络使用段落。因此,开发者有理由相信将这些文件在AGPLv3下许可是授权的。(另见此问题评论,其中有类似情况的另一个例子。)

= 许可

Elixir版权所有 (c) 2017--2020 其贡献者。它基于AGPLv3许可。 详情请参阅Elixir附带的COPYING文件。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号