在《信创之国产浪潮电脑+统信UOS操作系统体验2:安装visual studio code和cmake搭建C++开发环镜》介绍了在国产浪潮电脑+统信UOS操作系统中安装visual studio code和cmake搭建C++开发环镜的过程及案例,但上述过程仅限于编译,无法执行调试,且编译需要在控制台输入cmake和make指令才能执行。
实际上vscode是支持通过配置可以实现类似Visual C++等IDE开发工具使用菜单和快捷键直接进行程序编译构建的,这样构建的任务可以结合后续的调试配置进行IDE环境的程序调试,不过在之前必须先配置编译构建任务配置文件tasks.json。关于任务配置文件tasks.json的详细介绍请参考老猿在CSDN的博文《信创之国产浪潮电脑+统信UOS操作系统体验8:Visual Studio Code中的任务文件tasks.json和任务配置要素介绍》。
为了将编译构建过程集成到vscode界面中,需要在vscode中配置相关编译构建的设置。
详细配置过程如下:
终端->配置默认生成任务
,如图所示:由于本次使用不执行cmake和make,因此不需要先生成CMakeLists.txt,在此直接选择C++相关的任务,可以看到有多个C和C++的编译器,选择任何一个都可以,如图:
实际上这些编译生成模式对应的只有两个编译模式,一个是aarch64-linux-gnu-gcc-8
、一个是aarch64-linux-gnu-g++-8
,其他的编译模式的指令都是对应这两个编译器的软连接,但编译器并不知道,因此还是列出来了所有的编译指令。
从下面截图可以看到,g++
是g++-8
的软连接,g++-8
是aarch64-linux-gnu-g++-8
的软连接:
类似的gcc
是gcc-8
的软连接,gcc-8
是aarch64-linux-gnu-gcc-8
的软连接,如图:
我们选择g++编译器,实际上gcc和g++都可以编译C和C++程序,不过g++将C程序和C++程序都作为C++文件编译,gcc则将C程序作为C程序编译,C++则作为C++编译。
在完成上步的配置后,就会在当前工程的.vscode
目录下生成tasks.json
编译构建任务配置文件。
通过上面步骤配置生成的编译构建配置文件task.json内容默认如下:
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++ 生成活动文件",
"command": "/usr/bin/g++",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "编译器: /usr/bin/g++"
}
]
}
本次案例生成的tasks.json
文件是用于编译构建目标代码的,其实只要tasks.json
的文件内容正确,不通过上述配置步骤也可以指定编译构建的配置,并且有时候必须通过手工调整配置内容才能达成目标,如一个项目涉及2个及以上CPP源文件时,上述配置文件就无法完成构建任务,按上述配置只会编译当前打开文件。
老猿这个测试案例用了两个cpp文件和一个头文件,分别是set.cpp、hello.cpp和set.h,其中hello.cpp引用了set.cpp中的testSet函数。相关代码如下:
#ifndef SET_H
#define SET_H
#include <memory.h>
#include <sstream>
#include <iostream>
#define MAXARRSIZE 200
class set
{
public:
set(){_num=0;}
set(const int *arr,int count) ;
bool insert(int x);//添加
bool insert(set *pSet);
bool insert(set vSet){return &vSet;};
bool del(int x);//删除
void output();
int index(int x);//查找
bool find(int x){ return index(x)!=-1; }
void clear(){_num = 0;};
int size(){return _num;};
int& getVal(int index);
int& operator[](int index) {return getVal(index);};
set unionSet(set t);//并集
set interSet(set t);//交集
set diffSet(set t);//差集
private:
int _arr[MAXARRSIZE];
int _num;
};
int testSet();
#endif
//set.cpp
#include "set.h"
using namespace std;
set::set(const int *arr,int count)
{
unsigned long arrSize;
memcpy(_arr,arr,count*sizeof(int));
_num = count;
}
int& set::getVal(int index)
{
if(index>=_num)
{
stringstream ss;
ss << "数组访问越界:数组元素总个数为"<<+_num<<"个访问索引值为:"<<index;
throw ss.str().c_str();
}
else return _arr[index];
}
bool set::insert(int x)
{
if(_num>=MAXARRSIZE)return false;
if(!find(x))
{
_arr[_num]=x;
_num++;
}
return true;
}
bool set::insert(set *pSet)
{
int loop;
int size = pSet->size();
for(loop=0;loop<size;loop++)
if(!insert((*pSet)[loop]))return false;
return true;
}
bool set::del(int x)
{
int i,pos;
pos=index(x);
if(pos!=-1)
{
memcpy(_arr+pos,_arr+pos+1,(_num-pos-1)*sizeof(_arr[0])) ;
_num--;
return true;
}
else return false;
}
void set::output()
{
int i;
cout<<"{";
for(i=0;i<_num;i++)
cout<<_arr[i]<<" ";
cout<<"}"<<endl;
}
int set::index(int x){ //查找
int i;
for(i=0;i<_num;i++)
if(_arr[i]==x)
return i;
return -1;
}
set set::unionSet(set t)//并集
{
set temp;
temp.insert(this);
temp.insert(&t);
return temp;
}
set set::interSet(set t) //交集
{
set temp;
int loop,size,val;
size = t.size();
for(loop=0;loop<size;loop++)
{
val = t[loop];
if(find(val))temp.insert(val);
}
return temp;
}
set set::diffSet(set t) //差集
{
set temp;
int loop,val;
for(loop=0;loop<_num;loop++)
{
val = _arr[loop];
if(!t.find(val))temp.insert(val);
}
return temp;
}
int testSet()
{
set s2;
const int sInt1[] = {7,10,11,112,13,14,20,22};
set s1 (sInt1,sizeof(sInt1)/sizeof(int));
cout<<"集合s1为:" ;
s1.output();
s2.insert(8);
s2.insert(9);
s2.insert(10);
s2.insert(11);
s2.insert(12);
s2.del(8);//删除
s2.del(12);//删除
cout<<"集合s2为:";
s2.output();
cout<<"交集为:"<<endl;
s1.interSet(s2).output();
cout<<"并集为:"<<endl;
s1.unionSet(s2).output();
cout<<"差集为:"<<endl;
s1.diffSet(s2).output();
return 0;
}
#include <iostream>
#include "set.h"
using namespace std;
int main()
{
int loop;
cout<<"hello,world!"<<endl;
testSet();
return 0;
}
由于该测试工程包含了2个CPP文件,因此用上面步骤配置生成的tasks.json无法直接使用,下面进行测试验证一下。
在包含两个或更多CPP文件(如老猿测试用的项目包含hello.cpp和set.cpp)的情况下,用以上配置通过终端->运行生成任务...
进行编译构建测试,发现相关情况如下:
无法解析变量 ${file}。请打开一个编辑器。
;fatal error: set.h: 没有那个文件或目录
;/usr/bin/ld: /usr/lib/gcc/aarch64-linux-gnu/8/../../../aarch64-linux-gnu/crt1.o: in function `_start':
(.text+0x18): undefined reference to `main'
/usr/bin/ld: (.text+0x1c): undefined reference to `main'
因此为了编译含多个CPP源文件的工程,必须修改该缺省的编译任务配置文件,因为在编译命令中使用了${file}这个变量,从上面的介绍中可以知道,这个变量表示:“当前打开文件的绝对路径”,也就是vscode中当前显示在编辑窗口文件的文件名,如果没有打开文件,这个变量就无法解释,就会出现无法解析变量的报错。关于vscode的预定义变量请参考老猿在CSDN的博文《vscode中tasks.json文件使用的预定义变量及国产统信操作系统UOS下配置一个任务显示相关预定义变量的案例》的介绍。
为了支持编译这种包含这种多个文件的C++项目,需要手工修改配置文件的编译指令参数,将涉及到的文件包含进来,具体修改为编译指令command的附加参数选项args,用如下的两条配置替换原来的"${file}"配置,修改后的tasks.json配置文件如下:
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++ 生成活动文件",
"command": "/usr/bin/g++",
"args": [
"-fdiagnostics-color=always",
"-g",
"hello.cpp",
"set.cpp",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "编译器: /usr/bin/g++"
}
]
}
修改的这两行也可以用 " f i l e D i r n a m e / h e l l o . c p p " 、 " {fileDirname}/hello.cpp"、 " fileDirname/hello.cpp"、"{fileDirname}/set.cpp"替换,没有本质区别。
这样配置后,就可以通过运行生成任务执行项目的编译了,不过需要注意,此时必须打开一个CPP文件或h文件,否则vscode无法找到需要编译的文件,如果打开的是tasks.json,也找不到文件,大家想想为什么?不清楚的可以回看老猿在CSDN的博文《vscode中tasks.json文件使用的预定义变量及国产统信操作系统UOS下配置一个任务显示相关预定义变量的案例》的介绍。下面是运行的结果截图:
本文介绍了通过vscode构建配置任务并手工调整配置文件后,生成用于编译多个文件的C++项目的生成任务过程及配置解释,有助于大家熟练使用vscode编译C++项目。实际上老猿认为,除了这种方法,也可以通过配置其他任务方式执行C++项目的编译,比如对于更复杂的需要makefile的工程,应该是用配置任务使用make指令来构建编译任务,具体等后面老猿验证后再介绍。
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
更多关于VSCODE介绍的内容请参考专栏《国产信创之光》的其他文章。
前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《https://blog.csdn.net/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。