Contents


p1-stats

Setting up VS Code

Visual Studio Code is a lightweight, easy-to-use, source code editor with debugging support. It run on macOS, Windows, and Linux (including CAEN Linux). Visual Studio Code is not the same program as Visual Studio.

This tutorial will walk you through

Prerequisites

At this point, you should already have a folder for your project (instructions). Your folder location might be different. You should have downloaded and unpacked the starter files already (instructions).

$ pwd
/Users/awdeorio/src/eecs280/p1-stats
$ ls
Makefile      main_test.out.correct  p1_library.h           stats_tests.cpp
README.md     main_test_data.tsv     stats.h
main_test.in  p1_library.cpp         stats_public_test.cpp

Restarting this tutorial

If you tried using this tutorial in the past and want to “start clean”, here’s how to delete all VS Code configuration files. This will not delete your code. First, quit VS Code.

$ pwd
/Users/awdeorio/src/eecs280/p1-stats
$ rm -rf .vscode
$ rm -rf ~/.vscode
$ make clean
rm -rvf *.exe *~ *.out *.dSYM *.stackdump

Install

Choose your platform below.

macOS

Use the homebrew package manager.

$ brew cask install visual-studio-code

Windows

Install from the web https://code.visualstudio.com/.

Select “Add to PATH”.

Finally, reboot

Linux

Install the .deb package from the web https://code.visualstudio.com/docs/setup/linux.

CAEN Linux

VS Code is already installed on CAEN Linux desktop environment. You can use it while sitting at a CAEN Linux computer, or through a VNC connection to CAEN Linux. You’ll need to load the vscode/1.19.2 module any time you open new terminal.

$ module load vscode/1.19.2
$ module load git     # Optional, avoids warning about old git version

Pitfall: Do not use the Applications menu to open VS Code. It will open an older version. Always use the command line, as shown later in this tutorial.

All platforms

Make sure VS Code is installed correctly by checking the version. You need version 1.18.0 or higher.

$ code --version
1.18.0
dcee2202709a4f223185514b9275aa4229841aa7

Install the C/C++ extension

Start Visual Studio Code from your source code directory. Remember that the dot (.) means “the present working directory”.

$ pwd
/Users/awdeorio/src/eecs280/p1-stats
$ code .

Navigate to the extensions pane.

Install the C/C++ extension.

Create a project

VS Code doesn’t require any special setup for a project. However, we’ll add some files to our directory.

Start VS Code. If you’re on CAEN linux, don’t forget to load the vscode module with module load vscode/1.19.2.

$ pwd
/Users/awdeorio/src/eecs280/p1-stats
$ code .

Add new files

EECS 280 project 1 requires us to create two new files: stats.cpp and main.cpp.

Open the p1-stats folder by selecting File > Open Folder... > navigate to the p1-stats folder.

Select the add file icon and name the new file stats.cpp. Do this again to create main.cpp.

You’ll also see the new files at the command line.

$ ls
Makefile      main_test.out.correct  p1_library.h  stats_public_test.cpp
main.cpp      main_test_data.tsv     stats.cpp     stats_tests.cpp
main_test.in  p1_library.cpp         stats.h

Project 1 stats.cpp

Now let’s modify the files that you created. Edit stats.cpp and add function stubs. A function stub contains only assert(false); it’s like a placeholder that we’ll use to get our application to compile. Each of these stubs corresponds to a function prototype in stats.h. Don’t forget to save.

// stats.cpp
#include "stats.h"
#include <cassert>
#include <vector>
using namespace std;

vector<vector<double> > summarize(vector<double> v) {
  assert(false);
}

int count(vector<double> v) {
  assert(false);
}

double sum(vector<double> v) {
  assert(false);
}

double mean(vector<double> v) {
  assert(false);
}

double median(vector<double> v) {
  assert(false);
}

double mode(vector<double> v) {
  assert(false);
}

double min(vector<double> v) {
  assert(false);
}

double max(vector<double> v) {
  assert(false);
}

double stdev(vector<double> v) {
  assert(false);
}

double percentile(vector<double> v, double p) {
  assert(false);
}

Project 1 main.cpp

Start your main.cpp like this. All it does so far is “hello world”. We’ll include a few libraries that will be useful later.

//main.cpp
#include "stats.h"
#include "p1_library.h"
#include <iostream>
using namespace std;

int main() {
  cout << "hello from main!\n";
}

Compile

VS Code uses an executable you build at the command line. One executable should have exactly one main() function. Three of our project 1 files have main() functions.

Project 1 Target File with main() Other .cpp Build Sources
stats_tests.exe stats_tests.cpp stats.cpp, p1_library.cpp
stats_public_test.exe stats_public_test.cpp stats.cpp, p1_library.cpp
stats_tests.exe main.cpp stats.cpp, p1_library.cpp

Compile the executable you plan to run.

$ pwd
/Users/awdeorio/src/eecs280/p1-stats
$ make clean
rm -rvf *.exe *~ *.out *.dSYM *.stackdump
$ make stats_tests.exe
g++ -Wall -Werror -pedantic -g --std=c++11 stats_tests.cpp stats.cpp p1_library.cpp -o stats_tests.exe

PITFALL: VS Code debugging will fail if there are no debugging symbols. Double check the output of make and verify that you see -g being used in the commands. The EECS 280 defaults include -g.

Run

Navigate to the debugging pane.

Start the debugger.

Click the gear and select the C++ (GDB/LLDB) environment.

You may to need to click Reload.

Edit launch.json and save. Settings for different platforms are below.

macOS launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(lldb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/stats_tests.exe",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "lldb"
        }
    ]
}

Windows/Cygwin launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/stats_tests.exe",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "c:\\cygwin64\\bin\\gdb.exe",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": false
                }
            ]
        }
    ]
}

