Есть ли хорошие советы или инструменты для удаления сторонних библиотек C и C ++ из базы кода?(OS X или Linux) - PullRequest
5 голосов
/ 21 октября 2011

Я нахожусь в процессе сокращения и карантина моего использования некоторых библиотек.Многие существующие программы, которые я написал, используют эти библиотеки напрямую.Я хотел бы, чтобы компилятор (GCC и / или Clang в данном случае) или какой-либо инструмент помогли бы мне идентифицировать эти применения по всей моей кодовой базе.Короче говоря, я хотел бы отравить использование этих библиотек в кодовой базе, за исключением того, что они будут использоваться одной библиотекой, и что одна библиотека будет видна другим модулям в моей кодовой базе.

Вопрос:

1) Знаете ли вы об инструментах, которые могут помочь мне в этом?

2) или вы можете порекомендовать некоторые стратегии, которые облегчат этот процесс?

Условия и детали:

  • Удаление их включений не вариант.
  • Поиск не эффективен из-за размера моей кодовой базы и количествасимволов, которые я хочу поместить в карантин.
  • Использование инструментов рефакторинга будет слишком утомительным, учитывая сложность кодовой базы и количество удаляемых символов.
  • Отдельный устаревший символ не является обязательным вариантом.на количество объявлений в сторонних библиотеках.
  • Интерфейсы сторонних библиотек написаны в основном на C.
  • Переводы будут C ++ и Objective-C ++.
  • Хитрость препроцессора не изящна для конфигурации моих сборок и может изменить слишком много файлов.
  • Не нужно исключать каждое последнее использование.В идеале они были бы, но большинство применений удовлетворительно.Это не является обязательным требованием просто потому, что слишком много обновлений.
  • Удаление их со стадии связывания в этом случае не является хорошим вариантом (подробно описано в Обновлении № 3).
  • В идеале,этот инструмент или стратегия будут доступны в OS X, но я также могу собрать значительную часть программ, ориентированных на Linux.

Некоторые стратегии, которые приходят на ум:

Лучшее, что я до сих пор придумал для этого случая, - это переопределить типы, которые использует библиотека, и украсить их устаревшими атрибутами:

typedef IHREType IHREType __attribute__((__deprecated__));

Но это не охватит все случаии отношение сигнал / шум будет довольно высоким после нескольких итераций.

В качестве альтернативы можно было бы переопределить эти типы в используемых мной корневых пространствах имен:

namespace MON {
typedef t_poisoned IHREType;
}

, но это станетнемного грязно.

Итак, я полагаю, что начну со стратегии устаревших атрибутов, но прежде чем я это сделаю, я думаю, что кто-то другой уже решил бы эту проблему и знал бы о ставкеter solution.

Обновление # 1

  • K-Бал упоминал хорошую стратегию (отравление через включение).К сожалению, в моем случае это не сработает. API-интерфейсы, которые я бы хотел поместить в карантин, также можно найти в системных средах, которые включены через API-интерфейсы, которые я не хочу помещать в карантин.

Обновление № 2

Добавлен Linux из-за малого количества ответов.

Обновление # 3

> > Justin: Removing them from the link stage is not a good option in this case.
> thiton: Why not? 

Чтобы уточнить этот момент: Iкак то, как библиотеки и проекты размещены в это время.Существует комбинация статических и динамических библиотек.Изменение этой структуры и синхронизация зависимостей отнимает много времени (хотя отдельные случаи могут быть хорошим использованием времени для некоторых библиотек ...).Компоновщик также разрешает большое количество символов, которые я хочу удалить из-за зависимостей (например, в системных библиотеках).

План, который я имею, приближается к этому

Естьсотни проектов Xcode в базе кодов (добавьте к этим проектам для других сборщиков / IDE).

Я сосредоточусь на этих обновлениях в течение нескольких дней здесь и нескольких дней там; 100% охват не является реалистичной целью на данный период времени, и в настоящее время это не является обязательным требованием. Из-за размера задачи и текущего состояния кодовой базы, я бы хотел сосредоточиться на удалении вхождений по номеру в это время. Удаление по номеру также предпочтительнее, потому что это в конечном итоге приведет к сокращению времени (требуется время, чтобы все это выстроить). Как только это уменьшится, я перейду к полной ликвидации - по крайней мере, это мой текущий план. В этом случае у меня есть время, чтобы выполнить обновления, но это еще не срочно. Если ваша рекомендация отличается от этой модели, у меня есть гибкость.

