因为网络不通,无法使用服务器上的lxr,严重影响我阅读代码的效率,所以索性自己找来了LXR的最新版lxr-0.9.1,在本地机上试着安装一份。
LXR是使用WEB方式下的源代码整理浏览工具,最大的用途在于清理出了代码中函数、变量的定义、说明、应用的关系,并用链接的形式表现在网页上。LXR整理出代码的结构和调用关系,存在数据库中,并在显示时与源代码树结合,从功能上说,包括代码浏览、标识符搜索、文本搜索和文件搜索,其中的文本搜索和文件搜索利用的是第三方工具(即glimpse或swish-e)。它的主要组成部分包括三个:Perl编写的网页/CGI部分,基于MySQL的索引数据管理(新版本才有)和通用的文本搜索工具。目前的版本,采用Glimpse或者Swish-e中的一种作为通用文本搜索工具。在安装上,基本上也按照这三个部分来配置。
1.download
现在LXR已经成为sourceforge的一个project,所以可以到lxr.sourceforge.net上找到最新的lxr代码(当然也就是源代码了)。glimpse和swish-e另找。
要使LXR工作,至少需要以下部件:
一个支持CGI的Web服务器,Apache就不错;
Apache的mod_perl插件,以支持perl脚本的cgi解释,或者直接用Perl也可以;
MySQL或者Postgres,本人用的是MySQL;
ctags包,一般都有。
2.configure
尽管lxr源码里有一个INSTALL文件,但语焉不详,这里写下的是本人的配置经验,不一定是唯一的,也不一定是最佳的。
1)位置规划
LXR除了数据库那一部分不需要考虑存放位置以外,还有CGI/HTML部分、索引生成工具部分和所需要索引的源代码部分需要考虑,我的实践中使用的与INSTALL缺省的不同,最大的一点不同在于我将WEB部分和工具部分分离开,只允许WEB部分暴露给浏览器——主要是基于也许会更安全一些的考虑。
另一个不同是用符号链接而不是真正的源代码目录作为源代码部分,因为LXR索引的Linux Kernel是最常用的,而Kernel本身还被用来重编内核和升级,所以不适合完全拷贝过来。
本例中使用的是/usr/local/lxr目录作为LXR的根目录。
#tar zxvf lxr-0.9.1.tar.gz -C /usr/local ;将lxr解压到/usr/local/lxr下
#cd /usr/local/lxr
#mkdir http ;建http目录,用于存放WEB部分
#mv Local.pm diff fixhashbang ident find search source templates/* http
;将web相关部分移到http下
#rm -rf templates ;这个模板目录已经没用了
#ln http/Local.pm . -s
#ln http/lxr.conf . -s ;为web部分和工具部分都需要用的文件建符号连接
#mkdir src ;源代码部分的根
#cd src
#mkdir kernel ;内核代码目录
#vi versions ;编辑/usr/local/lxr/src/versions文件,内容为kernel,表示让lxr索引kernel
#cd kernel
#ln ../../../../src/linux-2.4.18 2.4.18 -s ;2.4.18才是真正的kernel源码根,之所以这么安排,主要是为了避免glimpse建索引时弄脏了/usr/src/linux-2.4.18/
#cd ../../ ;回到/usr/local/lxr
#mv lib /usr/lib/perl5/site_perl/LXR ;将自定义的perl库文件拷贝到perl/mod_perl使用的缺省库文件目录中,这是相对于redhat系统的
2)改写lxr.conf
准备好了目录结构,下一步就是改写lxr.conf文件。缺省的lxr.conf已经从templates拷贝到/usr/local/lxr/http/下了,并在/usr/local/lxr/下有个连接。
'glimpsebin'变量,改为glimpse命令的位置,用which glimpse可以找到(如果装了的话),缺省为/usr/bin/glimpse;
注释掉所有与swish-e相关的变量定义,——因为我编译swish-e时,make test执行了两天一夜也没有结束,所以只好改用glimpse,据说swish-e更强大些;
'genericonf'设为'/usr/lib/perl5/site_perl/LXR/Lang/generic.conf';
'baseurl'设为'http://10.129.6.244/lxr',这个IP当然不是通用的;
'range'改为[ readfile('/usr/local/lxr/src/versions') ],用绝对路径,主要是为了方便;
'default'改为'kernel',我自己定义的缺省的代码树名;
'sourceroot'设为'/usr/local/lxr/src',也用绝对路径;
'sourcerootname'设为'Linux',自定义的,它将显示在缺省的最高级源码目录上;
'glimpsedir' => '/usr/local/lxr/src/$v/',$v表示使用version变量的值,也就要求把glimpse的索引结果文件保存在/usr/local/lxr/src/kernel上,与2.4.18并列;
其余都不用改。
3)apache的httpd.conf
保证装了mod_perl的时候,在httpd.conf中添加以下几行:
Alias /lxr /usr/local/lxr/http
<Directory /usr/local/lxr/http>
AllowOverride None
Options FollowSymLinks
<Files ~ (search|source|ident|diff|find)$>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
</Files>
</Directory>
表示访问/lxr就相当于访问/usr/local/lxr/http,且用perl解释search、source、ident、diff和find几个脚本,而其他的仍然当成html来使用。
如果没有mod_perl,可以用SetHandler cgi-script代替perl-script,一样可以用,PerlHandler就不用了。
3.initialize
1)初始化MySQL数据库
运行mysql,在提示符下运行"\. initdb-mysql"。这样就建好了lxr用户,建好了lxr数据库可其中一系列表格,并让lxr能全权访问lxr数据库,但没有访问其他库的权限,而且,也不用密码。
2)建glimpse索引
在/usr/local/lxr/src/kernel/下运行'find . -name "*.[chS]" -follow | glimpseindex -H . -o -F',索引所有.c、.h、.S(汇编)文件。这个过程比较耗时,但比起下一个过程来,就小巫见大巫了。
3)建identity索引
这是LXR精髓所在,在/usr/local/lxr/下运行'./genxref --version=kernel --url=http://10.129.6.244/lxr',这个过程在我的机器上用了5个小时,其结果就是在MySQL中添东西。如果已经做过索引了,它就只关心那些修改过的或新的文件,速度就快多了。这个过程如果中断了,最好清空数据库重新来过,否则可能会有错误。
4)修改权限
最简单的办法就是把/usr/local/lxr/http下所有的文件都改成apache的属主。在/usr/local/lxr/下运行'chown apache.apache http -R'。
4.startup
重启mysql和httpd,然后访问http://10.129.6.244/lxr/source/就可以了。比较奇怪的是,因为这个cgi允许用类似目录一样的形式(source/)来访问,所以,如果服务器端有更新,浏览器端仍会使用老的页面,refresh也没用。这时只有清空本地cache了。
5.update
我还没有遇到更新的情况,但估计2.4.18升级到2.4.19时比较麻烦,因为目录名变了,而数据库里存的仍然是老名字,glimpse也用的老名字,所以更新可能需要重建一次数据索引,就是重新来一次3.initialize。
但如果仅仅是添加新的源代码树,则只需要修改src/versions文件,按照kernel/2.4.18的模子再在src下建一个目录树,并一样执行一次3.2、3.3、3.4就可以了。为了方便,我把3.x做成了两个脚本。
6.bugs
应该在源代码树的组织上。如果同时要索引kernel-2.4.18和kernel-2.2.19,逻辑上好像应该在kernel下建另一个连接指向2.2.19的代码,但实际上应该建一个kernel2与kernel并列在src目录下。
更新时看样子也会有问题,因为数据库里记录了2.4.18的目录信息,glimpse里也记录了2.4.18。重建实在耗时。
不知谁有更好的配置方案,尽管这做不了博士课题。
不知道有没有遗漏的地方。还多亏参考了别人已有的配置,尽管版本不同。
FIXIT:
1.在Config.pm中有一段处理baseurl的代码(_initialize()),屏蔽了所有config变量的生成。只能注释掉才能使其正常工作。
2.缺省情况下,glimpse采用case insensitive方式工作(search程序),需要去掉"-i"的开关。
---------------------------------------------------------------------------------------------------------------------------------------------
前段时间因为工作需要,从源码开始配置了apache2+modperl2+lxr-0.9.2,有些地方和本文所说不
同,所以把更新内容贴在这里,希望对后来者有用。
--------------
更新 040628:
1.从perl源码安装时没有DBI和DBD::mysql,需要自行安装。
DBI和DBD::mysql的源代码都可以直接从google中找到,下载后perl
Makefile.PL、make、make install即可。
2./usr/lib/perl5/site_perl下需要有一份Local.pm的链接,/usr/local/lxr下倒是不需要。
3.source脚本里使用的internal-gopher-*图片都不能正常显示,可能是mozilla或者是别的什么浏
览器的设置。需要恢复成注释掉的/icons/目录下的相应图片,这些图片apache的缺省安装都有。
4.不知道为什么,http目录下的那些template HTML文件在各个脚本里都打不开(doesn't
exist),除非将其拷贝到系统根目录(“/”)。没办法,只能在lxr.conf中使用绝对路径来说明
这些templates。
5.html-head.html和html-tail.html中都含有一些指向internet的图片链接,最简单的办法就是去
掉那个<img>。
6.swish-e的配置很简单,只要设置好lxr.conf中的变量就可以
了。但“file search”功能没有实现使用swish-e的版本,如果
要用,只能继续使用glimpse。glimpse的配置因为版本的变化
而和以前有所不同,而且在lxr.conf中已经没有glimpseindex的
变量定义了,需要手工添加。
7.swish-e的索引文件现在统一放在src/index目录下,因为
genxref会用'$version'作为索引文件的文件名前缀,因而可以放
在同一个目录下。
8.lxr可能原本用于同一软件的不同版本的源代码索引,例如
Linux的不同版本,因此它的version变量应该是代码的版本号,
但这里直接用这个版本号指向了不同的代码树。本来lxr索引的
不同版本的代码是可以diff markup的,现在这个功能也就同时
失去了意义。
9.使用mod_perl2的apache2的httpd.conf文件变化不大,只需要
将Apache::Registry改为ModPerl::Registry。
10.样例中的lxr.conf有两个swishdir和两个glimpsedir,后面那
一对实际上可以删除。
11.现在直接将代码拷贝到src目录下,而不是像以前那样在src
的子目录里再作目录链接,也就是说,少了一层目录。
12.html-ident.html最后那个table是冗余的,应该删除。
13.httpinit函数最后调用了printhttp来显示一些信息,但这些信
息会影响lxr输出的美观(位于题头),所以在
LXR::Common.pm中注释掉了。
14.0.9.2版的lxr把freetext索引和identity索引都集中在genxref脚
本中进行,且4.17版的glimpseindex不支持管道输入。
15.将glimpsedir设为"/usr/local/lxr/src/index",glimpseindex将
把索引文件建立在$glimpsedir/$release/目录下。这时应当修改
find和search,当它输出文件名时忽略掉$config->sourceroot/
$release/的前缀。和以前的配置相比,这一修改是当前仅有一
层源码目录引起的。
16.最终还是选用glimpse,因为它的freetext索引中有简短的上
下文。
更新040708:
因为发现lxr在Linux的几个浏览器下都只显示HTML代码,
所以怀疑是因为注释了printhttp()而缺少HTML Header,但加上
这个函数后仍然如此,HTML头信息直接显示在HTML代码最前
面。
参考linux-forum上tcpwl的配置,在httpd.conf中加上
“ForceType text/html”,就可以正确显示了。
如此设置后,printhttp()打印的几行Header信息仍然显示了
出来,仍然是参考tcpwl的配置,加上“PerlOptions ParseHeaders”,
但浏览时报错,说缺少http头。
注释掉printhttp()中“Content-Type”之前的两个打印语
句,总算正常了。
现在的httpd.conf中与lxr相关的部分如下:
----------
Alias /lxr /usr/local/lxr/http <Directory /usr/local/lxr/http> AllowOverride None Options FollowSymLinks <Files ~ (search|source|ident|diff|find)$> SetHandler perl-script PerlHandler ModPerl::Registry PerlOptions ParseHeaders Options +ExecCGI </Files> ForceType text/html </Directory>
现在的lxr.conf如下:
-----------
# -*- mode: perl -*- # Configuration file # ( { # Global configuration # Path to glimpse executable. # Define this OR the swish-e variables depending which search engine you want to use. 'glimpsebin' => '/usr/local/bin/glimpse', 'glimpseindex' => '/usr/local/bin/glimpseindex', # Where to store the glimpse index files 'glimpsedir' => '/usr/local/lxr/src/index', # Location of SWISH-E indexer binary # 'swishindex' => '/usr/local/bin/swish-e', # Location of SWISH-E search binary # 'swishsearch' => '/usr/local/bin/swish-e', # Where to store the swish index files # 'swishdir' => '/usr/local/lxr/src/index/', # Path to Exuberant Ctags executable 'ectagsbin' => '/usr/bin/ctags', # Place where lxr can write temporary files 'tmpdir' => '/tmp', # Location of the Generic.pm config file 'genericconf' => '/usr/lib/perl5/site_perl/LXR/Lang/generic.conf' }, { # Configuration for href=http://192.168.1.3/lxr.>http://192.168.1.3/lxr. # baseurl is used to select configuration block. 'baseurl' => 'http://172.16.109.67/lxr', # Put your URL here 'virtroot' => '/lxr', # The bit after the / above 'variables' => { # Define typed variable "v". This is the list of versions to index. 'v' => {'name' => 'Version', # This can come from a file, a function or be explicitly # ennumerated. # From a file: 'range' => [ readfile('/usr/local/lxr/src/versions') ], # Explicitly: # 'range' => [qw(v1 v2 v3.1 v4 experimental)], # If files within a tree can have different versions, # e.g in a CVS tree, 'range' can be specified as a # function to call for each file: #'range' => sub { return # ($files->allreleases($LXR::Common::pathname), # $files->allrevisions($LXR::Common::pathname)) # }, # deferred function call. # The default version to display 'default' => 'linux-2.6.6'}, # Define typed variable "a". First value is default. 'a' => {'name' => 'Architecture', 'range' => [qw(i386 alpha arm m68k mips ppc sparc sparc64)]}, }, # These do funky things to paths in the system - you probably don't need them. 'maps' => { '/include/asm[^\/]*/' => '/include/asm-$a/', '/arch/[^\/]+/' => '/arch/$a/', }, # Templates used for headers and footers 'htmlhead' => '/usr/local/lxr/http/html-head.html', 'htmltail' => '/usr/local/lxr/http/html-tail.html', 'htmldir' => '/usr/local/lxr/http/html-dir.html', 'htmlident' => '/usr/local/lxr/http/html-ident.html', 'htmlident_refs' => '/usr/local/lxr/http/html-ident-refs.html', 'sourcehead' => '/usr/local/lxr/http/html-head.html', 'sourcedirhead' => '/usr/local/lxr/http/html-head.html', 'stylesheet' => 'lxr.css', # sourceroot - where to get the source files from # For ordinary directories, this specifies a directory which has each version as a # subdirectory e.g. # indexed-src/version1/... # indexed-src/version2/... # The names of the version directories must match the values for the Version # variable above. 'sourceroot' => '/usr/local/lxr/src', # Alternatively, this can specify a CVS repository by setting the value to "cvs:" # followed by the path to the repository. Note this must be file accessible - remote # server access does NOT work. # 'sourceroot' => 'cvs:/hom/karsk/a/CVSROOT/linux', # The name to display for this source tree 'sourcerootname' => 'Codes', # The DBI identifier for the database to use # For mysql, the format is dbi:mysql:dbname=<name> # for Postgres, it is dbi:Pg:dbname=<name> # for Oracle, it is dbi:Oracle:host=localhost;sid=DEVMMS;port=1521 'dbname' => 'dbi:mysql:dbname=lxr', # If you need to specify the username or password for the database connection, # uncomment the following two lines # 'dbpass' => 'foo', # 'dbuser' => 'lxr', # For using glimpse, the directory to store the .glimpse files in is required # 'glimpsedir' => '/path/to/glimpse/databases', # Location of swish-e index database files if using swish-e # 'swishdir' => '/usr/local/lxr/src/$v', # where to look for include files inside the sourcetree. This is used to hyperlink # to included files. 'incprefix' => ['/include', '/include/linux'], # Which extensions to treat as images when browsing. If a file is an image, # it is displayed. 'graphicfile' => '(?i)\.(gif|jpg|jpeg|pjpg|pjpeg|xbm|png)$', #' # How to map files to languages # Note that the string for the key and the first entry in the # array MUST match 'filetype' => { # Format is # Language name, filepatten regexp, module to invoke, # (optional )tabwidth # Note that to have another language supported by Generic.pm, # you must ensure that: # a) exuberant ctags supports it # b) generic.conf is updated to specify information about the language # c) the name of the language given here matches the entry in generic.conf 'C' => ['C', '\.c$' #' , 'LXR::Lang::Generic', '8'], 'C++' => ['C++', '\.C$|((?i)\.c\+\+$|\.cc$|\.cpp$|\.cxx$|\.h$|\.hh$|\.hpp$|\.hxx$|\.h\+\+$)' #' , 'LXR::Lang::Generic', '8'], # Some languages are commented out until the relevant entries in generic.conf are made # The list here is the set supported by ctags 5.0.1 # ['Beta', '(?i)\.bet$' #' # , 'LXR::Lang::Generic'], # ['Cobol', '(?i)\.cob$' #' # , 'LXR::Lang::Generic'], # ['Eiffel', '(?i)\.e$' #' # , 'LXR::Lang::Generic'], # ['Fortran', '(?i)\.f$|\.for$|\.ftn$|\.f77$|\.f90$|\.f95$' #' # , 'LXR::Lang::Generic'], 'Java' => ['Java', '(?i)\.java$' #' , 'LXR::Lang::Java', '4'], # ['Lisp', '(?i)\.cl$|\.clisp$|\.el$|\.l$|\.lisp$|\.lsp$|\.ml$' #' # , 'LXR::Lang::Generic'], # No tabwidth specified here as an example 'Make' => ['Make', '(?i)\.mak$|makefile*' #' , 'LXR::Lang::Generic'], # ['Pascal', '(?i)\.p$|\.pas$' #' # , 'LXR::Lang::Generic'], 'Perl' => ['Perl', '(?i)\.pl$|\.pm$|\.perl$' #' , 'LXR::Lang::Generic', '4'], 'php' => ['php', '(?i)\.php$|\.php3$|\.phtml$' #' , 'LXR::Lang::Generic', '2'], 'Python' => ['Python', '(?i)\.py$|\.python$' #' , 'LXR::Lang::Generic', '4'], # ['rexx', '(?i)\.cmd$|\.rexx$|\.rx$' #' # , 'LXR::Lang::Generic'], # ['ruby', '(?i)\.rb$' #' # , 'LXR::Lang::Generic'], # ['scheme', '(?i)\.sch$|\.scheme$|\.scm$|\.sm$' #' # , 'LXR::Lang::Generic'], # ['shell', '(?i)\.sh$|\.bsh$|\.bash$|\.ksh$|\.zsh$' #' # , 'LXR::Lang::Generic'], # ['s-Lang', '(?i)\.sl$' #' # , 'LXR::Lang::Generic'], # ['tcl', '(?i)\.tcl$|\.wish$' #' # , 'LXR::Lang::Generic'], }, # Maps interpreter names to languages. The format is: # regexp => langname # regexp is matched against the part after #! on the first line of a file # langname must match one of the keys in filetype above. # # This mapping is only used if the filename doesn't match a pattern above, so # a shell script called shell.c will be recognised as a C file, not a shell file. 'interpreters' => { 'perl' => 'Perl', # 'bash' => 'shell', # 'csh' => 'shell', 'python' => 'Python', }, })
LXR 0.9.3 版本已经发布, 安装过程比较方便 , 生成网页的脚本修正了
不过安装前需要预先安装必须的工具(见附件MMagic)和glimpse最新版本
安装过程和0.9.2 基本相同,不需要手工运行glimpse, 由lxr 自己调用.