Странное поведение с readlink под cmake

Я пытаюсь использовать 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 = / опт / gcc4.9.3 / lib64 / libstdC++. So.6
LIBSTDCPP_ABSPATH=/ опт / gcc4.9.3 / lib64 / libstdC++. So.6

Это также происходит, если я обертываю его в сценарий оболочки: execute_process(COMMAND doreadlink.sh ${LIBSTDCPP_PATH} OUTPUT_VARIABLE LIBSTDCPP_ABSPATH2) message("LIBSTDCPP_ABSPATH2=${LIBSTDCPP_ABSPATH2}")

> LIBSTDCPP_ABSPATH2 = / опт / gcc4.9.3 / lib64 / libstdC++. So.6

Это также происходит с использованием get_filename_component() с REALPATH, что должно быть каноническим способом 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] close(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] 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] доступ ("/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
write(2, "LIBSTDCPP_ABSPATH=/usr/lib64/lib"..., 45LIBSTDCPP_ABSPATH=/usr/lib64/libstdC++. so.6
) = 45

Так что это выглядит как выполнение правильной системной команды.

Вот CMakeLists.txt, чтобы воспроизвести проблему:

Проект cmake_minimum_required(версия 2.8) (ТЕСТ CXX) множество (CPP11_PATH ${CMAKE_CURRENT_BINARY_DIR}/cpp11)
execute_process(КОМАНДА г ++ ${CMAKE_CURRENT_SOURCE_DIR}/cpp11.cpp -o${CPP11_PATH})

#execute_process(КОМАНДА LDD $ {CPP11_PATH} КОМАНДА Grep libstdC++ КОМАНДА AWK "{печать $3; }" COMMAND xargs readlink -f OUTPUT_VARIABLE LIBSTDCPP_PATH)
execute_process(КОМАНДА LDD $ {CPP11_PATH} КОМАНДА Grep libstdC++ COMMAND AWK "{печать $3; }" OUTPUT_VARIABLE LIBSTDCPP_PATH) сообщение ("LIBSTDCPP_PATH=${LIBSTDCPP_PATH}")
execute_process(COMMAND readlink -f ${LIBSTDCPP_PATH} OUTPUT_VARIABLE LIBSTDCPP_ABSPATH) сообщение ("LIBSTDCPP_ABSPATH=${LIBSTDCPP_ABSPATH}") 

2 ответа

Решение

Многие утилиты оболочки, которые выводят одну строку, заканчивают ее символом новой строки (\n). Это сделано для красивого вывода в терминале.

В отличие от оператора backtricks (`exec-some-command`) в оболочке Linux, который автоматически удаляет завершающий символ новой строки, execute_process не делает это по умолчанию.

Самый простой способ убрать завершающий перевод строки execute_process выход использовать OUTPUT_STRIP_TRAILING_WHITESPACE Вариант для этого:

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

Цыварев прибил это. Проблема в том, что в конце моего awk выводится завершающий символ новой строки. Если я изменю это с: awk "print $3" чтобы: awk "printf($3)"

Все работает как положено. Ура!

Есть более простой способ. Пожалуйста, используйте

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

-n или —-no-newline означает "не выводить завершающий перевод новой строки".

Другие вопросы по тегам