ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

银河麒麟内网SVN 1.8.14源码编译与svnserve配置实战

银河麒麟内网SVN 1.8.14源码编译与svnserve配置实战 简介面向银河麒麟国产 Linux服务器运维人员与研发环境搭建者的实践文档聚焦内网或离线场景下从源码编译安装 Subversion 及其依赖组件的完整流程帮助读者解决系统软件源缺失、自带版本偏旧导致 SVN 难以直接部署的问题。资源为 docx 文档压缩包内共 1 个文件约 202KB篇幅紧凑、按操作顺序编排可直接对照执行。内容覆盖 apr、apr-util、sqlite-amalgamation 与 subversion 指定版本的获取途径及 configure、make 编译参数/etc/profile 环境变量追加与 source 生效验证版本库根目录规划与 svnadmin create 建库以及 svnserve.conf、passwd、authz 三个配置文件的具体写法并特别提示首行顶格等易被忽略的配置错误此外还给出 svnserve 后台启动命令与写入 rc.local 实现开机自启的脚本做法。目前已有 2798 人学习下载适合需要快速在麒麟系统上落地 SVN 服务、规避权限与路径问题的读者参考。1. 内网机器上的版本库为什么我坚持源码编 subversion-1.8.14内网里那台银河麒麟服务器长期被当成共享盘用同事在文件名后缀里写_final_v3_改改回滚只能靠翻聊天记录。银河麒麟 SVN 环境这件事真正难的不是svnserve那几行命令而是发行版自带源里的 subversion 常常缺胳膊少腿svnadmin能跑svnserve起来就报共享库找不到或者版本对不上 sqlite。我一般走源码路线把 apr-1.6.5、apr-util-1.6.1、subversion-1.8.14 和 sqlite-amalgamation-3071501 一起落到/usr/local好处是版本可控、依赖不污染系统、出问题删目录就干净了。这套做法适合在内网替小团队搭版本库、又不想动系统包管理的运维和开发。2. 依赖三板斧apr、apr-util、sqlite 的编译顺序与参数2.1 为什么 subversion 1.8 绕不开 apr 和 apr-utilSubversion 从诞生那天起就把 APRApache Portable Runtime当成底座svnserve的网络监听、内存池、文件路径处理全部走 APR 的接口apr-util则在 APR 之上补了数据库抽象、XML 解析、Base64 编码这些能力subversion 的 DAV 与认证模块会用到它。也就是说你编出来的svnserve二进制和libapr-1.so、libaprutil-1.so是运行期绑定的不是静态塞进去就完事。那为什么不直接yum install apr apr-util subversion了事两条血泪经验。第一系统源的 apr 版本是跟着发行版冻结的可能比 subversion 1.8 需要的还老或者干脆被别的组件锁死你动它就可能把系统上别的服务带崩。第二多数组件编译时默认会去/usr找apr-1-config一旦它和系统里已有的 apr 混用编出来的 subversion 在链接期就出现符号冲突报错信息还特别绕。所以我选择把依赖全部装到独立前缀下用--with-apr、--with-apr-util精确点名谁也不污染。这套组合的对应关系是这样的组件版本安装前缀在链路里的角色apr1.6.5/usr/local/apr内存池、文件、网络抽象层apr-util1.6.1/usr/local/apr-utilXML、编码、数据库抽象依赖 aprsqlite amalgamation30715013.7.15.1编进 subversion 源码树版本库工作队列的本地库subversion1.8.14/usr/local/svnsvnserve、svnadmin、svn 客户端编译顺序有硬约束apr → apr-util → subversion。apr-util 的configure要拿 apr 的头文件和apr-1-config脚本subversion 又要同时拿两者的配置脚本顺序错了就只能在报错里原地打转。2.2 目录约定与解压先把工作区定死源码包从外部拷进内网机器之后别急着解压到/usr/local或者家目录乱放。我习惯在一个目录里把所有源码铺开编译完保留着日后想换参数重编不用重新传包。原文里用的是/home/dmdba/svn/这个约定挺好照抄就行。# 统一工作目录所有源码包都放这里 mkdir -p /home/dmdba/svn 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 -q sqlite-amalgamation-3071501.zip # 确认目录都在避免后面 cd 到不存在的路径 ls -d apr-1.6.5 apr-util-1.6.1 subversion-1.8.14 sqlite-amalgamation-3071501这段没有技术含量但省掉了后面一半的「路径写错」类翻车。tar -xzf里的z表示 gzipunzip是因为 sqlite 的 amalgamation 包给的是 zip 而不是 tar.gz这一点很多人第一次会顺手敲tar -xzf sqlite-amalgamation-3071501.zip然后拿到一句 gzip: stdin: not in gzip format。全程用 root 操作避免make install阶段因为目录权限半途失败、留下半套文件。2.3 apr-1.6.5--prefix是唯一必须想清楚的参数cd /home/dmdba/svn/apr-1.6.5 # 装到独立前缀不覆盖系统 /usr 下的 apr ./configure --prefix/usr/local/apr # 并行编译加速装完检查返回码 make -j$(nproc) make install--prefix/usr/local/apr决定了三件事头文件去/usr/local/apr/include/apr-1库文件去/usr/local/apr/lib配置脚本去/usr/local/apr/bin/apr-1-config。后面 apr-util 和 subversion 的--with-apr参数指的就是这个前缀不是bin目录也不是include目录。make -j$(nproc)用满核数apr 本身不大几秒就完如果你在虚拟机上碰到virtual memory exhausted之类的报错把-j降成-j2或者干脆去掉并行别硬扛。装完可以立刻验证一下前缀里到底落了什么这一步比事后 debug 便宜得多/usr/local/apr/bin/apr-1-config --version # 应输出 1.6.5 ls /usr/local/apr/lib/libapr-1.so* # 应有 .so 和 .so.0 软链apr-1-config --version能回出版本号说明--prefix生效了后面的组件就能靠这个脚本问出正确的头文件与库路径。2.4 apr-util-1.6.1--with-apr必须精确指向前缀cd /home/dmdba/svn/apr-util-1.6.1 # --with-apr 指向刚装好的 apr 前缀不能省 ./configure --prefix/usr/local/apr-util --with-apr/usr/local/apr make -j$(nproc) make install--with-apr/usr/local/apr是这一章最容易写错的一个参数。如果你省掉它configure会自己去PATH里找apr-1-config找到的极可能是系统/usr/bin/apr-1-config于是 apr-util 一半头文件来自/usr/include、一半来自/usr/local/apr/include编出来的.so里带着两套符号等到 subversion 链接时才会以undefined reference to apr_pool_create_ex这类面目出现排查成本极高。编译 apr-util 时若报错说找不到 expat属于常见情况它的 XML 支持依赖 expat 开发包。常规做法是先把系统侧的头文件补齐再重跑configure# 麒麟系统一般自带 yum新版可能是 dnf 的软链两者都试一下 yum install -y expat-devel zlib-devel openssl-devel # 装完清掉上次的 configure 缓存重新来 cd /home/dmdba/svn/apr-util-1.6.1 make clean ./configure --prefix/usr/local/apr-util --with-apr/usr/local/apr make -j$(nproc) make install装完同样验一遍/usr/local/apr-util/bin/apu-1-config --version要能回出版本且ldd出来的 apr-util 库文件指向的是/usr/local/apr/lib/libapr-1.so.0而不是/usr/lib64下的同名文件。2.5 sqlite amalgamation唯一不需要 configure 的依赖sqlite 的 amalgamation 包不是常规的 autotools 工程解压出来只有一个sqlite3.c加一个sqlite3.h老版本包里还有shell.c没有configure也没有Makefile。它在 subversion 1.8 的构建体系里扮演的是「源码级依赖」的角色——subversion 自己的构建脚本会去找源码根目录下的sqlite-amalgamation子目录把sqlite3.c直接编进libsvn_subr。所以正确的落地方式不是单独编译安装而是把它放进 subversion 源码树cd /home/dmdba/svn # 目录名必须是 sqlite-amalgamationsubversion 的构建脚本按这个约定找 mv sqlite-amalgamation-3071501 sqlite-amalgamation cp -r sqlite-amalgamation subversion-1.8.14/ # 确认关键文件在位 ls subversion-1.8.14/sqlite-amalgamation/sqlite3.c目录名这一条是实打实的坑你叫sqlite-amalgamation-3071501configure 阶段不报错make到了链接svnserve的时候才给你一句找不到sqlite3_open之类的符号。因为前面 configure 只是「没检测到自带 sqlite」于是它转头去找系统里已安装的 sqlite3 库系统的版本又可能不满足 1.8 分支的要求报错就发生在很靠后的位置。改成约定的名字等于把这条路走通。3. 编 subversion-1.8.14configure 参数与报错的对应关系3.1 configure 之前先确认三件事第一件是编译器与构建工具。银河麒麟桌面版和服务器版默认不一定装gcc最小化安装的系统经常只带gcc-c或干脆没有。# 逐个确认缺什么装什么 gcc --version | head -1 make --version | head -1 # 一次性补齐编译期依赖避免 configure 反复中断 yum install -y gcc make zlib-devel expat-devel openssl-devel第二件是/usr/local的写权限和磁盘空间。/usr/local单独挂载且配额很小的机器不是没见过装到一半No space left on device前面 apr、apr-util 全要重来。df -h /usr/local看一眼几十兆就够但心里有数。第三件是系统里有没有装过 subversion。如果之前yum install subversion过/usr/bin/svn和/usr/local/svn/bin/svn会同时存在PATH里谁在前谁生效日后运维时会莫名其妙调用到旧版。要么先卸掉系统包要么在/etc/profile里把/usr/local/svn/bin放在PATH前面别用PATH$PATH:...的追加写法。3.2 configure 参数逐项拆每个--with都指向一个具体前缀cd /home/dmdba/svn/subversion-1.8.14 ./configure \ --prefix/usr/local/svn \ --with-apr/usr/local/apr \ --with-apr-util/usr/local/apr-util \ --without-serf--prefix/usr/local/svn决定最终的bin、lib、include落点svnserve、svnadmin、svnlook、svn全部装到/usr/local/svn/bin。--with-apr和--with-apr-util分别指向两个前缀configure 会去前缀/bin下找apr-1-config、apu-1-config问出头文件与库的准确路径。这两个参数写错一个字符configure 就会退回系统默认路径编出来的东西在运行期报共享库版本不匹配。--without-serf这一项要看你的用途。serf 是 HTTP/DAV 协议的客户端库svn走http://、https://访问远端仓库时才需要。本文这套环境只做svn://的 svnserve加上它反而要多装一个依赖直接关掉最省事。不写这个参数也不会编不过configure 检测不到 serf 只是打一行警告然后禁用但那行警告埋在几十行输出里容易被忽略。至于 sqlite如果你已经按 2.5 把目录塞进源码树configure 会自动接管输出里能看到它采用内置的 sqlite3.c。个别版本识别不到时可以显式指定源码目录# 备选自动识别失败时显式指定 sqlite 源码目录 ./configure --prefix/usr/local/svn \ --with-apr/usr/local/apr \ --with-apr-util/usr/local/apr-util \ --with-sqlite/home/dmdba/svn/subversion-1.8.14/sqlite-amalgamation \ --without-serfconfigure 输出最后会打印一份摘要重点看三行APR的版本与前缀、APR-UTIL的版本与前缀、SQLite的来源是internal还是系统路径。三行都对上你再敲 make对不上现在改还来得及。3.3 make 阶段报错位置决定了排查方向cd /home/dmdba/svn/subversion-1.8.14 # 并行编译失败先看最后一个 error 而不是第一个 warning make -j$(nproc) make installsubversion 的源码体量比 apr 大一个量级make会跑上几分钟。中途报错时别从头翻直接看最后一个error:。三类报错各有对应关系出现cannot find -lsqlite3或undefined reference to sqlite3_*说明内置 sqlite 没被识别回 2.5 检查目录名出现cannot find -lapr-1说明链接期找不到 apr 的库目录/usr/local/apr/lib可能没进ld的搜索路径出现expat.h: No such file是系统侧expat-devel没装补装后make clean重来。make install完成后不要急着建库先确认二进制本身的依赖是干净的# 检查 svnserve 动态链接到哪个 apr必须是 /usr/local/apr/lib 下的 ldd /usr/local/svn/bin/svnserve | grep -E apr|sqlite # 若输出里指到 /usr/lib64/libapr-1.so.0说明前缀没被 ld 找到这个ldd是整套流程里最有价值的一条自检命令。它把「编译期正确」和「运行期正确」分开暴露——编译通过不代表运行期能找到库找不到的那一刻通常发生在svnserve -d启动时报error while loading shared libraries: libapr-1.so.0。3.4 环境变量与库搜索路径两处都要配先解决库路径再解决命令路径。库路径靠ldconfig的配置文件比改LD_LIBRARY_PATH更可靠因为它对 systemd 拉起的进程同样生效。# 把两个前缀的 lib 目录登记进动态链接器 cat /etc/ld.so.conf.d/svn-deps.conf EOF /usr/local/apr/lib /usr/local/apr-util/lib /usr/local/svn/lib EOF ldconfig再配命令路径。原文用vim /etc/profile手工追加我用 heredoc好处是可重复执行不会写重复行也避免 vim 里手滑删掉别的行。# 用 heredoc 追加PATH 前置保证 /usr/local/svn/bin 优先 cat /etc/profile EOF # subversion 1.8.14 源码安装 export PATH/usr/local/svn/bin:$PATH EOF # 当前会话立即生效 source /etc/profilePATH写在前面而不是$PATH:后面是为了压过可能存在的/usr/bin/svn。改完执行source只是让当前 shell 生效新开的 SSH 会话会自动读/etc/profile这一点在排错时要记牢你改了文件却没重登报了command not found别急着重装。验证环节用三条命令交叉确认比单跑--version靠谱命令期望输出说明which svnserve/usr/local/svn/bin/svnserve确认 PATH 生效不是系统旧版svnserve --version版本号 1.8.14确认二进制能加载全部动态库svnadmin --version版本号 1.8.14建库工具与 svnserve 同源svnserve --version能出来说明动态库、PATH、前缀三者全对这套编译就算真正完成了。出不来就看报错是「找不到命令」还是「找不到共享库」——前者是 PATH 问题后者是 3.4 上半段ldconfig的问题。4. 建库与三件套配置svnserve.conf、passwd、authz 的权限模型4.1svnadmin create之后目录里到底是什么# 版本库根目录注意这里只是容器不是仓库本身 mkdir -p /home/svn # 项目目录先建好再对其执行 create mkdir -p /home/svn/project svnadmin create /home/svn/project # 看一下生成了什么 ls /home/svn/projectsvnadmin create会在一秒内铺出一整套骨架认清楚每个目录的职责后面配置时才不会改错地方路径作用要不要动conf/svnserve.conf、passwd、authz 三个配置文件必须改db/版本库的真实数据Berkeley DB 或 FSFS 存储只备份不手改hooks/提交前后触发的钩子脚本模板按需启用locks/进程锁与数据库锁不动format版本库存储格式的版本号不动README.txt结构说明可读可不读这里有个容易混淆的点/home/svn是版本库的根目录后面svnserve -d -r指向它/home/svn/project才是一个真正的版本库。一个根目录下可以放多个版本库svnserve -r /home/svn之后客户端用svn://IP/project访问其中一个用svn://IP/another访问另一个互不干扰。4.2 svnserve.conf配置项必须顶格写这个文件的格式极其挑剔[general]段落下的键值对必须从行首开始前面多一个空格svnserve启动时就给你一句svnserve.conf:20: Option expected。原文特别强调「首行不可以留空要顶行」说的就是这件事——行首空白比空行更容易翻车。[general] # 匿名用户无任何权限必须登录 anon-access none # 认证用户可读可写 auth-access write # 密码文件相对 conf 目录 password-db passwd # 权限文件相对 conf 目录 authz-db authz # 认证域客户端缓存凭据时按这个区分 realm project四个参数里anon-access none和auth-access write决定认证前后的能力边界把anon-access设成read等于全网能读到你的代码内网也一样别这么干。password-db和authz-db写相对路径时基准是conf目录本身不是当前工作目录也不是版本库根目录写绝对路径也能用但日后整体搬迁版本库就要改配置不如相对路径省心。realm是给客户端看的认证域名字同一个realm下的多个仓库共用一份凭据缓存不同realm会各弹一次登录框多项目场景下按项目名区分更清晰。改这个文件用vi就行注意svnserve.conf里原有的注释行以#开头留着不碍事只要把需要的项取消注释并顶格。改完别急着启动先跑一次语法体检# 用 svnserve 自己做一次启动预演报错会直接指出行号 svnserve -d -r /home/svn --foreground # 能正常阻塞在前台说明配置无误CtrlC 退出--foreground让进程留在前台配置有错时立刻打印到终端比后台启动再去翻日志快得多。这个参数不在原文里但排查配置问题时省的时间最多。4.3 passwd 与 authz用户、群组、路径权限的优先级passwd只做一件事用户名对密码。格式简单到几乎没有出错空间真正的风险在别处。[users] admin 123456密码是明文存储的所以文件权限要收紧chmod 600 /home/svn/project/conf/passwd属主保持运行 svnserve 的那个账号。生产环境别用123456这种改成一个够长的随机串多人协作就一人一行别共用 admin。authz才是权限模型的核心它支持群组、路径、读写分离三层。[groups] # 管理员组成员 admin g_admin admin # 版本库根目录的权限 [/] g_admin rw * # 若只想给某个子目录更细的权限路径写全 [/docs] g_admin rw * r三个语法点必须说清楚。[/]表示版本库根目录不是某个叫 trunk 的目录很多人被「trunk」这个词带偏写成[/trunk]结果根目录反而没人有权限。g_admin rw里的表示引用群组去掉就变成用户g_admin而它根本不存在权限自然不生效。* 等号后留空表示「无任何权限」注意别写成* r那就成了全员可读。优先级规则记两条就够用路径越具体优先级越高所以[/docs]的规则会覆盖[/]里的同名设置同一路径下针对单个用户的条目优先于群组条目。也就是说给admin单独写一行admin rw会盖过g_admin的设定。改完 authz 不需要重启 svnserve下一次客户端请求就会读到新配置这一点比很多服务都友好。4.4 启动与客户端验证-d -r两个参数的含义# -d 后台运行-r 指定版本库根目录路径到 /home/svn 为止 svnserve -d -r /home/svn # 确认进程在 ps -ef | grep svnserve | grep -v grep # 确认 3690 端口在监听 ss -lntp | grep 3690-r的路径只到/home/svn不要写成/home/svn/project。写成后者的话客户端地址就变成svn://IP/而不是svn://IP/project两个项目共用一个 svnserve 也就无从谈起。这是新手最常犯的一个配置错误表现是「服务明明在跑checkout 却报仓库不存在」。客户端访问地址按svn://服务器地址/项目名拼例如内网地址是192.168.10.20就写# Linux 客户端验证先看 info 再 checkout svn info svn://192.168.10.20/project svn checkout svn://192.168.10.20/project ./project --username adminWindows 侧用任意 SVN 客户端填同一个地址即可首次连接会弹认证框输admin和对应密码。想快速确认权限是否按预期生效用svn ls试读、用一个新提交试写两步就能把 read 和 write 分开验证比翻配置文件快。5. 避坑与排查五条踩过的坑每条都有现场5.1 首行留空或键前有空格svnserve 直接拒绝启动现象svnserve -d -r /home/svn敲下去没反应ps里也没有进程前台跑会打印svnserve.conf:12: Option expected。原因svnserve.conf的解析器要求配置项顶格行首空白会被当成非法续行空行本身在多数版本里是容忍的但行首空格一定会翻车。原文提醒的「首行不可以留空」落到实操就是别让任何一行配置前面带缩进。解决grep -n ^[[:space:]] conf/svnserve.conf把所有带前导空白的行列出来逐行顶格。改完用svnserve -d -r /home/svn --foreground预演一次能正常阻塞再放后台。5.2 make 到链接阶段才报 sqlite 符号找不到现象configure一路绿灯make跑到后半段突然undefined reference to sqlite3_open_v2。原因sqlite 的 amalgamation 目录名不是 subversion 构建脚本约定的sqlite-amalgamationconfigure 判定为「无内置 sqlite」转去找系统库系统里又没有可链接的 sqlite3 开发文件于是链接失败。解决回到源码树ls subversion-1.8.14/sqlite-amalgamation/sqlite3.c目录名不对就改名然后make clean重跑 configure。不要试图用--with-sqlite指向原始解压目录名保持约定命名最省事。5.3 编译通过、启动报找不到 libapr-1.so.0现象svnserve --version报error while loading shared libraries: libapr-1.so.0: cannot open shared object file。原因apr 装在/usr/local/apr/lib这个路径没进动态链接器的搜索范围编译期的-L只影响链接不影响运行期加载。解决在/etc/ld.so.conf.d/下新建配置文件写入/usr/local/apr/lib和/usr/local/apr-util/lib执行ldconfig。临时应急可以用LD_LIBRARY_PATH但开机自启的脚本和 systemd 服务读不到你 shell 里的变量所以别把它当长期方案。5.4 客户端认证一直失败密码明明是对的现象svn checkout反复弹认证框输admin和密码始终提示认证失败服务端没有任何日志。原因多数的锅在authz。[groups]里写了g_admin admin但权限段里漏了写成g_admin rw解析器认为你在给一个名叫g_admin的用户授权而这个用户不存在于是所有人被* 挡在门外。解决检查authz里群组引用是否带再把svnserve.conf里的realm写上项目名避免客户端拿旧凭据反复重试。客户端侧清一下本地凭据缓存删掉~/.subversion/auth再试。5.5 重启机器后 svnserve 不见了现象手工启动正常重启服务器后ps -ef | grep svnserve空空如也。原因svnserve -d是一次性命令没有注册成服务。原文用/etc/rc.d/rc.local挂脚本前提是那个脚本本身有可执行权限且脚本里用的是svnserve的绝对路径——开机时/etc/profile里的 PATH 往往还没被非登录 shell 加载。解决脚本里写/usr/local/svn/bin/svnserve -d -r /home/svnchmod x脚本本身再确认rc.local有执行权限。更彻底的做法是写一个 systemd unit见下一章。6. 开机自启与备份让这套环境能扛住下一次重启6.1 两种自启写法选一个就别混用rc.local的路子最直白适合不想碰 systemd 的老机器# 自启脚本路径与参数都用绝对路径别指望 PATH cat /root/svn.sh EOF #!/bin/bash # 绝对路径启动开机阶段环境变量尚未加载 /usr/local/svn/bin/svnserve -d -r /home/svn EOF chmod 755 /root/svn.sh # 挂到 rc.local 末尾注意该文件本身要有执行权限 echo /root/svn.sh /etc/rc.d/rc.local chmod x /etc/rc.d/rc.local较新的发行版默认不执行rc.local这时候写 unit 更靠谱# /etc/systemd/system/svnserve.service [Unit] DescriptionSubversion Protocol Daemon Afternetwork.target [Service] Typeforking ExecStart/usr/local/svn/bin/svnserve -d -r /home/svn Restarton-failure [Install] WantedBymulti-user.targetsystemctl daemon-reload systemctl enable --now svnserve systemctl status svnserve --no-pagerTypeforking是因为svnserve -d会自己 fork 到后台用simple会让 systemd 误判主进程已退出反复重启。6.2 用 hotcopy 做每日备份并验证版本库最大的风险不是编译失败是磁盘写满或误删。svnadmin hotcopy能在不停止服务的前提下拷出一份一致的副本比cp -r安全得多。# 每日增量保留 7 天hotcopy 保证一致性 BACKUP/home/svnbackup mkdir -p $BACKUP/$(date %F) svnadmin hotcopy /home/svn/project $BACKUP/$(date %F)/project # 备份完立刻验一遍能 list 出来才算数 svnlook youngest $BACKUP/$(date %F)/projectsvnlook youngest输出的是当前最新版本号这个数字和线上库一致说明副本完整报错则说明备份不可用别等真出事才发现。把它写进 crontab每天凌晨跑一次顺手find $BACKUP -maxdepth 1 -mtime 7 -exec rm -rf {} \;清旧副本。这套东西我是被一次磁盘写满教育出来的当时只做了cp -r拷到一半空间不足副本里db/current和db/revs对不上真要用的时候才发现那份备份根本读不出来。从那以后我每次配完 svnserve都强制先把 hotcopy 加进 crontab、跑一次svnlook youngest验一遍再交付给同事用。希望帮到你。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表