
简介版本控制系统是团队协作与代码管理的核心工具SVN作为经典集中式版本控制方案在政企内网环境中依然广泛应用。在银河麒麟V10这类信创系统上受限于离线环境或yum源版本过旧直接安装往往无法满足生产需求。通过源码编译方式可以自主掌控依赖版本与安装路径解决APR、APR-util、SQLite等组件的兼容性问题。本文从源码编译原理出发详解SVN 1.8.14在银河麒麟上的完整构建流程包括依赖配置、svnserve服务部署、权限认证以及systemd自启管理为运维与研发人员提供一套可落地的内网SVN服务器搭建方案确保版本库稳定运行并支持多项目权限管控。1. 银河麒麟上自己编译 SVN为什么不能直接 yum以及这套步骤能解决什么拿到一台银河麒麟 V10想在上面装 SVN 服务器第一反应是yum install subversion。实际做的时候会发现离线内网环境下 yum 源要么连不上要么源里只有老掉牙的 1.6 版本。我这次是在一台只有基础软件包的麒麟机器上从源码编译了 subversion 1.8.14配合 apr、apr-util 和 sqlite 四个组件最后把仓库、权限、开机自启全部跑通。这份记录适合和我一样在内网搭 SVN 的运维或研发照着做能把一套独立可用的 svnserve 服务器立起来如果只是想在 Windows 上用 TortoiseSVN那不需要看这些服务器端才需要。整个编译过程没有“下一步下一步”的图形界面全部靠命令行。最坑的往往不是 SVN 本身而是它的两个前置依赖 APR 和 APR-util。下面从下载版本开始一步步拆开讲。2. 源码下载与版本组合SVN 1.8.14、APR 1.6.5、APR-util 1.6.1 与 SQLite 30715012.1 为什么是“源码编译”而不是 rpm信创环境的依赖现实银河麒麟底子是 CentOS 那一套理论上rpm -qa | grep subversion能看到系统自带 subversion但版本通常很旧。旧版本在客户端认证和权限控制上问题不少比如svnserve的安全配置解析不严格或者不支持某些authz写法。源码编译的好处是自己控制安装路径不污染系统目录坏处是必须先搞定依赖。SVN 的源码依赖关系是subversion 依赖 apr、apr-utilapr-util 又依赖 aprsqlite 则是被 subversion 源码内嵌调用的用于存储元数据。很多人编译 subversion 失败不是 SVN 本身问题而是 APR 没装对路径或者 SQLite 的 amalgamation 版本没放对位置。所以我会先把这四个包一次性下载齐全再开始编译。2.2 从 archive.apache.org 拉取四个包的下载命令老版本的 SVN 不在当前下载页而在 archive.apache.org 的归档目录下。Subversion 1.8.14、APR 1.6.5、APR-util 1.6.1 都能在归档目录里找到固定地址SQLite 的 amalgamation 压缩包单独从 sqlite.org 下载。我一般先把所有压缩包放到/home/dmdba/svn/这个目录下统一下载免得后面找文件。mkdir -p /home/dmdba/svn cd /home/dmdba/svn # 下载 subversion 源码包老版本走 archive wget http://archive.apache.org/dist/subversion/subversion-1.8.14.tar.gz # 下载 apr 和 apr-util wget http://archive.apache.org/dist/apr/apr-1.6.5.tar.gz wget http://archive.apache.org/dist/apr/apr-util-1.6.1.tar.gz # 下载 sqlite amalgamation 源码包 wget http://www.sqlite.org/sqlite-amalgamation-3071501.zip这段命令的路径很有讲究archive.apache.org/dist/后面跟的是项目名和版本号版本号必须和 SVN 1.8.14 的依赖要求匹配。SVN 1.8 的源码在 configure 时会对 SQLite 做版本检查3071501 是 SQLite 3.7.15.1 的 amalgamation 包名这个版本号是 SVN 1.8.14 编译时官方配套的。下载完成后建议先看文件大小是否合理。tar.gz一般几百 KB 到几 MB如果 wget 下来的文件只有几 KB八成是走了代理或被防火墙拦截成了 HTML 错误页。可以用md5sum做校验不过 archive.apache.org 没有为这些老包统一维护校验和我一般直接看解压能否完整通过。2.3 目录规划与解压校验避免后面 configure 找不到文件我习惯给每个源码包单独解压成一目录目录名保留版本号。不要图省事解压成apr、apr-util这种通用名否则你编译第二个依赖时会产生“到底是哪个版本”的错觉。cd /home/dmdba/svn tar -xzf apr-1.6.5.tar.gz tar -xzf apr-util-1.6.1.tar.gz tar -xzf subversion-1.8.14.tar.gz unzip sqlite-amalgamation-3071501.zip ls -l /home/dmdba/svn解压后你会看到/home/dmdba/svn/apr-1.6.5、/home/dmdba/svn/apr-util-1.6.1、/home/dmdba/svn/subversion-1.8.14以及一个sqlite-amalgamation-3071501目录。SVN 编译时找 SQLite 有两种方式一种是把sqlite3.c和sqlite3.h拷到 subversion 源码目录里另一种是 configure 时用--with-sqlite指定路径。包名版本解压目录作用apr1.6.5/home/dmdba/svn/apr-1.6.5提供跨平台基础库SVN 必需apr-util1.6.1/home/dmdba/svn/apr-util-1.6.1APR 的工具库SVN 配置解析依赖subversion1.8.14/home/dmdba/svn/subversion-1.8.14SVN 主程序sqlite-amalgamation3071501/home/dmdba/svn/sqlite-amalgamation-3071501内嵌数据库SVN 元数据存储目录规划这一步经常被跳过但很重要。APR 编译安装后的实际路径是/usr/local/apr跟源码目录/home/dmdba/svn/apr-1.6.5不是一回事。后面 configure 参数指向的是安装路径不是源码路径。如果你把--with-apr错写成源码目录configure 时会直接报“APR not found”或者“invalid APR”一类错误。3. 编译安装三步 make 与 configure 参数背后的绑定关系3.1 先装 APR--prefix 是安装根不是源码目录APR 是 Apache Portable RuntimeSVN 依赖它做文件操作、网络通信和线程管理。编译顺序必须先把 APR 装好因为 APR-util 和 SVN 都要找它。cd /home/dmdba/svn/apr-1.6.5 ./configure --prefix/usr/local/apr make make install--prefix指定安装根目录/usr/local/apr装好后可执行文件在$prefix/bin库文件在$prefix/lib。我一般会把安装路径固定下来方便后面两个 configure 引用。这一步如果机器上没有 C 编译器会提示configure: error: no acceptable C compiler found in $PATH这时候需要先安装gcc和make内网环境可以用麒麟系统自带的安装介质。APR 编译时间很短通常一两分钟。如果 configure 过程卡在“checking for APR... no”之类先检查/usr/local/apr是否真的生成。不要在这里偷懒用./configure不带 prefix默认装到/usr/local会让后面 SVN 的--with-apr定位困难。3.2 再装 APR-util必须用 --with-apr 指认上一轮结果APR-util 是 APR 的上层工具库负责 XML 解析、数据库访问等。它本身不依赖 SVN但 SVN 强烈依赖它。configure 时最关键的是--with-apr参数得让它明确找到上一步安装的 APR。cd /home/dmdba/svn/apr-util-1.6.1 ./configure --prefix/usr/local/apr-util --with-apr/usr/local/apr make make install--prefix/usr/local/apr-util是 APR-util 自己的安装目录--with-apr/usr/local/apr是 APR 的安装根目录。这两个路径经常有人写反或者漏写--with-apr结果 configure 去系统库里找 APR找到的是 CentOS 自带版本版本不匹配后面 SVN 编译照样挂。如果你在 configure 时看到checking for APR... no先冷静看一下是不是/usr/local/apr/bin/apr-1-config这个文件存在。APR-util 是通过apr-1-config脚本定位 APR 的路径错一个字母都找不到。3.3 最后编 SVN 本体把 APR、APR-util、SQLite 三件事一次讲清SVN 1.8.14 的 configure 需要同时指定 APR、APR-util还要让 SQLite 能通过编译。这一步最容易翻车因为三个依赖都要一次性给全。cd /home/dmdba/svn/subversion-1.8.14 # 如果 configure 找不到 sqlite把解压出的 sqlite3.c 和 sqlite3.h 放到本目录 cp /home/dmdba/svn/sqlite-amalgamation-3071501/sqlite3.c . cp /home/dmdba/svn/sqlite-amalgamation-3071501/sqlite3.h . ./configure --prefix/usr/local/svn \ --with-apr/usr/local/apr \ --with-apr-util/usr/local/apr-util \ --with-sqlite/home/dmdba/svn/sqlite-amalgamation-3071501 make make install这段参数的含义--prefix/usr/local/svn是 SVN 自己的安装目录装好后svnserve在/usr/local/svn/bin/--with-apr和--with-apr-util分别指向上一步的两个安装目录--with-sqlite指向 sqlite-amalgamation 解压目录这个目录里必须有sqlite3.c和sqlite3.h。有个常见做法是只把sqlite3.c和sqlite3.h复制到当前目录然后用./configure自动检测。我习惯把--with-sqlite写明确避免它跑到系统其他路径找一个旧 sqlite。configure 完成后注意最后的 summary 输出里面会列出Features:和Available filesystem backends:正常情况应该包含fsfs。3.4 环境变量 PATH 与版本自检编译完成后/usr/local/svn/bin/svnserve已经存在但/usr/local/svn/bin还没进 PATH。如果不配置环境变量直接敲svnserve会提示 command not found。vim /etc/profile # 在文件末尾追加 export PATH$PATH:/usr/local/svn/bin # 保存后执行 source /etc/profile # 验证版本 svnserve --version这里有个细节source /etc/profile只在当前 shell 生效。如果你重新开一个终端或者通过 SSH 远程执行部署脚本PATH 还是会丢。所以实际工作时我更喜欢直接创建/etc/profile.d/svn.sh并在里面写export PATH$PATH:/usr/local/svn/bin这样所有新 shell 登录都会自动加载。svnserve --version输出里会显示svnserve, version 1.8.14同时列出它支持的 repository backends确认这一步没白装。4. 创建仓库与配置权限svnserve.conf、passwd、authz 三个文件的完整落地4.1 仓库根目录与 svnadmin create一个目录就是一个仓库SVN 和 Git 不同它没有中央裸仓库的概念svnadmin create会在指定目录生成一套仓库格式。我这边把/home/svn作为所有版本库的根目录每个项目单独建子目录比如/home/svn/project。这样做的好处是 svnserve 启动时-r直接指到根目录客户端访问 URL 就能用svn://IP/项目名不用把整个磁盘路径暴露出去。mkdir -p /home/svn/project svnadmin create /home/svn/project ls /home/svn/project执行完ls能看到conf/、db/、hooks/等目录。其中conf/是三个核心配置文件所在svnserve.conf、passwd、authz。db/是真实数据hooks/是服务端钩子脚本目录。很多新手到这一步就开始改配置结果把db/当成数据重复目录实际上你只需要关心conf/。4.2 svnserve.conf先关匿名再开写权限svnserve 的配置文件在conf/svnserve.conf它控制服务端整体行为。最基础的四个配置项是匿名访问、认证访问、密码文件和权限文件。vim /home/svn/project/conf/svnserve.conf[general] anon-access none auth-access write password-db passwd authz-db authz第一行anon-access none表示匿名用户不允许任何操作这是最重要的安全开关。如果写成read任何人都能匿名拉代码。auth-access write表示认证用户可读写。password-db passwd指定用户名密码文件为同目录下的passwdauthz-db authz指定权限文件为authz。原笔记里特别警告过这个文件的首行不能留空而且[general]必须顶到行首。我实测过确实如此svnserve 对 ini 格式解析极严格行首有空格会报配置错误。另外这些配置项不能出现在[general]前面否则 svnserve 会当成未知段落直接忽略。4.3 passwd用户名与密码的写法及不要犯的格式错passwd文件非常直白[users]段落下面一行一个用户格式是用户名密码。vim /home/svn/project/conf/passwd[users] admin123456要注意等号两边不要留空格admin 123456这种写法在某些 svnserve 版本里会把空格也算进密码导致客户端认证失败。这个文件默认存在且内容被注释掉了所以你先确认 [users] 段没被注释。密码只是演示用实际生产环境至少 8 位以上的强口令因为svnserve的认证协议本身不加密在内网也最好别裸奔。4.4 authz用户组、根目录权限与“其余人全禁”authz文件负责控制用户能读、能写哪些目录。它是 svnserve 权限模型的灵魂也是在客户端用 SVN 时最容易出怪问题的地方。vim /home/svn/project/conf/authz[groups] g_admin admin [/] g_admin rw * 第一段[groups]是用户组定义g_admin admin表示把用户admin放进组g_admin。第二段[/]表示仓库根目录g_admin rw给这个组读写权限* 则是把其他用户全部禁掉空值表示无任何权限。注意组名前面必须带符号否则 svnserve 会把它当成普通用户名。原笔记把[/]注释成“对根目录 trunk 的权限”这是个容易误导人的地方。实际[/]就是整个仓库根不是 trunk。如果你只想给某条路径开权限应该写成[/trunk]这种绝对路径格式。多个用户组可以逗号分隔比如g_admin, g_rd rw。4.5 多项目场景下权限策略怎么扩展当/home/svn下有多个项目仓库时svnserve 的-r参数只指到/home/svn权限文件按仓库隔离。每个仓库自己的authz只管自己的路径。[groups] g_admin admin g_rd reader [/] g_admin rw g_rd r * 如果你想给只读用户开放访问就把g_rd写进[groups]并在根目录给r权限。这个“只有管理员能写、其他用户只能读”的配置在内网很常用。要注意的是authz是按用户和路径做匹配的路径匹配优先级是从最具体的段开始到根目录。如果配置了[/trunk]却没有给[/]任何权限用户访问根目录时会直接Permission denied不要把这个报错当成仓库不存在。5. 避坑与排查五个我在银河麒麟上踩过的真实问题5.1 svnserve.conf 首行空格导致配置解析失败现象svnserve 启动后客户端连不上查进程svnserve还活着但访问任何仓库都报svnserve.conf:2: Option expected或者直接Cant open file /home/svn/project/conf/svnserve.conf: No such file or directory后者其实是配置文件读不了时的误报。原因配置文件[general]那一行前面有空格或者文件以空行开头。svnserve 的配置解析不像 Windows ini 那么宽容行首空白会让它认为这不是一个合法 section。解决用sed -i s/^ *// /home/svn/project/conf/svnserve.conf去掉每行行首空格再检查文件第一行确实是[general]。以后修改配置我坚持用cat -A看看行尾和空白字符尤其从 Windows 复制过去的文件还可能出现^M换行符问题也顺手用sed -i s/\r$//清掉。5.2 configure 时找不到 APR 或 expat 开发包现象编译 subversion 时./configure卡在checking for APR...然后输出configure: error: APR not found或者报libexpat找不到。原因要么--with-apr路径写错要么系统缺少 expat 开发包。APR 本身编译问题不大但 SVN 的配置解析、版本库 diff 功能都会用到 expat。银河麒麟离线环境下yum 源里未必有expat-devel。解决首先确认/usr/local/apr/bin/apr-1-config是否存在不存在就回到第 3 章重新编译 APR。缺 expat 时直接yum install expat-devel或者从安装光盘找 rpm 包装上。装完后再跑 configure 就会看到checking expat.h presence... yes。5.3 缺 SQLite amalgamation 导致 make 中途退出现象configure 顺利通过make编译到一半突然报错sqlite not found或subversion-1.8.14/sqlite3.c: No such file or directory。原因SVN 1.8 源码没有内置 SQLite 文件。SQLite 的 amalgamation 包解压后要放到能被编译器找到的位置。我见过很多人下载了sqlite-amalgamation-3071501.zip但解压后忘了指定--with-sqliteconfigure 没报错到 make 阶段才露馅。解决把sqlite3.c和sqlite3.h复制到subversion-1.8.14源码根目录或者在 configure 时显式加--with-sqlite/home/dmdba/svn/sqlite-amalgamation-3071501。随后重新 configure 并 make通常能过。如果还报cannot find SQLite检查一下版本号3071501 是配套 1.8.14 的换成更高版本可能反而出现不兼容。5.4 客户端连不上-r 根目录、端口与仓库路径的关系现象Windows 上 TortoiseSVN 访问svn://服务器IP/project报No repository found或Cant connect to host。原因分两层。第一层是svnserve -d -r /home/svn的根目录和仓库路径不匹配。如果启动时写的是-r /home/svn/project那客户端 URL 必须变成svn://IP/因为/project已经被当作根目录了。第二层是防火墙没放行 3690 端口。解决先用ps -ef | grep svnserve看启动参数确认-r /home/svn再检查监听端口netstat -tlnp | grep 3690。如果一切正常但客户端连不上多半是防火墙拦了执行firewall-cmd --permanent --add-port3690/tcp firewall-cmd --reload。我还会顺手用telnet IP 3690做端口连通性测试比在 SVN 客户端反复试快得多。5.5 重启后 svnserve 不在了rc.local 脚本的隐藏坑现象配好/root/svn.sh和/etc/rc.d/rc.local后重启发现 svnserve 没启动ps -ef | grep svnserve空无一物。原因rc.local执行时环境变量不像登录 shell 那么完整脚本里直接写svnserve系统找不到/usr/local/svn/bin/svnserve或者脚本没有执行权限或者/etc/rc.d/rc.local本身没有可执行权限银河麒麟上默认可能没有 x 权限。解决脚本内用绝对路径/usr/local/svn/bin/svnserve -d -r /home/svn给chmod 755 /root/svn.sh并检查ll /etc/rc.d/rc.local没有 x 权限就chmod x /etc/rc.d/rc.local。从那次之后我每次改自启脚本都用bash -x /root/svn.sh先在前台跑一遍确认没有路径和权限问题再重启验证。6. 开机自启增强与端口验证给 SVN 服务加一道“后悔药”最后一件事是验证整套服务真的能用并且把开机自启从“能跑”改成“自动拉起来”。光靠rc.local其实有隐患因为如果 svnserve 已经运行再执行一次启动会报地址占用。我后来改用 systemd 管理银河麒麟 V10 对 systemd 支持很好服务单元文件比 rc.local 更省心。cat /etc/systemd/system/svnserve.service EOF [Unit] DescriptionSubversion server Afternetwork.target [Service] Typeforking ExecStart/usr/local/svn/bin/svnserve -d -r /home/svn ExecStop/usr/bin/kill -TERM $MAINPID PIDFile/run/svnserve.pid [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable svnserve systemctl start svnserve这个 service 单元有几个关键点Typeforking对应 svnserve 的-d后台模式ExecStart写了绝对路径避免 PATH 没加载的问题。启用后重启机器直接systemctl status svnserve就能看到 active (running)。这套方式比rc.local靠谱得多因为 systemd 会在网络就绪后再拉起服务重启后不会出现脚本早于网络启动造成的失败。日常维护有个习惯我保留至今每次改了conf/里三个文件后我不会直接杀进程而是先跑/usr/local/svn/bin/svnserve --version确认二进制还在再用systemctl restart svnserve平滑重启。验证端口时用ss -tlnp | grep 3690而不是netstat因为新版麒麟上 netstat 不一定默认安装。从那以后我在内网机器上装 SVN 都强制走这一整套下载归档源码、编译三次、配置三个文件、systemd 管服务、重启后先看ps -ef | grep svnserve再决定要不要查端口。这套流程的每一步都反馈到自己的检查清单上再也没有出现过“明明配好了第二天重启就丢服务”的尴尬。希望帮到你。本文还有配套的精品资源点击获取