web-dev-qa-db-fra.com

Comment définir des indicateurs de l'éditeur de liens pour OpenMP dans la fonction try_compile de CMake

Je voudrais vérifier que le compilateur actuel peut construire avec le support openmp. L'application s'est déployée sur une grande variété de systèmes Unix, dont certains pourraient avoir d'anciennes versions d'OpenMP, et je voudrais tester les fonctionnalités importantes d'OpenMP. Donc, je veux créer un fichier source de test qui incorpore certains des appels OpenMP.

Ainsi, j'ai créé un fichier de test très simple et j'ai essayé d'utiliser la fonction try_compile de CMake. Malheureusement, il ne semble pas appliquer correctement l'indicateur de l'éditeur de liens -fopenmp. Quelqu'un sait-il comment forcer l'indicateur de l'éditeur de liens ou voir si l'indicateur de l'éditeur de liens est appliqué quelque part?

de CMakeLists.txt

try_compile(
    HAVE_OPENMP
    ${APBS_ROOT}/src/config
    ${APBS_ROOT}/src/config/omp_test.c
    CMAKE_FLAGS "-DCMAKE_C_FLAGS=-fopenmp -DCMAKE_EXE_LINKER_FLAGS=-fopenmp"
    OUTPUT_VARIABLE TRY_COMPILE_OUTPUT
    )

de omp_test.c

#include <stdio.h>
#include <omp.h>

int main()
{
    int i;
    int threadID = 0;
    #pragma omp parallel for private(i, threadID)
    for(i = 0; i < 16; i++ )
    {
        threadID = omp_get_thread_num();
        #pragma omp critical
        {
            printf("Thread %d reporting\n", threadID);
        }
    }
    return 0;
}

La sortie résultante est

Change Dir: src/config/CMakeFiles/CMakeTmp

Run Build Command:/usr/bin/make "cmTryCompileExec/fast"
/usr/bin/make -f CMakeFiles/cmTryCompileExec.dir/build.make CMakeFiles/cmTryCompileExec.dir/build
make[1]: Entering directory `src/config/CMakeFiles/CMakeTmp'
/usr/bin/cmake -E cmake_progress_report /data/work/source/apbs/src/config/CMakeFiles/CMakeTmp/CMakeFiles 1
Building C object CMakeFiles/cmTryCompileExec.dir/omp_test.c.o
/usr/bin/gcc    -o CMakeFiles/cmTryCompileExec.dir/omp_test.c.o   -c /data/work/source/apbs/src/config/omp_test.c
Linking C executable cmTryCompileExec
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec.dir/link.txt --verbose=1
/usr/bin/gcc         CMakeFiles/cmTryCompileExec.dir/omp_test.c.o  -o cmTryCompileExec -rdynamic 
CMakeFiles/cmTryCompileExec.dir/omp_test.c.o: In function `main':
omp_test.c:(.text+0x19): undefined reference to `omp_get_thread_num'
collect2: ld returned 1 exit status
make[1]: *** [cmTryCompileExec] Error 1
make[1]: Leaving directory `src/config/CMakeFiles/CMakeTmp'
make: *** [cmTryCompileExec/fast] Error 2

CMake Error at CMakeLists.txt:688 (message):
  Test OpenMP program would not build.  OpenMP disabled

Lorsque j'essaie de compiler le programme de test sur la ligne de commande, cela fonctionne bien

src/config$ gcc -fopenmp omp_test.c -o omp_test && ./omp_test
Thread 1 reporting
Thread 4 reporting
Thread 7 reporting
Thread 11 reporting
Thread 9 reporting
Thread 12 reporting
Thread 6 reporting
Thread 8 reporting
Thread 15 reporting
Thread 13 reporting
Thread 10 reporting
Thread 0 reporting
Thread 3 reporting
Thread 2 reporting
Thread 5 reporting
Thread 14 reporting
45
dusktreader

CMake a un module standard pour tester si le compilateur prend en charge OpenMP:

find_package(OpenMP)
if (OPENMP_FOUND)
    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()

Remarque :
Il n'est plus recommandé d'utiliser cette réponse pour inclure OpenMP dans le projet pour les versions actuelles de CMake. Se référer par exemple à this question ou les autres réponses.

117
sakra

Depuis CMake 3.9, il existe des cibles OpenMP importées par langue. Je considère que c'est une solution beaucoup plus élégante. Voici un exemple en C++:

cmake_minimum_required(VERSION 3.9)
project(solver LANGUAGES CXX)

find_package(OpenMP REQUIRED)
add_executable(solver solver.cc)
target_link_libraries(solver PRIVATE OpenMP::OpenMP_CXX)

C'est plus pratique car c'est moins de frappe, et de cette façon vous n'avez pas à vous ajuster avec les drapeaux de compilation, les bibliothèques, etc. qui sont sujettes aux erreurs. C'est la direction que va prendre CMake moderne.


Si vous travaillez avec quelque chose de plus ancien que CMake 3.9, je ne recommande toujours pas réponse actuellement acceptée . Je pense qu'il est préférable de définir les indicateurs par cible:

add_executable(solver solver.cc)
target_link_libraries(solver PRIVATE "${OpenMP_CXX_FLAGS}")
target_compile_options(solver PRIVATE "${OpenMP_CXX_FLAGS}")

Cela peut ne pas fonctionner avec certains compilateurs; c'est en partie pourquoi CMake a réorganisé son support OpenMP dans CMake 3.9.

33
Levi Morrison

Si vous essayez d'utiliser la méthode "moderne" avec g ++, vous pouvez également faire:

find_package(OpenMP REQUIRED)

add_executable(Foo foo.cpp)
target_compile_options(Foo PRIVATE -Wall ${OpenMP_CXX_FLAGS})
target_link_libraries(Foo PRIVATE ${OpenMP_CXX_FLAGS})

Remarquer:

  1. Si vous laissiez de côté uniquement les options target_compile_options, vos pragmas seraient simplement ignorés (les avertissements activés vous le diraient)

  2. Si vous laissiez de côté uniquement les bibliothèques target_link_libraries, votre code ne compilerait pas, car g ++ n'est pas correctement lié

  3. Si vous omettez les deux, la note 1. applique le rendu de la liaison qui n'est plus nécessaire et votre code se compilerait.

Je ne sais pas si ce lien "hack" avec les drapeaux fonctionne également pour d'autres compilateurs.

6
Mojomoko

La prise en charge OpenMP a été considérablement améliorée dans CMake 3.9+

CMakeLists.txt

cmake_minimum_required(VERSION 3.9)
project(openmp_test) # you can change the project name

find_package(OpenMP)

add_executable(openmp_para_test main.cpp) # you can change the excutable name

if(OpenMP_CXX_FOUND)
    target_link_libraries(openmp_para_test PUBLIC OpenMP::OpenMP_CXX)
endif()

De cette façon, la ligne de liaison de bibliothèque sera correctement définie différemment de la ligne de compilation si nécessaire.

Source .

1
SenDjasni