Ответы [ 6 ]

2 голосов
/ 28 октября 2011

Чтобы уточнить этот момент: мне нравится, как библиотеки и проекты разрабатываются в настоящее время.Существует комбинация статических и динамических библиотек.Изменение этой структуры и синхронизация зависимостей отнимает много времени (хотя отдельные случаи могут быть хорошим использованием времени для некоторых библиотек ...).Компоновщик также разрешает большое количество символов, которые я хочу удалить из-за зависимостей (например, в системных библиотеках).

Спасибо за разработку.Я опишу подход, основанный на компоновщике, потому что я не думаю, что эти причины являются полными ограничителями показа, но это, конечно, вам решать.

Вы можете написать очень маленькую библиотеку, которая содержит готовые версиивсех устаревших функций и вставьте их в вызов компоновщика для библиотек, где ваши функции должны быть устаревшими.Поскольку 99,99% линий компоновщика выглядят следующим образом:

ld $(FLAGS) a.o b.o c.o -la -lb -lc

, вы сможете вставить свою библиотеку следующим образом:

ld $(FLAGS) a.o b.o c.o -lpoison -la -lb -lc

без фактического изменения структуры ссылок.

Плюсы:

  • Этот подход должен работать и с libtool.
  • Нет необходимости менять источник.
  • Работает с системными библиотеками.
  • Перехватывает 100% вызовов функции.
  • Когда -lpoison связывается среальные объекты, вы можете выдавать предупреждения вместо ошибок во время выполнения.

Минусы:

  • Без использования какой-либо магии командной строки компоновщика (я не знаю ничего для этого,но у компоновщика есть вся необходимая информация), вам придется прибегнуть к ошибкам во время выполнения и трассировке стека во время выполнения, чтобы получить фактическое местоположение вызова.
  • Невозможно перехватить макросы или встроенные функции.

Пример: чтобы поймать использование pthread_create, вам нужно записать файл вроде:

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) {
     /* Print a backtrace and exit */
}

Скомпилировать этот файл в статическую библиотеку libpoison.a и добавитьэто ваш путь включения.

Предположим, что libA - это ваша интерфейсная библиотека для pthread, а libB и progc ее используют.Затем вы изменяете пути компоновщика следующим образом:

 # Leave that one unmodified
 ld -o libA.a libA-foo.o libA-bar.o -lpthread
 # Poison the rest
 ld -o libB.a libB-foo.o libB-bar.o -lpoison -lA
 ld -o progc progc-foo.o progc-bar.o -lpoison -lB -lA
2 голосов
/ 27 октября 2011

Вы можете использовать директиву #pragma GCC poison identifier, чтобы попросить GCC предупредить о дальнейшем использовании данного identifier

. Вы также можете использовать __attribute__((deprecated)) (в GCC) для аналогичных целей.

Если ваша кодовая база достаточно велика, чтобы затратить усилия, вы можете разработать плагин GCC 4.6 (или расширение GCC MELT , чтобы делать то, что вы хотите. (MELT - домен высокого уровня)специфический язык для расширения GCC).

И плагин GCC (болезненно закодированный в C) или расширение MELT (более легко кодируемое в MELT) может вести себя для вставки этих атрибутов или #pragma для вас.* Но автоматизировать такие задачи стоит только для не слишком маленькой базы кода.

2 голосов
/ 21 октября 2011

Я бы предоставил поверхностную версию включений с директивой #error или #warning, чтобы препроцессор сообщал мне, кто использует эти файлы.

1 голос
/ 01 ноября 2011

Является ли базовый размер кода хорошей причиной, чтобы не использовать что-то вроде find и grep? Они будут выполняться значительно быстрее, чем компиляция проектов.

Если вы беспокоитесь только о библиотеках, которые связаны между собой, вы можете ограничиться просмотром файлов конфигурации сборки. Вы говорите об OS X, так что, возможно, это просто файлы конфигурации xcode - иначе вы бы добавили make-файлы или что-то еще. В любом случае поиск нового типа файла конфигурации будет быстрее, чем изменение тех же файлов конфигурации для создания выходных данных особым образом.

