Когда используемая функция не появится в таблице символов объектного файла

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

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

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

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

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

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

(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 -aC .../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);
}

person jw_    schedule 28.03.2020    source источник


Ответы (1)


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

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

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

person walnut    schedule 28.03.2020