【问题标题】:strange behaviour with readlink under cmakecmake下readlink的奇怪行为
【发布时间】:2016-05-19 21:44:15
【问题描述】:

我正在尝试使用 readlink -f 获取所有符号链接之后的共享库的绝对路径。

>readlink -f /opt/gcc4.9.3/lib64/libstdc++.so.6 /opt/gcc4.9.3/lib64/libstdc++.so.6.0.20

但是当我在 cmake 中执行此操作时,它不会扩展完整路径 例如。 set(CPP11_PATH ${CMAKE_CURRENT_BINARY_DIR}/) execute_process(COMMAND ldd ${CPP11_PATH} COMMAND grep libstdc++ COMMAND awk "{ print $3; }" OUTPUT_VARIABLE LIBSTDCPP_PATH) message("LIBSTDCPP_PATH=${LIBSTDCPP_PATH}") execute_process(COMMAND readlink -f ${LIBSTDCPP_PATH} OUTPUT_VARIABLE LIBSTDCPP_ABSPATH) message("LIBSTDCPP_ABSPATH=${LIBSTDCPP_ABSPATH}")

打印:

LIBSTDCPP_PATH=/opt/gcc4.9.3/lib64/libstdc++.so.6 LIBSTDCPP_ABSPATH=/opt/gcc4.9.3/lib64/libstdc++.so.6

如果我将它包装在 shell 脚本中,也会发生这种情况: execute_process(COMMAND doreadlink.sh ${LIBSTDCPP_PATH} OUTPUT_VARIABLE LIBSTDCPP_ABSPATH2) message("LIBSTDCPP_ABSPATH2=${LIBSTDCPP_ABSPATH2}")

>LIBSTDCPP_ABSPATH2=/opt/gcc4.9.3/lib64/libstdc++.so.6

使用带有 REALPATH 的 get_filename_component() 也会发生这种情况,这应该是执行此操作的规范 cmake 方式。 get_filename_component(LIBSTDCPP_PATH ${LIBSTDCPP_PATH} REALPATH) message("LIBSTDCPP_PATH2=${LIBSTDCPP_PATH}")

谁能解释一下?

我已经尝试了 cmake rebuild_cache 和删除 CMakeCache.txt 并使用 --trace 运行以确保我认为正在运行的内容确实正在运行。 我还确认它发生在 rhel5 rhel6 和 rhel7 以及 cmake 2.8 和 3.4 上。

有一个行为正确的解决方法: execute_process(COMMAND ldd ${CPP11_PATH} COMMAND grep libstdc++ COMMAND awk "{ print $3; COMMAND xargs readlink -f }" OUTPUT_VARIABLE LIBSTDCPP_PATH)

cmake 可能在幕后做什么?

我尝试运行: strace -f cmake pwd

一些输出是:

