在wsl上写mp的辛酸血泪史
November 7, 2019About 8 min
在wsl上写mp的辛酸血泪史
大一学习ECE120时用vscode写C程 (课程的mp, machine problem) 的工作流,做了简单的记录。主要包括自动编译调试脚本,valgrind调试输出。以及在不同虚拟机平台调试C程的方法。因为是仅针对课程内容的环境调试,内容比较个性化,适合初学者使用,也能更加熟悉vscode的运行逻辑。但是针对较大的项目建议使用cmake和clion等成熟框架IDE。
引子:我为啥又折腾了
学校给的垃圾虚拟机真的太蛋疼了,没有root权限,不能装软件,还是32位的,ssh全程调试都不行。老老实实的做得要全用gdb来debug,都9102年了,纯命令行debug,您是人🐎?作为一个被vscode宠坏的人,没有ui界面是不行的。所以。。。又折腾了。。。
这个流程看起来有点复杂,其实花点时间搞清vscode的逻辑后就很清晰了。只是把原来要一遍一遍输入的命令组合调用。而且一旦熟练了可以省下更多的时间。
Warning
大工程还是老老实实用ide,不然会死🐴
目录
@[toc]
0. 总览

在vscode上写c/cpp的细致教程参考这一篇:VSCode 如何编写运行 C、C++ 程序? - 知乎
1. 总结出来的流程
- 配置 ‘Makefile’ 复制一遍, 把 “main” 变成自己的mymain
- 配置自己的mymain.c, 一般来说直接复制main, 把里面不能编译的 i386 代码删除, 把不测试的部分先注释掉, 写好一部分测试一部分
- 配置tasks.json,用到valgrind的, 把(mpX) valgrind leak check配置了
- 配置launch.json, 每个mp新建一个launch, 复制前一个, 改掉program和args
- 开始写代码 - 保证内存管理 - 先把load和free写了, 直接测试tasks里的(mpX) valgrind
- 会生成一个.valgrind文件, 打开这个文件, 有高亮支持(需要vscode插件支持)
- 看这个文件, 也可以用F5, 保证内存控制正确
 
- 先把
- 测试功能 - 正常写就行了
- 不用单步调试的话, 直接用valgrind, 可以看输出
- F5进单步调试慢慢看
 
- 代码注意点: - 记得写注释
- 低耦合, 分离模块
 
 
- 保证内存管理 
- 功能完善之后, 可以写测试文件 - 有gold的可以用test.sh
- test.sh放进- Makefile
 
