svn

Win32平台下编译SVN源码全过程

5

前段时间曾经总结过一些在win32平台下基于SVN开发的一些注意事项,主要是在利用svn官方发布的二进制库进行开发过程中使用的方法和一些值得注意的问题。

 

由于svn官方发布的win32平台下的二进制文件是基于vc6编译的,在使用vc2005进行开发时,会遇到因CRT冲突而引起的link错误。因此,如果是使用vc2005(我推测使用VC2003也会遇到同样的问题,尚未验证)附带的CRT库与svn官方发布的binary进行link,那么无论如何都会出现crash的问题。最为彻底的解决方案,还是自行编译svn源码。

 

在win32下编译svn源码说明:

 首先需要从官方下载一份SVN源码,版本可以根据需要选取,比如最新的Release 1.6.3(目前已经更新到1.6.6)可以在这个地址下载到:

http://subversion.tigris.org/downloads/subversion-1.6.3.zip

以及svn所需的依赖包:

http://subversion.tigris.org/downloads/subversion-deps-1.6.3.zip

如果需要支持ssl的话,还需要下载openssl(根据实际需要选择相应版本):

http://www.openssl.org/source/

如果需要BerkeleyDB的话,需要下载WindowsBDB(BDB是可选的,如果不使用BDB,则默认使用FSFS):

http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=688&expandFolder=688&folderID=2627

此外还有Windows libintl:

http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=2627&expandFolder=2627&folderID=8100

 

 

解压svn源码包,可以在subversion-1.6.3目录中找到这么一个官方发布的说明文件INSTALL。该文件详述了安装通过源码编译SVN所需依赖的工具及第三方库,并且给出了详细的步骤。

网上同样有一个INSTALL的说明,可以在这里访问到:

http://svn.collab.net/repos/svn/trunk/INSTALL

 

编译开源项目的话,其附带的INSTALL说明都是最重要也是最全面的参考。网上搜索的其他资料,也会有相应的参考价值,但无论如何,其信息的来源也是INSTALL。因此编译开源项目时,认真阅读INSTALL是最重要且效率最高的。

 

从Google上进行一下简单的搜索的话,可以找到一篇介绍svn源码编译的文章,在这里:http://rocksun.cn/?p=103

 

为了后续的步骤方便,我们需要先准备编译所必须的一些东西:

包括Perl:http://www.activestate.com/activeperl/

Python:http://www.python.org/download/

 

 

安装Python以及Perl,比如分别安装到D:\Python26以及D:\Perl。安装好之后,将python以及perl的bin目录设为系统目录并重新启动使之生效。

 

编译svn源码第一步,将下载的svn源码包解压到X:\SVN\svn—trunk下。X可以是任意一个盘符。在我的机器上,我使用了F盘,下文中皆以F盘举例。

 

在F:\SVN\svn-trunk中解压了刚才下载的svn源码包以及依赖之后,可以在目录

F:\SVN\src-trunk\subversion-1.6.3中看到以下文件及目录:

以及文件:

Svn的编译需要依赖libapr以及libapr-util,SQLite,zlib,libintl可选,libneon/libserf二则择一,openssl可选,BerkeleyDB可选,libsasl可选,对Python,Perl,Java,Ruby支持的模块可选,以及KDELibs,GNOME Keyring可选。

 

我们依次先编译依赖项:首先进入到subversion-1.6.3\apr目录中。可以看到存在apr.dsw以及apr.dsp文件,这是VC6的工程文件。我们如果想在2005下编译的话,需要将其转换成sln及vcproj文件,简单的用vc2005打开该文件并保存即可。该目录下还有Makefile.win文件,是win下的makefile,我们打开makefile.win文件查看一下说明:可以得知如果需要编译.sln文件的话,需要置USESLN=1。

 

在VC2005的命令行中输入nmake -f makefile.win buildall checkall USESLN=1便可以开始编译apr了。Checkall表示编译完成后会去运行所有的测试用例。

 

编译完成后,当前目录下会多出2个文件夹,分别是LibR – StaticRelease,Release – DllRelease。如果选择Debug编译,则会生成LibD – StaticDebug, Debug – DllDebug。

 

类似的,我们将apr-util以及apr-iconv也编译好。

 

编译zlib:

进入zlib目录后,使用以下命令编译zlib库

nmake -f win32/Makefile.msc

 

编译openssl:

将此前下载的openssl解压到F:\SVN\openssl

阅读其INSTALL文档(INSTALL.W32)

使用VC编译openssl首先需要运行configure:

perl Configure VC-WIN32

接着运行

ms\do_masm

这里的do_masm是一个bat脚本,该脚本会生成nt.mak以及ntdll.mak分别是Release版本的静态和动态的库的make文件。如果想生成debug版本的make文件,可以通过修改do_masm.bat中的调用mk1mf.pl脚本处的参数实现,具体参数可以参考mk1mf.pl文件自身的说明。

接下来,创建动态链接库版本的ssl库用nmake -f ms\ntdll.mak,以及静态版本使用:nmake -f ms\nt.mak

生成的结果文件位于out32dll文件夹,以及out32文件夹中。

 

编译neon

进入F:\SVN\src-trunk\subversion-1.6.3\neon目录

nmake –f neon.mak

默认生成的是release版的libneon.lib (debug版为libneonD.lib)

可以用nmake –f neon.mak DEBUG_BUILD=1生成debug版的lib。

 

回到F:\SVN\src-trunk\subversion-1.6.3

运行python gen-make.py –help可以了解如何使用gen-make.py生成我们所需的svn编译文件。

由于在此,我打算选用neon, libintl, openssl(本例中并不打算使用BDB,如果需要BDB则需要增加—with-berkeley-db=DIR参数)进行编译,目前需要关注的几个重要参数如下:

