microsoft / vscode-cpptools

Official repository for the Microsoft C/C++ extension for VS Code.
Other
5.53k stars 1.56k forks source link

Cannot override value of __cplusplus macro with c_cpp_properties.json #2248

Closed Christian-Marx closed 6 years ago

Christian-Marx commented 6 years ago

Issue Type: Bug (I suppose - please correct me if my usage is wrong.)

I searched for a similar existing issue but didn't find anything matching exactly. The closest match might be #1770.

Steps to reproduce:

  1. Create a default c_cpp_properties.json and switch intellisenseMode to msvc-x64:
{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "intelliSenseMode": "msvc-x64"
        }
    ],
    "version": 4
}
  1. Create a file foo.h:
#if (__cplusplus < 201103L)
#error foo
#else
#error bar
#endif

When hovering the cplusplus macro, Intellisense shows "#define cplusplus 199711L" and the first error directive "foo" is active.

  1. Add a define to section "defines" in c_cpp_properties.json to override the value of the __cplusplus macro:
    "defines": [
    "_DEBUG",
    "UNICODE",
    "_UNICODE",
    "__cplusplus=201103L"
    ]

    In foo.h, the second error directive "bar" should be active, but cplusplus is still defined as 199711L. Is that intended behavior? Is there another way to override the value of the cplusplus macro for IntelliSense?

I understand that the default value for the cplusplus macro comes from the msvc-x64 configuration. However, I am just using that configuration for IntelliSense while building with a different compiler. As that compiler is conforming with C++17, I would like to override the value of the cplusplus macro and have IntelliSense gray out the correct sections of code.

Extension version: 0.17.6 VS Code version: Code - Insiders 1.26.0-insider (adfa9ce9778a6e79197477fcc60cb5420a31979a, 2018-07-10T05:19:09.185Z) OS version: Windows_NT x64 10.0.15063

bobbrow commented 6 years ago

This is actually the expected behavior. cl.exe only recently started setting this macro correctly. We don't have support in the extension to turn on the switch yet.

sean-mcmanus commented 6 years ago

But it sounds like he's not using cl.exe? If you set your compilerPath to a compiler that sets __cplusplus correctly by default then it should work.

bobbrow commented 6 years ago

intelliSenseMode is msvc-x64 in the config above, so I'm assuming cl.exe. I looked at the engine code and it should be setting this variable to a higher value for clang mode.

bobbrow commented 6 years ago

@Christian-Marx, is there any reason you didn't want to have IntelliSense mimic your compiler more closely? You should be able to set the compilerPath property in your config to the path of your non-cl.exe compiler and then change the intelliSenseMode to clang-x64 and let the extension figure out the system includes/defines for you.

Christian-Marx commented 6 years ago

@sean-mcmanus, right - I'm using VS Code as an editor only, but still would like to have correct syntax highlighting. My compiler is a cross compiler for ARM.

@bobbrow, that's interesting - how would the extension figure out the correct value of __cplusplus and other defines when I set the compilerPath property to the path of my compiler? Does it invoke the compiler to get the predefined values? That might not work with my compiler, as it has rather exotic switches for that.

Basically, my question was: shouldn't a define of __cplusplus in c_cpp_properties.json override a built-in value? (I understand that clang mode sets a higher value, but still...) Thanks for clarifying.

bobbrow commented 6 years ago

Compilers like gcc allow us to query the system includes and defines, so when you set the compilerPath we can just ask the compiler what to use. It seems that gcc might let you override __cplusplus, but msvc doesn't.

Christian-Marx commented 6 years ago

Are you saying that it's beyond the control of your extension whether the __cplusplus value defined in _c_cppproperties.json is overridden later on, before being passed to IntelliSense?

Christian-Marx commented 6 years ago

I like the approach of asking the compiler what to use for __cplusplus and other predefined macros. Could you imagine adding an option in _c_cppproperties.json for configuring the compile switch to be used for that?

For example:

"compileSwitchPredefinedMacros": "--c++ --predef_macros - "

bobbrow commented 6 years ago

I'm saying that just for "msvc-x64" mode, you can't override __cplusplus. I tried overriding it for "clang-x64" mode by adding it to the "defines" array, and it worked for me.

We do support some compiler switches already. You can try adding them directly to the compilerPath property (so that the "path" includes the arguments as well)

Christian-Marx commented 6 years ago

Thanks for clarifying. I was able to override the __cplusplus value in "clang-x64" mode using the defines section. However, I still wanted to look a bit further into the approach of asking the built-in values from the compiler. I tried adding compiler switches to the compilerPath property directly. That didn't seem to work, so I tried to narrow the problem further down.

In order to rule out our compiler as a source of error, I created a batch file C:\Temp\setDefines.bat with the following content:

@echo off
echo #define FOO 42

I suppose that's what a compiler would print to stdout when being asked for predefined macros, is that correct? Then I set the compilerPath property to point to that batch file and enabled logging level 6.

The output of the plugin tells me:

Attempting to get defaults from compiler in "compilerPath" property: 'C:\Temp\setDefines.bat'
Attempting to get defaults from compiler found on the machine: C:\Temp\setDefines.bat
  Folder: C:/WORK/REPROVSCODEISSUE/ will be indexed

There is no error, but IntelliSense still does not resolve FOO in my code. Any suggestions?

bobbrow commented 6 years ago

It's an interesting experiment, but I would strongly recommend against integrating this into your daily workflow. If something is not working right with getting the information from your compiler, we'd like to understand the issue so we can fix it. This is supposed to be as easy as adding FOO=1 to the "defines" array in c_cpp_properties.json. The documentation for compilerPath is here

But to debug your issue, we expect to see include paths from GCC compilers as well so your current script will be assumed to not be a compiler. If you want to hack this, you'll need to do the following:

@echo off
echo #include "..." search starts here:
echo #include ^<...^> search starts here:
echo End of search list.
echo #define FOO 42

and make sure that intelliSenseMode is clang-x64. We don't have a way to hack the msvc-x64 support right now that doesn't mess with your Visual Studio installation or the registry.

You'll also want to add the system includes in there otherwise IntelliSense will be mostly broken.

Christian-Marx commented 6 years ago

Sorry for my late response. Following your suggestions, I was finally able to get everything working. My setup is as follows:

c_cpp_properties.json:

...
"intelliSenseMode": "clang-x64",
"compilerPath": "C:\\predefs.bat"
...

predefs.bat:

echo #include "..." search starts here:
<echo my paths here>
echo #include ^<...^> search starts here:
<echo my paths here>
echo End of search list.

<invocation of compiler with compile switches for predefined macros>

Using a batch file for compiler invocation allows me to add the include search lines which my compiler doesn't print out and gives me more control over the command line switches passed to the compiler, as the default ones passed by the extension are not supported and lead to errors.

The absolute path in compilerPath will be replaced by a relative one, as soon as it will be supported by the extension (#1982 should fix that).

Thanks again for your help, and for providing such a great extension.