Windows/WSL launch.json

To use the gdb installed by WSL, you’ll need to tell VS Code to invoke gdb inside a bash shell. Note the paths for the "program" and "cwd" entries begin with /mnt/. You will need to update these for each project.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "C++ Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "/mnt/c/Users/awdeorio/Desktop/eecs280/p1-stats/stats_tests.exe",
            "args": [],
            "stopAtEntry": true,
            "cwd": "/mnt/c/Users/awdeorio/Desktop/eecs280/p1-stats",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "pipeTransport": {
                "pipeCwd": "",
                "pipeProgram": "c:\\windows\\sysnative\\bash.exe",
                "pipeArgs": ["-c"],
                "debuggerPath": "/usr/bin/gdb"
            },
            "sourceFileMap": {
                "/mnt/c": "c:\\"
            }
        }
    ]
}

Linux launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/stats_tests.exe",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": false
                }
            ]
        }
    ]
}

Input redirection

Skip this subsection on your first time through the tutorial. You can use input redirection to avoid typing program input each time you run (for debugging) a program.

Without input redirection, here’s how you type input at the command line. Notice that the program asks the user to enter a filename and then the user types main_test_data.tsv. Then, the program asks the user to enter a column name and the user types B.

$ make clean
rm -rvf *.exe *~ *.out *.dSYM *.stackdump
$ make main.exe
g++ -Wall -Werror -pedantic -g --std=c++11 main.cpp stats.cpp p1_library.cpp -o main.exe
$ ./main.exe
enter a filename
main_test_data.tsv
enter a column name
B
...

If we put the user input in a file we can automate the user input. We’ll put it in a file called main_test.in.

$ cat main_test.in   # Peek at the contents of a file
main_test_data.tsv
B
$ ./main.exe < main_test.in  # Redirect file content to main's stdin (cin)
enter a filename
enter a column name
reading column B from main_test_data.tsv
...

Without input redirection, here’s how to type input in the Visual Studio Code command line. In some configurations, a window will pop up, in others, you’ll type into a pane on the VS Code interface.

To configure input redirection, edit launch.json.

{
    "configurations": [
        {
            ...
            "program": "${workspaceFolder}/main.exe",
            "args": ["<", "main_test.in"],
            ...
        }
    ]
}

Arguments and options

Skip this subsection for EECS 280 project 1. You’ll need it for project 2 and beyond.

Arguments and options are inputs to a program typed at the command line. Arguments are often required. Options (AKA flags or switches) start with a hyphen (-), and are typically optional.

Arguments example from project 2: resize.exe is the name of the program, and the arguments are horses.ppm, horses_400x250.ppm, 400, and 250.

$ ./resize.exe horses.ppm horses_400x250.ppm 400 250

Options example from project 5: main.exe is the name of the program. train_small.csv and test_small.csv are arguments. --debug is an option.

$ ./main.exe train_small.csv test_small.csv --debug

To run a program with options or arguments in VS Code, edit launch.json. Be sure to put each option or argument as a separate comma-separated string.

"args": ["train_small.csv", "test_small.csv", "--debug"],

Debug

Run the debugger.

Visual Studio Code is actually running gdb stats_tests.exe under the hood (lldb on macOS). The debugger highlights the next line of code to be run (in this case, the first line of the program).

Click “Step Over” to run the highlighted line of code all at once. Our test fails immediately because we haven’t implemented sum() yet.

Restart the program.

Click “step into”. You’ll see that the cursor enters the function.

Click “step over” a few times until you’re on this line of code. Hover over a variable to see its value.

If you have trouble viewing the contents of the vector in the previous step, see the Pretty Printing STL Containers with gdb section, below.

Pro-tips

The C/C++ extension for Visual Studio Code has more features. Check out this Blog Post from the Visual C++ Team Blog. https://blogs.msdn.microsoft.com/vcblog/2016/03/31/cc-extension-for-visual-studio-code/

You can optionally use the command line to install VS Code extensions.

$ code --install-extension ms-vscode.cpptools
Found 'ms-vscode.cpptools' in the marketplace.
Installing...
Extension 'ms-vscode.cpptools' v0.14.0 was successfully installed!

Next steps

Return to the main set up tutorial.

Pretty-printing STL Containers with gdb

Visual Studio Code uses gdb under the hood. Some installations of gdb don’t ship with pretty printing support for STL containers like vector.

If you have this problem, you’ll see something like this when you try to view the contents of a vector while debugging.

Install Subversion and Python. If you’re using Cygwin, install additional packages with the Cygwin installer.

Get the GDB STL pretty printers. These are written in Python.

$ mkdir ~/.gdb.d/
$ svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python ~/.gdb.d/python

Use this command to create a .gdbinit file in your home directory.

$ echo -e 'python\nimport os\nimport sys\nsys.path.insert(0, os.path.expanduser("~/.gdb.d/python"))\nfrom libstdcxx.v6.printers import register_libstdcxx_printers\nregister_libstdcxx_printers (None)\nend' > ~/.gdbinit

Double check everything:

$ cat ~/.gdbinit
python
import os
import sys
sys.path.insert(0, os.path.expanduser("~/.gdb.d/python"))
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
$ ls -R ~/.gdb.d/
/Users/awdeorio/.gdb.d/:
python

/Users/awdeorio/.gdb.d/python:
Makefile.am  Makefile.in  hook.in  libstdcxx

/Users/awdeorio/.gdb.d/python/libstdcxx:
__init__.py  v6

/Users/awdeorio/.gdb.d/python/libstdcxx/v6:
__init__.py  printers.py  xmethods.py

Finally, restart VS Code and try to check the contents of vector again.