0

When trying to compile this piece of code:

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

using

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

I get the follwing errors (in line 7):

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

I am using Windows 10 with Visual Studio's cl.exe (Version 19.16.27031.1 for x64) and CUDA toolkit 10.1.

When replacing cmath with math.h and or with || (alternatively add #include <ciso646>), the errors disappear. However, are there some compiler options or other possibilities so that I can keep the code as is?

Also why did -Xcompiler=/permissive- not help?

Oscillon
  • 165
  • 3
  • 13

1 Answers1

2

There are 2 issues here:

  1. Apparently nvcc includes cmath prior to parsing your code. As discussed in the accepted answer here, if you include cmath and you don't have the define instantiated at that point, you won't get M_PI defined, and subsequent inclusions of cmath won't fix this, due to include guards. A possible workaround for this is to add -D_USE_MATH_DEFINES to your compile command line. This puts the define in place from the start of the compilation process, and M_PI gets defined that way.

  2. Contrary to what I read as correct or standard behavior, the use of or in place of || seems to be conditioned on inclusion of ciso646 (on nvcc on windows/visual studio only. nvcc on linux doesn't seem to need this). Yes, I understand it is not supposed to work that way, but nevertheless it appears to be necessary. This may be an issue with Visual Studio. You can experiment with the /Za switch if you like. (It didn't seem to help when I tried it.)

With CUDA 10.1, on VS2019, when I compile this:

#include <cstdio>
#include <ciso646>

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

with this command line:

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

I get no errors or warnings. Note that I have also changed your printf format specifier from %d to %f to be consistent with the type of M_PI.

If you really don't want to include ciso646, nvcc supports the -include switch to include a file directly from the command line. Therefore I can compile this:

#include <cstdio>

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

like this:

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

with no errors or warnings.

Robert Crovella
  • 143,785
  • 11
  • 213
  • 257
  • Thanks, this is very informative! Do you have insight on why -Xcompiler=/permissive- did not work? I was hoping it will pass the permissive- option to the cl compiler. PS: Sry for the d/f typo in printf. – Oscillon May 29 '19 at 06:45
  • I don't know what you were expecting with that switch and "did not work" or "not help" doesn't shed any light on it for me. Have you read the [docs](https://learn.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=vs-2019) for it? What were you expecting that switch to do in this case? What did not work? Note that `permissive-` with the minus sign at the end makes the compiler **more restrictive**. It disables languange permissive behavior and attempts to perform more strict compliance. – Robert Crovella May 29 '19 at 12:44
  • Also note from the docs linked above that `permissive-` appears to be the default behavior starting with later versions of VS2017. So I'm not sure that adding it would make any difference; it is already on by default. – Robert Crovella May 29 '19 at 13:11
  • To be more clear, my expectation was that with `/permissive-` I would not get errors regarding the use of `or` based on: https://stackoverflow.com/questions/24414124/why-does-vs-not-define-the-alternative-tokens-for-logical-operators – Oscillon May 29 '19 at 18:04