Да предположим, че работите с кодова база, включваща няколко инструмента и библиотеки, и искате да пренесете (или възкресите) някакъв компонент в рамките на такава кодова база, но всяка следа за това къде се намират символите в различните библиотеки е или изгубена, или ще отнеме много време, за да разберете, като погледнете самия код (да, подобрената документация може да избегне подобни проблеми, но е доста взискателна). Кой е най-бързият начин да откриете в коя библиотека можете да намерите символи, използвани в кода?
Как да намеря къде е дефиниран символ сред статични библиотеки
Отговори (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 секунди
Използването на превключвателя --defined-only
на nm е полезно тук, тъй като ще премахне недефинираните препратки. По-долу е даден 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