Usually, when we develop Linux programs, there are two options:

  1. Write programs directly on Linux and run tests and debugs
  2. Remote development with tools on Windows or Mac OS X

there are many people who are engaged in development work in the Windows environment. If you leave your familiar system to an unfamiliar environment, it may affect your productivity.

So today we will look at how to use Visual Studio 2019 for remote development of Linux on Windows and how to avoid common pitfalls.

Introduction to Visual Studio’s cross-platform development capabilities

Starting from visual studio 2017, Microsoft introduced the cross-platform development function of vs. You can edit the code in vs., then perform cross-platform compilation and remote debugging, and automate the work that we need to manually complete, greatly reducing our burden. . The platforms supported include Android and Linux, which are the protagonists we will focus on today.

Maybe you will be curious, how is vs. remote development, although you can develop without knowing this knowledge, but I still hope to make a short explanation in two minutes.

Vs for remote development is divided into two steps:

  1. Create a connection to the remote environment, and then let vs synchronize the system header files in the remote environment to the local (you can also specify the header files in other places, as explained later). The C++ code completion only needs the header file.
  2. When the code is written, select the appropriate remote environment, vs. copy the target file and code to the specified location in the remote environment, and then compile according to your configuration.
  3. Then vs will run your program in the console’s gdb or gdbserver, during which you can fully enjoy the efficiency and convenience brought by vs debugger.

After the above steps, you can debug your own cross-platform program in vs.

Remote development of Linux using vs2019

This is the end of the introduction, let’s take a look at the graphic tutorial for Linux development in vs2019. Before we get started, we must first do some preparatory work:

  1. Install vs2019 and check the c++ for Linux function.
  2. Prepare an available Linux remote environment, such as a Linux virtual machine configured with static IP, and have installed the GCC toolchain and openssh.

When we are ready, we should get to the point.

Create project

After installing the c++ for Linux function, we will see the Linux options in the panel for creating a new project,

Here we have chosen a blank console program built using the traditional vs project solution. You can also see how to create a cmake project in the following articles, not to mention here.

There is nothing to say below, choose the storage location of the project, pay attention to the local location, the location of the remote machine will be configured later:

Click Create and our remote development project was created successfully.

Configuring remote projects

Vs can’t edit the configuration of an empty project, so let’s create one in the project main.cpp, then click on the top menu: Project -> Properties, you can see the project’s configuration interface:

The remote computer was added in the Remote Connection Manager in the debug. There is usually no need to change this unless you need to change the type of project or where the compiled results are stored. If you have multiple remote environments, you can also choose here.

The debugging part provides, gdband the gdbserverformer is to let vs start a console on Linux, then run gdb in it and return the output. If your terminal on Linux is configured with color output, then regret that vs does not know them, it will be displayed as The original string; gdbserver will be enabled remotely when using gdbserver, the local vs parsing the returned data will not be murmur. Here we have chosen gdbserver, if you find that you can not break points, then refer to Microsoft’s suggestion, in exchange for the gdb program:

Then there is the focus of the configuration. The first is to configure the header files of the remote environment that need to be synchronized. With these files, you can automatically complete and prompt your code:

The default copy path usually already contains most of the header files on Linux, and we usually don’t need to change them. Synchronization of header files occurs manually after the first build project is successful or after adding a remote connection.

Next is the choice of the c/c++ compiler, which is the configuration of the gcc and g++ compiler parameters. Explaining these parameters is beyond the scope of our discussion. We only need to select the appropriate C++ standard version here:

Here we have chosen c++17. Other settings are the same as when developing on Windows, vs can be automatically converted to g++ parameters, so I won’t go into details here.

Add a remote environment

With a remote environment we can synchronize header files or debug runs.

When you compile or debug your project for the first time, vs will automatically let you connect to the remote environment. Of course, we recommend setting it in Debug -> Options -> Cross-Platform -> Connection Manager:

Fill in your remote ip/domain name, the port ssh defaults to 22. For security reasons, you need to change to other ports. Here is a convenient demonstration using the default configuration. The password is the same as above. You should consider using a more secure ssh private key to log in.

After the login is successful, the connection is added. We see that there is a remote header manager setting under the manager. This is used to synchronize the header files:

Clicking the Update button will start synchronizing the header files, which will be cached locally, because it takes a long time to copy a large number of files from the remote at once.

This way the remote environment is added and you can start writing code.

Local authoring and remote debugging

At this point you can already write the code for the Linux platform in vs., auto-completion works fine:

Develop_app_for_Linux_vs2019_10.jpg

 

You can see that the header files and structures in Linux are already recognized. If you find that you can’t auto-complete (usually after you just added a remote connection or the project settings have changed), try turning off vs re-opening. If it’s not useful, try refreshing intellisense or resynchronizing the header files.

