Получение указателя на член std::string::size не может связать с libC++, но работает с libstdC++

Я нахожусь на проекте, где мне нужно использовать libC++. У меня возникла следующая проблема:

Когда я пытаюсь скомпилировать следующий код:

#include <string>
int main()
{
    std::string::size_type (std::string::*function)() const = &std::string::size;
    return 0;
}

Я получаю следующую ошибку:

ld: символы не найдены для архитектуры x86_64

Если я использую libstdC++ вместо libC++, я не получаю ошибок, поэтому проблема должна быть связана с libC++.

Полный вывод ниже:

clang++ --stdlib=libc++ -v main.cpp 
Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.10.0 -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 241.9 -v -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0 --stdlib=libc++ -fdeprecated-macro -fdebug-compilation-dir /Users/filipe/Downloads -ferror-limit 19 -fmessage-length 197 -stack-protector 1 -mstackrealign -fblocks -fobjc-runtime=macosx-10.10.0 -fencode-extended-block-signature -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -vectorize-slp -o /var/folders/8k/34ll5dcj3c5c9sph_bwk1zr00000gn/T/main-5b89bb.o -x c++ main.cpp
clang -cc1 version 6.0 based upon LLVM 3.5svn default target x86_64-apple-darwin14.1.0
ignoring nonexistent directory "/usr/include/c++/v1"
#include "..." search starts here:
#include <...> search starts here:
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /usr/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.10.0 -o a.out /var/folders/8k/34ll5dcj3c5c9sph_bwk1zr00000gn/T/main-5b89bb.o -lc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::size() const", referenced from:
      _main in main-5b89bb.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

2 ответа

Решение

Это выглядит как libc++ ошибка этой темы: _LIBCPP_INLINE_VISIBILITY и std::string::length, которые делают нечто подобное, и ответ Говарда Хиннанта таков:

Я считаю, что это связано с плохим взаимодействием в компиляторе между внешними шаблонами и __attribute__ ((__always_inline__)). Если std:: string не объявлен как внешний шаблон, тогда компилятор наметит член size(), и вы не получите эту ошибку ссылки.

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

Обоснованием использования Always_inline в libC++ является управление ABI libC++. В прошлом я наблюдал, как компиляторы используют разные эвристики от выпуска к выпуску при принятии встроенного / набросочного решения. Это может привести к тому, что код будет добавлен в dylib и удален из него. С использованием always_inline я говорю компилятору никогда не добавлять этот код в двоичный файл libC++. Dylib.

Каждый из макросов, определенных и используемых libC++, может быть переопределен.

_LIBCPP_INLINE_VISIBILITY управляет назначением встроенной функции и по умолчанию:

#ifndef _LIBCPP_INLINE_VISIBILITY
#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__))
#endif

Вы можете отключить это с:

-D_LIBCPP_INLINE_VISIBILITY = ""

И внешние шаблоны сделаны с:

#ifndef _LIBCPP_EXTERN_TEMPLATE
#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
#endif

Этот последний сложнее "выключить". Заклинание это:

-D'_LIBCPP_EXTERN_TEMPLATE (...) ="

Использование любого (или обоих) из этих обходных путей отключит ошибку вашей ссылки. Но сообщение об ошибке в Clang может быть лучшим долгосрочным решением.

Я не могу воспроизвести это на coliru, но я могу на wandbox и используя оптимизацию, которая использует -O2 флаг убирает проблему Я не смог заставить wandbox принять -D варианты, предложенные выше, поэтому не уверен, что это работает.

На моей локальной машине работает решение Говарда:

clang++ -D_LIBCPP_INLINE_VISIBILITY="" -D'_LIBCPP_EXTERN_TEMPLATE(...)='

Я не нашел сообщения об ошибке, и если я его не найду, его может иметь смысл подать.

Изучив информацию Shafik Yaghmour, я нашел решение, которое не требует изменения флагов компиляции.

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

#include <string>

template class std::basic_string<char>;

int main()
{
    std::string::size_type (std::string::*function)() const = &std::string::size;
    return 0;
}

Более подробная информация здесь: использование шаблона extern (C++11)

Другие вопросы по тегам