[pid 23195] execve("/usr/lib64/qt-3.3/bin/readlink", ["readlink", "-f", "/lib64/libstdc++.so.6\n"], [/* 53 vars */]) = -1 ENOENT(没有这样的文件或目录) [pid 23195] execve("/usr/local/bin/readlink", ["readlink", "-f", "/lib64/libstdc++.so.6\n"], [/* 53 vars */]) = -1 ENOENT(没有这样的文件或目录) [pid 23195] execve("/usr/bin/readlink", ["readlink", "-f", "/lib64/libstdc++.so.6\n"], [/* 53 vars */] [pid 23174] "", 1) = 0 [pid 23195]) = 0 [pid 23174] 关闭 (11) = 0 [pid 23174] rt_sigprocmask(SIG_SETMASK, [], [pid 23195] brk(0 [pid 23174] NULL,8) = 0 [pid 23195] ) = 0x12e5000 [pid 23174] 读取(9,“”,1024)= 0 [pid 23174] 关闭 (9) = 0 [pid 23195] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 [pid 23174] 关闭 (6) = 0 [pid 23195] ) = 0x7ff41654f000 [pid 23174] 关闭(8) = 0 [pid 23195] 访问(“/etc/ld.so.preload”,R_OK [pid 23174] 选择(8,[3 5 7],NULL,NULL,NULL [pid 23195] ) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("/usr/local/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) [pid 23195] stat("/usr/local/lib/tls/x86_64", 0x7fff36038350) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("/usr/local/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) [pid 23195] stat("/usr/local/lib/tls", 0x7fff36038350) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("/usr/local/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录)

剪辑

O_RDONLY|O_CLOEXEC) = -1 ENOENT(没有这样的文件或目录) [pid 23195] stat("/usr/lib/oracle/10.2.0.4/client/lib/tls", 0x7fff36038350) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("/usr/lib/oracle/10.2.0.4/client/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) [pid 23195] stat("/usr/lib/oracle/10.2.0.4/client/lib/x86_64", 0x7fff36038350) = -1 ENOENT (没有这样的文件或目录) [pid 23195] open("/usr/lib/oracle/10.2.0.4/client/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有这样的文件或目录) rt_sigprocmask(SIG_BLOCK, [INT TERM CHLD], [], 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 ioctl(0, SNDCTL_TMR_TIMEBASE 或 SNDRV_TIMER_IOCTL_NEXT_DEVICE 或 TCGETS, {B38400 opost isig icanon echo ...}) = 0 ioctl(0, SNDCTL_TMR_TIMEBASE 或 SNDRV_TIMER_IOCTL_NEXT_DEVICE 或 TCGETS, {B38400 opost isig icanon echo ...}) = 0 写(2,“LIBSTDCPP_ABSPATH=/usr/lib64/lib”...,45LIBSTDCPP_ABSPATH=/usr/lib64/libstdc++.so.6 ) = 45

所以它甚至看起来像是在执行正确的系统命令。

这是重现问题的 CMakeLists.txt:

cmake_minimum_required(版本 2.8) 项目(TEST CXX) 设置(CPP11_PATH ${CMAKE_CURRENT_BINARY_DIR}/cpp11) 执行进程(命令 g++ ${CMAKE_CURRENT_SOURCE_DIR}/cpp11.cpp -o${CPP11_PATH}) #execute_process(COMMAND ldd ${CPP11_PATH} COMMAND grep libstdc++ COMMAND awk "{ print $3; }" COMMAND xargs readlink -f OUTPUT_VARIABLE LIBSTDCPP_PATH) execute_process(COMMAND ldd ${CPP11_PATH} COMMAND grep libstdc++ COMMAND awk "{ print $3; }" OUTPUT_VARIABLE LIBSTDCPP_PATH) 消息(“LIBSTDCPP_PATH=${LIBSTDCPP_PATH}”) 执行进程(命令读取链接 -f ${LIBSTDCPP_PATH} OUTPUT_VARIABLE LIBSTDCPP_ABSPATH) 消息(“LIBSTDCPP_ABSPATH=${LIBSTDCPP_ABSPATH}”)

【问题讨论】:

  • strace 输出中显示,您将换行终止路径 传递给readlink:“/lib64/libstdc++.so.6\n”。这可能是与直接readlink 调用不同的原因。
  • 我想你已经快把它钉在那里了。 \n 似乎没有这样做,但尾随空格可以。那么问题就变成了尾随字符来自哪里?
  • 如果您是声誉点追逐者,您可以添加答案,我会接受,否则我会接受我自己的。无论哪种方式,感谢您的提示。

标签: linux cmake readlink


【解决方案1】:

Tsyvarev 成功了。问题是由我的 awk 输出引起的尾随换行符。 如果我将其更改为: awk "print $3" 到: awk "printf($3)"

一切都按预期工作。万岁!

【讨论】:

    【解决方案2】:

    许多输出 单行 的 shell 实用程序以换行符 (\n) 终止它。这样做是为了在终端中获得漂亮的输出。

    与 Linux shell 中的 backtricks operator (`exec-some-command`) 不同,它会自动去除尾随的换行符,execute_process 默认情况下不会这样做。

    execute_process 输出中去除尾随换行符的最简单方法是使用OUTPUT_STRIP_TRAILING_WHITESPACE 选项:

    execute_process(COMMAND <...>
        OUTPUT_VARIABLE LIBSTDCPP_PATH
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    

    【讨论】:

      【解决方案3】:

      有一个更简单的方法。请使用

      “execute_process(COMMAND readlink -fn ${SYMLINK_PATH} OUTPUT_VARIABLE FILE_PATH)
      

      -n 或 --no-newline 表示“不输出尾随的换行符”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-26
        • 2020-12-09
        • 1970-01-01
        • 1970-01-01
        • 2019-12-08
        • 2015-09-24
        • 1970-01-01
        相关资源
        最近更新 更多