Если это чистые заголовочные файлы, вы, вероятно, можете найти соответствующие пути включения в файлах конфигурации.

Одна из самых больших проблем была бы, если вы пытаетесь предотвратить использование системных заголовочных библиотек. В этом случае вам придется выполнить поиск исходного кода.

Если вы действительно против поиска, вы можете создать оболочки для вашего компилятора (и компоновщиков и т. Д.), Который ищет нужные аргументы, выдает предупреждение или ошибку, если найдены, и в противном случае передает их реальному компилятору.

1 голос
/ 31 октября 2011

Я бы порекомендовал посмотреть на doxygen . Может генерировать CALL_GRAPH и CALLER_GRAPH ( пример ).

Таким образом, вы можете просто генерировать документацию из своего кода и искать сторонние заголовки. Вы можете определить, кто вызвал эту функцию.

К сожалению, вам нужно знать, какие функции вы вызываете.

0 голосов
/ 02 ноября 2011

Следующее - это то, что я в конечном итоге использовал для подробного дампа использования по всей базе кода.

Я написал скрипт bash, который получил вывод nm (выводит символы изображения), исправил ифильтровал символы, затем grep просматривал результаты сопоставления символов по всей кодовой базе.

Осторожно: мои скриптовые способности ужасны.

#!/usr/bin/env bash

# TODO enter your source root to search here:
source_root=SOME_PATH_TO_SOURCE_CODE

# TODO enter the path to your binary to extract symbols from here:
binary=SOME_PATH_TO_BINARY

# a list of the symbols in binary
nm_symbols=$(nm -g -U -j $binary)

invalid_symbol="INVALID"

function trim_and_filter_symbol() {

    # note: input expects osx binaries
    # you may also want to disable some filters. this is the filter set I used:

    sym=${1}

    if [[
        "_" == ${sym:0:1} &&
        "_" == ${sym:1:1} &&
        "Z" == ${sym:2:1}
        ]]; then
        # ignore c++ symbols
        echo $invalid_symbol
    else
        sym=${sym#_}
        sym=${sym#_}
        sym=${sym#_}
    fi

    char_zero=${sym:0:1}
    char_last=${sym:${#at}-1:1}

    if [[ $char_zero == "$" ]]; then
        echo $invalid_symbol
    elif [[
        $char_zero == "+" ||
        $char_zero == "-" ||
        $char_zero == "[" ||
        $char_last == "]" ||
        $sym == *OBJC_METACLASS_* ||
        $sym == *OBJC_EHTYPE_* ||
        $sym == *OBJC_CLASS_* ||
        $sym == *OBJC_IVAR_*
        ]]; then
        # ignore objc symbols
        echo $invalid_symbol
    elif [[
        $sym == *PRETTY_FUNCTION* ||
        $sym == *func__.* ||
        $sym == *lock.* ||
        $sym == s.* ||
        $sym == *dyfunc.* ||
        $sym == *static_init.* ||
        $sym == *destroy_helper_block* ||
        $sym == *copy_helper_block* ||
        $sym == *block_holder_tmp* ||
        $sym == *block_descriptor_tmp* ||
        $sym == *_block_invoke_*
        ]]; then
        # ignore other miscellaneous symbols
        echo $invalid_symbol

    else
            # return the symbol
        echo $sym
    fi
}

function dump_grep_results() {
    symbol=${1}
    grep_result=${2}

    # filter or format to taste
    echo "*** Output for symbol '$symbol' :"
    echo ${grep_result}
    echo
    echo
    echo
}

echo Grepping source tree $source_root
echo for symbols in binary: $binary...
echo
echo
echo

for symbol_at in $nm_symbols;
do
    trimmed=$(trim_and_filter_symbol ${symbol_at})
    if [[ $invalid_symbol != $trimmed ]]; then

        grep_result=$(grep -r -n -I -H ${trimmed} ${source_root})

        if [[ "0" != ${#grep_result} ]]; then
            dump_grep_results ${trimmed} "$grep_result"
        fi
    fi
done

Я собираюсь назначить наградуМайклу Андерсону за то, что он подтолкнул нас в правильном направлении для решения, которое было ближе всего к тому, что требовала моя проблема (см. Комментарий).Спасибо всем за помощь и ответы - я проголосовал за все ваши ответы =)

...