ошибки компиляции nvcc с M_PI и/или

При попытке скомпилировать этот фрагмент кода:

#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdio>

void minimal_example(){
    int i=2;
    if(i==3 or i==4) printf("I want %d!\n",M_PI);
}

с использованием

nvcc -x cu -Xcompiler=/permissive- -dc cuda_nvcc_cl_test.cu -o cuda_nvcc_cl_test.obj

Я получаю следующие ошибки (в строке 7):

error: expected a ")"
error: identifier "M_PI" is undefined

Я использую Windows 10 с Visual Studio cl.exe (версия 19.16.27031.1 для x64) и набор инструментов CUDA 10.1.

При замене cmath на math.h и or на || (как вариант добавить #include <ciso646>) ошибки исчезают. Однако есть ли какие-то параметры компилятора или другие возможности, чтобы я мог сохранить код как есть?

И почему -Xcompiler=/permissive- не помогло?


person Oscillon    schedule 27.05.2019    source источник
comment
M_PI также определяется в cmath через включение math.h   -  person Oscillon    schedule 29.05.2019


Ответы (1)


Здесь есть 2 проблемы:

  1. По-видимому, nvcc включает cmath перед синтаксическим анализом вашего кода. Как обсуждалось в принятом ответе здесь, если вы включаете cmath и у вас нет экземпляра определения в этот момент, вы не получите определение M_PI, и последующие включения cmath не исправят это из-за включить охрану. Возможный обходной путь для этого — добавить -D_USE_MATH_DEFINES в командную строку компиляции. Это устанавливает определение с самого начала процесса компиляции, и M_PI определяется таким образом.

  2. Вопреки тому, что я считаю правильным или стандартным поведением, использование or вместо ||, по-видимому, обусловлено включением ciso646 (только для nvcc в Windows/Visual Studio. nvcc в Linux, похоже, это не нужно). Да, я понимаю, что так не должно работать, но тем не менее это представляется необходимым. Это может быть проблема с Visual Studio. Вы можете поэкспериментировать с переключателем /Za, если хотите. (Кажется, это не помогло, когда я попробовал.)

С CUDA 10.1 на VS2019, когда я компилирую это:

#include <cstdio>
#include <ciso646>

void minimal_example(){
    int i=2;
    if(i==3 or i==4) printf("I want %f!\n",M_PI);
}

с этой командной строкой:

nvcc -x cu -dc test.cu -o test.obj -D_USE_MATH_DEFINES

Я не получаю никаких ошибок или предупреждений. Обратите внимание, что я также изменил спецификатор формата printf с %d на %f, чтобы он соответствовал типу M_PI.

Если вы действительно не хотите включать ciso646, nvcc поддерживает переключатель -include для включения файла непосредственно из командной строки. Поэтому я могу скомпилировать это:

#include <cstdio>

void minimal_example(){
    int i=2;
    if(i==3 or i==4) printf("I want %f!\n",M_PI);
}

нравится:

nvcc -x cu -dc test.cu -o test.obj -D_USE_MATH_DEFINES -include ciso646

без ошибок и предупреждений.

person Robert Crovella    schedule 29.05.2019
comment
Спасибо, это очень информативно! У вас есть понимание, почему -Xcompiler=/permissive- не работает? Я надеялся, что он передаст параметр permissive- компилятору cl. PS: извините за опечатку d/f в printf. - person Oscillon; 29.05.2019
comment
Я не знаю, чего вы ожидали от этого переключателя, и он не работал или не помогал, не проливает на это никакого света для меня. Вы читали документы для этого? Что вы ожидали от этого переключателя в этом случае? Что не сработало? Обратите внимание, что permissive- со знаком минус в конце делает компилятор более строгим. Он отключает разрешительное поведение языка и пытается обеспечить более строгое соответствие. - person Robert Crovella; 29.05.2019
comment
Также обратите внимание на документы, указанные выше, что permissive- является поведением по умолчанию, начиная с более поздних версий VS2017. Так что я не уверен, что его добавление что-то изменит; он уже включен по умолчанию. - person Robert Crovella; 29.05.2019
comment
Чтобы быть более ясным, я ожидал, что с /permissive- я не получу ошибок относительно использования or на основе: stackoverflow.com/questions/24414124/ - person Oscillon; 29.05.2019