Proper way to use OpenMP: target_link_libraries() enough?

With a project that uses OpenMP, is it sufficient to set target_link_libraries(... OpenMP::OpenMP_C) or do we need to set compiler options (in addition to linker options) separately?

The following test project works fine:

cmake_minimum_required(VERSION 3.27)

project(foo)

find_package(OpenMP)

add_executable(foo main.c)
target_link_libraries(foo PRIVATE OpenMP::OpenMP_C)

-fopenmp is added both when compiling the sources and when linking the object files. I expected target_link_libraries to only affect linker flags, not compiler flags. How do the compiler flags get added, and how could I figure out from the CMake docs that target_link_libraries is sufficient?

How do the compiler flags get added

That happens in FindOpenMP module, which is called when you execute find_package(OpenMP).

how could I figure out from the CMake docs that target_link_libraries is sufficient

Well, that’s a fair amount of docs that you would need to read to get to that understanding. In short, I’d say that this part of the documentation wouldn’t be specific to OpenMP, as this topic is rather common and applies to any library/package in general.

The target_link_libraries() is sufficient when the library files are already discovered, so you can provide them to this function as arguments, but obviously you first need to discover those files, and that is what find_package() does (among other things, as you can see in that FindOpenMP module). You can write your own discovery procedure which wouldn’t set -fopenmp flags, if that is what you are after. Alternatively, perhaps you could also overwrite those flags right after find_package(OpenMP) line.

Looking more carefully, it is this bolded part of the target_link_libraries() documentation that I should have paid more attention to:

Specify libraries or flags to use when linking a given target and/or its dependents. Usage requirements from linked library targets will be propagated. Usage requirements of a target’s dependencies affect compilation of its own sources.

Correct?

Yes, that is correct. Usage requirements include “what is needed to use this target” and can indeed involve compilation flags.