66

I would like to verify that the current compiler can build with openmp support. The application has do deploy across a wide variety of unix systems, some of which might have old versions of OpenMP, and I would like to test for important OpenMP functionality. So, I want to build a test source file that incorporates some of the OpenMP calls.

Thus, I created a very simple test file, and attempted to use the try_compile function from CMake. Ufortunately, it doesn't seem to apply the -fopenmp linker flag correctly. Does anyone know how to either force the linker flag or to see if the linker flag is being applied anywhere?

from CMakeLists.txt

try_compile(
    HAVE_OPENMP
    ${APBS_ROOT}/src/config
    ${APBS_ROOT}/src/config/omp_test.c
    CMAKE_FLAGS "-DCMAKE_C_FLAGS=-fopenmp -DCMAKE_EXE_LINKER_FLAGS=-fopenmp"
    OUTPUT_VARIABLE TRY_COMPILE_OUTPUT
    )

from omp_test.c

#include <stdio.h>
#include <omp.h>

int main()
{
    int i;
    int threadID = 0;
    #pragma omp parallel for private(i, threadID)
    for(i = 0; i < 16; i++ )
    {
        threadID = omp_get_thread_num();
        #pragma omp critical
        {
            printf("Thread %d reporting\n", threadID);
        }
    }
    return 0;
}

The resulting output is

Change Dir: src/config/CMakeFiles/CMakeTmp

Run Build Command:/usr/bin/make "cmTryCompileExec/fast"
/usr/bin/make -f CMakeFiles/cmTryCompileExec.dir/build.make CMakeFiles/cmTryCompileExec.dir/build
make[1]: Entering directory `src/config/CMakeFiles/CMakeTmp'
/usr/bin/cmake -E cmake_progress_report /data/work/source/apbs/src/config/CMakeFiles/CMakeTmp/CMakeFiles 1
Building C object CMakeFiles/cmTryCompileExec.dir/omp_test.c.o
/usr/bin/gcc    -o CMakeFiles/cmTryCompileExec.dir/omp_test.c.o   -c /data/work/source/apbs/src/config/omp_test.c
Linking C executable cmTryCompileExec
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec.dir/link.txt --verbose=1
/usr/bin/gcc         CMakeFiles/cmTryCompileExec.dir/omp_test.c.o  -o cmTryCompileExec -rdynamic 
CMakeFiles/cmTryCompileExec.dir/omp_test.c.o: In function `main':
omp_test.c:(.text+0x19): undefined reference to `omp_get_thread_num'
collect2: ld returned 1 exit status
make[1]: *** [cmTryCompileExec] Error 1
make[1]: Leaving directory `src/config/CMakeFiles/CMakeTmp'
make: *** [cmTryCompileExec/fast] Error 2

CMake Error at CMakeLists.txt:688 (message):
  Test OpenMP program would not build.  OpenMP disabled

When I try to compile the test program on the command line, it works fine

src/config$ gcc -fopenmp omp_test.c -o omp_test && ./omp_test
Thread 1 reporting
Thread 4 reporting
Thread 7 reporting
Thread 11 reporting
Thread 9 reporting
Thread 12 reporting
Thread 6 reporting
Thread 8 reporting
Thread 15 reporting
Thread 13 reporting
Thread 10 reporting
Thread 0 reporting
Thread 3 reporting
Thread 2 reporting
Thread 5 reporting
Thread 14 reporting
sakra
  • 62,199
  • 16
  • 168
  • 151
dusktreader
  • 3,845
  • 7
  • 30
  • 40

4 Answers4

147

CMake has a standard module for testing if the compiler supports OpenMP:

find_package(OpenMP)
if (OPENMP_FOUND)
    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}")
endif()

Note:
This answer is not recommended to be used anymore for including OpenMP in the project for current CMake versions. Refer to the other answers.

Levi Morrison
  • 19,116
  • 7
  • 65
  • 85
