# Working with Visual Studio Code

This section describes the basic setup for Visual Studio Code.

Correctly configured Visual Studio Code showing – among other things – left, debugging, testmate, and cmake pane selectors, and at the bottom, build type, kit, current target, and CTest runner.

## Assumptions

- For brevity, non-standard libraries are expected to be in the folder `./deps/thirdParty`.

- MSYS2/MinGW 64 Bit is used.

## Installation

1. Install Visual Studio Code (https://code.visualstudio.com)

2. Install Extensions

Name | Purpose
--- | ---
C/C++ | Support for C/C++, including IntelliSense and debugging
CMake Tools | Extended CMake support
C++ Testmate | Run and debug GoogleTest
MSYS2/Cygwin/MinGW/Clang support | MSYS2/MinGW configuration adapter
Remote Development | Development using DevContainers
Docker | Additional information for DevContainer prerequisites

## Set Up Development Containers in Visual Studio Code

### Introduction

This section provides step-by-step instructions on setting up development containers in Visual Studio Code (VSCode). Development containers allow you to define and manage your development environment using Docker containers, ensuring consistent and reproducible setups across different machines.

### Prerequisites

Before you begin, make sure `docker` is installed in your system. If `docker` is not installed, follow the below steps.

1. Open PowerShell in Administrator Mode by right-clicking and selecting “Run as administrator.”.

2. To install wsl, run the following command and then restart the machine:

       wsl --install

   The above command only works if WSL is not installed at all. If you run `wsl --install` and see the WSL help text, try running `wsl --list --online` to see a list of available distros and run `wsl --install -d <Linux DistroName>` to install a distro. The recommended distro is `Ubuntu` and the following steps assumes the distro as `Ubuntu`

3. Once the distro is installed, check the version of the installed distro

       wsl -l -v

   If the version is 1, then change it to 2 using the command `wsl --set-version <distro> 2`

4. After successful installation, open Ubuntu by searching `Ubuntu` in windows search bar

5. Install the dependencies to run docker on the distro using the following command

       sudo apt install --no-install-recommends apt-transport-https ca-certificates curl

6. On Debian or Ubuntu, first temporarily set some OS-specific variables:

       . /etc/os-release

   Then, make sure `apt` trust the docker repo

       curl -fsSL https://download.docker.com/linux/${ID}/gpg | sudo tee /etc/apt/trusted.gpg.d/docker.asc

   ID will be either `ubuntu` or `debian`, as appropriate, depending on what is in `/etc/os-release`.

7. Add docker repo information to the `apt` to install docker.

       echo "deb [arch=amd64] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.list
       sudo apt update

8. Install Docker and add user to the `docker` group

       sudo apt install docker-ce docker-ce-cli containerd.io
       sudo usermod -aG docker $USER

   Replace `$USER` with your user name on distro. Then close the WSL window, and launch WSL again. You should see `docker` when you run the command `groups` on command prompt to list group memberships.

9. Launch `dockerd` using the following command

       sudo dockerd

   There should be several lines of info, warnings related to cgroup blkio, and the like, with something like API listen on /var/run/docker.sock at the end. If so, you have success. If there is any network controller issue, execute the following compile_commands

       echo -e "[network]\ngenerateResolvConf = false" | sudo tee -a /etc/wsl.conf
       sudo unlink /etc/resolv.conf
       echo nameserver 1.1.1.1 | sudo tee /etc/resolv.conf

   Also switch to legacy iptables using the following command

       update-alternatives --config iptables

   And select iptables-legacy Rerun the command `sudo dockerd` and check if it is succeeded.

10. To check if `docker` is running from Windows, in PowerShell execute the following command.

>     wsl -d Ubuntu docker -H unix:///var/run/docker.sock --version

1. Open a terminal window.

2. Execute the following command

       docker --version

   If Docker is installed, you will see the version information displayed in the terminal.

3. If Docker is not installed, you can install it using the following steps:

   1. Update your package list using the command:

          sudo apt update

   2. Install Docker using the following command:

          sudo apt install docker.io

   3. You may need to add your user to the “docker” group to use Docker without sudo. Run the following command to add your user to the group (replace <username> with your actual username):

          sudo usermod -aG docker <username>

Note

For more detailed instructions and troubleshooting related to Docker, refer to the official Docker documentation: https://docs.docker.com/get-docker/

### DevContainers

Open the repository in VSCode as folder, e.g. by calling `code openpass` after checking out and then define the development container configuration.

1. Open the repository as folder, e.g. by calling `code openpass` after checking out.

2. Create the folder `.devcontainer` at the root of the project and configure your development container using JSON format. Below is an example configuration:

   devcontainer.json

       1{
       2  "name": "openPASS DevContainer",
       3  "dockerFile": "../utils/Dockerfile",
       4  "workspaceFolder": "/workspaces/openPASS"
       5}

   `Download`

   Note

   To use docker daemons running on WSL, open `settings` in VSCode and search for `Execute In WSL` and select the option to execute in WSL. Also, under `Execute in WSLDistro` enter your distro name, for example: `Ubuntu`

   devcontainer.json

       1{
       2  "name": "openPASS DevContainer",
       3  "dockerFile": "../utils/Dockerfile",
       4  "workspaceFolder": "/workspaces/openPASS"
       5}

   `Download`

3. Open Your Project in a Development Container:

   1. Open the command palette by pressing Ctrl+Shift+P.

   2. Type “Dev Containers: Open Folder in Container” and select your project folder.

   3. VSCode will build the Docker container based on the configuration and open your project inside it.

4. Developing in the Container:

   1. You can now edit files, install packages, and run code within the development container.

   2. Installed extensions and settings in the container will be isolated from your local environment.

5. To exit the container, click on the bottom left status bar where it shows the container name and click “Close Remote Connection.”

## Configuration

### MSYS2 Path

Normally, runtime dependencies (DLLs) are not copied into the executables folder within the build process. This means, that programs cannot be executed natively from Windows shells or the explorer. It is therefore highly recommended, to set the environmental variable `MSYSTEM=MINGW64` and `CHERE_INVOKING=1`. The setting of `MSYSTEM` will cause the environment to be set up correctly for MinGW64. Windows will then look for DLLs within the msys64 folders, allowing native execution. `CHERE_INVOKING` makes sure the shell stays in the current working directory. As investigated recently, the `C:\msys64\usr\bin``must also be added to the ``PATH` environment variable in order to resolve dependencies to `cygpath.exe`.

Note

If `C:\msys64` is not already listed in `PATH` variable, then add `C:\msys64` in `PATH` variable before adding `C:\msys64\usr\bin` to the `PATH` variable. If there are any other Unix like environments installed on Windows operating systems (example: cygwin), there might even be file collisions when calling certain cmake commands. Therefore, it is suggested to add `C:\msys64` in `PATH` variable before any other Unix like environmental calls.

Either set environment variable through the `Windows PowerShell`

    # check if set
    echo ${env:path}
    echo ${env:MSYSTEM}
    echo ${env:CHERE_INVOKING}

    # if not
    setx path "%PATH%;C:\msys64\usr\bin"
    setx MSYSTEM "MINGW64"
    setx CHERE_INVOKING "1"

or

1. Open the start search

2. Type in “env” and choose “Edit the system environment variables”

3. Choose “Environment Variables…”

4. Set the environment variables:

   1. MSYSTEM=MINGW64

   2. CHERE_INVOKING=1

   3. Add `C:\msys64\usr\bin` to PATH

Visual Studio Code needs to be reloaded/restarted after the path update.

Note

An optimal solution would be to set the system environment variables in VSCode under `settings.json`. This is currently not possible. Please contact us if you find a better solution.

### Build Kit

Add and select MSYS2/MinGW64 Build Kit:

1. Execute `Ctrl+Shift+P`: `CMake: Edit User-Local CMake Kits`

2. Insert/Update:

   cmake-tools-kits.json

        1[
        2    {
        3        "name": "MinGW64",
        4        "preferredGenerator": {
        5            "name": "MSYS Makefiles"
        6        },
        7        "environmentVariables": { "PATH": "${command:mingw64.path}" },
        8        "compilers": {
        9            "C": "${command:mingw64.cc.exe}",
       10            "CXX": "${command:mingw64.cxx.exe}",
       11            "Fortran": "${command:mingw64.fc.exe}"
       12        },
       13        "keep": true
       14    }
       15]

   `Download`

3. `Ctrl+Shift+P`: `CMake: Select a Kit` = `MinGW64`

Select System Build Kit:

`Ctrl+Shift+P`: `CMake: Select a Kit` = `GCC 10.2.0`

See also Installing Prerequisites.

### User Settings

1. Execute `Ctrl+Shift+P`: `Preferences Open Workspace Settings (JSON)`

2. Insert/Update:

   settings.json

        1{
        2    //
        3    // CMAKE
        4    //
        5    // Following settings are from the MSYS2 extension documentation
        6    "cmake.cmakePath": "C:\\msys64\\mingw64\\bin\\cmake.exe",
        7    "cmake.preferredGenerators": [
        8        "MSYS Makefiles"
        9    ],
       10    "cmake.configureSettings": {
       11        "CMAKE_MAKE_PROGRAM": "C:\\msys64\\mingw64\\bin\\make.exe",
       12        "CMAKE_PREFIX_PATH": [
       13            "${workspaceRoot}/deps/thirdParty/win64/Yase",
       14            "${workspaceRoot}/deps/thirdParty/win64/FMILibrary",
       15            "${workspaceRoot}/deps/thirdParty/win64/MantleAPI",
       16            "${workspaceRoot}/deps/thirdParty/win64/osi",
       17            "${workspaceRoot}/deps/thirdParty/win64/protobuf",
       18            "${workspaceRoot}/deps/thirdParty/win64/protobuf-shared",
       19            "${workspaceRoot}/deps/thirdParty/win64/googletest",
       20            "${workspaceRoot}/deps/thirdParty/win64/minizip",
       21            "${workspaceRoot}/deps/thirdParty/win64/openscenario_engine/release",
       22            "${workspaceRoot}/deps/thirdParty/win64/openscenario_api",
       23            "${workspaceRoot}/deps/thirdParty/win64/zlib",
       24            "${workspaceRoot}/deps/thirdParty/win64/open-simulation-interface",
       25            "${workspaceRoot}/deps/thirdParty/win64/units",
       26            "${workspaceRoot}/deps/scmThirdParty/win64/stochastics",
       27            "C:/msys64/mingw64/bin"
       28        ],
       29        "CMAKE_INSTALL_PREFIX": "${workspaceRoot}/bin/core",
       30        "CMAKE_BUILD_TYPE": "Debug",
       31        "USE_CCACHE": true,
       32        "WITH_DEBUG_POSTFIX": false,
       33        "OPENPASS_ADJUST_OUTPUT": false,
       34        "WITH_API_DOC": false,
       35        "WITH_DOC": false,
       36        "INSTALL_EXTRA_RUNTIME_DEPS": true,
       37        "INSTALL_SYSTEM_RUNTIME_DEPS": true,
       38        // For integration with IntelliSense (see c_cpp_properties.json)
       39        "CMAKE_EXPORT_COMPILE_COMMANDS": true
       40    },
       41    // Optional: Adjust to your needs
       42    "cmake.parallelJobs": 4,
       43    //
       44    // TESTMATE
       45    //
       46    // Optional: Adjust to your needs
       47    "testMate.cpp.test.parallelExecutionLimit": 4,
       48    "testMate.cpp.test.parallelExecutionOfExecutableLimit": 2,
       49    // Optional: Set, if you like to debug test discovery and test start issues
       50    "testMate.cpp.log.logfile": "C:\\temp\\cpp.testmate.log",
       51    // Optional:    As CTest triggers the install step, dependencies between test executables
       52    //              and openpass libraries can be resolved by linking text executables to
       53    //              openpass install directory
       54    // Alternative: Check dependencies of test executables by 'ldd <_Tests.exe> and copy
       55    //              libraries right next to test executable within build direcory
       56    "testMate.cpp.test.advancedExecutables": [
       57        {
       58            "pattern": "build/**/*{tests,Tests,TESTS}*",
       59            "env": {
       60                "Path": "C:\\msys64\\mingw64\\bin;${workspaceFolder}\\bin\\core;${workspaceFolder}\\bin\\core\\lib;${os_env:PATH};${workspaceFolder}\\deps\\thirdParty\\win64\\FMILibrary\\lib;${workspaceFolder}\\deps\\thirdParty\\win64\\osi\\lib\\osi3"
       61            }
       62        }
       63    ],
       64    //
       65    // VSCODE
       66    //
       67    // Optional: Integration of MinGW64 Terminal in VS Code
       68    "terminal.integrated.profiles.windows": {
       69        "MinGW64": {
       70            "overrideName": true,
       71            "path": [
       72                "C:\\msys64\\usr\\bin\\bash.exe"
       73            ],
       74            "args": ["--login", "-i"],
       75            "icon": "terminal-bash",
       76            "env": {
       77                "MSYSTEM": "MINGW64",
       78                "CHERE_INVOKING": "1",
       79                "MSYS2_PATH_TYPE": "inherit"
       80            }
       81        }
       82    },
       83    "terminal.integrated.defaultProfile.windows": "MinGW64",
       84    // Enforce usage of .clang-format of modified code
       85    "editor.formatOnSave": true,
       86    "editor.formatOnSaveMode": "modifications",
       87    // EOL and whitespace enforcement
       88    "editor.detectIndentation": true,
       89    "editor.insertSpaces": true,
       90    "editor.renderFinalNewline": "dimmed",
       91    "files.insertFinalNewline": true,
       92    "files.trimFinalNewlines": true,
       93    "files.trimTrailingWhitespace": true
       94}

   `Download`

   settings.json

        1{
        2    //
        3    // CMAKE
        4    //
        5    // Optional: Adjust to your needs
        6    "cmake.parallelJobs": 4,
        7    // See openPASS documentation for individual WITH_* settings
        8    "cmake.configureSettings": {
        9        // Adjust paths depending on your system
       10        "CMAKE_PREFIX_PATH": [
       11            "${workspaceFolder}/deps/thirdParty/linux64/Yase",
       12            "${workspaceFolder}/deps/scmThirdParty/linux64/stochastics",
       13            "${workspaceFolder}/deps/thirdParty/linux64/MantleAPI",
       14            "${workspaceFolder}/deps/thirdParty/linux64/FMILibrary",
       15            "${workspaceFolder}/deps/thirdParty/linux64/protobuf",
       16            "${workspaceFolder}/deps/thirdParty/linux64/protobuf-shared",
       17            "${workspaceFolder}/deps/thirdParty/linux64/googletest",
       18            "${workspaceFolder}/deps/thirdParty/linux64/minizip",
       19            "${workspaceFolder}/deps/thirdParty/linux64/openscenario_api",
       20            "${workspaceFolder}/deps/thirdParty/linux64/openscenario_engine/release",
       21            "${workspaceFolder}/deps/thirdParty/linux64/open-simulation-interface",
       22            "${workspaceFolder}/deps/thirdParty/linux64/zlib",
       23            "${workspaceFolder}/deps/thirdParty/linux64/units"
       24        ],
       25        "CMAKE_INSTALL_PREFIX": "/usr/local/openPASS/bin/core",
       26        "CMAKE_BUILD_TYPE": "Debug",
       27        "USE_CCACHE": true,
       28        "WITH_DEBUG_POSTFIX": false,
       29        "OPENPASS_ADJUST_OUTPUT": false,
       30        "INSTALL_EXTRA_RUNTIME_DEPS": true,
       31        "WITH_API_DOC": false,
       32        "WITH_DOC": false,
       33        "WITH_TESTS": true,
       34        // For integration with IntelliSense (see c_cpp_properties.json)
       35        "CMAKE_EXPORT_COMPILE_COMMANDS": true
       36    },
       37    //
       38    // TESTMATE
       39    //
       40    // Optional: Adjust to your needs
       41    "testMate.cpp.test.parallelExecutionLimit": 4,
       42    "testMate.cpp.test.parallelExecutionOfExecutableLimit": 2,
       43    // Optional: Set, if you like to debug test discovery and test start issues
       44    "testMate.cpp.log.logfile": "/tmp/cpp.testmate.log",
       45    //
       46    // VSCODE
       47    //
       48    // Enforce usage of .clang-format of modified code
       49    "editor.formatOnSave": true,
       50    "editor.formatOnSaveMode": "modifications",
       51    // EOL and whitespace enforcement
       52    "editor.detectIndentation": true,
       53    "editor.insertSpaces": true,
       54    "editor.renderFinalNewline": "dimmed",
       55    "editor.renderWhitespace": "all",
       56    "editor.trimAutoWhitespace": true,
       57    "files.insertFinalNewline": true,
       58    "files.trimFinalNewlines": true,
       59    "files.trimTrailingWhitespace": true
       60}

   `Download`

### C++ and IntelliSense

1. Execute `Ctrl+Shift+P`: `C/C++: Edit Configurations (JSON)`

2. c_cpp_properties.json

        1{
        2    "configurations": [
        3        {
        4            "name": "openpass",
        5            "cStandard": "c99",
        6            "cppStandard": "c++17",
        7            "configurationProvider": "ms-vscode.cmake-tools",
        8            "compileCommands": "${workspaceFolder}/build/compile_commands.json",
        9            "intelliSenseMode": "linux-gcc-x64"
       10        }
       11    ],
       12    "version": 4
       13}

   `Download`

### Configure the Build

Execute `Ctrl+Shift+P`: `CMake: Configure`

CMake should now be able to configure the project. If not, cmake should give you at least a hint, what’s missing (normally external libraries). Read CMake Variables and Options or Installing Prerequisites for more information.

CMake

Some changes such as changing the build type (Debug/Release) will cause CMake to updates the configuration automatically. Other changes won’t trigger an update, such as changing the paths to libraries (CMAKE_PREFIX_PATH), the cmake cache needs to be cleared before reconfiguration: `Ctrl+Shift+P` > `CMake: Delete Cache and Reconfigure`

### Debug Targets

CMake Tools and C++ Testmate automatically use custom launch configurations, if available. When using the debugging functionality, the according executable will be executed from where they are built (per default inside the `build` folder).

- This is acceptable for unit test, which do not require openPASS specific libraries. The corresponding config is `CMake Target`.

- For the core, located at `./build/sim/src/core/opSimulation/opSimulation`, this does not work, as no libraries and no configurations are available. As a solution, a second debug target `opsimulation` points at the installed executable instead.

  Warning

  Don’t forget to run the target `install` before debugging .

1. Got to “Run and Debug” (`Ctrl+Shift+D`) and create a launch.json file.

2. Insert/Update:

launch.json

     1{
     2    "version": "0.2.0",
     3    "configurations": [
     4        {
     5            // FOR TESTMATE (SELECTED TEST) AND CMAKE (DEBUG CMAKE TARGET)
     6            "name": "CMake Target",
     7            "type": "cppdbg",
     8            "request": "launch",
     9            "program": "${command:cmake.launchTargetPath}",
    10            "args": [],
    11            "stopAtEntry": false,
    12            "cwd": "${workspaceFolder}",
    13            "environment": [
    14                {
    15                    "name": "PATH",
    16                    "value": "$PATH:${command:msys2.root}\\bin;${command:mingw64.root}\\x86_64-w64-mingw32\\lib${command:cmake.buildkit.launch.path}"
    17                }
    18            ],
    19            "externalConsole": false,
    20            "MIMode": "gdb",
    21            "miDebuggerPath": "${command:cmake.buildkit.gdb.exe}",
    22            "setupCommands": [
    23                {
    24                    "description": "Enable pretty-printing for gdb",
    25                    "text": "-enable-pretty-printing",
    26                    "ignoreFailures": true
    27                }
    28            ]
    29        },
    30        {
    31            // FOR DEBUGGING opSimulation (DON'T FORGET TO CALL make install)
    32            "name": "opsimulation",
    33            "type": "cppdbg",
    34            "request": "launch",
    35            "program": "${workspaceFolder}\\bin\\core\\opSimulation.exe",
    36            "args": [],
    37            "stopAtEntry": false,
    38            "cwd": "${workspaceFolder}\\bin\\core",
    39            "environment": [
    40                {
    41                    "name": "PATH",
    42                    "value": "$PATH:${command:msys2.root}\\bin;${command:mingw64.root}\\x86_64-w64-mingw32\\lib${command:cmake.buildkit.launch.path}"
    43                }
    44            ],
    45            "externalConsole": false,
    46            "MIMode": "gdb",
    47            "miDebuggerPath": "${command:cmake.buildkit.gdb.exe}",
    48            "setupCommands": [
    49                {
    50                    "description": "Enable pretty-printing for gdb",
    51                    "text": "-enable-pretty-printing",
    52                    "ignoreFailures": true
    53                }
    54            ]
    55        }
    56    ]
    57}

`Download`

launch.json

     1{
     2    "version": "0.2.0",
     3    "configurations": [
     4        {
     5            // FOR TESTMATE (SELECTED TEST) AND CMAKE (DEBUG CMAKE TARGET)
     6            "name": "CMake Target",
     7            "type": "cppdbg",
     8            "request": "launch",
     9            "program": "${command:cmake.launchTargetPath}",
    10            "args": [],
    11            "stopAtEntry": false,
    12            "cwd": "${workspaceFolder}",
    13            "externalConsole": false,
    14            "MIMode": "gdb",
    15            "setupCommands": [
    16                {
    17                    "description": "Enable pretty-printing for gdb",
    18                    "text": "-enable-pretty-printing",
    19                    "ignoreFailures": true
    20                }
    21            ]
    22        },
    23        {
    24            // FOR DEBUGGING opSimulation (DON'T FORGET TO CALL make install)
    25            "name": "opsimulation",
    26            "type": "cppdbg",
    27            "request": "launch",
    28            "program": "/usr/local/openPASS/bin/core/opSimulation",
    29            "args": [],
    30            "stopAtEntry": false,
    31            "cwd": "/usr/local/openPASS/bin/core/",
    32            "externalConsole": false,
    33            "MIMode": "gdb",
    34            "setupCommands": [
    35                {
    36                    "description": "Enable pretty-printing for gdb",
    37                    "text": "-enable-pretty-printing",
    38                    "ignoreFailures": true
    39                }
    40            ]
    41        }
    42    ]
    43}

`Download`

Note

IntelliSense uses the `compile_commands.json` of generated through `CMAKE_EXPORT_COMPILE_COMMANDS=ON` (see `settings.json`). This is necessary for proper resolution of the include files.

## Troubleshooting

Program does not start

The most effective way to debug startup issues is by means of the Process Monitor.

But normally, its a missing DLL. When executing the program via command line or explorer a message box should prompt which DLLs are missing. A simple solution is to copy the according DLLs into the folder of the executable. Another solution is to make the path available by extending the `PATH` environment variable. Potential sources for missing DLLs are `C:\msys64\mingw64\bin`, `C:\msys64\mingw64\x86_64-w64-mingw32\lib`, and the `build` folder itself.

Tests are not listed

For test discovery, C++ Testmate needs to know the location of all additional dependencies. This information is retrieved from the current debug configuration.

1. Testmate discovers tests only after they are built. It pays to `Run CTest` to build all test targets. After this, you should see all tests in the testing pane on the left.

2. Still not listed? Set `testMate.cpp.log.logfile` in `settings.json` and check log.

   1. Test executable not mentioned at all: Executable name might not fit (check glob pattern in `testMate.cpp.test.executables`).

   2. Log reports Error: Not a supported test executable: a library/DLL might be missing.