OpenMP support in OS X via g++

OpenMP is a convenient tool for quickly prototyping multi-processing algorithms in C/C++. Most modern compilers provide an implementation, including LLVM. Unfortunately, Apple thought it was useless. It is possible to compile OpenMP yourself but i decided to install g++ anyway, mainly because many clusters provide g++ only and both compiler are not 100% compatible.

In this short note, I will quickly explain how to install g++ and enable OpenMP via manual compilation or via CMake.

Installation

First, install gcc via brew:

$ brew install gcc

Then, create symbolic links:

$ ln -s /usr/local/bin/gcc /usr/local/bin/gcc-7
$ ln -s /usr/local/bin/gcc/cc /usr/local/bin/gcc-7
$ ln -s /usr/local/bin/gcc/g++ /usr/local/bin/g++-7
$ ln -s /usr/local/bin/gcc/c++ /usr/local/bin/c++-7

And add this directory to your path if not present yet:

export PATH=/usr/local/bin:$PATH

You can also use aliases, but CMake will not be aware of them. Note that if you want to use boost with g++, you will have to compile it yourself. The easiest way is:

$ brew install boost --cc=gcc-7

Manual compilation

If you are using g++ for compilation and linking, you are ready to go:

$ g++-7 example.cpp -o example -fopenmp

However, if you are using ld to link your program, things are a little trickier as you have to tell it where to find libraries installed via brew. Note that by default OS X will ignore the LD_LIBRARY_PATH environment variable. You can either manually disable this protection or give the additional search path explicitly to the linker. The simplest way to get the path where brew installed OpenMP is to compile a simple program with verbosity enabled:

$ g++-7 example.o -o example -fopenmp -v
Using built-in specs.
COLLECT_GCC=g++-7
...
Library search paths:
        /Users/filippo/repos/dynet/build/dynet
        /Users/filippo/repos/dynet/build/dynet
        .
        /usr/local/Cellar/gcc/7.2.0/lib/gcc/7/gcc/x86_64-apple-darwin17.0.0/7.2.0
        /usr/local/Cellar/gcc/7.2.0/lib/gcc/7
        /usr/lib
        /usr/local/lib
...

Thus, the linking command will be something like:

$ ld \
    -o example example.o \
    -lgomp \
    -lstdc++ \
    -lSystem \
    -arch x86_64 \
    -L/usr/local/lib \
    -L/usr/local/Cellar/gcc/7.2.0/lib/gcc/7/gcc/x86_64-apple-darwin17.0.0/7.2.0 \
    -L/usr/local/Cellar/gcc/7.2.0/lib/gcc/7/gcc/x86_64-apple-darwin17.0.0/7.2.0/../../..

Note that the OpenMP shared object file is called libgomp.so and not libopenmp.so, hence the -lgomp option.

CMake

You have to make sur that CMake use g++, either as a command line option:

$ cmake .. -DCMAKE_CXX_COMPILER=g++

or in your CMakelist.txt file:

set(CMAKE_CXX_COMPILER "g++")

You have two options to enable OpenMP. The first one is to add the compiler options globally with FindOpenMP:

include(FindOpenMP)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")

The second one is to manually link the library to desired targets:

set_target_properties(example PROPERTIES COMPILE_FLAGS "-fopenmp")
target_link_libraries(example gomp)

social