Catégories

How to compile C++ code with VS Code and cl

Bonjour, this is a step by step procedure which explains how to compile C++ code with VS Code (aka Visual Studio Code). As you will see the compiler and the linker I will use are the ones coming with Visual Studio 2017. Fundamentally the steps explained here should be similar if you use another compiler. OK, let’s start with the software settings :

  • I’m using Windows 10.
  • Visual Studio 2017 (15.6.2) is installed and at least the C++ load is up and running. I mean you are able to compile some C++ project with Visual Studio 2017.
  • VS Code (1.21.1) is also installed.
  • You don’t have to but if you plan to edit some C++ code in VS Code I would recommend to install the C/C++ for Visual Studio Code extension.

C/C++ for VS Code

Now, even if Visual Studio 2017 (not VS Code) is able to edit, run and debug a C++ code without any project you may want to do something similar using VS Code. Here is how I did.

Compiling a debug version with VS Code

From the Visual Studio 2017 group, open a Developper Command Prompt. If you either select the Developper Command Prompt or the Native x86 Developper Command Prompt then the generated code will be 32 bits. If you open the x64 Developper Command Prompt then the generated code will be 64 bits.

Here I picked the x64 Developper Command Prompt. Once the console is open, move to a directory where you want to make your tests. Check the « cd » command below:

x64 command prompt

Make sure the directory is empty (check the « dir » command below) and launch VS Code from there. To do so, simply type « code . » in the console. Do not forget the « . »

Invoking VS Code from the command prompt

Question

Why do I need to open a Developer Command Prompt and launch VS Code manually?

Using a Developer Command Prompt (and not a basic console) helps to make sure that all the paths and environment variables are set up correctly. For example from a Developer Command Prompt you can invoke « cl » (the Microsoft compiler) while this command might not be successful from a regular console. Yes, this is specific to Microsoft compiler. However if clang in installed, before to jump in VS Code you need to make sure you can call it. In other word, you need to make sure the path is set such a way that calling clang does not return an error.

VS Code be on screen and the directory (workspace) from which we invoked it should be visible on the left side of the environment. Remember that, in the Developer Command Prompt, before to call VS Code, we moved to a directory named « Test VS Code ». This is what we can see in VS Code hereafter.

VS Code on screen and the open folder

So far so good. Let’s write some complex C++ code to stress our compiler…

CTRL + N to create a new file. Then few lines of code.

Basic code in VS Code

At this point the code looks bad because it is not yet recognized as a C++ code. Let’s save it. CTRL + S and let’s call it main.cpp.

Basic code in VS Code but with intellisense active

If the C/C++ extension is installed then the source code looks much better now. If you find some red squiggles take the time to help Intellisense. This is a very good investment. Indeed, even at this point we can do some interesting stuff like reviewing the code and edit it with the help of Intellisense. See below :

Intellisence in action in VS Code

Ok, now the big question… How do we compile this source code? The point is that VS Code has no idea about the compiler you want to use, where it is on the hard drive, which parameters to use etc. So we will create what VS Code call a Task. Don’t panic… From now, all the modifications will remains local to the current directory. Nothing will be hidden in the Windows registry nor in some hidden files. In any cas, if at one point you get lost… Just delete the .vscode directory which will be created soon in the current directory and start over the process.

Ok, now, inside VS Code let’s press F1 (or CTRL + SHIFT + P). In the control bar, after the « > » sign, type the word « task » then select the »Configure Default Build Task »

Default Build Task in VS Code

Now select the « Create tasks.json file from a template » option

Create tasks.json in VS Code

Finally select « Other » since we don’t want to use MSBuild, maven etc. to build our application

Other task for tasks.json in VS Code

Once the file is available on screen I propose to modify it as follow :

First version of tasks.json in VS Code

Here is a version you can copy and paste

