Let's do Linux System Programming with Visual Studio Code and Azure! (From helloworld to nginx development and remote debugging)

This time, Remote Development of Visual Studio Code I want to try Linux System Programming (C language) in Ubuntu of Azure Virtual Machine using the extensionpack) function. I think.

I prepared helloworld to try it out for the time being. Also, as a form close to actual development, I will try remote debugging using nginx as a subject.

--helloworld development and remote debugging --Development and remote debugging of nginx

1. Prepare Ubuntu Virtual Machine on Microsoft Azure

Create an Ubuntu Virtual Machine. The points are as follows.

--This time, Ubuntu Server 18.04 LTS -Gen1 is used as the Linux Virtual Machine. --Authentication Type uses SSH Public Key --Inbound ports are set to 22 (SSH) and 8080 (used in the latter half of nginx)

As you all know about creating a Virtual Machine, you can skip it, but please create it according to the above.

1.1. Create an Ubuntu Virtual Machine

From the Microsoft Azure portal screen, select Create a resource to create a Virtual Machine. Select Ubuntu Server 18.04 LTS -Gen1 as shown below. After making your selection, press Review + Create.

image.png

When you press Create on the confirmation screen, the Download Private Key and Create Virtual Machine buttons will be displayed. Press them again. Please save the Private Key so that you do not lose it, as you will need it when using it with SSH on the created Ubuntu.

image.png

After the Virtual Machine is created, check the IP address of the connection destination from the Virtual Machine screen.

2. Prepare Visual Studio Code

After installing Visual Studio Code on Windows 10, set up remote development. (MacOS is also the same, but this time, it is amazing that the actual Linux System Programming can be done on that Windows, so I will proceed with Windows 10)

2.1. Install Visual Studio Code

First of all, please download Visual Studio Code from the following site. https://code.visualstudio.com/

image.png

Run the downloaded installer to install it. You will be asked to select a task to add during installation, but this time I set it as follows. A Visual Studio Code shortcut will be created on your desktop, which you should use when running it in this article.

image.png

2.2. Install the extensions required for remote development in Visual Studio Code

After starting Visual Studio Code, install the extensions from the Extensions icon on the left (① in the figure below). Enter the following extension name in the search box (② in the figure below) to search. When the extension is displayed, press Install (③ in the figure below) to complete the installation.

Extension name: Remote Development ms-vscode-remote.vscode-remote-extensionpack https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack

image.png

When Remote Development is installed, you will see a green button at the bottom left, click on it.

image.png

2.3. Connect to Azure Virtual Machine with SSH

From the green button at the bottom left, select "Remote-SSH: Open Configuration File ..." to register the ssh connection destination. Set the HostName to the public IP address of the Virtual Machine and the IdentityFile to the Private Key downloaded when the Virtual Machine was created.

.ssh/config


Host linuxsystemprograming-vm
  HostName xxx.xxx.xxx.xxx
  IdentityFile C:\Users\kentaro\Downloads\linuxsystemprograming-vm_key.pem
  User azureuser

Next, select "Remote-SSH: Connect to Host ..." from the green button at the bottom left, select the connection destination you registered earlier, and select Linux as the platform to connect. Now that you are logged in to the Azure Virtual Machine, install the packages required for development on the Ubuntu side. Select New Terminal from the Terminal menu to display the Ubuntu Terminal for the Azure Virtual Machine.

image.png

3. Prepare the Ubuntu development environment for Azure Virtual Machine

In Terminal, type the following command to install gcc and gdb on Ubuntu for your Azure Virtual Machine.

sudo apt update
sudo apt install -y build-essential gdb

4. Let's make Hello World

From Terminal, create a directory on Ubuntu for Azure Virtual Machine and create a Hello World C language file.

cd /home/azureuser/
mkdir helloworld
cd helloworld
touch helloworld.c

From the Explore icon in the upper right, open the directory / home / azureuser / helloworld you just created.

image.png