sakra
  • 62,199
  • 16
  • 168
  • 151
  • 5
    Awesome! I wonder why I didn't find this in my searches... I assume it handles different compiler (icc, gcc, borland, etc) flags correctly? – dusktreader Sep 13 '12 at 15:28
  • 2
    Looking at the FindOpenMP.cmake source, it seems to handle GNU, MSVC, Intel, Sun, HP, IBM and MIPSpro compilers. – sakra Sep 13 '12 at 17:24
  • 6
    The linker flags need to be set, too. I don't know how to set them, but readers be warned. – Jason Feb 19 '17 at 17:11
  • If your OpenMP was pulled via your gcc install, would the find_package() call still be for OpenMP, or go by another name? I can't get CLion to perform as in the command line for a simple multi-threaded program using OpenMP! – lrthistlethwaite May 23 '17 at 03:04
  • 1
    CMAKE_EXE_LINKER_FLAGS didn't exist and was not needed. The module documentation doesn't say anything about that flag either. https://cmake.org/cmake/help/v3.0/module/FindOpenMP.html – Siamaster Feb 28 '18 at 12:59
  • Even for old cmake versions this will set compiler flags for all targets which is often unnecessary, [Leve's answer](https://stackoverflow.com/a/51448364/5238478) offers a finer control. – Yibo Jul 07 '20 at 02:06
78

As of CMake 3.9 there are imported OpenMP targets per language. I consider this to be a much more elegant solution. Here's an example in C++:

cmake_minimum_required(VERSION 3.9)
project(solver LANGUAGES CXX)

find_package(OpenMP REQUIRED)
add_executable(solver solver.cc)
target_link_libraries(solver PRIVATE OpenMP::OpenMP_CXX)

This is more convenient since it is less typing, and this way you don't have to adjust with compile flags, libraries, etc which are error-prone. This is the direction that modern CMake is going.


If you are working with something older than CMake 3.9 I still don't recommend the currently accepted answer. I believe setting the flags per-target is better:

add_executable(solver solver.cc)
target_link_libraries(solver PRIVATE "${OpenMP_CXX_FLAGS}")
target_compile_options(solver PRIVATE "${OpenMP_CXX_FLAGS}")

This may not work with some compilers; this is partly why CMake revamped its OpenMP support in CMake 3.9.

Levi Morrison
  • 19,116
  • 7
  • 65
  • 85
  • 1
    If you are using CLion: I thought that it was not working, because CMake was not able to find OpenMP. Then I tried on the command line and it worked. So it was a problem with CMake caches. Going to Tools -> CMake -> Reset Cache and Reload Project fixed it for me – Martin Cook Dec 14 '18 at 08:43
  • Why PRIVATE and not PUBLIC as recommended by https://cliutils.gitlab.io/modern-cmake/chapters/packages/OpenMP.html? If my halfbaked understanding of CMake is right, PUBLIC is also plausible because linking a library built with OpenMP requires the -fopenmp flag again, see https://nanxiao.me/en/the-caveat-of-building-openmp-program/. In practice it doesn't make a difference since it's on the default header/lib search paths anyway, but I would like to know the correct way. – nnnmmm Oct 19 '20 at 18:13
  • 1
    "Why PRIVATE and not PUBLIC[?]" You only use PUBLIC if both the internal and external interfaces need it. I showed an executable, so in practice it's moot and I prefer to default to PRIVATE over PUBLIC. In a library it's still probably PRIVATE though, because you generally don't expose OpenMP types in your headers. – Levi Morrison Oct 26 '20 at 14:24
18

OpenMP support has been improved in CMake 3.9+

CMakeLists.txt

cmake_minimum_required(VERSION 3.9)
project(openmp_test) # you can change the project name

find_package(OpenMP)

add_executable(openmp_para_test main.cpp) # you can change the excutable name

if(OpenMP_CXX_FOUND)
    target_link_libraries(openmp_para_test PUBLIC OpenMP::OpenMP_CXX)
endif()

This way will correctly set the library link line differently from the compile line if needed.

Source.

asendjasni
  • 963
  • 1
  • 16
  • 36
  • 5
    Upvoted since it shows the correct way to include OpenMP (which is to use a target) in case it's an optional dependency, unlike existing answers including my own. – Levi Morrison Oct 03 '19 at 21:57
6

In case you try to use the "modern" way with g++, you could also do:

find_package(OpenMP REQUIRED)

add_executable(Foo foo.cpp)
target_compile_options(Foo PRIVATE -Wall ${OpenMP_CXX_FLAGS})
target_link_libraries(Foo PRIVATE ${OpenMP_CXX_FLAGS})

Notice:

  1. If you would leave out only the target_compile_options your pragmas would simple be ignored (enabled warnings would tell you)

  2. If you would leave out only the target_link_libraries your code wouldn't compile, as g++ is not properly linked

  3. If you leave both out the 1. note applies rendering the linking no longer needed and your code would compile.

I don't know whether this linking "hack" with the flags is working for other compilers as well.

Levi Morrison
  • 19,116
  • 7
  • 65
  • 85
Mojomoko
  • 471
  • 5
  • 12
  • 1
    The variables should be `OpenMP_CXX_FLAGS` (no underline between `Open` and `MP`). – dm4 Jul 26 '18 at 07:58