- 有gold的可以用
- 功能全部完成后, valgrind最后再检查一次内存
- svn上传, 虚拟机里最终检查
- 最后检查注释, 上传
2. vscode的配置文件
tasks文件
task文件简单来说就是你要在命令行执行的命令。除了传统的gcc编译命令之外,也可以调用make命令。这里的作用是在进入调试(launch)之前,先把保存好的文件编译一遍,保证测试的是当前修改完的代码。调用方式是 ctrl+ B
下面注释解释了三个功能块:基本功能(gcc为例),组合功能(clean and make为例),valgrind功能(valgrind在vscode中没有很好的集成,不像clion方便,但是通过这里的task和插件 vscode-valgrind 做到valgrind显示结果且高亮)
    {
        "version": "2.0.0",
        "tasks": [
    //////////////////////////////////////
    				//示例: 把gcc filename.c -o filename -g -Wall 变成tasks格式
            {"label": "g++ build active file",//名字:在后面的launch中用到,意思是执行launch命令之前,先跑一遍这个task命令
                "type": "shell",
                "command": "/usr/bin/g++",    //要用的程序,gcc,make和其他的都可以,只要terminal能能用他就能用
                "args": [                     //传入的参数
                    "${file}",
                    "-o",
                    "${fileDirname}/${fileBasenameNoExtension}",
                    "-g",
                    "-Wall"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                },
                "problemMatcher": [
                    "$gcc"
                ],
                "group": "build"               //最好选"build"这样在都在一起方便看
            },
    //////////////////////////////////////
            {"label": "gcc build active file",
                "type": "shell",
                "command": "/usr/bin/gcc",
                "args": [
                    "${file}",
                    "-o",
                    "${fileDirname}/${fileBasenameNoExtension}",
                    "-g",
                    "-Wall"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                },
                "problemMatcher": [
                    "$gcc"
                ],
                "group": "build"
            },
            {"label": "make",
                "type": "shell",
                "command": "/usr/bin/make",
                "options": {
                    "cwd": "${fileDirname}"
                },
                "group": "build",
                "problemMatcher": [
                    "$gcc"
                ]
            },
            {"label": "make_clean",
                "type": "shell",
                "command": "/usr/bin/make",
                "args": [
                    "clean"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                },
                "group": "build"
            },
    //////////////////////////////////////
            {"label": "clean and make",   //意思是把上面两个tasks连在一起,按照顺序用(也可以并行“parallel”)
                "dependsOn":["make_clean","make"],
                "dependsOrder": "sequence",
                "problemMatcher":[]
            },
    //////////////////////////////////////
            {"label": "valgrind start gdbserver",//这个是错误示例,不要用!vscode的gdb调试似乎不支持gdb的server
                "type": "shell",
                "command": "/usr/bin/valgrind",
                "args": [
                    "--tool=memcheck",
                    "--vgdb=yes",
                    "--vgdb-error=0",
                    "--leak-check=full",
                    "${fileDirname}/${fileBasenameNoExtension}"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                }
            },
    //////////////////////////////////////
            {"label": "(mpX) valgrind leak check", // 针对mp的valgrind命令
                "type": "shell",
                "command": "/usr/bin/valgrind",
                "args": [
                    "--tool=memcheck",
                    "--leak-check=full",
                    "--track-origins=yes",
                    "${fileDirname}/mp11",//TODO: change the number here 
                    "graph",              //TODO:这里相当于测试时给mp11传入的参数,要修改为对应mp的   
                    "requests",
                    ">",                  //后面三行让valgrind的输出写入名为mp11.valgrind的文件,在另一个窗口打开这个文件就能看到高亮的输出了,见前文图右上角
                    "${fileDirname}/mp11.valgrind",//TODO: change the number here 
                    "2>&1",
                ],
                "options": {
                    "cwd": "${fileDirname}"
                },
                "problemMatcher":[],
                "group": "build",
            },
            {"label": "valgrind leak check", //对任意文件的valgrind命令
                "type": "shell",
                "command": "/usr/bin/valgrind",
                "args": [
                    "--tool=memcheck",
                    "--leak-check=full",
                    "${fileDirname}/${fileBasenameNoExtension}",
                    "2>&1",
                    "&"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                },
                "group": "build",
            },
            {"label": "valgrind",//gcc和valgrind组合
                "dependsOrder": "sequence",
                "dependsOn": [
                    "gcc build active file",
                    "valgrind leak check"
                ],
                "group": "build"
            },
            {"label": "(mpX) make and valgrind",//make和valgrind组合
                "dependsOrder": "sequence",
                "dependsOn": [
                    "make",
                    "(mpX) valgrind leak check"
                ],
                "group": "build",
                "problemMatcher":[]
            },
    //////////////////////////////////////
            {"label": "lc3as assemble", //lc3的一些命令,用不到的可以删了
                "type": "shell",
                "command": "/home/gavin/bin/lc3as",
                "args": [
                    "${file}"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                },
                "presentation": {
                    "echo": true,
                    "reveal": "always",
                    "focus": false,
                    "panel": "shared",
                    "showReuseMessage": true,
                    "clear": false
                },
                "group": "build",
                "problemMatcher": []
            },
            {"label": "lc3sim-tk simulate",
                "type": "shell",
                "command": "DISPLAY=:0",
                "args": [
                    "/home/gavin/bin/lc3sim-tk",
                    "${fileBasenameNoExtension}.obj"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                },
                "presentation": {
                    "echo": false,
                    "reveal": "never"
                }
            },
            {"label": "lc3sim simulate",
                "type": "shell",
                "command": "/home/gavin/bin/lc3sim",
                "args": [
                    "${fileBasenameNoExtension}.obj"
                ],
                "options": {
                    "cwd": "${fileDirname}"
                }
            },
            {"label": "lc3 tk debug",
                "type": "shell",
                "dependsOrder": "sequence",
                "dependsOn": [
                    "lc3as assemble",
                    "lc3sim-tk simulate"
                ],
                "problemMatcher": [],
                "group": "build"
            },
            {"label": "lc3 CLI debug",
                "type": "shell",
                "dependsOrder": "sequence",
                "dependsOn": [
                    "lc3as assemble",
                    "lc3sim simulate"
                ],
                "problemMatcher": []
            }
        ]
    }launch文件
