在cmake下使用readlink的奇怪行为

时间:2016-02-09 18:54:11

标签: linux cmake readlink

我尝试使用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)

可能会在幕后做些什么?

我试过跑步: 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 (No such file or directory)
[pid 23195] execve("/usr/local/bin/readlink", ["readlink", "-f", "/lib64/libstdc++.so.6\n"], [/* 53 vars */]) = -1 ENOENT (No such file or directory)
[pid 23195] execve("/usr/bin/readlink", ["readlink", "-f", "/lib64/libstdc++.so.6\n"], [/* 53 vars */] 
[pid 23174]  "", 1)   = 0
[pid 23195]  )      = 0
[pid 23174] close(11)                   = 0
[pid 23174] rt_sigprocmask(SIG_SETMASK, [],  
[pid 23195] brk(0 
[pid 23174]  NULL, 8) = 0
[pid 23195]  )         = 0x12e5000
[pid 23174] read(9, "", 1024)           = 0
[pid 23174] close(9)                    = 0
[pid 23195] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 
[pid 23174] close(6)                    = 0
[pid 23195]  )        = 0x7ff41654f000
[pid 23174] close(8)                    = 0
[pid 23195] access("/etc/ld.so.preload", R_OK 
[pid 23174] select(8, [3 5 7], NULL, NULL, NULL 
[pid 23195]  )      = -1 ENOENT (No such file or directory)
[pid 23195] open("tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] open("tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] open("x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] open("libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] open("/usr/local/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] stat("/usr/local/lib/tls/x86_64", 0x7fff36038350) = -1 ENOENT (No such file or directory)
[pid 23195] open("/usr/local/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] stat("/usr/local/lib/tls", 0x7fff36038350) = -1 ENOENT (No such file or directory)
[pid 23195] open("/usr/local/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

剪断

O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] stat("/usr/lib/oracle/10.2.0.4/client/lib/tls", 0x7fff36038350) = -1 ENOENT (No such file or directory)
[pid 23195] open("/usr/lib/oracle/10.2.0.4/client/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 23195] stat("/usr/lib/oracle/10.2.0.4/client/lib/x86_64", 0x7fff36038350) = -1 ENOENT (No such file or directory)
[pid 23195] open("/usr/lib/oracle/10.2.0.4/client/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
rt_sigprocmask(SIG_BLOCK, [INT TERM CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(2, "LIBSTDCPP_ABSPATH=/usr/lib64/lib"..., 45LIBSTDCPP_ABSPATH=/usr/lib64/libstdc++.so.6

) = 45

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

这是一个重现问题的CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(TEST CXX) 

set(CPP11_PATH ${CMAKE_CURRENT_BINARY_DIR}/cpp11)
execute_process(COMMAND 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)
message("LIBSTDCPP_PATH=${LIBSTDCPP_PATH}")
execute_process(COMMAND readlink -f ${LIBSTDCPP_PATH} OUTPUT_VARIABLE LIBSTDCPP_ABSPATH)
message("LIBSTDCPP_ABSPATH=${LIBSTDCPP_ABSPATH}")

3 个答案:

答案 0 :(得分:1)

输出单行的许多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
)

答案 1 :(得分:0)

Tsyvarev已经钉了它。问题是由我的awk输出引起的尾随换行。 如果我改变它: awk "print $3" 至: awk "printf($3)"

一切按预期工作。乌拉!

答案 2 :(得分:0)

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

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

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