CMake + Apple Clang で OpenMP 5 を使う
Mac で OpenMP 5 を使おうとして、苦戦したのでメモ。
C++ は割とわかっていないことが多いので、何か間違っていたらコメントください!
前提
- ビルドには CMake 3.29.0 を利用
- OpenMP は以下のように
find_package()
を使って発見します。
- OpenMP は以下のように
find_package(OpenMP 5.0)
if(OpenMP_CXX_FOUND)
target_link_libraries(${PROJECT_NAME} PUBLIC OpenMP::OpenMP_CXX)
else()
message(WARNING "OpenMP not found. It runs on single thread.")
endif()
- MacBook Pro 2019, Intel Core i9
- macOS Sonoma 14.2.1
試したこと
- gcc の OpenMP を使う
- Apple Clang + libomp
結論からいえば、2がうまく行きましが、設定に一手間必要でした。
1の方は gcc(brew で入れたもの) の OpenMP がどうしても 4.5 までしかいかず、 5 系は使えなかった・・・
gcc のドキュメントを見ると、OpenMP 5.0 の実装ステータスが N のものが結構あるので、まだだめなのかもしれません。
ここからは 2 の方の設定方法を書いていきます。
libomp
libomp は LLVM の OpenMP ランタイムライブラリです。 brew 経由でインストールできます。
brew install libomp
たぶん、libomp でうまくいくということは LLVM の Clang を使えばきっとうまくいくんですが、 VSCode の CMake 拡張機能で「構成」タブに LLVM が現れなかったので Apple Clang に libomp を組み合わせる方針でいきました。
Apple Clang は謎に2つある
CMake に libomp の場所を教える
CMake を使わずにコンパイルする際には -Xpreprocessor -fopenmp -lomp
オプションを付ければいけるようです(参考:Apple ClangでOpenMPを使う|Qiita)。しかし、 CMake でやろうとすると、 OpenMP が見つからないというエラーが出てなかなかうまく行きませんでした。
-- Could NOT find OpenMP_C (missing: OpenMP_C_FLAGS OpenMP_C_LIB_NAMES) (Required is at least version "5.0")
-- Could NOT find OpenMP_CXX (missing: OpenMP_CXX_FLAGS OpenMP_CXX_LIB_NAMES) (Required is at least version "5.0")
色々探し回った結果、みつけたのがこちら。
For macOS, first do:
brew install libomp
and set in ~/.zshrc
export OpenMP_ROOT=$(brew --prefix)/opt/libomp
環境変数 OpenMP_ROOT
を設定するのが肝でした。記事の通り ~/.zshrc
に以下の記述を加えます。
export OpenMP_ROOT=$(brew --prefix)/opt/libomp
これで、 CMake が libomp の場所を知ることができます!
場合によってはもうひと手間要る
この状態で cmake コマンドを実行すると、以下の警告が出ます。
CMake Warning (dev) at CMakeLists.txt:29 (find_package):
Policy CMP0074 is not set: find_package uses <PackageName>_ROOT variables.
Run "cmake --help-policy CMP0074" for policy details. Use the cmake_policy
command to set the policy and suppress this warning.
Environment variable OpenMP_ROOT is set to:
/usr/local/opt/libomp
For compatibility, CMake is ignoring the variable.
This warning is for project developers. Use -Wno-dev to suppress it.
-- Could NOT find OpenMP_C (missing: OpenMP_C_FLAGS OpenMP_C_LIB_NAMES) (Required is at least version "5.0")
-- Could NOT find OpenMP_CXX (missing: OpenMP_CXX_FLAGS OpenMP_CXX_LIB_NAMES) (Required is at least version "5.0")
要約すると、CMP0074 というポリシーが設定されておらず、環境変数の設定が無視されているようです。 CMP0074 を見てみましょう。
❯ cmake --help-policy CMP0074
CMP0074
-------
.. versionadded:: 3.12
``find_package()`` uses ``<PackageName>_ROOT`` variables.
In CMake 3.12 and above the ``find_package(<PackageName>)`` command now
searches prefixes specified by the ``<PackageName>_ROOT`` CMake
variable and the ``<PackageName>_ROOT`` environment variable.
Package roots are maintained as a stack so nested calls to all ``find_*``
commands inside find modules and config packages also search the roots as
prefixes. This policy provides compatibility with projects that have not been updated to avoid using ``<PackageName>_ROOT`` variables for other purposes.
The ``OLD`` behavior for this policy is to ignore ``<PackageName>_ROOT``
variables. The ``NEW`` behavior for this policy is to use
``<PackageName>_ROOT`` variables.
This policy was introduced in CMake version 3.12.
It may be set by ``cmake_policy()`` or ``cmake_minimum_required()``.
If it is not set, CMake warns, and uses ``OLD`` behavior.
.. note::
The ``OLD`` behavior of a policy is
``deprecated by definition``
and may be removed in a future version of CMake.
このポリシーは CMake 3.12 で追加されたポリシーで、 find_package()
が <PackageName>_ROOT
を使う、というポリシーになっています。
このポリシーを NEW
に設定するとポリシーが採用され、CMake または環境の変数<PackageName>_ROOT
によってパッケージルートを指定することが可能になります。
<PackageName>_ROOT
を他の目的で使っているプロジェクトとの互換性を保つため、デフォルトでは OLD
になっているようです。
以下のように明示的にポリシーを採用してあげるか、
cmake_policy(SET CMP0074 NEW)
cmake_minumum_required
を 3.12 以上に上げれば OpenMP_ROOT
が使われるようになります。
cmake_minimum_required(VERSION 3.12)
再度 cmake コマンドを実行すると・・・
❯ cmake -S . -B build
-- Found OpenMP_C: -Xclang -fopenmp (found suitable version "5.0", minimum required is "5.0")
-- Found OpenMP_CXX: -Xclang -fopenmp (found suitable version "5.0", minimum required is "5.0")
-- Found OpenMP: TRUE (found suitable version "5.0", minimum required is "5.0")
行けた!!
おわりに
というわけで、CMake + Apple Clang で OpenMP 5 を使うはなしでした。
他の方法があれば、ぜひコメントにて教えて下さい!
Discussion
CMake の requirement を 3.12 にすればすべて解決するかもしれない・・・