MacOS,CMake和OpenMP

时间:2017-09-25 21:45:15

标签: 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

我已检查clangclang++是否正确指向/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。

这是正确的做法吗?

4 个答案:

答案 0 :(得分:10)

该消息基本上告诉您必须提供库的路径和库的名称。以下示例应解决您的问题(另请参阅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库(请参阅pthreadwiki)。

答案 1 :(得分:4)

显然,大小写很重要。对于不相关的项目,我可以使其适用于

find_package ( OPENMP REQUIRED )

这不起作用:

find_package ( OpenMP REQUIRED )

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

答案 2 :(得分:3)

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

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

除此之外,OpenMP_CXX_LIB_NAMES不应带有前缀lib,因为它会引起类似-llibomp的错误,而应使用-lomp

我还注意到,如果我将CMAKE_C_COMPILER_ID放在AppleClang之后,则Clangproject(playground)而不是cmake_minimum_required。相反,它是Clang,很烦人,我不知道为什么。

Xpreprocessor的使用是因为Apple clang不随OpenMP一起提供,并且此标志告诉编译器在其他地方寻找编译指示(预处理器扩展)。在我们的例子中,它是libomp安装所在的include路径中的头文件。

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.

答案 3 :(得分:1)

使用最新版本的 CMake(3.18,不适用于 3.14)和全新安装的 MacOS(当然安装了开发人员 CL 工具),brew install libomp 是使事情正常运行所需的唯一操作。