{    
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Debug",
            "type": "shell",
            "command": "cl",
            "args": [
                "/MDd /W4 /EHsc /ZI",
                "main.cpp"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Note

With VS Code version 1.22.1 and higher it seems it is better to put one argument per line and to write the tasks.json file as follow :

{    
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Debug",
            "type": "shell",
            "command": "cl",
            "args": [
                "/MDd",
                "/W4",
                "/EHsc",
                "/ZI",
                "main.cpp"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Question

Can you explain what is going on here?

  • Well, the content of the .json file is a list of tasks (line 5) that VS Code can execute.
  • Here, for the moment, we only have one task. The task is named « Build Debug » (line 7).
  • This task tells VS Code how to build a debug version of our application. To do so VS Code will have to run the command in a shell (line 8)
  • and the command will be « cl » (line 9). cl.exe is the name of the Microsoft compiler.
  • This command will have a set of arguments (line 11 and 12). If you already have compiled some C++ code in a console you should not be surprised by the parameters. As a remainder :
    • /MDd tells the compiler to use DLLs (rather than static lib, doing so, the final code is much smaller)
    • /W4 is the highest warning level available
    • /EHsc is for the exceptions
    • /ZI is for the format of the debug information.
    • If you want more information, Google is your friend 🙂
  • A t the very end of the file, the « group » (line 14) instructs VS Code that the command will be the default build command. This mean one will be able to invoke it by pressing CTRL + SHIFT + B.

Let’s save the tasks.json and… Press CTRL + SHIFT + B. If everything works fine the VS Code terminal should show up and display various messages during the build process.

First build debug version in VS Code

Finally we should see the following files in our current folder. Yes, I know, this is a mess…

Anyway, congratulations! We created our first Debug version on the application. Few comments however:

  1. It would be nice if we could keep our folder as clean as possible. Ideally we may want to generate the executable and all the other files in a Debug directory
  2. So far the application’s name is main.exe. This might be ok and we may don’t care if we do some quick and dirty testing but if we have more than a file this will not work.

Let’s modify the tasks.json file as follow.

Second version of tasks.json in VS Code

Again, here is a version you can copy’n paste

{    
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Debug",
            "type": "shell",
            "command": "cl",
            "args": [
                "/MDd /W4 /EHsc /ZI",
                "/Fe: '${workspaceFolder}/Debug/test.exe'",
                "/Fd: '${workspaceFolder}/Debug/'", 
                "/Fo: '${workspaceFolder}/Debug/'",
                "main.cpp"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Note

With VS Code version 1.22.1 and higher you should write :

{    
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Debug",
            "type": "shell",
            "command": "cl",
            "args": [
                "/MDd",
                "/W4",
                "/EHsc",
                "/ZI",
                "/Fe:${workspaceFolder}/Debug/test.exe",
                "/Fd:${workspaceFolder}/Debug/", 
                "/Fo:${workspaceFolder}/Debug/",
                "main.cpp"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Before anything else, let’s save the tasks.json.

The new arguments only concern :

  • The output name with /Fe
  • The directory where to store the program database file with /Fd
  • The directory where to put the object files with /Fo

To go further, one can read this page for more information and additional flags.

Please note how the ‘ and the ‘ are used on lines 12,13 and 14. This is mandatory if the path include spaces between words like in « c:/Program Files (x86)/Hakuna matata/… ». In addition note the use of the variable ${workspaceFolder}. VS Code support many other variables. Read this page for more information about variables and variables substitution in VS Code.

Note

I just spend 2 days to find and fix a weird issue so I want to share what I learnt so far. The problem was :

  • My workspace is on Dropbox. I mean I’m using the exact same source files and scripts in both cases.
  • Using one PC I’m able to compile the C++ code from VS Code following the above procedure.
  • Using a second PC (same version of Windows, VS Code, Visual Studio, sames plugins…) cl, the Microsoft compiler, is not able to find the file main.cpp and to compile it

I tried many many things… At the end here is what I keep in mind

  1. This is not part of the solution but it is good to know. You must remember that the escape chars are console dependent. What I mean is :
    1. In a PowerShell terminal one must surround our path with  » ‘  » and  » ‘ « . See the ‘${workspaceFolder}/Debug/test.exe’  parameter on line 10 of the previous tasks.json.
    2. In you want to use cmd instead of Powershell then use \ » and \ » (read this page for example)
  2. The solution was to make sure I do not have any script interfering with PowerShell. Since I’m under Windows 10, the default terminal in VS Code is based on Powershell. In my case I have a « …\MyName\Documents\WindowsPowerShell » directory which contains a file named « Microsoft.PowerShell_profile.ps1 ». In order to avoid the I had to comment this line :
Import-Module 'C:\Users\frbaucop\Downloads\posh-git\src\posh-git.psd1'

Note

If you have any doubt you can launch VS Code from a console and pass some parameters on the command line interface. You can try –verbose or –disable-extensions for example. Read this page for more information.

 

OK, let’s back on track. One last step to build the code and palce it in a dedicated Debug directory… Go back in the directory and do the following :

  1. Except for main.cpp and the .vscode sub directory, delete all the other files
  2. Create a Debug and Release sub-directories. The Release sub-directory will be in use soon.

The directory should now look like this :

Ready?  Press CTRL + SHIFT + B. If everything works fine, at the end of the compilation, no new file should be added in the workspace folder but the Debug should looks like this :

Debuging with VS Code

This is all fine but now we would like to go one step further. In fact, it is time to debug our code…

To do so, in the Debug menu, select the Open Configurations option

Open Configurations in VS Code

Then select C++ Windows

Select C++ Windows configuration in VS Code

A launch.json file similar to the one below should appear

Default launch.json in VS Code

As requested on line 11, let’s modify the program entry. I propose the following modification :

Custom version of launch.json in VS Code

Now « program » points to the debug version of our code, in the ./Debug sub-directory.

Note

During my testing I had no need to enclose the path the test.exe with ‘ and ‘.

Last but no least, it is time to go back to the source code and to set a break point on line 5 for example (int bob = 3;)

Set a breakpoint in VS Code

Ready? Let’s strike F5… If everything goes well a console with the canonical greeting message should appear. Much more important, the code should stop on line 5 and VS Code should looks like this :

Debug session in VS Code

This is a kind of little miracle… I really like that. The code is stopped. Look on the left side, bob is set to 0. Now, if we press F10, we move one step forward and bob is set to 3.

Step forward (F10) during debug session in VS Code

Ok, let’s imagine we fixed some issues in the code and that everything works as expected. Show times! Let’s compile a released version of the code

Compiling a release version with VS Code

This is very similar to what we did in the first place with the debug task. Let’s edit the tasks.json and let’s modify it as follow.

tasks.json with Debug and Release tasks in VS Code

Here is a text version of the file

{    
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Debug",
            "type": "shell",
            "command": "cl",
            "args": [
                "/MDd /W4 /EHsc /ZI",
                "/Fe: '${workspaceFolder}/Debug/test.exe'",
                "/Fd: '${workspaceFolder}/Debug/'", 
                "/Fo: '${workspaceFolder}/Debug/'",
                "main.cpp"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "Build Release",
            "type": "shell",
            "command": "cl",
            "args": [
                "/MD /W4 /EHsc",
                "/Fe: '${workspaceFolder}/Release/test.exe'",
                "/Fd: '${workspaceFolder}/Release/'", 
                "/Fo: '${workspaceFolder}/Release/'",
                "main.cpp"
            ]
        }
    ]
}

Pay attention to the « , » on line 21 which separates the two tasks in the list. For the rest, the second task is named Build Release, the arguments no longer include debug option and the output subdirectory now points to the Release subdirectory. No big surprise…

Note

With VS Code version 1.22.1 and higher you should write :

{    
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Test",
            "type": "shell",
            "command": "cl",
            "command": "cl",
            "args": [
                "/MDd",
                "/W4", 
                "/EHsc",
                "/ZI",
                "/std:c++17",
                "/Od",
                "/Fe:${workspaceFolder}/Debug/test.exe",
                "/Fd:${workspaceFolder}/Debug/",
                "/Fo:${workspaceFolder}/Debug/",
                "main.cpp"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "Build Release",
            "type": "shell",
            "command": "cl",
            "args": [
                "/MD",
                "/W4",
                "/EHsc",
                "/std:c++17",
                "/O2",
                "/Fe:${workspaceFolder}/Release/test.exe",
                "/Fd:${workspaceFolder}/Release/", 
                "/Fo:${workspaceFolder}/Release/",
                "main.cpp"
            ]
        }
    ]
}

OK, let’s save the new version of tasks.json

Now click on the Tasks menu (ALT+T) and select the Execute Task option. In the list select the Build Release option

Select a task in VS Code

You may have to select one additional option saying something like « Continue without analysing the output of the task » (I’m really not sure about the purpose of the different options available here…).

At the end, the Release subdirectory should looks like

We can now double click on test.exe. When the console is on screen while getchar() is waiting, we can press CTRL + ALT + SUPP, select the Task Manager and find test.exe in the list

Since there is no « (32 bits) » after the name of the application this confirms our application is 64 bits. This is a confirmation of the fact that I ran an x64 Developper Command Prompt at the very beginning.

Next steps?

LLVM 5.0 is installed on my PC. I’m able to compile using clang but lld (lld-link.exe) fails miserably. However I can finish the job and link the code with Microsoft linker. Anyway… Since LLVM 6.0 is available since March 8 it would be cool to install it, check how the linker now works and make some tests with VS Code. No?

 

 

 

3 comments to How to compile C++ code with VS Code and cl

  • Using LLVM 6 I can compile and link. No need to compile with clang and to link with Microsoft linker.
    This is a very good news 🙂

  • Merlimau

    Bonjour. Very good instruction for me as beginner. Working on Win7. Installed Visual Studio 2017 and try out your code example to compile. It works. Compiler starts and compile as you described.

    Installed VScode. But starting VScode from command prompt doesn’t find the exe. Even all the path entry (which should be done via VS 2017) are missing. So, compiling with the command CL doesn’t work in VScode.

    Installed the Visual Studio Build Tools. Run the command to install all path needed doesn’t installed the paths.

    What I’m doing wrong?

  • I always was concerned in this subject and stock still am, appreciate it for posting.

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  

  

  

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.