web-dev-qa-db-fra.com

MacOS, CMake et OpenMP

J'utilise le plus récent CMake (3.9.3) de Homebrew avec LLVM 5.0.0 également de Brew, car Clang a ici le support d'OpenMP.

Cela a fonctionné dans CMake 3.8.2 avec LLVM 5.


Dans mon CMakeLists.txt J'ai

find_package( OpenMP )

et plus tard je veux faire

if( OpenMP_CXX_FOUND )

Cependant CMake ne semble pas reprendre la directive find_package.

Je lance CMake avec

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

où j'ai vérifié que clang et clang++ pointe correctement vers /usr/local/opt/llvm/bin/clang et /usr/local/opt/llvm/bin/clang++

Tout ce que je reçois, ce sont ces deux lignes:

-- 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")

Si je mets OpenMP_C_FLAGS Moi-même (avec -DOpenMP_C_FLAGS=-fopenmp=libomp), Cela change l'erreur en

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

Notez qu'il modifie le numéro de version, il doit donc trouver quelque chose, non?

Que me manque-t-il pour que cela fonctionne correctement?


D'accord, il semble qu'à l'intérieur du FindOpenMP.cmake Fourni par CMake, nous faisons un try_compile, Qui échoue silencieusement (parce que nous le faisons souvent et que la plupart échouent, cela a du sens). Cependant, avec Clang, un indicateur -Werror Est fourni, qui échoue en raison d'un argument de ligne de commande inutilisé. Je peux donc ajouter:

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()

à mon projet parce que je sais que -fopenmp=libomp fonctionnera pour ce Clang.

Est-ce la bonne façon de procéder?

9
Mads Ohm Larsen

Le message vous indique essentiellement que vous devez fournir le chemin d'accès aux bibliothèques et les noms des bibliothèques. L'exemple suivant devrait résoudre votre problème (voir aussi find_package (OpenMP) ). Notez que j'utilise l'installation de brew en utilisant la commande "brew install llvm". Les quatre premières lignes sont juste pour être complètes.

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)

Vous voudrez peut-être définir par exemple set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lpthread") de telle sorte que l'éditeur de liens détecte automatiquement la bibliothèque pthread appropriée (voir pthread et wiki ).

14
Franzi

Apparemment, le cas est important. Pour un projet indépendant, je peux le faire fonctionner avec

find_package ( OPENMP REQUIRED )

Cela n'a pas fonctionné:

find_package ( OpenMP REQUIRED )

Avec cette directive, pas besoin de régler tous les autres drapeaux à la main. cmake 3.13.2, clang-1000.11.45.5 (High Sierra)

6
mjskier

C'est peut-être une version CMake, je trouve une solution légèrement différente avec Franzi's .

J'utilise également brew install libomp Sur ma machine. Il semble que OpenMP_CXX_FLAGS Soit utilisé pour compiler le code source du projet au lieu de compiler l'omp (l'indicateur est stocké dans la cible omp et sera rempli par la commande target_link_libraries).

En plus de cela, OpenMP_CXX_LIB_NAMES Ne devrait pas avoir de préfixe lib car cela entraînera une erreur comme -llibomp Introuvable, où -lomp Devrait être utilisé à la place.

J'ai également remarqué que CMAKE_C_COMPILER_ID Est AppleClang au lieu de Clang si je mets project(playground) après cmake_minimum_required. En sens inverse, c'est Clang, assez ennuyeux et je ne sais pas pourquoi.

Xpreprocessor utilisé ici parce que Apple clang n'est pas livré avec OpenMP et cet indicateur indique au compilateur de rechercher pragma (extension de préprocesseur) ailleurs. Dans notre cas, c'est l'en-tête fichiers dans le chemin d'inclusion où le libomp est installé.

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)

Voici mon helloworld

#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;
}

la sortie est,

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.
0
Izana