launch简单来说就是gdb时给的命令。基本就是一个mp建一个新的,mp小工程没必要用cmake,但好处在于按F5能进入gui调试界面,友好许多。
    //launch 文件示例,每个mp都不一样,具体按照要求来
    //看mp11大概指导怎么写就行了,别的mp的基本都是重复
    {
        // 使用 IntelliSense 了解相关属性。 
        // 悬停以查看现有属性的描述。
        // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [
            {
    //////////////////////////////////////
    						//示例:原本输入命令为./mp11 graph request如何变成launch的形式
                "name": "mp11",                   //debug栏中显示的名称
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/mp11", //TODO:要运行的文件
                "args": [                         //文件名后传入的参数,根据mp要求文档来
                    "graph", 
                    "requests",
                    //"mygraph", 
                    //"myrequests",
                ],
                "stopAtEntry": false,             //开始调试时在文件起点暂停与否
                "cwd": "${fileDirname}",          //调试时的目录,查找data文件确定相对路径
                "environment": [],                //一般不用填
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "clean and make", //这个很重要,要在tasks.json中编辑
                "miDebuggerPath": "/usr/bin/gdb"
            },
    //////////////////////////////////////
            {
                "name": "mp10",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/mp10", //TODO:change this within test/mpX
                "args": [
                    // "tests/maze3.txt" //TODO:change this within test/
                ],
                "stopAtEntry": false,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "clean and make",
                "miDebuggerPath": "/usr/bin/gdb"
            },
            {
                "name": "mp9",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/mp9", //TODO:change this within test/mpX
                "args": [
                    "tests/maze3.txt" //TODO:change this within test/
                ],
                "stopAtEntry": false,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "clean and make",
                "miDebuggerPath": "/usr/bin/gdb"
            },
            {
                "name": "mp8",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/mp8", //TODO:change this within test/mpX
                "args": [
                    "sudoku1.txt"
                ],
                "stopAtEntry": false,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "clean and make",
                "miDebuggerPath": "/usr/bin/gdb"
            },
            {
                "name": "mp7",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/mp7", //TODO:change this within test/mpX
                "args": [
                    "/home/gavin/2019_FALL/ece220fa19/mp7/Images/tajmahal.png",
                    "/home/gavin/2019_FALL/ece220fa19/mp7/Images/my_tajmahal.png",
                    "0",
                ],
                "stopAtEntry": false,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "clean and make",
                "miDebuggerPath": "/usr/bin/gdb"
            },
            {
                "name": "mp6",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/gameoflife",
                "args": [
                    "<",
                    "life4.dat"
                ],
                "stopAtEntry": true,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "make_ignore_warning",
                "miDebuggerPath": "/usr/bin/gdb"
            },
            {"name": "g++ build and debug active file",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/${fileBasenameNoExtension}",
                // "args": ["${fileDirname}/testfour.txt"],
                "stopAtEntry": false,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "g++ build active file",
                "miDebuggerPath": "/usr/bin/gdb"
            },
            {"name": "gcc build and debug active file",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}/${fileBasenameNoExtension}",
                "stopAtEntry": false,
                "cwd": "${fileDirname}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "gcc build active file",
                "miDebuggerPath": "/usr/bin/gdb"
            },
            {"name": "cppdbg launch", //官方示例
                "type": "cppdbg",
                "request": "launch",
                "program": "enter program name, for example ${workspaceFolder}/a.out",
                "args": [],
                "stopAtEntry": false,
                "cwd": "${workspaceFolder}",
                "environment": [],
                "externalConsole": false,
                "pipeTransport": {
                    "debuggerPath": "/usr/bin/gdb",
                    "pipeProgram": "/usr/bin/ssh",
                    "pipeArgs": [],
                    "pipeCwd": ""
                },
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            }, 
        ]
    }3. 细数踩过的坑
archlinux(官方ECE220虚拟机)
- 用ssh连接vscode- 没有openssh-server
 
- 尝试获得root权限- 不可能的,要用来考试的机子不会放权限的
 
- 安装vscode- root没有不能用pacman
- 直接build没有找到,可能可以,但是既然他要用来考试,一般是找不到了
 
ubuntu
- ✔快乐32位虚拟机 - 还是向oracle VM屈服了,装了32位的16.04
- 但是笔记本性能真的不太好,内存显存cpu给足了感觉还是卡
- 好就好在32位的程序能跑
- 为啥用vm就能装32位的呢???
 
- 尝试ssh连接vscode- 不支持32位的ssh server
- 研究了一下下虚拟机的网络连接模式,小有收获
 
- ✔安装vscode - 直接用apt装成功了
- 也可以直接编译32位的文件,但是如果有错误【指针指向\0或者别的】会直接爆掉,虚拟机直接异常关闭。de一次bug就要重启
- 界面不太流畅,经常有闪烁的黑框,而且32位的vscode在1.35之后就不更新了
 - 目前找到的最好的解决方案,如果不出奇怪错误的话 
wsl
- ✔64位编译32程序 - 缺少multilib库
- makefile编译指令 -m32 -m64
- 最后还是要去32位的机器上跑test,就是写起来比较流畅
 
- docker玩交叉开火 - 还没玩,说不定是新世界