提问者:小点点

MacOS、CMake 和 OpenMP


我使用的是Homebrew中最新的CMake(3.9.3)以及Brew的LLVM 5.0.0,因为这里的Clang支持OpenMP。

这在 CMake 3.8.2 和 LLVM 5 中有效。

在我的CMakeLists中.txt我有

find_package( OpenMP )

后来我想做

if( OpenMP_CXX_FOUND )

然而,CMake似乎并没有接受find_package指令。

我运行CMake与

cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DUSE_WERROR=ON

我已经检查了 clang 和 clang 正确指向 /usr/local/opt/llvm/bin/clang 和 /usr/local/opt/llvm/bin/clang

我得到的只是这两行:

-- Could NOT find OpenMP_C (missing: OpenMP_C_FLAGS OpenMP_C_LIB_NAMES) (found version "1.0")
-- Could NOT find OpenMP_CXX (missing: OpenMP_CXX_FLAGS OpenMP_CXX_LIB_NAMES) (found version "1.0")

如果我自己设置OpenMP_C_FLAGS(使用 -DOpenMP_C_FLAGS=-fopenmp=libomp),它将错误更改为

-- Could NOT find OpenMP_C (missing: OpenMP_C_LIB_NAMES) (found version "3.1")

请注意,它更改了版本号,因此它必须找到一些东西,对吗?

我缺少什么才能正常工作?

好吧,似乎在CMake提供的FindOpenMP.cmake中,我们做了一个try_compile,它以静默方式失败(因为我们做了很多次,其中大多数都会失败,这是有道理的)。但是,在 Clang 中提供了 -Werror 标志,该标志由于未使用的命令行参数而失败。因此,我可以补充:

if(APPLE)
    if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
        set(OpenMP_C_FLAG "-fopenmp=libomp -Wno-unused-command-line-argument")
    endif()
    if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
        set(OpenMP_CXX_FLAG "-fopenmp=libomp -Wno-unused-command-line-argument")
    endif()
endif()

到我的项目,因为我知道 -fopenmp=libomp 将适用于这个 Clang。

这是正确的做法吗?


共3个答案

匿名用户

该消息基本上告诉您,您必须提供库的路径和库的名称。以下示例应该可以解决您的问题(另请参阅 find_package(OpenMP))。请注意,我使用命令“brew install llvm”使用brew安装。前四行只是为了完整起见。

set(CMAKE_C_COMPILER "/usr/local/Cellar/llvm/5.0.1/bin/clang")
set(CMAKE_CXX_COMPILER "/usr/local/Cellar/llvm/5.0.1/bin/clang++")
set(OPENMP_LIBRARIES "/usr/local/Cellar/llvm/5.0.1/lib")
set(OPENMP_INCLUDES "/usr/local/Cellar/llvm/5.0.1/include")

OPTION (USE_OpenMP "Use OpenMP to enamble <omp.h>" ON)

# Find OpenMP
if(APPLE AND USE_OpenMP)
    if(CMAKE_C_COMPILER_ID MATCHES "Clang")
        set(OpenMP_C "${CMAKE_C_COMPILER}")
        set(OpenMP_C_FLAGS "-fopenmp=libomp -Wno-unused-command-line-argument")
        set(OpenMP_C_LIB_NAMES "libomp" "libgomp" "libiomp5")
        set(OpenMP_libomp_LIBRARY ${OpenMP_C_LIB_NAMES})
        set(OpenMP_libgomp_LIBRARY ${OpenMP_C_LIB_NAMES})
        set(OpenMP_libiomp5_LIBRARY ${OpenMP_C_LIB_NAMES})
    endif()
    if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
      set(OpenMP_CXX "${CMAKE_CXX_COMPILER}")
      set(OpenMP_CXX_FLAGS "-fopenmp=libomp -Wno-unused-command-line-argument")
      set(OpenMP_CXX_LIB_NAMES "libomp" "libgomp" "libiomp5")
      set(OpenMP_libomp_LIBRARY ${OpenMP_CXX_LIB_NAMES})
      set(OpenMP_libgomp_LIBRARY ${OpenMP_CXX_LIB_NAMES})
      set(OpenMP_libiomp5_LIBRARY ${OpenMP_CXX_LIB_NAMES})
    endif()
endif()

if(USE_OpenMP)
  find_package(OpenMP REQUIRED)
endif(USE_OpenMP)

if (OPENMP_FOUND)
    include_directories("${OPENMP_INCLUDES}")
    link_directories("${OPENMP_LIBRARIES}")
    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(OPENMP_FOUND)

您可能希望设置例如 set(CMAKE_EXE_LINKER_FLAGS “${CMAKE_EXE_LINKER_FLAGS} -lpthread”),以便链接器自动检测适当的 pthread 库(参见 pthread 和 wiki)。

匿名用户

显然,案例很重要。对于一个不相关的项目,我可以让它使用

find_package ( OPENMP REQUIRED )

这不起作用:

find_package ( OpenMP REQUIRED )

使用该指令,无需手动设置所有其他标志。cmake 3.13.2, clang-1000.11.45.5 (高山脉)

匿名用户

也许这是一个CMake版本的东西,我想出了一个与Franzi略有不同的解决方案。

我还在我的机器上使用brew install libomp。似乎OpenMP_CXX_FLAGS用于编译项目源代码而不是编译 omp(该标志存储在 omp 目标中,将由命令 target_link_libraries 填充)。

除此之外,OpenMP_CXX_LIB_NAMES不应该有前缀lib,因为它会导致像-llibomp unfound这样的错误,应该使用-lomp代替。

我还注意到,如果我把项目(操场)放在cmake_minimum_required之后,CMAKE_C_COMPILER_IDAppleClang而不是Clang。反过来,它是叮当声,很烦人,我不知道为什么。

这里使用的Xpreprocessor是因为Apple clang没有随OpenMP一起提供,这个标志告诉编译器在其他地方寻找杂注(预处理器扩展)。在我们的例子中,它是安装 libomp 的包含路径中的头文件。

cmake_minimum_required(VERSION 3.12)

project(playground)

if(APPLE)
    set(CMAKE_C_COMPILER clang)
    set(CMAKE_CXX_COMPILER clang++)

    if(CMAKE_C_COMPILER_ID MATCHES "Clang\$")
        set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp")
        set(OpenMP_C_LIB_NAMES "omp")
        set(OpenMP_omp_LIBRARY omp)
    endif()

    if(CMAKE_CXX_COMPILER_ID MATCHES "Clang\$")
        set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp")
        set(OpenMP_CXX_LIB_NAMES "omp")
        set(OpenMP_omp_LIBRARY omp)
    endif()

endif()

find_package(OpenMP REQUIRED)

add_executable(helloworld helloworld.cxx)
target_link_libraries(helloworld PRIVATE OpenMP::OpenMP_CXX)

这是我的问候世界

#include <cstdio>
#include <thread>
#include <sstream>

int main(void)
{
    #pragma omp parallel
    {
      std::stringstream ss;
      ss << std::this_thread::get_id();
      printf("%s, Hello, world.\n", ss.str().c_str());
    }

  return 0;
}

输出是,

0x700002dc8000, Hello, world.
0x10a17d5c0, Hello, world.
0x7000045d1000, Hello, world.
0x7000055d7000, Hello, world.
0x700005dda000, Hello, world.
0x7000035cb000, Hello, world.
0x7000065dd000, Hello, world.
0x700003dce000, Hello, world.
0x700007de6000, Hello, world.
0x700004dd4000, Hello, world.
0x7000075e3000, Hello, world.
0x700006de0000, Hello, world.