Предположим, вы работаете с кодовой базой, состоящей из нескольких инструментов и библиотек, и вы хотите портировать (или воскресить) какой-то компонент в этой кодовой базе, но любая подсказка о том, где символы лежат в различных библиотеках, либо потеряна, либо потребуется время, чтобы выяснить это, глядя на код. сам код (да, улучшенная документация может избежать таких проблем, но она довольно требовательна). Как быстрее всего узнать, в какой библиотеке можно найти символы, используемые в коде?
Как найти, где символ определен среди статических библиотек
Ответы (3)
Предполагая, что это Linux-система, на помощь приходит инструмент nm, перечисляющий имена в библиотечных файлах.
Его можно использовать для расширенного поиска следующим образом: сначала можно найти все доступные библиотеки (при условии, что проект был успешно скомпилирован без добавляемого компонента) с помощью поиска, затем такой поиск можно заключить в цикл, в котором вы вызывать nm для всех обнаруженных библиотек; вывод, который вы затем выполняете grep для отбрасывания ссылок «U» (неопределенные символы, то есть где еще используется символ). В одной строке bash, которая дает:
for lib in $(find base_path -name \*.a) ; do echo $lib ; nm $lib | grep my_symbol | grep -v " U " ; done
куда:
- base_path — это корень вашей кодовой базы.
- my_symbol — это символ, который вы ищете
Эхо генерирует список всех найденных библиотек, что не так чисто, поскольку выводит имена библиотек, не содержащих символ, но это был самый быстрый способ получить прямую ссылку на библиотеку, поэтому, когда вы видите:
base_path/component/libA.a
0000000000000080 D my_symbol
Вы нашли своего обычного подозреваемого.
Используя nm
, можно перечислить символы, определенные в двоичном формате, а переключатель --defined-only
игнорирует неопределенные ссылки.
Вариант 1: find
В одной команде:
find $path -name \*.a -exec bash -c "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}" \;
где $path
— корень дерева файлов, содержащего двоичные файлы, а $symbol
— имя искомого символа.
Вариант 2: find
+ GNU parallel
Выполнение nm
для всех файлов может занять некоторое время, поэтому было бы полезно обрабатывать результаты find
параллельно (используя GNU parallel
):
find $path -name \*.a | parallel "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"
Вариант 3: fd
И, наконец, мой любимый. Использование инструмента fd
с более простым синтаксисом, чем find
, как правило, быстрее и обрабатывает результаты параллельно. по умолчанию:
fd '.*\.a$' -x bash -c "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"
Простой тест
Поиск символа gz_write
в /usr/lib
на моем ноутбуке:
find
занимает около 23 секундfind | parallel
занимает около 10 секундfd
занимает около 8 секунд
Здесь полезно использовать переключатель nm --defined-only
, так как он удалит неопределенные ссылки. Ниже приведен скрипт csh, который может быть полезен другим.
#!/bin/csh
#
#recurse from current dir and output name of any .a files
#that contain the desired symbol.
echo "Search for: $1"
foreach i (`find . -name '*.a'`)
nm --defined-only $i | grep $1
if ($status == 0) then
echo $i
endif
end