After editing, we can click on the debug button to run our program:

Note that the architecture must be consistent with the remote environment. For example, the remote environment is x64. You can choose x64 or x86 here, but you can’t choose arm, otherwise you will get an error.

This is the test code that will output the current version of the Linux kernel:

#include <sys/utsname.h>
#include <iostream>
#include <cstdio>

int main()
{
    auto start = chrono::high_resolution_clock::now();
    utsname names;
    if (uname(&names) != 0) {
        std::perror("cannot get unames");
    }

    std::cout << "Linux kernel version: " << names.release << std::endl;
}

Click Debug -> Linux Console to display a console that you can interact with, you can type in the content or see the output of the program:
The program ran successfully.

Avoid stepping on the pit

After the remote compilation is successfully completed, we can then use the vs debugger to set breakpoints, view variables at breakpoints, and even perform dynamic performance analysis on running Linux.

But before that, there are still some pits that need to be stepped out in advance.

Chinese garbled

The troubles caused by coding problems will always be put in the first place. After all, when people see that the expected output is actually a bunch of garbled characters, they will always be nervous.

As we all know, the coding problem has always been a big problem, especially when the Chinese environment on Windows is usually GB18030 or GBK, and Linux is unified as utf8.

Let’s look at a practical example. Usually, if our program only contains ASCII characters, it is not easy to cause problems, so we add a little Chinese characters:

#include <sys/utsname.h>
#include <iostream>
#include <cstdio>
#include <string>

int main()
{
    utsname names;
    if (uname(&names) != 0) {
        std::perror("cannot get unames");
    }

    std::cout << "Linux kernel version: " << names.release << std::endl;
    std::cout << "输入内容:";
    std::string input;
    std::cin >> input;
    std::cout << "你输入了:" << input << std::endl;
}

For the above test program, we added a little Chinese output information, now open the console for debugging:


Develop_app_for_Linux_vs2019_13.jpg

 

You can see that the Chinese output has become garbled. We enter some information and it is the result of the operation:


Develop_app_for_Linux_vs2019_14.jpg

 

It can be seen that the Chinese written in the program has been garbled, and our input is not. The reason is very simple, the input is really in the linux console environment, the encoding defaults to utf8, so our input is correctly encoded, and the content in the source file is GB18030, so in the Linux console (by default utf8 decodes the data and Garbled characters appear in the display).

The reason for the error is that it is very simple to solve. It is OK to change the encoding of the source file to utf8. We choose the easiest way advance save to modify the encoding. (This menu option is hidden by default. There are many on-line instructions on how to display it. Methodological data):

After setting up the file, the file encoding has been changed to utf8.

Now run the modified program:

The result of the operation is also normal:


Develop_app_for_Linux_vs2019_17.jpg

 

Use math functions and third-party libraries

Using the math functions provided by the standard library on Linux is also a common problem. There are several cases depending on whether you use cpp or c:

  1. When using cpp, libstdc++ relies on libm, so when you compile your program with g++, it automatically links the math library;
  2. When using c, if it is sqrt(4)such a form, the newer gcc provides a replacement measure, and does not need to display the link libm;
  3. Next, if your argument is a variable, the compiler may choose to link libm.

Usually we don’t have to worry about this on Windows, but it’s hard to ignore this problem when using C on Linux.

So for the sake of insurance, if you are writing a c program that uses a math function, it is always correct to specify the connection libm. (Specific reference can be found here)

Also, when you use a third-party library such as boost, you need to pay attention. On Windows we usually specify the additional include directory and additional library directory to compile normally, but the name of the link library must be explicitly specified on Linux, so we set it in the project properties.

On Linux, we can use pkg-config to alleviate the duplication of work mentioned above. In vs. we can’t directly use this tool. When your project uses a lot of third-party libraries, it will be no small trouble if you want To solve this problem, you can refer to the vs+cmake build project that I will introduce in the following article.

Below we add a little boost chrono functional test to the example, you need to specify on Linux -lboost_chrono, this is the setting:

Here is the complete code:

#include <sys/utsname.h>
#include <iostream>
#include <cstdio>
#include <string>
#include <boost/chrono.hpp>

int main()
{
    namespace chrono = boost::chrono;
    auto start = chrono::high_resolution_clock::now();
    utsname names;
    if (uname(&names) != 0) {
        std::perror("cannot get unames");
    }

    std::cout << "Linux kernel version: " << names.release << std::endl;
    std::cout << "输入内容:";
    std::string input;
    std::cin >> input;
    std::cout << "你输入了:" << input << std::endl;
    auto counter = chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start);
    std::cout << "程序运行了:" << counter.count() << "ms\n";
}

Click the Run button, the program will be able to debug normally, otherwise it will report an error:


Develop_app_for_Linux_vs2019_19.jpg