前言
本文主要解决的问题是:在没有root权限账户的情况下,如何通过源码、完全的自定义路径配置,在Linux平台安装Asterisk服务器软件。
应公司项目需求,需要研究SIP协议,搭建一个SIP服务器,方便自己测试、开发、研究协议。在搜索对比了五花八门的各类开源服务器后,机选了asterisk安装(没看出太大差别,选择了下面文章推荐的第一个),于是开始了苦哈哈的填坑之路。
开发环境:公司使用公用的linux开发环境,为每个员工分配了一个可登录的账户,这些账户没有root权限,这就意味者,在系统软件默认安装目录是没有写权限的,这意味着apt-get install ,yum这样的快速安装方法是无法使用的。通过下载源码,编译、安装、运行软件,是唯一的方法。
大型的开源软件,大多依赖许多第三方库开发的,因此需要安装第三方的开源库库才能运行,asterisk软件也不列外。但由于linux平台环境差异,总是缺少各种第三方的开源库文件,这是迈向成功的最大障碍。如果能够将所有缺少的库文件正确的安装,配置,理论上就能够完全解决问题。
然后实际操作是令人崩溃的,搭建一个简单的环境就耗费了一整天时间,由于Linux环境原因,遇到了许多问题,不得不通过研究其configure、makeopts等来解决问题。大致包括以下几类问题:
- 库源码找不到下载的地方
- 下载的库版本与软件不兼容,特别是最新的库,有些需要的接口可能已经被去掉或修改了。这就造成编译的时候,符号表找不到
- 存在库无法通过configure参数进行配置,可能是作者配置项写掉了
- 存在库必须使用集成的库(pjproject),自动下载解压放到third-party目录下,手动配置的路径--with_pjproject不起作用。而自动下载的库的链接已经挂掉了
- make的时候,库(pjproject)会被rebuid一次,pjproject默认安装路径在编译时候被设置成/opt/pjproject,尝试了PJPROJECT_CONFIGURE_OPTS也无法改变,最终由于权限问题,make install的时候安装pjproject失败了。
- 编译成功后,如何运行?由于所有的库安装路径都是自定义的,并非在系统默认库目录下,Asterisk软件启动的时候将存在找不到动态库目录的问题。
本文将详细记录这些问题的解决方案,已告慰那一天幸苦而枯燥的时光
一、总体流程
1 下载源码---->2 运行配置脚本生产makefile 文件 ./configure
---->3 发现检查不通过的库文件-->4 下载库文件源码、编译安装
---->5 ./configure 运行参数中添加对应库路径 ----->重复2-5,直到configure检查通过,产生makefile 文件
----->6 执行make-->7 执行make install -->8 make samples --->9 写启动脚本,配置环境变量
二、源码下载地址,包括各种需要的库的地址
以下资源全部汇总上传到CSDN:
Asterisk地址:我下载的是当前最新的18.11.1Downloads ⋆ Asteriskhttps://www.asterisk.org/downloads/
jansson地址:Index of /jansson/releases (digip.org)http://digip.org/jansson/releases/
libuuid地址:Download libuuid from SourceForge.net
libuuid download | SourceForge.nethttps://sourceforge.net/projects/libuuid/
libproject:
https://github.com/pjsip/pjproject/archive/refs/tags/2.11.tar.gz
Releases · pjsip/pjproject · GitHubhttps://github.com/pjsip/pjproject/releasesPJSIP - Open Source SIP, Media, and NAT Traversal Libraryhttps://www.pjsip.org/libedit:
https://www.sqlite.org/2022/sqlite-autoconf-3380200.tar.gz
SQLite Download Pagehttps://www.sqlite.org/download.htmlopenssl:别下载最新版本,不兼容
https://www.openssl.org/source/old/1.1.1/openssl-1.1.1.tar.gz
/source/old/index.html (openssl.org)https://www.openssl.org/source/old/
/source/index.html (openssl.org)https://www.openssl.org/source/
三、配置安装路径、库路径
在开源库源码根目录下,一般情况下,有一个叫 configure(有的是config)的脚本文件,这个文件可以根据需求输入参数自动生成Makefile文件,用于编译,比如指定编译器、目标运行环境、配置安装路径,开启或关闭某些模块的编译等。
Asterisk也有一个这样的脚本文件configure,至于怎么用,最好的指导永远是自己的帮助文档,以及......脚本的注释(不得不研究脚本的时候)。./configure -h 可以查看帮助文档,本文主要关注以下几类参数:
(1)安装目录 Installation directories
可设置依赖库安装目录
--prefix=PREFIX install architecture-independent files in PREFIX
[/usr/local]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[PREFIX]
(2)调整个别文件安装路径:Fine tuning of the installation directories
(3)模块开关:Optional Features
(4)指定库路径(重点关注):Optional Package
格式为: --with-库名称=路径,比如
--with-libedit=PATH use NetBSD Editline library files in PATH
(5)编译参数: Some influential environment variables
可以设置编译器、平台等,一般在交叉编译时使用,如果缺省的情况下,为当前平台,不用设置。
另一方面,处理可以设置asterisk软件的编译参数,可以设置其依赖的独立的第三方库文件编译时的配置参数,这部分主要针对采用软件集成的库源码,在configure执行过程中,可自动下载,并跟随asterisk一起进行编译和安装。
如pjproject的编译选项:
PJPROJECT_CONFIGURE_OPTS
Additional configure options to pass to bundled pjproject
eg:
PJPROJECT_CONFIGURE_OPTS=--prefix=$HOME/tools/pjproject
本文的编译配置参数设置如下,其中自定义了安装目录,并且根据报错情况配置了需求要的库。
./configure --prefix=$HOME/tools/asterisk \
--with-libedit=$HOME/tools/libedit-20210910-3.1 \
--with-libuuid=$HOME/tools/libuuid-1.0.3 \
--with-pjproject=$HOME/tools/pjproject \
--with-sqlite3=$HOME/tools/sqlite3 \
--with-jansson=$HOME/tools/jansson-2.11 \
--with-ssl=$HOME/tools/openssl-1.1.1
这些库文件的配置,是根据实际情况进行的,当configure执行后,会逐一对所有必须的库文件进行检测测试,直到出现错误,会提示缺少哪个库,如下是由于缺少libedit库的提示;
checking for LIBEDIT... no
checking for history_init in -ledit... no
configure: error: *** Please install the 'libedit' development package.
此时下载libedit源码,执行编译安装步骤即可。这里的库文件编译时,基本较为简单,没遇到复杂的,设置好安装路径,其余参数均用默认接口即可。
./configure --prefix=$HOME/tools/libedit-20210910-3.1
make
make install
当然,凡事有特殊情况,并非所有的库按照如此操作都能成功,这里边遇到了两个比较特殊的,libuuid和pjproject,这两个一个configure中没有添加相关的配置选项,另一个必须采用集成方式进行安装,这个两个单独在第四和第五小节中进行介绍。
四、libuuid库没有自定义配置路径,手动修改configure脚本
如下所示缺少libuuid库时出现的报错问题:
checking for uuid_generate_random in -luuid... no
checking for uuid_generate_random in -le2fs-uuid... no
checking for uuid_generate_random... no
configure: error: *** uuid support not found (this typically means the uuid development package is missing)
于是在帮助文档中进行搜索时,惊讶的发现竟然没有这个预期的选项,有点懵啊
--with-pjproject=$HOME/tools/pjproject
不得不对configure 文档进行关键字uuid搜索,找到了下面的脚本
# Find required UUID support.
# * -luuid on Linux
# * -le2fs-uuid on OpenBSD
# * in libsystem on OS X
if test "x${PBX_LIBUUID}" != "x1" -a "${USE_LIBUUID}" != "no"; then
pbxlibdir=""
# if --with-LIBUUID=DIR has been specified, use it.
if test "x${LIBUUID_DIR}" != "x"; then
if test -d ${LIBUUID_DIR}/lib; then
pbxlibdir="-L${LIBUUID_DIR}/lib"
else
pbxlibdir="-L${LIBUUID_DIR}"
fi
fi
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} "
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_random in -luuid" >&5
$as_echo_n "checking for uuid_generate_random in -luuid... " >&6; }
if ${ac_cv_lib_uuid_uuid_generate_random+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-luuid ${pbxlibdir} $LIBS"
后面就是针对这个库进行接口检测的脚本了。看到这个,尤其是注释# if --with-LIBUUID=DIR has been specified, use it.明显是有这方面的判断的,我猜测多半是开发人员忘记写配置项了,这时最简单的办法就是手动加上自己安装的库所在目录即可,比如在这段脚本前加上:
LIBUUID_DIR=$HOME/tools/libuuid-1.0.3
经过简单验证后,发现果然有效果。
然后手贱的我,又对比其他库的配置项,依葫芦画瓢,做了一个配置项。(该步骤可以不用做了)
(1)在ac_user_opts列表中添加with_libuuid库的选项
ac_user_opts='
enable_option_checking
with_gnu_ld
....
with_x11
with_z
with_libuuid
enable_xmldoc
(2)添加库选项判断
# Check whether --with-libuuid was given.
if test "${with_libuuid+set}" = set; then :
withval=$with_libuuid;
case ${withval} in
n|no)
USE_LIBUUID=no
# -1 is a magic value used by menuselect to know that the package
# was disabled, other than 'not found'
PBX_LIBUUID=-1
;;
y|ye|yes)
ac_mandatory_list="${ac_mandatory_list} LIBUUID"
;;
*)
LIBUUID_DIR="${withval}"
ac_mandatory_list="${ac_mandatory_list} LIBUUID"
;;
esac
fi
(3)最后添加上帮助文档
...
--with-z=PATH use zlib compression files in PATH
--whth-libuuid=PATH use libuuid files in PATH
(4) configure 参数中添加上libuuid库路径
--with-libuuid=$HOME/tools/libuuid-1.0.3
五、pjproject自定义路径不生效
如下所示,pjproject这个是出现问题的第一个库,从提示看,显然configure脚本希望自动下载安装时失败了,通过复制地址,通过浏览器和下载工具,发现根本无法下载。
checking for embedded pjproject (may have to download)... configuring
[pjproject] Downloading https://raw.githubusercontent.com/asterisk/third-party/master/pjproject/2.10/pjproject-2.10.tar.bz2 to /tmp/pjproject-2.10.tar.bz2
[pjproject] Retrying download
[pjproject] Downloading https://raw.githubusercontent.com/asterisk/third-party/master/pjproject/2.10/pjproject-2.10.tar.bz2 to /tmp/pjproject-2.10.tar.bz2
make: *** [Makefile:102: /tmp/pjproject-2.10.tar.bz2] Error 4
首先想到的第一个方法就是通过三小节中提到的方法手动下载安装pjproject库,安装成功后,在配置参数中加入了配置参数
--with-pjproject=$HOME/tools/pjproject \
发现依然失败,显然configure脚本的逻辑必须采用集成的库方式进行安装,为了不修改脚本,绕过下载,做了如下尝试:
(1)通过第二小节中提到的地址,手动下载pjproject tar包:pjproject-2.10.tar.gz
(2)将下载的tar包解压,重新压缩成tar.bz2格式
(3) 将压缩后的包复制到/tmp目录
(4) 计算pjproject-2.10.tar.bz2的md5值,并修改写入到文件asterisk-18.11.1/third-party/pjproject/pjproject-2.10.tar.bz2.md5
(5)重新执行configure
tar -xzf pjproject-2.10.tar.gz
tar -cjf pjproject-2.10.tar.bz2 pjproject-2.10
cp pjproject-2.10.tar.bz2 /tmp/
md5sum /tmp/pjproject-2.10.tar.bz2 > asterisk-18.11.1/third-party/pjproject/pjproject-2.10.tar.bz2.md5
六、编译
如下所示表示makefile生成成功了,接下来执行make进行编译即可,尽管makefile生成成功了,依然遇到了一些问题。
config.status: creating makeopts
config.status: creating autoconfig.h
configure: Menuselect build configuration successfully completed
.$$$$$$$$$$$$$$$=..
.$7$7.. .7$$7:.
.$$:. ,$7.7
.$7. 7$$$$ .$$77
..$$. $$$$$ .$$$7
..7$ .?. $$$$$ .?. 7$$$.
$.$. .$$$7. $$$$7 .7$$$. .$$$.
.777. .$$$$$$77$$$77$$$$$7. $$$,
$$$~ .7$$$$$$$$$$$$$7. .$$$.
.$$7 .7$$$$$$$7: ?$$$.
$$$ ?7$$$$$$$$$$I .$$$7
$$$ .7$$$$$$$$$$$$$$$$ :$$$.
$$$ $$$$$$7$$$$$$$$$$$$ .$$$.
$$$ $$$ 7$$$7 .$$$ .$$$.
$$$$ $$$$7 .$$$.
7$$$7 7$$$$ 7$$$
$$$$$ $$$
$$$$7. $$ (TM)
$$$$$$$. .7$$$$$$ $$
$$$$$$$$$$$$7$$$$$$$$$.$$$$$$
$$$$$$$$$$$$$$$$.
configure: Package configured for:
configure: OS type : linux-gnu
configure: Host CPU : x86_64
configure: build-cpu:vendor:os: x86_64 : pc : linux-gnu :
configure: host-cpu:vendor:os: x86_64 : pc : linux-gnu :
1.头文件uuid 找不到
[CC] chan_audiosocket.c -> chan_audiosocket.o
chan_audiosocket.c:34:23: fatal error: uuid/uuid.h: No such file or directory
#include <uuid/uuid.h>
查看了生成了编译规则makeopts文件,uuid的头文件目录是加入了编译头文件目录
UUID_INCLUDE=-I/home/wangfk/tools/libuuid-1.0.3/include
UUID_LIB=-L/home/wangfk/tools/libuuid-1.0.3/lib -luuid
没有再去细查原因,直接将头文件的目录uuid复制到了asterisk-18.11.1/include 的目录下,解决了问题。
2、版本不兼容
第三方的库文件可能一直在更新维护中,下载的库版本与asterisk的更新版本不一定的兼容。比较常见的一种情况是,随着第三方库的维护和更新,有的库弃用了一些老的接口,很不幸的是,这个接口刚好是软件所需要的。
在接下来的编译中,就遇到了这样的问题。如下所示,报了openssl库中找不到函数的错误,openssl用得库是最新的库,显然这个接口在目前编译的库中已不存在了。
In function `handle_tcptls_connection':
/media/sdc1/home_sdca/wangfk/work/tool/testAsterisk/asterisk-18.11.1/main/tcptls.c:192: undefined reference to `SSL_get1_peer_certificate'
collect2: error: ld returned 1 exit status
这时候就只能重新选择一个版本,重新进行编译安装,重新安装了1.1.1版本解决了问题。
七、安装与运行
如下 所示,编译已成功。make install 进行安装,到了这里,眼瞅着离成功越来越近,依然遇到了问题。
+--------- Asterisk Build Complete ---------+
+ Asterisk has successfully been built, and +
+ can be installed by running: +
+ +
+ make install +
+-------------------------------------------+
1、pjproject安装路径被强制修改为/usr/bin/install
在运行安装命令后,出现如下的错误:
/usr/bin/install: cannot create directory ‘/opt/pjproject’: Permission denied
由于pjproject采用的集成方式安装,重新编译一遍时发现,pjproject也随之被重新编译了一遍,如下:
[pjproject] Rebuilding
[pjproject] Configuring with --with-ssl=/home/wangfk/tools/openssl-1.1.1 --prefix=/opt/pjproject --disable-speex-codec --disable-speex-aec --disable-bcg729 --disable-gsm-codec --disable-ilbc-codec --disable-l16-codec --disable-g722-codec --disable-g7221-codec --disable-opencore-amr --disable-silk --disable-opus --disable-video --disable-v4l2 --disable-sound --disable-ext-sound --disable-sdl --disable-libyuv --disable-ffmpeg --disable-openh264 --disable-ipp --disable-libwebrtc --without-external-pa --without-external-srtp --disable-resample --disable-g711-codec --enable-epoll
[pjproject] Compiling libpj-x86_64-unknown-linux-gnu.a
于是尝试在编译参数中加入pjproject的编译参数:
PJPROJECT_CONFIGURE_OPTS=--prefix=$HOME/tools/pjproject
发现开头的参数的确多了一个指定的-prefix参数,默认的参数--prefix=/opt/pjproject依然存在,安装验证生效的是后者,因此依然无法安装成功。
Rebuilding
[pjproject] Configuring with --prefix=/home/wangfk/tools/pjproject --with-ssl=/home/wangfk/tools/openssl-1.1.1 --prefix=/opt/pjproject --disable-speex-codec --disable-speex-aec --disable-bcg729 --disable-gsm-codec --disable-ilbc-codec --disable-l16-codec --disable-g722-codec --disable-g7221-codec --disable-opencore-amr --disable-silk --disable-opus --disable-video --disable-v4l2 --disable-sound --disable-ext-sound --disable-sdl --disable-libyuv --disable-ffmpeg --disable-openh264 --disable-ipp --disable-libwebrtc --without-external-pa --without-external-srtp --disable-resample --disable-g711-codec --enable-epoll
[pjproject] Compiling libpj-x86_64-unknown-linux-gnu.a
在asterisk-18.11.1/third-party/pjproject目录下,Makefile.rules文件中发现如下设置,显然默认的路径是在这里生成的,将其修改为自己的路径。
PJPROJECT_CONFIG_OPTS = $(PJPROJECT_CONFIGURE_OPTS) --prefix=/opt/pjproject \
修改后,重新进行编译安装,如下所示,表示安装成功了。
+---- Asterisk Installation Complete -------+
+ +
+ YOU MUST READ THE SECURITY DOCUMENT +
+ +
+ Asterisk has successfully been installed. +
+ If you would like to install the sample +
+ configuration files (overwriting any +
+ existing config files), run: +
+ +
+ For generic reference documentation: +
+ make samples +
+ +
+ For a sample basic PBX: +
+ make basic-pbx +
+ +
+ +
+----------------- or ---------------------+
+ +
+ You can go ahead and install the asterisk +
+ program documentation now or later run: +
+ +
+ make progdocs +
+ +
+ **Note** This requires that you have +
+ doxygen installed on your local system +
+-------------------------------------------+
2、编写启动脚本运行
安装成功后,make samples,安装默认的配置参数,在etc/asterisk目录下会产生许多文件。接下来就是如何将软件运行起来,由于所有的库都不是安装在默认路径下,因此,会因为找不到库而无法运行。
为了能够找到库,需要将所有的库路径加入到环境变量中,例如$HOME/tools/libuuid-1.0.3/lib目录的库:
export LD_LIBRARY_PATH=$HOME/tools/libuuid-1.0.3/lib:$LD_LIBRARY_PATH
为了能够方便快速启动,将其写成脚本:
LIBPATH_LIST="$HOME/tools/libuuid-1.0.3/lib
$HOME/tools/sqlite3/lib
$HOME/tools/jansson-2.11/lib
$HOME/tools/openssl-1.1.1/lib
$HOME/tools/pjproject/var/lib
$HOME/tools/libedit-20210910-3.1/lib"
echo $LD_LIBRARY_PATH
for libdir in $LIBPATH_LIST
do :
echo "libdir $libdir"
if [[ $LD_LIBRARY_PATH =~ $libdir ]]
then
echo -e "the lib dir $libdir exist \n"
else
export LD_LIBRARY_PATH=${libdir}:$LD_LIBRARY_PATH
fi
done
echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
$HOME/tools/asterisk/sbin/asterisk -r
运行启动脚本,就能够启动服务器软件了。
总结
这个故事告诉我们,没事别瞎折腾。