VSCode: setting up Fortran and debugging QUANTICS

Setting up VS Code for Fortran

Language Server set up

Install the Modern Fortran Extension

Then install the Fortran Language Server Fortls using your favourite method.
Make sure that the Modern Fortran Extension can find Fortls.
Go to the Modern Fortran Settings and check Fortran > Fortls:Path
(use $ which fortls to check path)

If all is correct then right clicking on variables will offer an option to go to definition or to find all references

Compiling

To compile from VScode can either run in the terminal or set up a task in the task.json file

 {
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
      {
          "label": "echo",
          "type": "shell",
          "command": "echo $PATH"
      },
      {
          "label": "debug compile",
          "type": "shell",
          "command": "compile -D ${fileBasenameNoExtension}",
          "problemMatcher": [],
          "group": {
              "kind": "build",
              "isDefault": true
          }
      }
  ]
  }

If this is run on a fileBasename.f90 file it will attempt to run the compile command on that file. So for example to compile Quantics you would have quantics.f90 file open and active in VScode. Then run this task. If successful this will build the debug version of Quantics. Obviously removing the -D will compile the normal version of Quantics.

To create a task in VSCode go Terminal→Configure Tasks… and select from the options

the task.json is normally saved in the .vscode folder created as part of the projec

Debugging

To debug, first make sure you have the overall quantics folder open as the workspace in Vscode.
Then create a launch.json

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
      {
          "name": "Python: Current File",
          "type": "python",
          "request": "launch",
          "program": "${file}",
          "console": "integratedTerminal"
      },
      {
          "name": "(gdb) Launch",
          "type": "cppdbg",
          "request": "launch",
          "program": "${workspaceFolder}/bin/binary/x86_64/${fileBasenameNoExtension}D",
          "args": [
              "INPUT_FILE"
          ],
          "stopAtEntry": true,
          "cwd": "/home/user/folder/you/have/put/your/files,
          //"cwd": "${workspaceFolder}",
          "environment": [],
          "externalConsole": false,
          "MIMode": "gdb",
          "setupCommands": [
              {
                  "description": "Enable pretty-printing for gdb",
                  "text": "-enable-pretty-printing",
                  "ignoreFailures": true
              }
          ]
      }
  ]
}

This contains two different launches. The first will launch python with the current file (so run python file.py). The second is more interesting (for a value of interesting) as it will launch GDB and so let you debug Fortran and C. There is a lot going on so we will break it down:

“program”: command is the name of the program to be launched. In this case it has the path relative to the workspace folder where the quantic binaries are saved. This path might be different depending on where you have defined your workspace. Also note that it combines the file name with a D to make sure you are using the debug binary (which you have just compiled, see here)

“args” are the command line arguments that you want to send to the programme. They need to be written as a comma separated list.

“stopAtEntry” this command is whether the programme should pause as soon as it stops or not.

“cwd” this is the current working directory. In this example it is the folder where the data files are stored. There is also a commented out line which would set cwd to the workspace folder.

To then debug go to the debug menu, make sure the correct launch option is chosen and click the green button next to it.

You can add breakpoints by clicking to the left of a line of code in the main window. If you right click you get some more options to create clever breakpoints (note as of writting the stop after certain number of hits doesn’t work)

GDB - useful commands

If you want GDB commands that VScode doesn’t provide then you can run them directly in the debugger terminal.
Add -exec infront of the commands in the debugger terminal

Info on breakpoints, including how many times hit

info breakpoints

For a given breakpoint will ignore this number of hits before triggering

ignore <breakpoint number> <hit count>	

Print stack trace

bt

print <variable name> - prints out the value of the variable

ptype <variable name> - what is the type of the variable

p sizeof(<variable name>) - what is the size in memory of variable

Debug hints

Use breakpoints, a lot to narrow down where the problem occurs.
Once you know check for obvious problems. If you hover over a variable it should give you the current value, or it is available in the debugging menu on the left under WATCH.
Step through line by line

More advanced tricks

It is possible to launch and debug from multiple programmes at the same time.
For example, if you are interacting with a C (or Fortran) library from Python, can do the following
Use following launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Attach",
            "type": "cppdbg",
            "request": "attach",
            "program": "/home/mike/miniconda3/bin/python", 
            "processId": "${command:pickProcess}",
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        },
        
        
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "cwd": "${workspaceFolder}/.vscode/ar_he_nacm_35b_S_4_19_mom_st12_4/"
        }
    ]
} 

Run on the Python file. Use below to find its ID

ps aux | grep python

or this should pull just the python access token

ps aux | grep python | grep -Po 'token \K\S+'

Then debug GDB attach on the C/Fortran file and give the access token when requested.

You can now debug both the Python code and the Library code

2 Likes

This is awesome, thanks @leoncigrang for a very detailed writeup! :heart_hands: (and sorry that we did not get to it during the hackathon. Debugging would definitely be a good topic for the next one…)

Thank you @leoncigrang ! That’s going to make life much much easier !

1 Like