Help us understand the problem. What is going on with this article?

C++のコードを何も考えずにclangでコンパイルしたらこけた

プログラミングの授業で、C++のコードが公開されていた。
Mac環境でターミナルからコンパイルしようとしてこけたのでメモ

>>> TL;DR (解決法) <<<

Disclaimer

  • 学校でLinuxでC言語の課題をやる際に使っていたコンパイル用コマンドは以下の通り。C言語の時は、 Macでも通っていた。
    • gcc -Wall -o exec_name source_1_name.c source_2_name.c ....
  • 学校でやった流れで家のMacでもgccと打ち込んだが、中身はclangである。
  • 以前この記事は、「Windows環境で書かれたC++コード(WINAPIを利用するように見えて実は利用しないコード)」に対して書いていましたが、WINAPIが必要なコードは結局Macでもコンパイルすることはないだろう(少なくともこの記事の解決法はそれを回避する方法が書いていない)と考えたのでもう少し一般的なところに書き直しました
$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

コードの構造

Project
|- subclass.cpp (main.cppで使うクラスを定義)
|- subclass.h (↑のヘッダファイル)
|- main.cpp (int main()はここ)

何も考えずにgcc (or clang)

$ clang -Wall main.cpp subclass.cpp
Undefined symbols for architecture x86_64:
  "std::__1::locale::use_facet(std::__1::locale::id&) const", referenced from:
      _main in main-f40c0c.o
  "std::__1::ios_base::getloc() const", referenced from:
      _main in main-f40c0c.o
  "std::__1::basic_ostream<char, std::__1::char_traits<char> >::put(char)", referenced from:
      _main in main-f40c0c.o
  "std::__1::basic_ostream<char, std::__1::char_traits<char> >::flush()", referenced from:
      _main in main-f40c0c.o
  "std::__1::basic_ostream<char, std::__1::char_traits<char> >::operator<<(int)", referenced from:
      _main in main-f40c0c.o
  "std::__1::cout", referenced from:
      _main in main-f40c0c.o
  "std::__1::ctype<char>::id", referenced from:
      _main in main-f40c0c.o
  "std::__1::locale::~locale()", referenced from:
      _main in main-f40c0c.o
  "std::terminate()", referenced from:
      ___clang_call_terminate in main-f40c0c.o
  "operator delete[](void*)", referenced from:
      IntArray::~IntArray() in IntArray-0d8654.o
      IntArray::~IntArray() in IntArray-0d8654.o
  "operator new[](unsigned long)", referenced from:
      IntArray::IntArray(int) in IntArray-0d8654.o
      IntArray::IntArray(int) in IntArray-0d8654.o
  "___cxa_begin_catch", referenced from:
      ___clang_call_terminate in main-f40c0c.o
  "___gxx_personality_v0", referenced from:
      _main in main-f40c0c.o
      Dwarf Exception Unwind Info (__eh_frame) in main-f40c0c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

WTF?!?!?!?
Xcodeでの開発の経験があったので、こういうパターンの出力は何らかのライブラリがない(か、ヘッダで宣言だけして実装を忘れるというポカをやった)可能性があるということはわかったのだが、includeの必要なものは全てやったはずだった。

少し調べてみると何も考えずにclangでコンパイルした場合C++ライブラリが使われないことが判明した。

正しいコンパイル方法

明示的にlibc++とリンクする

$ clang -Wall main.cpp subclass.cpp -lc++

clang++を使う

$ clang++ -Wall main.cpp subclass.cpp

こいつはコンパイル時に-lc++をつけてくれる。-vで処理を詳しくみるとわかる。
出力はかなり長いが、注目すべき場所はclangldを呼んだ時の-lSystemフラグの前だ。

  • clangの出力内容の一部
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.11.0
...(中略)...
-lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/lib/darwin/libclang_rt.osx.a
  • clang++の出力内容の一部
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.11.0
...(中略)...
-lc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/lib/darwin/libclang_rt.osx.a

追記 2019/10/23: Apple LLVM Version 10.0.0でも対処法は同じことを確認済みです。

・ω)┌┘’,;’;≡三<ClpsPLUG R1 (H31) 10/23 10:58:32)
> gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away