[内核分析]LXR安装心得(0.9.1版)

因为网络不通,无法使用服务器上的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 自己调用.

你可能感兴趣的:(安装)