Подтвердить что ты не робот

Как установить флаги компоновщика для OpenMP в функции CMake try_compile

Я хотел бы проверить, что текущий компилятор может построить с поддержкой openmp. Приложение действительно развертывается во множестве Unix-систем, некоторые из которых могут иметь старые версии OpenMP, и я бы хотел проверить важные функции OpenMP. Итак, я хочу создать тестовый исходный файл, который включает в себя некоторые вызовы OpenMP.

Таким образом, я создал очень простой тестовый файл и попытался использовать функцию try_compile из CMake. К сожалению, он, похоже, не корректно применяет флаг компоновщика -fopenmp. Кто-нибудь знает, как либо заставить флаг компоновщика, либо посмотреть, применяется ли флаг компоновщика в любом месте?

из 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
    )

из 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;
}

Результирующий результат

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

Когда я пытаюсь скомпилировать тестовую программу в командной строке, она отлично работает

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
4b9b3361

Ответ 1

CMake имеет стандартный модуль для проверки, поддерживает ли компилятор 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()

Примечание:
Этот ответ больше не рекомендуется использовать для включения OpenMP в проект для текущих версий CMake. Обратитесь к другим ответам.

Ответ 2

Начиная с CMake 3.9, для каждого языка импортируются цели OpenMP. Я считаю это гораздо более элегантным решением. Вот пример в 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)

Это более удобно, так как при этом меньше набирается текста, и таким образом вам не нужно настраивать флаги компиляции, библиотеки и т.д., Которые подвержены ошибкам. Это направление, в котором движется современный CMake.


Если вы работаете с чем-то более старым, чем CMake 3.9, я все еще не рекомендую принятый в настоящее время ответ. Я считаю, что установка флагов для каждой цели лучше:

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

Это может не работать с некоторыми компиляторами; отчасти поэтому CMake обновил свою поддержку OpenMP в CMake 3.9.

Ответ 3

Если вы пытаетесь использовать "современный" способ с g++, вы также можете сделать:

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

Обратите внимание:

  1. Если вы пропустите только target_compile_options, ваши прагмы будут просто проигнорированы (включенные предупреждения скажут вам)

  2. Если вы не укажете только target_link_libraries, ваш код не скомпилируется, так как g++ неправильно связан

  3. Если вы не укажете и то, и другое, обратите внимание на то, что 1. примечание приводит к тому, что ссылки больше не нужны, и ваш код скомпилируется.

Я не знаю, работает ли эта связь "взломать" с флагами и для других компиляторов.

Ответ 4

Поддержка OpenMP была значительно улучшена в 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()

Этот способ корректно установит строку ссылки библиотеки иначе, чем строка компиляции, если это необходимо.

Источник