When you select helloworld.c displayed in Explore, a message to install the C / C ++ extension is displayed in the lower right, so select install. (If you don't see it, install the C / C ++ extensions from the Extensions on the left)

image.png

Reloading is required, so please reload from the reload button on the center of the screen.

image.png

4.1. Write helloworld.c in IntelliSense

The source code of helloworld.c is as follows.

helloworld.c


#include <stdio.h>

int main(int argc, char *argv[])
{
    int i;
    for (i = 3; i > 0; i--)
    {
        printf("%d...\n", i);
    }
    printf("Hello World!\n");
    return 0;
}

Make sure IntelliSense is enabled in Visual Studio Code.

image.png

After entering, save it with Ctl -s.

4.2. Set how to build helloworld.c

Select Configure Default Build Task ... from the Terminal menu, then select C / C ++: gcc build active file.

image.png

Since it will be editing taks.json, set as follows. (I haven't changed what was created automatically)

task.json


{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "shell",
			"label": "C/C++: gcc build active file",
			"command": "/usr/bin/gcc",
			"args": [
				"-g",
				"${file}",
				"-o",
				"${fileDirname}/${fileBasenameNoExtension}"
			],
			"options": {
				"cwd": "${workspaceFolder}"
			},
			"problemMatcher": [
				"$gcc"
			],
			"group": {
				"kind": "build",
				"isDefault": true
			}
		}
	]
}

Make sure you can build from "Run Build Task ..." in the Terminal menu. A helloworld executable file will be created so you can run it.

image.png

4.3. Set how to debug helloworld.c

Select "Add Configuration ..." from the Terminal menu, select "C ++ (GDB / LLDB)", and select "gcc --Build and debug active file" to set the debugging method.

image.png

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": "gcc - Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: gcc build active file",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}

4.4. Remotely debug helloworld.c

After completing the settings, with Helloworld.c selected, press F5 or select "Start Start Debugging" from the Run menu to debug helloworld. You can also set breakpoints by clicking on the left side where the number of lines is displayed, you can step through and check the value of the variable.

image.png

Next, let's debug and execute nginx running on Ubuntu of Azure Virtual Machine.

5. Build and debug nginx with Visual Studio Code

Hello World is not practical, so I would like to develop and debug with Visual Studio Code using nginx as a subject.

5.1. Download nginx and install required packages

Download the nginx source code and set up the nginx development environment. Also, install the packages required to build nginx.

sudo apt install -y libpcre3-dev libz-dev
cd ~/
wget https://nginx.org/download/nginx-1.19.2.tar.gz
tar xvfz nginx-1.19.2.tar.gz
cd nginx-1.19.2/

Let's try building nginx for debugging. Make sure you can build without errors.

cd ~/nginx-1.19.2/
./configure --with-cc-opt="-O0" --prefix=`pwd`/nginx
make

5.2. Check the nginx code with Visual Studio Code

Select "Open Folder ..." from the Visual Studio Code File menu to open the nginx directory (/home/azureuser/nginx-1.19.2). I think you can use IntelliSense.

Also, since this development will be carried out by azureuser, change the listen port of nginx to 8080 etc. Change the port setting around line 36 in conf / nginx.conf to 8080. (If you are doing make install, change nginx / conf / nginx.conf as well)

image.png

5.3. Set the build method of nginx

Select Configure Default Build Task ... from the Terminal menu, then select C / C ++: gcc build active file.

task.json


{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "shell",
			"label": "C/C++: gcc build active file",
			"command": "/usr/bin/make",
			"args": [			
				"install"
			],
			"options": {
				"cwd": "${workspaceFolder}"
			},
			"problemMatcher": [
				"$gcc"
			],
			"group": {
				"kind": "build",
				"isDefault": true
			}
		}
	]
}

Make sure you can build from "Run Build Task ..." in the Terminal menu. After the build, nginx will be installed in /home/azureuser/nginx-1.19.2/nginx.

5.4. Set how to debug nginx

After selecting /home/azureuser/nginx-1.19.2/src/core/nginx.c, select "Add Configuration ..." from the Terminal menu, select "C ++ (GDB / LLDB)", and then select "C ++ (GDB / LLDB)". Select gcc --Build and debug active file to set the debugging method. nginx sets the option not to run in the daemon. Also, stopAtEntry is set to true so that it can be stepped at runtime.

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": "gcc - Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/nginx/sbin/nginx",
            "args": ["-g", "daemon off;"],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: gcc build active file",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}

