web-dev-qa-db-fra.com

Pourquoi ne pouvez-vous pas cliqueter avec libc ++ en mode c ++ 0x pour lier cet exemple boost :: program_options?

Compilation de cet exemple de code pour boost :: program_options: http://svn.boost.org/svn/boost/trunk/libs/program_options/example/first.cpp

... sur MacOS Lion (10.7.2), en utilisant boost-1.48.0 installé avec MacPorts:

$ clang++ -v
Apple clang version 3.0 (tags/Apple/clang-211.12) (based on LLVM 3.0svn)
Target: x86_64-Apple-darwin11.2.0
Thread model: posix
$ clang++ -std=c++0x --stdlib=libc++ -lc++ -I/opt/local/include -L/opt/local/lib -lboost_program_options first.cpp -o first
Undefined symbols for architecture x86_64:
  "boost::program_options::options_description::options_description(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned int, unsigned int)", referenced from:
      _main in cc-6QQcwm.o
  "boost::program_options::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, boost::program_options::options_description const&)", referenced from:
      _main in cc-6QQcwm.o
  "boost::program_options::abstract_variables_map::operator[](std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const", referenced from:
      boost::program_options::variables_map::operator[](std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const in cc-6QQcwm.o
  "boost::program_options::detail::cmdline::set_additional_parser(boost::function1<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>)", referenced from:
      boost::program_options::basic_command_line_parser<char>::extra_parser(boost::function1<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>) in cc-6QQcwm.o
  "boost::program_options::detail::cmdline::cmdline(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)", referenced from:
      boost::program_options::basic_command_line_parser<char>::basic_command_line_parser(int, char const* const*) in cc-6QQcwm.o
  "boost::program_options::to_internal(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
      std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > boost::program_options::to_internal<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&) in cc-6QQcwm.o
  "boost::program_options::invalid_option_value::invalid_option_value(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
      void boost::program_options::validate<int, char>(boost::any&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, int*, long) in cc-6QQcwm.o
  "boost::program_options::validation_error::validation_error(boost::program_options::validation_error::kind_t, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
      std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const& boost::program_options::validators::get_single_string<char>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, bool) in cc-6QQcwm.o
  "boost::program_options::value_semantic_codecvt_helper<char>::parse(boost::any&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, bool) const", referenced from:
      vtable for boost::program_options::typed_value<int, char> in cc-6QQcwm.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Le même code compilé/lié avec g ++ 4.7 installé avec MacPorts:

$ g++-mp-4.7 -std=c++0x -I/opt/local/include -L/opt/local/lib -lboost_program_options -o first first.cpp

... fonctionne bien. Tout comme l'utilisation de clang sans libc ++:

clang++ -std=c++0x -I/opt/local/include -L/opt/local/lib -lboost_program_options first.cpp -o first

Qu'est-ce qui ne va pas? Pourquoi boost :: program_options et libc ++ ne fonctionnent-ils pas ensemble?

63
x-x

Vous devez reconstruire le boost en utilisant clang ++ -stdlib = libc ++.

libc ++ n'est pas compatible binaire avec libstdc ++ de gcc (à l'exception de quelques trucs de bas niveau comme l'opérateur new). Par exemple, le std::string dans libstdc ++ de gcc est recompté, alors que dans libc ++ il utilise "l'optimisation des chaînes courtes". Si vous deviez accidentellement mélanger ces deux chaînes dans le même programme (et les confondre avec la même structure de données), vous obtiendriez inévitablement un crash d'exécution.

Cet accident est exactement ce qui s'est produit dans votre cas.

Afin de transformer ce plantage au moment de l'exécution en une erreur de temps de liaison, libc ++ utilise une fonctionnalité de langage C++ 11 appelée inline namespace pour changer le ABI de std::string sans impact sur API of std::string. Autrement dit, pour vous std::string semble pareil. Mais pour l'éditeur de liens, std::string est modifié comme s'il se trouvait dans l'espace de noms std::__1. Ainsi, l'éditeur de liens sait que std::basic_string et std::__1::basic_string sont deux structures de données différentes (la première provenant de libstdc ++ de gcc et la seconde provenant de libc ++).

134
Howard Hinnant