プログラミングの授業で、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
で処理を詳しくみるとわかる。
出力はかなり長いが、注目すべき場所はclang
がld
を呼んだ時の-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