–with-apr=DIR

–with-apr-util=DIR

–with-apr-iconv=DIR

–with-neon=DIR

–with-libintl=DIR

–with-openssl=DIR

–with-zlib=DIR

–vsnet-version=VER

 

运行

F:\SVN\src-trunk\subversion-1.6.3>python gen-make.py -t vcproj

–with-apr=apr –with-apr-iconv=apr-iconv –with-apr-util=apr-util –with-libintl=svn-win32-libintl –with-openssl=..\..\openssl –with-zlib=zlib –vsnet-version=2005

 

(其中的libintl需要解压到当前文件夹中)

即可生成vc2005的sln(subversion_vcnet.sln)文件了。

 

打开vc2005,选择Debug编译选项,对项目ALL进行编译。如果一切顺利,则会生成一个F:\SVN\src-trunk\subversion-1.6.3\Debug目录。内容包括svn的所有的lib及可执行文件。

将svn\svn.exe以及所有目录下的.dll文件拷贝到一个新建的bin目录下。将openssl的dll,apr, apr-util, apr-iconv的dll拷贝到同样的bin目录下,如下图:

运行svn –version看看结果吧~

 

最后,当我们有了自行编译的svn可以做什么?你可以做任何你想做的事——比如自己基于svn的接口进行开发(可以参考开源项目rapidsvn以及TortoiseSVN的源码)

subversion_logo_hor-468x64

Win32平台下基于SVN开发的若干问题整理

16

 

Keywords: svn  svn_cmdline_init crash 1.5.6 win32

subversion_logo_hor-468x64

 SVN(SubVersion)是目前开源的版本管理工具中较为流行的,最新的release是1.6.1。但是遗憾的是基于SVN开发的资料在互联网上异常的少。

         最近一段时间,我在工作上需要编写一个使用SVN进行版本管理的编辑器。(需要对编辑器生成的文件做版本管理以利于多人合作开发)起初是通过调用svn自身携带的的客户端程序svn.exe以实现相关功能,然而由于实际中的若干设计问题,最终的速度很不理想。于是产生了借用svn自身提供的api接口实现所需功能的想法。

 

         在实际使用svn提供的api时遇到了一些问题,经过多番查找资料以及尝试最终得以解决。将问题整理在此,以方便日后与我遇到类似问题的朋友。

 

         Svn提供的第三方开发接口sdk可以在这里下载到。目前最新的release是1.6.1。我在项目中实际使用的版本是1.5.6。开发需要的几个压缩包分别如下:

Svn发布的2进制可运行文件,包括客户端与服务端,以及所需的dll:

http://subversion.tigris.org/files/documents/15/45230/svn-win32-1.5.6.zip

Svn开发所需的lib及头文件以及文档:

http://subversion.tigris.org/files/documents/15/45236/svn-win32-1.5.6_dev.zip

Svn的调试符号文件:

http://subversion.tigris.org/files/documents/15/45234/svn-win32-1.5.6_pdb.zip

 

此外,在编写基于SVN的程序时,在链接时还有一些必要的库需要添加,分别是:

Berkeley DB for Windows:

http://subversion.tigris.org/files/documents/15/32472/db-4.4.20-win32.zip

libintl binaries for Windows:

http://subversion.tigris.org/files/documents/15/20739/svn-win32-libintl.zip

 

有了这几个包,就可以使用SVN提供的api开发基于SVN的第三方软件了。

 

         基于SVN1.5及之后的版本开发的时候,会遇到一个CRT冲突的问题,该问题会导致在调用svn_cmdline_init时,如果在error stream参数中传入非NULL值,则会直接crash。一个针对该问题的描述可以参见这里

         我下载了调试符号以及源代码之后,跟踪调试到svn_cmdline_init函数当中,发现crash发生在一个CRT函数(setvbuf)的调用当中。实际跟踪调试的过程中发现,虽然该函数是crt中的函数,然而vc调试器却无法基于本地的调试符号正确跟踪到其源文件当中。

又该问题在1.4及之前的版本不存在。究其原因,我猜测可能是由于自1.5版本之后,SVN提供的库是基于动态链接的CRT库的。而svn本身的lib在编译时链接的crt与客户的VC6的CRT版本不符导致的。(1.4版本之前则是静态链接的CRT)

对该问题的描述还可以参见这里

 

The problem is stderr — it is a FILE* which is a CRT type which means 
you have to be using the same CRT as the dll’s were built with. 
Unfortunately, there are a few API’s where raw CRT types crept in that 
aren’t wrapped by APR. 

You can either avoid those API’s, rebuild Subversion with your 
compiler, or link to the static libraries instead of the dynamic 
libraries and use the no-default-libs option to make sure that your 
CRT is linked in instead of the VC6 one (I believe this is how it 
worked prior to 1.5). 

DJ 

 

解决该问题的方法之一是自行编译svn的全部源码,而不使用官方提供的dev包。然而svn的源码编译要求的环境异常复杂(需要配置非常多的环境项:包括cygwin,python等等)。更简单的解决方案是使用静态链接版本的svn库。

svn_cmdline_init位于libsvn_subr-1.lib当中。该版本的lib在1.5及以后的版本开发包中是动态库,实际运行时需要libsvn_subr-1.dll的支持。同在该开发包中发布的还有一个静态版本的该库,名为svn_subr-1.lib。

但是链接静态版本的svn_subr-1.lib时,由于其中静态链接了CRT库,因此VC自带的libcmt.lib/libcmtd.lib会与之冲突。实际链接时会报出一堆同一个符号被多次链接的错误,只需将VC自带的libcmt.lib/libcmtd.lib设置忽略即可。

Go to Top