5.5. Check the operation of nginx

Before you debug, make sure that the Azure Virtual Machine's Inbound security rule allows port 8080. image.png

From Terminal, install and run nginx.

cd ~/nginx-1.19.2/
make install
./nginx/sbin/nginx -g "daemon off;"

In a web browser, access the Azure Virtual Machine public IP address port 8080 and verify that nginx is running. After checking, exit with Ctl -c.

image.png

5.6. Remote debug nginx

With /home/azureuser/nginx-1.19.2/src/core/nginx.c selected, press F5 or select "Start Debugging" from the Run menu to debug nginx.

image.png

You can debug!

As a test, set a breakpoint immediately after waiting for a request from a web browser. It is around line 802 of /home/azureuser/nginx-1.19.2/src/event/modules/ngx_epoll_module.c.

800:    events = epoll_wait(ep, event_list, (int) nevents, timer);
801:
802:    err = (events == -1) ? ngx_errno : 0;

image.png

Since this is the part that runs as a worker process (child process) after starting nginx, set it to attach to the child process with gdb before being forked. Enter the gdb command at the bottom of DEBUG CONSOLE while debugging Visual Studio Code.

-exec set follow-fork-mode child

image.png

Also, if you want to check the current status, it will be as follows.

-exec show follow-fork-mode

Once set to gdb, continue running with "Continue" (a triangle icon like play). When you access the Azure Virtual Machine public IP address port 8080 again, the web browser goes into a wait state. This is because it stops at the breakpoint set in Visual Studio Code (gdb).

image.png

If you check the value returned from epoll_wait in Visual Studio Code, 1 is included. You can also step. Great! (man epoll_wait : https://linuxjm.osdn.jp/html/LDP_man-pages/man2/epoll_wait.2.html)

image.png

Also, if you want to set follow-fork-mode to child from the start of debugging, set setupCommands as shown below.

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": "gcc - Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/nginx/sbin/nginx",
            "args": ["-g", "daemon off;"],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "Set follow-fork-mode to child",
                    "text": "set follow-fork-mode child",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: gcc build active file",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}

6. Finally

Linux System Programming has become more familiar with Visual Studio Code and Azure Virtual Machine. It's like a dream to be able to remotely debug Linux running in the cloud.

If you want to write a server, please try it.

By the way, there are many books on TCP / UDP server program development, but many of them lack error handling, so I would like to introduce some recommended books for those who are studying from now on.

--UNIX Network Programming <Vol.1> W.Richard Stevens (It's a UNIX textbook book, but it's only used ...) https://amzn.to/335xUel

If you know the basic code of UNIX and want to deal with a large number of clients on a server with Linux, the following books are recommended.

--Linux programming interface Michael Kerrisk https://amzn.to/3j6ITKp --Linux System Programming Robert Love https://amzn.to/2GilXsM

I've read a bit of the nginx code for this article, but it's pretty, so it's a great learning experience.

Well then.

Recommended Posts

Let's do Linux System Programming with Visual Studio Code and Azure! (From helloworld to nginx development and remote debugging)
Remote debugging with Visual Studio 2017
Remote debugging in Visual Studio (Linux)
Cross-compiling Raspberry Pi and building a remote debugging development environment with VS Code
Introduce VS Code and Remote Development to an offline environment to make linux development comfortable
Build Python development environment with Visual Studio Code
Execute C ++ functions from Python with Pybind11 (for Windows & Visual Studio Code people) Debugging
Problems and solutions for using the remote debugging environment for Linux apps in Visual Studio 2017
App development to tweet in Python from Visual Studio 2017
Python development environment with Windows + Anaconda3 + Visual Studio Code
Python development environment with Windows + Python + PipEnv + Visual Studio Code
How to use linux commands in Visual Studio Code terminal
Set up a Python development environment with Visual Studio Code
[Linux] Compress folders and transfer files from remote to local
Build an environment to execute C ++ functions from Python with Pybind11 (for Windows & Visual Studio Code people)