libreadline undefined symbol:使用|时bash中的PC bc -l

时间:2014-06-26 06:57:00

标签: bash bc libreadline

我通过ssh连接到另一台机器来执行bash脚本,其中有问题的部分如下:

fkeypar "ex1.fef[1]" TSTARTI         #### fkeypar is an external command to get some values to assign to the subsequent variables
t0i="$(expr $(pget fkeypar value) - 11544)"                                          
fkeypar "ex1lc.fits[2]" TELAPSE
lengthini=`pget fkeypar value`
fkeypar "ex7lc.fits[2]" TSTOP
lengthfin=`pget fkeypar value`
fkeypar "ex1lc.fits[2]" TSTART      
ijd=`pget fkeypar value`

i=$(echo "($ijd - $t0i) / $period + 1" | bc -l | sed 's/\..*//')
ifin=$(echo "($lengthfin - $ijd)/$period + 1" | bc -l | sed 's/\..*//')
echo "($ijd - $t0i) / $period + 1" | bc

for ((n=$i; n<=$ifin; n++))
do
   ...

这会返回以下错误:

bc: symbol lookup error: /science/heasoft-6.14/x86_64-unknown-linux-gnu-libc2.9/lib/libreadline.so.6: undefined symbol: PC
bc: symbol lookup error: /science/heasoft-6.14/x86_64-unknown-linux-gnu-libc2.9/lib/libreadline.so.6: undefined symbol: PC
bc: symbol lookup error: /science/heasoft-6.14/x86_64-unknown-linux-gnu-libc2.9/lib/libreadline.so.6: undefined symbol: PC
./script: line 39: ((: n=: syntax error: operand expected (error token is "=")

谷歌搜索很多,我发现我与这些“错误”非常相关: https://science.nrao.edu/forums/viewtopic.php?f=44&t=75

https://bugzilla.redhat.com/show_bug.cgi?id=162023

https://dba.stackexchange.com/questions/31143/libreadline-so-6

我不知道如何解决它,不尝试随机的东西。任何帮助真的很感激。

编辑:我忘了提到,在我的许多试验中,经过多次抨击,我设法以某种方式得到错误并运行脚本,使用与问题中报告的语法相同的语法。那一刻,我认为这是一个语法问题,但随后错误再次出现在ssh-ings上。

EDIT2:我加载的heasoft版本无关紧要,heasoft-6.14版本始终显示错误。我认为这与可能的解决方案有关。

2 个答案:

答案 0 :(得分:1)

这大部分是我们无法解决的问题 - 拥有重新编译bc的管理权限的人(或者,更好的是,知道为什么你没有做的人理智的事情和使用操作系统供应商提供的版本)将需要修复它。 (这可能就像在bc下重命名/science/heasoft-6.14一样简单,并允许在PATH中使用供应商提供的实现来代替。)

那就是说,如果你只做整数数学运算,那么这个脚本就没有理由使用bc了:

i=$(( (idj - t01) / period + 1 ))
ifin=$(( ( lengthfin - ijd ) / period + 1 ))
echo "$(( ( ijd - t01 ) / period + 1 ))"

第39行的错误是bc中这些错误的结果 - 脚本希望i包含一个数字,但它是一个空字符串,因此n=$i可以不会将"$i"评估为数字,因此会失败。在数学上下文中(这是双括号创建的),i如果变量未定义则求值为0,但$i在同一场景中导致错误;使用其中哪些取决于您期望的行为。如果您希望在未定义变量时出错,请在$varname内使用(( ));如果您希望脚本继续使用值0,请使用裸varname

答案 1 :(得分:1)

<块引用>

我不知道如何修复它,不尝试随机的事情。任何帮助真的很感激。

在您的平台上构建 Readline 的方法已失效。这是技术细节...共享对象缺少符号,这还可以:

$ ldd -r -d /usr/local/lib/libreadline.so
        linux-vdso.so.1 (0x00007ffea672a000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fec922eb000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fec92521000)
undefined symbol: UP    (/usr/local/lib/libreadline.so)
undefined symbol: PC    (/usr/local/lib/libreadline.so)
undefined symbol: BC    (/usr/local/lib/libreadline.so)
undefined symbol: tputs (/usr/local/lib/libreadline.so)
undefined symbol: tgoto (/usr/local/lib/libreadline.so)
undefined symbol: tgetflag      (/usr/local/lib/libreadline.so)
undefined symbol: tgetent       (/usr/local/lib/libreadline.so)
undefined symbol: tgetnum       (/usr/local/lib/libreadline.so)
undefined symbol: tgetstr       (/usr/local/lib/libreadline.so)

实际上,我认为构建应该会因为缺少符号而失败。但维护者不这么认为,更愿意将他的痛苦和痛苦传播给他的库的用户。

缺少的符号是 Ncurses 和 Terminfo 的一部分,但缺少链接库。那不行。链接库应该类似于 libtinfo.solibtinfow.so 但它丢失了:

$ ldd /usr/local/lib/libreadline.so
        linux-vdso.so.1 (0x00007ffd535cb000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3a5183c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3a520b5000)

这里是UPPC 和朋友所在的位置:

$ nm -D /usr/local/lib/libtinfow.so | grep -E 'UP|PC'
000000000023797e B PC
0000000000237968 B UP

您应该能够在 Readline 配置期间将 -ltinfo-ltinfow 添加到您的 LIBS/LDLIBS 中,但这不起作用。添加 -ltinfo-ltinfow 将被忽略。

实践中的解决方法是修补 Readline makefile,然后从源代码构建 Ncurses 和 Readline。

这是 Readline 补丁的样子。该补丁是使用 diff -u 创建的:

--- shlib/Makefile.in
+++ shlib/Makefile.in
@@ -174,11 +174,11 @@
 
 $(SHARED_READLINE):    $(SHARED_OBJ)
    $(RM) $@
-   $(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_OBJ) $(SHLIB_LIBS)
+   $(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_OBJ) $(SHLIB_LIBS) -ltinfo
 
 $(SHARED_HISTORY): $(SHARED_HISTOBJ) xmalloc.so xfree.so
    $(RM) $@
-   $(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_HISTOBJ) xmalloc.so xfree.so $(SHLIB_LIBS)
+   $(SHOBJ_LD) ${SHOBJ_LDFLAGS} ${SHLIB_XLDFLAGS} -o $@ $(SHARED_HISTOBJ) xmalloc.so xfree.so $(SHLIB_LIBS) -ltinfo
 
 # Since tilde.c is shared between readline and bash, make sure we compile 
 # it with the right flags when it's built as part of readline

修复 makefile 并构建 Ncurses 和 Readline 后,您的链接库将包含 libtinfo.so。狗屎将不再被打破。请注意 libtinfo.so 的链接如下。

$ ldd /usr/local/lib/libreadline.so
        linux-vdso.so.1 (0x00007ffd535cb000)
        libtinfow.so.6 => /usr/local/lib/libtinfow.so.6 (0x00007f3a51c2d000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3a5183c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3a520b5000)

现在,正确配置 Ncurses 可能很棘手。那是因为所有库都有非宽版和宽版。 Ncurses 中有 6 个类似的东西:

$ ls /usr/local/lib/lib*w\.so*
/usr/local/lib/libformw.so         /usr/local/lib/libncursesw.so.6
/usr/local/lib/libformw.so.6       /usr/local/lib/libncurses++w.so.6.1
/usr/local/lib/libformw.so.6.1     /usr/local/lib/libncursesw.so.6.1
/usr/local/lib/libmenuw.so         /usr/local/lib/libpanelw.so
/usr/local/lib/libmenuw.so.6       /usr/local/lib/libpanelw.so.6
/usr/local/lib/libmenuw.so.6.1     /usr/local/lib/libpanelw.so.6.1
/usr/local/lib/libncurses++w.so    /usr/local/lib/libtinfow.so
/usr/local/lib/libncursesw.so      /usr/local/lib/libtinfow.so.6
/usr/local/lib/libncurses++w.so.6  /usr/local/lib/libtinfow.so.6.1

我使用配置选项 --enable-widec 构建了 版本的 Ncurses。 --enable-widecdescribed as

<块引用>

这个开关导致宽字符库(例如,libncursesw.so.6.2) 要构建而不是正常的(例如,libncurses.so.6.2)。这些 宽字符库可用于多字节和传统 8 位语言环境,而普通库只能在 8 位中正常工作 语言环境。宽字符库和普通库是源兼容的, 但不兼容二进制。

如果您使用 --enable-widec 配置 Ncurses,那么您使用 libtinfow.so 作为 Readline 的链接库。如果您使用非宽版本,则使用 libtinfo.so 作为 Readline 的链接库。

如果您使用 --enable-widec 配置 Ncurses,那么您应该使用 --enable-multibyte 配置您的宽 Readline。如果您从源代码构建 Bash 并使用广泛的 Readline,那么您应该使用 --enable-multibyte 配置 Bash。你要注意细节...

不,同一选项的不同标志 -- --enable-widec--enable-multibyte -- 是正确的。当您可以添加混淆时,为什么要保持一致?


你可以感谢维护 Ncurses 和 Readline 的人搞砸了这个烂摊子。他不遵循标准的 GNU 工作流程或 Linux 最佳实践。我鄙视与他维护的废话一起工作。您将花费数小时试图弄清楚如何做一些应该很简单的事情,比如使用哪些选项,或者让 Readline 使用正确的链接库,或者让 BC 或 OpenLDAP 等依赖项正确构建。

另一个宝石是内存泄漏。如果您不幸在 Android 上需要它,那么您可以指望资源耗尽,因为库泄漏了太多内存。 Android 通过 JNI 将加载和卸载共享对象数千次,并且由于累积的内存泄漏而导致内存不足。

最后,Ncurses 和 Readline 没有公共存储库。没有办法针对他的来源提出拉取请求或提供补丁。他对 git pull 的想法是这样的废话:Applying Patches