Building OpenMP code is actually possible using Apple Clang that comes default with macOS’s Xcode! Although Apple does not build the OpenMP library, the compiler still supports it. In this post, I demonstrate the procedure necessary to include OpenMP in your build, both with the new support in CMake 3.12, as well as how it would be done without it.
Building OpenMP
The first order of business is to obtain a copy of the OpenMP runtime library. The procedure is outlined by the LLVM OpenMP project, but I would recommend using Homebrew. If you are using that, just run the following line:
brew install libomp
This will install the necessary files into $(brew --prefix libomp)
(usually
/usr/local/opt/libomp
) and symbolically link them into $(brew --prefix)
(usually /usr/local
). You can always unlink from the main prefix directory by
running brew unlink libomp
.
Using OpenMP directly
If you want to build with OpenMP, you would normally do something like this:
clang++ -fopenmp myfile.cxx
But, as you probably know, this fails on Apple Clang due to the missing the
built-in OpenMP library. But, Apple Clang does allow you to process the OpenMP
pragmas with -Xpreprocessor -fopenmp
, and then you can manually link to the
OpenMP library. Assuming /usr/local
contains OpenMP and you have your paths
set up for it, you can simply run:
clang -Xpreprocessor -fopenmp -lomp myfile.cxx
If you don’t, you need to add explicit directories:
clang -Xpreprocessor -fopenmp -lomp -I"$(brew --prefix libomp)/include" -L"$(brew --prefix libomp)/lib" myfile.cxx
In this case, you might need to also set DYLD_LIBRARY_PATH for the runtime library to be correctly discovered.
Using OpenMP in CMake
Modern method:
CMake 3.12 has built in support for AppleClang’s OpenMP, as long as you use the
target based system. An example of a CMakeLists.txt
that would support OpenMP
on macOS:
cmake_minimum_required(VERSION 3.12)
project(openmptest CXX)
add_executable(sample sample.cpp)
find_package(OpenMP REQUIRED)
target_link_libraries(sample PRIVATE OpenMP::OpenMP_CXX)
Thanks to Roman Bange for the example. You can also conditionally add the OpenMP target if it doesn’t exist, if you want to support a wide range of CMakes (I recommend simply requiring CMake 3.12 if the user wants OpenMP + Apple). See Modern CMake’s OpenMP example or the example at the end of this post.
Classic method:
If you want to use OpenMP in CMake older than 3.12, or if the library you are building does not use the target system, you can either add the following to the command line when you build:
-DOpenMP_CXX_FLAGS="-Xpreprocessor -fopenmp -I$(brew --prefix libomp)/include" -DOpenMP_CXX_LIB_NAMES="omp" -DOpenMP_omp_LIBRARY=$(brew --prefix libomp)/lib/libomp.a
You’ll want a recent version of CMake, and you’ll need the package author to use
the OpenMP::OpenMP_CXX
target instead of linking to the flags (which used to
be common in older CMakes but is incorrect).
Or, if you are working on a CMakeLists, you can include my cmake
helpers in
your module path and include(PatchAppleOpenmp)
, and those lines will be added
if you are using Apple Clang and have the Homebrew package.
Bonus: Using FindOpenMP correctly:
This is the best way to add OpenMP to be compatible with CMake 3.1+. I’m assuming OpenMP is required and that you are working on a target called MyProgram:
find_package(OpenMP REQUIRED)
if(NOT TARGET OpenMP::OpenMP_CXX)
add_library(OpenMP_TARGET INTERFACE)
add_library(OpenMP::OpenMP_CXX ALIAS OpenMP_TARGET)
target_compile_options(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS})
find_package(Threads REQUIRED)
target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads)
target_link_libraries(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS})
endif()
target_link_libraries(MyLibraries PUBLIC OpenMP::OpenMP_CXX)