MacOS、CMake和OpenMP

19

我正在使用来自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()

我知道这个Clang可以使用-fopenmp=libomp,因此我将其用于我的项目。

这样做正确吗?


没问题,LGTM。你可以从现在开始使用导入目标,让你的生活变得更轻松一些。 - compor
5个回答

18

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


10

显然,大小写很重要。对于一个不相关的项目,我可以通过它使其工作。

find_package ( OPENMP REQUIRED )

这个没有起作用:

find_package ( OpenMP REQUIRED )

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


1
遗憾的是,这对我没有用。 - valentin
1
这样可以消除“找不到包”错误,但现在目标OpenMP :: OpenMP_CXX不再存在。将其改为全大写也没有帮助。 - ShnitzelKiller

7
也许这是CMake版本的问题,我提出了一个与Franzi's略有不同的解决方案。
我在我的机器上还使用了brew install libomp。似乎OpenMP_CXX_FLAGS用于编译项目源代码而不是编译omp(该标志存储在omp目标中,并将通过命令target_link_libraries填充)。
除此之外,OpenMP_CXX_LIB_NAMES不应该带有前缀lib,因为这会导致出现错误,例如找不到-llibomp,应该使用-lomp代替。
我还注意到如果我将project(playground)放在cmake_minimum_required之后,CMAKE_C_COMPILER_IDAppleClang而不是Clang。反过来则是Clang,非常烦人,我不知道为什么。

Xpreprocessor 的使用是因为苹果的 clang 编译器没有 OpenMP,这个标志告诉编译器在其他地方查找 pragma(预处理器扩展)。在我们的情况下,它是安装了 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.

1
整个 if(APPLE) 代码块是不必要的:CMake 可以检测到 Apple Clang 和标准 Clang 的正确 OpenMP 选项。 - Yongwei Wu
1
这是唯一对我有效的解决方案。奇怪的是,在另一个项目中,我不需要这样做,它可以很好地找到OpenMP。但是当我创建了一个小测试来查看是否可以始终使用OpenMP构建时,find_package()无法再次找到OpenMP。相同的参数-DCMAKE_CXX_COMPILER,相同的环境变量。 - ShnitzelKiller

2

最近版本的CMake(3.18,使用3.14不起作用),以及MacOS的全新安装(当然已安装了开发人员CL工具),唯一需要做的就是brew install libomp,就可以让事情正常运作。


你安装了macOS Big Sur吗? - nac001
1
@nac001 是的,我做了。 - CharlesB
brew install libomp 对我有效。 - Jimmy

0

MacOS Ventura

cmake:/usr/local/Cellar/cmake/3.25.1 OpenMP:/usr/local/Cellar/libomp/15.0.7 llvm:/usr/local/Cellar/llvm/15.0.7_1

在将编译器目录和libomp目录设置为正确值后,上述解决方案有效。

更改如下:

set(OpenMP_C_FLAGS“-fopenmp=libomp”)

对于clang和clangxx部分均需更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接