sankantsuのブログ

技術メモ・競プロなど

MacOS: binary release の clang を使う際のビルドエラーの解消

概要

デフォルトでインストールされている clang++ と違うバージョンのものを使う必要があり、 https://releases.llvm.org/ から tar.xz アーカイブでダウンロードして使っていたところ、ビルドの際にエラーが出ていた。

対処法などをメモしておく。

環境

https://github.com/llvm/llvm-project/releases/tag/llvmorg-16.0.0

から

https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.0/clang+llvm-16.0.0-arm64-apple-darwin22.0.tar.xz

をダウンロードして、/usr/local/以下にインストールした状態

$ sw_vers
ProductName:        macOS
ProductVersion:     13.3.1
ProductVersionExtra:    (a)
BuildVersion:       22E772610a
$ clang++ --version
clang version 16.0.0
Target: arm64-apple-darwin22.4.0
Thread model: posix
InstalledDir: /usr/local/bin

デフォルトの clang++ (/usr/bin/clang++) だと問題は生じない

問題

// main.cc
int main() {}

例えば、上のような空の main 関数だけのファイルを

$ clang++ main.cc

コンパイルするだけでも、以下のリンクエラーが発生

ld: library not found for -lSystem
clang-16: error: linker command failed with exit code 1 (use -v to see invocation)

さらに、標準ヘッダをなにか使うようなものをコンパイルしてみると...

// hello.cc
#include <iostream>

int main() {
    std::cout << "Hello, clang!" << std::endl;
}

以下のように大量にエラーが出てくる。

In file included from hello.cc:1:
In file included from /usr/local/bin/../include/c++/v1/iostream:43:
In file included from /usr/local/bin/../include/c++/v1/ios:220:
In file included from /usr/local/bin/../include/c++/v1/__ios/fpos.h:14:
In file included from /usr/local/bin/../include/c++/v1/iosfwd:100:
In file included from /usr/local/bin/../include/c++/v1/__mbstate_t.h:29:
/usr/local/bin/../include/c++/v1/wchar.h:143:77: error: use of undeclared identifier 'wcschr'
wchar_t* __libcpp_wcschr(const wchar_t* __s, wchar_t __c) {return (wchar_t*)wcschr(__s, __c);}
                                                                            ^
/usr/local/bin/../include/c++/v1/wchar.h:150:87: error: use of undeclared identifier 'wcspbrk'
wchar_t* __libcpp_wcspbrk(const wchar_t* __s1, const wchar_t* __s2) {return (wchar_t*)wcspbrk(__s1, __s2);}

/* ... */
                                                                                      ^
/usr/local/bin/../include/c++/v1/stdlib.h:150:34: error: unknown type name 'ldiv_t'
inline _LIBCPP_INLINE_VISIBILITY ldiv_t div(long __x, long __y) _NOEXCEPT {
                                 ^
/usr/local/bin/../include/c++/v1/stdlib.h:151:12: error: no member named 'ldiv' in the global namespace
  return ::ldiv(__x, __y);
         ~~^
/usr/local/bin/../include/c++/v1/stdlib.h:154:34: error: unknown type name 'lldiv_t'
inline _LIBCPP_INLINE_VISIBILITY lldiv_t div(long long __x,
                                 ^
/usr/local/bin/../include/c++/v1/stdlib.h:156:12: error: no member named 'lldiv' in the global namespace
  return ::lldiv(__x, __y);
         ~~^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.

stdlib.hwchar.h 等のC由来のヘッダファイルがうまく読み込まれていない?

対処法

リンクエラーについて、もう一回内容を見てみる。

ld: library not found for -lSystem
clang-16: error: linker command failed with exit code 1 (use -v to see invocation)

libSystem というライブラリが見つからないと言っているらしい。

探してみると...

$ fd 'libSystem' /
/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/lib/libSystem.tbd
/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/lib/libSystem.B_asan.tbd
/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/lib/libSystem.B.tbd
/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/lib/libSystem_asan.tbd
/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/CoreTelephony.framework/Support/libSystemDetermination.tbd
# more files...

どうやら /Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk 以下などにあるらしい。

実際、

clang++ -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib main.cc

などで明示的にライブラリの search path に入れてやることでコンパイルが通るようになった。 (/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/ はバージョン番号付きの .sdk ディレクトリへのシンボリックリンクになっている。)

ヘッダファイルの方に関するエラーも

$ clang++ \
    -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1 \
    -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include \
    -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib \
    hello.cc

のように明示的に include path を追加してやるとコンパイルが通った。

環境変数

コマンドラインでパスを明示してやることで一応の解決はするのだが、オプションが長すぎてやってられない。 これらのパスを常に探してくれるように指定するためには環境変数を使ってやればよい。

ライブラリのほうは LIBRARY_PATH、ヘッダのほうは CPATH を使えば良いようである。

設定の一例を以下に載せておく。

export SDK_ROOT="/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"

export CPATH="${SDK_ROOT}/usr/include:${CPATH}"
export CPATH="${SDK_ROOT}/usr/include/c++/v1:${CPATH}"

export LIBRARY_PATH="${SDK_ROOT}/usr/lib:${LIBRARY_PATH}"

蛇足

環境変数について、man clang の ENVIRONMENT セクションにドキュメントされている。 ただし、この中に LIBRARY_PATH の記述は見当たらない。

man gcc のほうには記述があるので、clang 側が暗黙に gcc への互換性を保つような実装をしているということだろうか?

ライブラリの search path について、LDFLAGSLD_LIBRARY_PATH 等を使えば良いと書いてある記述も見かけたが、自分の環境ではうまく動かなかった。

また、一応以上のやり方で解決に至ったものの、MacOS まわりの開発環境に疎いのもあって結局 MacOSX.sdk が何者なのかとかはよくわからない。 詳しい方がいたらぜひ教えていただけたら幸いである。