UsingVSCode: Difference between revisions

From GNU Radio
Jump to navigation Jump to search
(Created page with "= Building and source level debugging OOT C++ modules with Visual Studio Code = The following instructions were created using VSCode v1.33.1 on Ubuntu 18.04 == Prerequisites...")
 
(GNURadio Integration extension)
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
= Building and source level debugging OOT C++ modules with Visual Studio Code =
= Prerequisites =


The following instructions were created using VSCode v1.33.1 on Ubuntu 18.04
Tools used in this tutorial:
* GNU Radio v3.10 or newer
* [https://code.visualstudio.com Visual Studio Code] or [https://vscodium.com VSCodium]


== Prerequisites ==
The following instructions have been tested with GNU Radio v3.10.9 and VSCodium v1.92 in Ubuntu 24.04 LTS.


'''VSCode must be run as sudo to debug using GDB. Haven't found a way around this yet.'''
== Extensions for VSCode users ==
* "[https://marketplace.visualstudio.com/items?itemName=ms-python.python Python]" - for working with Python code and debugging it;
* "[https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools C/C++]" - for working with C++ code and debugging it;
* "[https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools CMake Tools]" - for working with the CMake project, using tasks to configure, build and test it;
* "[https://marketplace.visualstudio.com/items?itemName=ivannovak1004.gnuradio-integration GNU Radio Integration]" - for working with GNU Radio modules, an interface to gr_modtool;
* "[https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml YAML]" - for working with GRC files manually.


<nowiki>
== Extensions for VSCodium users ==
sudo code . --user-data-dir $TMPDIR</nowiki>
* "[https://open-vsx.org/extension/ms-python/python Python]" - for working with Python code and debugging it;
* "[https://open-vsx.org/extension/llvm-vs-code-extensions/vscode-clangd clangd]" - language server for working with C++ code;
* "[https://open-vsx.org/extension/vadimcn/vscode-lldb CodeLLDB]" or "[https://open-vsx.org/extension/webfreak/debug Native Debug]" - for debugging C++ code;
* "[https://open-vsx.org/extension/ms-vscode/cmake-tools CMake Tools]" - for working with the CMake project, using tasks to configure, build and test it;
* "[https://open-vsx.org/extension/AsriFox/gnuradio-integration GNU Radio Integration]" - for working with GNU Radio modules, an interface to gr_modtool;
* "[https://open-vsx.org/extension/redhat/vscode-yaml YAML]" - for working with GRC files manually.


where $TMPDIR is a temporary location for VS Code to place its user data files. 
== Extension pack ==


NOTE: Using . as the user-data-dir will litter the current directory with files and folder.
To get the extensions for editing, you can install "GNU Radio development pack" ([https://marketplace.visualstudio.com/items?itemName=asrifox.gnuradio-extension-pack VSCode], [https://open-vsx.org/extension/AsriFox/gnuradio-extension-pack VSCodium]).


== Instructions ==
You will still need to install "CMake Tools" and all C++ extensions separately.


= Setting up for editing GNU Radio modules =


1) In VSCode Extensions Marketplace, install C++ and GDB Extensions (also Python Debugger for stepping through Python Code)
"GNURadio Integration" extension provides a graphical interface to ''gr_modtool'' within VSCode. It allows you to:
* Create new OOT modules;
* Query information about the module;
* Discover the module's blocks in the '''OOT Module Explorer''';
* Add, rename and remove blocks;
* Create or update Python bindings to C++ blocks;
* Update XML block definitions to YAML.


2) Build the target OOT module and install into the pybombs prefix (or whatever other install method was used for GNU Radio)
Additionaly, you can:
* Launch '''GNURadio Companion''' from the command palette;
* Open the current GRC flowgraph file in '''GNURadio Companion''';
* Compile the current GRC flowgraph into an application;
* Run the current GRC flowgraph.


* Be sure when building the OOT module, use -DCMAKE_BUILD_TYPE=Debug as one of the cmake flags, e.g:
To properly set up the development environment, follow the procedure:


<nowiki>
=== Step 1: Discover GNURadio ===
cmake ../ -DCMAKE_BUILD_TYPE=Debug</nowiki>


3) Create a flowgraph that calls your module
GNURadio can be installed system-wide (with the distribution's package manager, e.g. ''apt'') or locally. You can check the installation prefix with "gnuradio-config-info --prefix" command.


* In GRC, it is helpful to spool a temporary .py by changing the ID in options, generating the flowgraph, then changing the id back, so that direct changes to the python are not overwritten when the flowgraph is run from GRC
For [[CondaInstall|Conda-based installations]] the prefix is related to the virtual environment, so it can be discovered using "Select Interpreter" command of the "Python" extension:


4) Add a sleep into the python file
[[File:Vscode_python_interpreters.png|border|"Select Interpreter" dialog]]


* Place after the import statement for your module
If there is a specific Python interpreter or environment you would like to use by default, you can specify '''Default interpreter''' and '''Default PYTHONPATH''' in the ''Settings''.
* If you are debugging the constructors of your module, then place the sleep before your import


<nowiki>
In Linux, the default system-wide install prefix is ''/usr'', but it can be defined by the user in [[LinuxInstall#From_Source|source builds]] (default: ''/usr/local''). In [[WindowsInstall#Installation_Options|native Windows builds]], the install prefix is always user-defined. To provide the editor with the required path to use GNURadio scripts, you will need to specify '''GNURadio Prefix''' in the ''Settings''.
import mymodule
import time; time.sleep(15)</nowiki>


5) Set breakpoints in VSCode that you want to hit
=== Step 2: Open the module's directory ===
* Like any other IDE with source level debugging, these can also be set while the code is free running


6) In VSCode, Debug --> Open Configurations brings up a "Set Environment" selection
You can create a new OOT module from VSCode using '''Create OOT Module''' command. It will prompt you for a name for the new module, and then prompt you to select the directory, in which the new module project will be created. For example, if you enter "sample" as the name and select ''~/Documents'' as the location, the module project will be created in ''~/Documents/sample''. After that, the editor will ask if you want to open this module's directory in the current editor.
* Choose GDB
* This brings up launch.json


7) Add Attach type of configuration
Alternatively, modules can be created with ''gr_modtool'' (see [[Creating Python OOT with gr-modtool#Creating an OOT Module|Creating an OOT Module]]). You can open their directories manually, using '''Open Directory''' command (Ctrl+K -> Ctrl+O). The same is applicable to existing OOT modules.
* Debug --> Add Configuration
* Select C/C++ (gdb) Attach
* This inserts some code


8) Modify the configuration so that the program to debug is python (either python2 or python3 depending gnuradio branch)
=== Step 3: Use the Module Explorer ===
* The launch.json should look like this:
 
<nowiki>
[[File:Vscode_module_tree.png|thumb|Module Explorer view]]
 
If an OOT module is detected in the workspace, the '''GNURadio Module''' tree view will appear in the Explorer container in the sidebar. All blocks within that module are presented with the corresponding files:
* YAML GRC block definition;
* Python implementation source or Python blocks;
* C++ header and implementation source for C++ blocks;
* Python and C++ QA (unit testing) source files.
 
Click the "+" button in the Module Explorer header to create a new block. The "Refresh" button is used to refresh the view after external changes.
 
Context menus (Right mouse click) for blocks contain the module manipulation commands:
* Rename block;
* Remove block;
* Convert XML to YAML (if XML definition is present);
* Create Python bindings (if the block's source code is C++).
 
=== Step 4: Edit the module's source code ===
 
Related tutorials: [[Creating Your First Block]], [[Creating Python OOT with gr-modtool]], [[Creating C++ OOT with gr-modtool]].
 
To enable syntax highlighting, autocompletion, documentation and other code editing features, you need to install the language server extension for the corresponding language:
* For Python, install "Python" extension.
* For C++, install "C/C++" or "clangd" extension.
 
=== Step 5: Build and test the module ===
 
You can [[Creating C++ OOT with gr-modtool#Compiling and Installing the Block|build and install]] the module using CMake either from a terminal or with "CMake Tools" extension. Build flags can be set in the command line or in ''build/CMakeCache.txt''.
 
You can perform unit testing for your blocks with QA functions (''python/module/qa_block.py'', ''lib/qa_block.cc''). '''Testing''' panel provides an overview of all test fixtures in the module.
 
After installing the module you can use your blocks in flowgraphs. It is considered a good practice to add examples for your module to demonstrate the usage of your blocks. Example flowgraphs can also be used for [[#Source level debugging]].
 
=== Step 6 (Optional): Use additional features ===
 
Some features of "GNURadio Integration" require presence of other extensions.
 
* "Python" extension is required to discover GNURadio installation in a Python virtual environment using "Select Interpreter" command.
* "YAML" extension is required to use syntax highlighting and validation in GRC flowgraph files and YAML GRC block definition files.
** "YAML Embedded Languages" extension can provide additional highlighting for embedded code blocks (e.g. "make" templates).
 
= Source level debugging =
 
The procedure described below allows source level debugging within VSCode through the use of the module's QA functions or flowgraphs. A debugger extension is required (see [[#Extensions for VSCode users]] and [[#Extensions for VSCodium users]]).
 
To debug your blocks using flowgraphs:
# Configure, build and install it using CMake;
#* Be sure to set build type to "Debug" at the configure step as a cache variable (''build/CMakeCache.txt'') or as a CMake command flag: <pre>cmake .. -DCMAKE_BUILD_TYPE=Debug</pre>
# Create and compile a flowgraph that uses your module;
# Run the compiled flowgraph with a debugger.
 
=== Launching from VSCode ===
 
The simplest way to achieve source level debugging is to launch the top level flowgraph from VSCode. To do that:
 
# Set breakpoints in code that you want to hit.
# In the '''Debug''' panel (''Ctrl-Shift-D''), create a launch configuration;
#* Create a configuration with "request": "launch";
#* Set "type" according to the target block type:
#** "debugpy" for Python blocks;
#** "cppdbg" for C++ blocks with "C/C++" extension;
#** "lldb" for C++ blocks with "CodeLLDB" extension;
#** "gdb", "lldb-mi" or "mago-mi" for C++ blocks with "Native Debug" extension;
#* Set "program" as your Python interpreter, e.g. "/usr/bin/python3";
#* Set "args" as your compiled flowgraph: <code>["-u", "/path/to/flowgraph.py"]</code>;
#* Alternatively, if your flowgraph compiles to C++, set "program" as your compiled and built flowgraph: "/path/to/flowgraph/build/flowgraph".
#: Complete ''launch.json'' example:
#: <syntaxhighlight lang="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",
     "version": "0.2.0",
     "configurations": [
     "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "/usr/bin/python3",
            "args": ["-u", "/path/to/flowgraph.py"],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        },
    ]
}
</syntaxhighlight>
# Start a debugging session with '''"Debug: Start Debugging"''' command (F5).
# The debugger will then land on your breakpoints.


=== Attaching to Process ===
Another alternative is to attach to an already running process. This is useful for more complicated long-running systems and flowgraphs. To do that:
# Set breakpoints in code that you want to hit.
# In the '''Debug''' panel (''Ctrl-Shift-D''), create a launch configuration;
#* Create a configuration with "request": "attach";
#* Set "type" according to the target block type:
#** "debugpy" for Python blocks;
#** "cppdbg" for C++ blocks with "C/C++" extension;
#** "lldb" for C++ blocks with "CodeLLDB" extension;
#** "gdb", "lldb-mi" or "mago-mi" for C++ blocks with "Native Debug" extension;
#* Set "program" as your Python interpreter, e.g. "/usr/bin/python3";
#* Set "processId" as "${command:pickProcess}" to pick from a list of running Python processes;
#: Complete ''launch.json'' example:
#: <syntaxhighlight lang="json">
{
    "version": "0.2.0",
    "configurations": [
         {  
         {  
             "name": "(gdb) Attach",
             "name": "(gdb) Attach",
Line 76: Line 195:
             ]
             ]
         },
         },
     ]
     ]
}</nowiki>
}
 
</syntaxhighlight>
 
# Launch your flowgraph from a terminal;
9) From a terminal, launch the python script which uses your module in a flowgraph
#* If necessary, delay the startup in code (e.g. by adding <code>sleep</code> or <code>raw_input</code> and give the debugger time to attach:
 
#: <syntaxhighlight lang="python">
10) From VSCode, Start Debugging (F5), and you will be prompted to select the process to attach to
if __name__ == "__main__":
 
    if GDB_ATTACH:
11) Start typing python, and then choose the python instance which is running your flowgraph
        print(f"Blocked waiting or GDB attach (pid = {os.getpid()}). "
 
              "Press ENTER after GDB is attached.", flush=True)
12) At this point (or after the script passes time.sleep) GDB should attach and breakpoints will be active
        raw_input()
    main()
</syntaxhighlight>
# Start a debugging session with '''"Debug: Start Debugging"''' command (F5).
# You will be prompted to select the process to attach to; type "python" to filter Python instances and select the one running your flowgraph.
# The debugger will then attach and land on your breakpoints.

Latest revision as of 08:59, 4 September 2024

Prerequisites

Tools used in this tutorial:

The following instructions have been tested with GNU Radio v3.10.9 and VSCodium v1.92 in Ubuntu 24.04 LTS.

Extensions for VSCode users

  • "Python" - for working with Python code and debugging it;
  • "C/C++" - for working with C++ code and debugging it;
  • "CMake Tools" - for working with the CMake project, using tasks to configure, build and test it;
  • "GNU Radio Integration" - for working with GNU Radio modules, an interface to gr_modtool;
  • "YAML" - for working with GRC files manually.

Extensions for VSCodium users

  • "Python" - for working with Python code and debugging it;
  • "clangd" - language server for working with C++ code;
  • "CodeLLDB" or "Native Debug" - for debugging C++ code;
  • "CMake Tools" - for working with the CMake project, using tasks to configure, build and test it;
  • "GNU Radio Integration" - for working with GNU Radio modules, an interface to gr_modtool;
  • "YAML" - for working with GRC files manually.

Extension pack

To get the extensions for editing, you can install "GNU Radio development pack" (VSCode, VSCodium).

You will still need to install "CMake Tools" and all C++ extensions separately.

Setting up for editing GNU Radio modules

"GNURadio Integration" extension provides a graphical interface to gr_modtool within VSCode. It allows you to:

  • Create new OOT modules;
  • Query information about the module;
  • Discover the module's blocks in the OOT Module Explorer;
  • Add, rename and remove blocks;
  • Create or update Python bindings to C++ blocks;
  • Update XML block definitions to YAML.

Additionaly, you can:

  • Launch GNURadio Companion from the command palette;
  • Open the current GRC flowgraph file in GNURadio Companion;
  • Compile the current GRC flowgraph into an application;
  • Run the current GRC flowgraph.

To properly set up the development environment, follow the procedure:

Step 1: Discover GNURadio

GNURadio can be installed system-wide (with the distribution's package manager, e.g. apt) or locally. You can check the installation prefix with "gnuradio-config-info --prefix" command.

For Conda-based installations the prefix is related to the virtual environment, so it can be discovered using "Select Interpreter" command of the "Python" extension:

"Select Interpreter" dialog

If there is a specific Python interpreter or environment you would like to use by default, you can specify Default interpreter and Default PYTHONPATH in the Settings.

In Linux, the default system-wide install prefix is /usr, but it can be defined by the user in source builds (default: /usr/local). In native Windows builds, the install prefix is always user-defined. To provide the editor with the required path to use GNURadio scripts, you will need to specify GNURadio Prefix in the Settings.

Step 2: Open the module's directory

You can create a new OOT module from VSCode using Create OOT Module command. It will prompt you for a name for the new module, and then prompt you to select the directory, in which the new module project will be created. For example, if you enter "sample" as the name and select ~/Documents as the location, the module project will be created in ~/Documents/sample. After that, the editor will ask if you want to open this module's directory in the current editor.

Alternatively, modules can be created with gr_modtool (see Creating an OOT Module). You can open their directories manually, using Open Directory command (Ctrl+K -> Ctrl+O). The same is applicable to existing OOT modules.

Step 3: Use the Module Explorer

Module Explorer view

If an OOT module is detected in the workspace, the GNURadio Module tree view will appear in the Explorer container in the sidebar. All blocks within that module are presented with the corresponding files:

  • YAML GRC block definition;
  • Python implementation source or Python blocks;
  • C++ header and implementation source for C++ blocks;
  • Python and C++ QA (unit testing) source files.

Click the "+" button in the Module Explorer header to create a new block. The "Refresh" button is used to refresh the view after external changes.

Context menus (Right mouse click) for blocks contain the module manipulation commands:

  • Rename block;
  • Remove block;
  • Convert XML to YAML (if XML definition is present);
  • Create Python bindings (if the block's source code is C++).

Step 4: Edit the module's source code

Related tutorials: Creating Your First Block, Creating Python OOT with gr-modtool, Creating C++ OOT with gr-modtool.

To enable syntax highlighting, autocompletion, documentation and other code editing features, you need to install the language server extension for the corresponding language:

  • For Python, install "Python" extension.
  • For C++, install "C/C++" or "clangd" extension.

Step 5: Build and test the module

You can build and install the module using CMake either from a terminal or with "CMake Tools" extension. Build flags can be set in the command line or in build/CMakeCache.txt.

You can perform unit testing for your blocks with QA functions (python/module/qa_block.py, lib/qa_block.cc). Testing panel provides an overview of all test fixtures in the module.

After installing the module you can use your blocks in flowgraphs. It is considered a good practice to add examples for your module to demonstrate the usage of your blocks. Example flowgraphs can also be used for #Source level debugging.

Step 6 (Optional): Use additional features

Some features of "GNURadio Integration" require presence of other extensions.

  • "Python" extension is required to discover GNURadio installation in a Python virtual environment using "Select Interpreter" command.
  • "YAML" extension is required to use syntax highlighting and validation in GRC flowgraph files and YAML GRC block definition files.
    • "YAML Embedded Languages" extension can provide additional highlighting for embedded code blocks (e.g. "make" templates).

Source level debugging

The procedure described below allows source level debugging within VSCode through the use of the module's QA functions or flowgraphs. A debugger extension is required (see #Extensions for VSCode users and #Extensions for VSCodium users).

To debug your blocks using flowgraphs:

  1. Configure, build and install it using CMake;
    • Be sure to set build type to "Debug" at the configure step as a cache variable (build/CMakeCache.txt) or as a CMake command flag:
      cmake .. -DCMAKE_BUILD_TYPE=Debug
  2. Create and compile a flowgraph that uses your module;
  3. Run the compiled flowgraph with a debugger.

Launching from VSCode

The simplest way to achieve source level debugging is to launch the top level flowgraph from VSCode. To do that:

  1. Set breakpoints in code that you want to hit.
  2. In the Debug panel (Ctrl-Shift-D), create a launch configuration;
    • Create a configuration with "request": "launch";
    • Set "type" according to the target block type:
      • "debugpy" for Python blocks;
      • "cppdbg" for C++ blocks with "C/C++" extension;
      • "lldb" for C++ blocks with "CodeLLDB" extension;
      • "gdb", "lldb-mi" or "mago-mi" for C++ blocks with "Native Debug" extension;
    • Set "program" as your Python interpreter, e.g. "/usr/bin/python3";
    • Set "args" as your compiled flowgraph: ["-u", "/path/to/flowgraph.py"];
    • Alternatively, if your flowgraph compiles to C++, set "program" as your compiled and built flowgraph: "/path/to/flowgraph/build/flowgraph".
    Complete launch.json example:
    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "(gdb) Launch",
                "type": "cppdbg",
                "request": "launch",
                "program": "/usr/bin/python3",
                "args": ["-u", "/path/to/flowgraph.py"],
                "stopAtEntry": false,
                "cwd": "${workspaceFolder}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            },
        ]
    }
    
  3. Start a debugging session with "Debug: Start Debugging" command (F5).
  4. The debugger will then land on your breakpoints.

Attaching to Process

Another alternative is to attach to an already running process. This is useful for more complicated long-running systems and flowgraphs. To do that:

  1. Set breakpoints in code that you want to hit.
  2. In the Debug panel (Ctrl-Shift-D), create a launch configuration;
    • Create a configuration with "request": "attach";
    • Set "type" according to the target block type:
      • "debugpy" for Python blocks;
      • "cppdbg" for C++ blocks with "C/C++" extension;
      • "lldb" for C++ blocks with "CodeLLDB" extension;
      • "gdb", "lldb-mi" or "mago-mi" for C++ blocks with "Native Debug" extension;
    • Set "program" as your Python interpreter, e.g. "/usr/bin/python3";
    • Set "processId" as "${command:pickProcess}" to pick from a list of running Python processes;
    Complete launch.json example:
    {
        "version": "0.2.0",
        "configurations": [
            { 
                "name": "(gdb) Attach",
                "type": "cppdbg",
                "request": "attach",
                "program": "/usr/bin/python3",
                "processId": "${command:pickProcess}",
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            },
        ]
    }
    
  3. Launch your flowgraph from a terminal;
    • If necessary, delay the startup in code (e.g. by adding sleep or raw_input and give the debugger time to attach:
     if __name__ == "__main__":
         if GDB_ATTACH:
             print(f"Blocked waiting or GDB attach (pid = {os.getpid()}). "
                   "Press ENTER after GDB is attached.", flush=True)
             raw_input()
         main()
    
  4. Start a debugging session with "Debug: Start Debugging" command (F5).
  5. You will be prompted to select the process to attach to; type "python" to filter Python instances and select the one running your flowgraph.
  6. The debugger will then attach and land on your breakpoints.