Когда используемая функция не появится в таблице символов объектного файла - PullRequest
0 голосов
/ 28 марта 2020

Иногда некоторые явно называемые функции в единице перевода (TU) отсутствуют в таблице символов скомпилированного объектного файла (с nm -a C file.o). В чем может быть причина?

Причина может быть:

(1) Вызов оптимизирован: не для приведенного ниже примера, это отладочная версия, скомпилированная с -g.

(2) Вызов предварительно обработан и удален: не для приведенного ниже примера, нет #if вокруг вызова

(3) Он имеет псевдоним или предварительно обработан, чтобы иметь другое имя: не для Ниже приведен пример поиска в исходном коде AOSP под веткой skia. Нет связанных с ним # define / typedef

(4) Поскольку он встроен, для повышения скорости компиляции он может не скомпилироваться в каждом TU, вызывающем it.

(4-1) Но даже если он не скомпилирован, он, по крайней мере, появится в объектном файле как неопределенный символ, который будет найден компоновщиком позже, но этот символ вообще отсутствует Пример ниже.

(4-2) Если это так, учитывая, что все TU, которые вызывают функцию, компилируются независимо, как компилятор решает, когда компилировать встроенную функцию или нет?

Каковы другие возможные причины ?

Одним примером является SkOTTable_name. cpp в AOSP10:

namespace {
bool BCP47FromLanguageIdLess(const BCP47FromLanguageId& a, const BCP47FromLanguageId& b) {
    return a.languageID < b.languageID;
}
}

bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) {
...

    // Handle format 0 languages, translating them into BCP 47.
    const BCP47FromLanguageId target = { languageID, "" };
    int languageIndex = SkTSearch<BCP47FromLanguageId, BCP47FromLanguageIdLess>(
        BCP47FromLanguageID, SK_ARRAY_COUNT(BCP47FromLanguageID), target, sizeof(target));
...
}

Вызванная инстанцированная шаблонная встроенная функция " SkTSearch " не является результатом "nm - a C ... / SkOTTable_name.o ". Кстати, эта функция "SkOTTableName :: Iterator :: next" (которая вызывает "SkTSearch") находится в таблице символов.

Ссылка:

Вызванная функция "SkTSearch" находится в SkTSearch.h :

template <typename T, bool (LESS)(const T&, const T&)> struct SkTLessFunctionToFunctorAdaptor {
    bool operator()(const T& a, const T& b) { return LESS(a, b); }
};

// Specialization for case when T==K and the caller wants to use a function rather than functor.
template <typename T, bool (LESS)(const T&, const T&)>
int SkTSearch(const T base[], int count, const T& target, size_t elemSize) {
    static SkTLessFunctionToFunctorAdaptor<T, LESS> functor;
    return SkTSearch(base, count, target, elemSize, functor);
}

1 Ответ

1 голос
/ 28 марта 2020

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

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

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

...