vscode c/c++ 和 MSYS2 环境配置记录

vscode c/c++ 和 MSYS2 环境配置记录

网上的教程有一定错误和过时,这里收集了当前的最优配置。

MinGW/MSYS2 安装

MSYS2 是一个类似于Linux的shell环境,可以在Windows上使用pacman安装软件包。它包含了一个mingw-w64工具链,可以在Windows上编译出可执行文件。

MinGW-w64 - for 32 and 64 bit Windows
选择MinGW-W64 GCC-8.1.0 或以上版本,x86_64-posix-seh

基本上二选一即可,msys2 的环境更全面一些,空间占用也相应更多。

[科普][FAQ]MinGW vs MinGW-W64及其它

c/c++ vscode环境搭建

c/c++ vscode环境搭建参考这篇知乎文章: 给萌新的C/C++环境搭建攻略(VSCode和MSYS2)

msys2 配置

msys2安装完成后,开始菜单会有多个启动方式:

MSYS2 MSYS
MSYS2 MinGW 64bit
MSYS2 MINGW 32bit
MSYS2 UCRT64
MSYS2 Clang64
MSYS2 ClangARM64

msys2 默认使用的是 mintty 作为终端模拟器。win11 可以考虑使用 Windows Terminal 获得更优质的体验。

推荐使用 UCRT64 环境。要如何使用呢?简单来说就是使用 pacman 指定安装 ucrt 的软件。比如 mingw 工具链 mingw-w64-ucrt-x86_64-toolchain,包含了 19 个 packages,覆盖了常见的 gcc、git、gdb、make 和 binutils,这里的软件包会被安装到 \msys64\ucrt64\ 目录下。所以使用时要用UCRT64(黄色图标) 启动。

msys 环境通常安装了 shell、常见的 linux 工具,模拟了 linux 环境,而其他的环境继承使用 msys 环境的工具,并且可以安装对应环境的工具进行开发 windows 程序。

好奇有什么区别的可以看:msys2 中 mingw64 ucrt64 clang64 的区别MSVCRT vs UCRT

最新版官方已经配置好了镜像源,不用担心下载速度的问题。

msys 环境配置

msys 环境作为基础环境,提供了一个类 linux 的环境,并且提供了对应的包管理器 pacman,因此我们就可以很方便的安装一些 linux 上的一些生产力工具:zsh、fish、tmux 等。(目前可以使用 wsl 作为上位替代)

安装也十分简单:

pacman -S zsh fish tmux
resolving dependencies...
looking for conflicting packages...
......
:: Proceed with installation? [Y/n] y

在其他终端中会遇到 tmux 打开时显示 open terminal failed: not a terminal。需要编写对应的 wrapper function:

#!/bin/bash
tmux() {
  # execute tmux with script
  TMUX="command tmux ${@}"
  SHELL=/usr/bin/bash script -qO /dev/null -c "eval $TMUX"
}

将其添加到 bash / zsh 的配置文件中即可。

将 window 当前用户目录挂载到 msys2 根目录下

编辑 /etc/fstab

添加一行新行:

C:\Users\your_name /your_name

即可将 C:\Users\your_name 挂载到 /your_name 目录,方便在 msys2 中切换路径。

配置 msys2 默认 shell / 启动 msys2 相关设置

有些教程会这么教你:

配置 zsh 为 bash 默认终端 <---- 这句话漏洞百出,堪称一绝:

|___|  |____________|  
 |            |
zsh 是 shell  |
              |
          bash 也是 shell,zsh 不能是 bash 终端。这句话混淆了 shell 和终端的概念。Shell 是一个命令行解释器,它提供了一个用户和操作系统进行交互的界面。Bash 和 Zsh 都是 shell 的一种。而终端(Terminal)则是一个用于接收用户输入并显示 shell 输出的程序。所以,你不能将一个 shell 配置为另一个 shell 的“默认终端”,因为 shell 和终端是两个不同的概念。

混淆了默认 shell 的设置方式:你可以将 Zsh 配置为你的默认 shell,这意味着当你打开一个新的终端窗口时,会自动启动 Zsh。但是,你不能将 Zsh 配置为 Bash 的“默认终端”,因为 Bash 是一个 shell,而不是一个终端。你可以在 Bash 中启动 Zsh,但这并不会改变你的默认 shell。

编辑 ~/.bashrc,加入下面的几行。

# Launch Zsh
if [ -t 1 ]; then
exec zsh
fi

想法很美好,但是代价是什么呢

你每次想要使用 bash 交互都会被迫打开 zsh。

在 msys2 的目录中有多个启动器来启动 msys2 环境,所有的多个默认启动器都是由相应的 .ini 文件进行配置。 .ini 文件必须与 .exe 文件位于同一目录中,并且具有相同的文件名。以 msys2.ini 为例,此配置文件对应着 msys2.exe 启动器,并且指定了对应的MSYSTEM和相关环境变量配置:

#MSYS=winsymlinks:nativestrict
#MSYS=error_start:mingw64/bin/qtcreator.exe|-debug|<process-id>
#CHERE_INVOKING=1
MSYS2_PATH_TYPE=inherit
MSYSTEM=MSYS
SHELL=/usr/bin/fish

这里的 MSYS2_PATH_TYPE=inherit 将从 Windows 继承 PATH 环境变量。 SHELL=/usr/bin/fish 使得启动时启用 fish shell 而不是默认的 bash,这里只需要填写对应 shell 在 msys2 中的位置即可。以 zsh 为例, 使用 which zsh,我们就可以获得 zsh 在msys2 环境中的位置:

❯ which zsh
/usr/bin/zsh

附上 ucrt64.ini 进行对比:

#MSYS=winsymlinks:nativestrict
#MSYS=error_start:mingw64/bin/qtcreator.exe|-debug|<process-id>
#CHERE_INVOKING=1
#MSYS2_PATH_TYPE=inherit # strict|minimal|inherit
MSYSTEM=UCRT64
SHELL=/usr/bin/fish

通过指定 SHELL=/usr/bin/fish,我们就成功配置 fish 作为默认 shell。


使用 Windows Terminal 并配置对应环境的默认 shell

最新的 msys2 提供了 msys2_shell.cmd 简化了在其他终端添加配置所需要做的操作。

如果使用的是新的 Windows 终端,只需要在终端的新建配置中的命令行处填上对应命令行。

打开终端设置,添加新配置文件,选择添加空白配置文件,将命令行填上对应内容即可,启动目录设置为 ~ 或者 %USERPROFILE% 或者 %HOMEDRIVE%%HOMEPATH% 都是Windows 当前用户主目录。

以一个命令行为例:

D:/Scoop/apps/msys2/current/msys2_shell.cmd -defterm -here -no-start -use-full-path -ucrt64 -shell zsh
  • -ucrt64 将启动 UCRT64 环境

  • -shell zsh 将登录 shell 设置为 zsh

  • -use-full-path-full-path 使 msys2 可以使用当前 shell 中的 path(在 wt 中相当于cmd 拉起的 msys2,即添加了 Windows PATH)。默认 MSYS2_PATH_TYPEminimal

  • -no-start 不使用 start 命令,并且返回登录 shell 的 errorcode 作为批处理的 errorcode

  • -defterm 设置终端类型,没有设置会使用 mintty

  • -here 使用当前目录作为工作目录,防止登录脚本将工作目录更改为用户的主目录。不同的 shell 表现不同,目前 fish 没有这个参数也是这个行为(zsh 未测试)。

本质上这些参数也是在设置 CHERE_INVOKING MSYSTEM SHELL MSYS2_PATH_TYPE 等环境变量:

C:\Windows\System32\cmd.exe /C "set MSYSTEM=MINGW64&& start /B D:\Scoop\apps\msys2\current\usr\bin\bash.exe -l"
# 或者不使用 cmd
D:/Scoop/apps/msys2/current/usr/bin/env.exe MSYS='enable_pcon winsymlinks:nativestrict' CHERE_INVOKING=1 MSYSTEM=MSYS /bin/bash --login
# 参考https://github.com/microsoft/terminal/issues/1669#issuecomment-830732471

WT 1.18 则提供了另一种不用使用 cmd 启动脚本的设置环境变量的方法:

https://github.com/msys2/MSYS2-packages/issues/1684#issuecomment-1597116569

如果启动目录想设置为 msys2 的家目录,需要手动指定 msys2 的家目录位置作为启动位置。(如果有更好的方法请指出!)


使用 Tabby 导致 msys2 加载出现问题的一种原因

Tabby 在启动时会将 %HOME% 环境变量设置为 Windows 用户目录,这可能会导致 msys2 的启动出现问题。在正常情况下,msys2 期望 %HOME% 环境变量指向 msys2 的用户目录,而不是 Windows 用户目录。如果 %HOME% 被设置为 Windows 用户目录,msys2 可能无法找到正确的配置文件或者执行其他依赖于 %HOME% 环境变量的操作,从而导致启动失败或者运行异常。

解决方法是在新配置中设置环境变量:

HOME=/home/对应用户名

msys2 更新

原文:https://www.msys2.org/docs/updating/

MSYS2 是一个滚动发布发行版,仅支持完整的系统升级,这意味着各种软件包会频繁进行次要和主要更新,并且您只能一次更新所有软件包。
要更新所有包,请运行以下命令:

$ pacman -Suy
:: Synchronizing package databases...
 mingw32 is up to date
 mingw64 is up to date
 ucrt64 is up to date
 clang32 is up to date
 clang64 is up to date
 msys is up to date
:: Starting core system upgrade...
 there is nothing to do
:: Starting full system upgrade...
 there is nothing to do

在某些情况下,某些核心包将会更新,并且 pacman 会提示需要关闭所有 msys2 终端:

:: To complete this update all MSYS2 processes including this terminal will be closed.
   Confirm to proceed [Y/n]

确认后我们需要启动一个新终端并再次运行更新( pacman -Suy )以更新剩余的非核心软件包。

如果超过半年没有更新 MSYS2,可能会导致致 pacman 无法验证包或数据库签名,从而导致更新失败。通过运行 pacman-key --refresh-keys ,这会更新已安装的密钥。然后即可正常更新。

开始使用 UCRT64 环境

打开 MSYS2 ,输入 pacman -Syu 更新后,输入:

pacman -S mingw-w64-ucrt-x86_64-toolchain

这将安装 gcc 等工具,学校教学任务基本上够用了。

make:

pacman -Smingw-w64-ucrt-x86_64-make

cmake:

pacman -Smingw-w64-ucrt-x86_64-cmake

bat:

具有语法突出显示和 git 集成的Cat

mingw-w64-ucrt-x86_64-bat

vscode 配置文件

文章中没有提到vscode的配置文件的编写,这里补充一下。

在 vsocde 运行 c/c++ 代码,需要配置 launch.json 和 tasks.json 两个文件。
这两个文件在当前文件夹内的.vscode 文件夹下。 这里给出我的配置文件,修改一下路径就可以使用了。
这里使用绝对路径的写法,不依赖环境变量。(不推荐使用环境变量,到后面会有坑)

launch.json

{
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "g++.exe Debug", // 配置名称,将会在启动配置的下拉菜单中显示
            "type": "cppdbg", // 配置类型,cppdbg对应cpptools提供的调试功能;可以认为此处只能是cppdbg
            "request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加)
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", // 将要进行调试的程序的路径
            "args": [], // 程序调试时传递给程序的命令行参数,一般设为空即可
            "stopAtEntry": false, // 设为true时程序将暂停在程序入口处,相当于在main上打断点
            "cwd": "${workspaceFolder}", // 目标的工作目录
            "environment": [
                {
                    "name": "PATH",
                    "value": "C:/programs/msys2/ucrt64/bin;${env:PATH}" // 环境变量,将会在程序运行前进行设置
                }
            ], // 环境变量,将会在程序运行前进行设置
            "externalConsole": false, // 如果为 true,则为调试对象启动控制台即会有小黑框。如果为 false,它在 Linux 和 Windows 上会显示在集成控制台中。
            "MIMode": "gdb", // 指示 MIDebugEngine 要连接到的控制台调试程序。允许的值为 "gdb"、"lldb"。
            "miDebuggerPath": "C:/programs/msys2/ucrt64/bin/gdb.exe", // MI 调试程序(如 gdb)的路径。如果未指定,将首先在路径中搜索调试程序。
            "setupCommands": [
                { // 模板自带,可以更好地显示STL容器的内容
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "g++.exe Debug" // 调试会话开始前执行的任务,一般为编译程序.g++.exe build active file与tasks中的同名任务对应,即在调试前会执行tasks中的这个任务
        },
        {
            "name": "g++.exe Release", // 配置名称,将会在启动配置的下拉菜单中显示
            "type": "cppdbg", // 配置类型,cppdbg对应cpptools提供的调试功能;可以认为此处只能是cppdbg
            "request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加)
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", // 将要进行调试的程序的路径
            "args": [], // 程序调试时传递给程序的命令行参数,一般设为空即可
            "stopAtEntry": false, // 设为true时程序将暂停在程序入口处,相当于在main上打断点
            "cwd": "${workspaceFolder}", // 目标的工作目录
            "environment": [
                {
                    "name": "PATH",
                    "value": "C:/programs/msys2/ucrt64/bin;${env:PATH}" // 环境变量,将会在程序运行前进行设置
                }
            ], // 环境变量,将会在程序运行前进行设置
            "externalConsole": false, // 如果为 true,则为调试对象启动控制台即会有小黑框。如果为 false,它在 Linux 和 Windows 上会显示在集成控制台中。
            "MIMode": "gdb", // 指示 MIDebugEngine 要连接到的控制台调试程序。允许的值为 "gdb"、"lldb"。
            "miDebuggerPath": "C:/programs/msys2/ucrt64/bin/gdb.exe", // MI 调试程序(如 gdb)的路径。如果未指定,将首先在路径中搜索调试程序。
            "setupCommands": [
                { // 模板自带,可以更好地显示STL容器的内容
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "g++.exe Release" // 调试会话开始前执行的任务,一般为编译程序.g++.exe build active file与tasks中的同名任务对应,即在调试前会执行tasks中的这个任务
        },
    ]
}

tasks.json

{
    // 有关 tasks.json 格式的文档,请参见
    // https://go.microsoft.com/fwlink/?LinkId=733558
    "tasks": [
        {
            "type": "shell",
            "label": "g++.exe Debug", // 任务名称,与launch.json中对应,使用g++编译cpp文件,并在同目录下生成可执行文件
            "command": "g++",
            "args": [
                "-fdiagnostics-color=always",
                "-g", // 生成和调试有关的信息
                //
                // "-fexec-charset=GBK", // 处理mingw中文编码问题
                // "-finput-charset=UTF-8", // 处理mingw中文编码问题
                //
                "-Wall", // 显示所有的警告信息
                "${file}",
                "-o", // 指定输出文件名,不加该参数则默认输出a.exe,Linux下默认a.out
                "${fileDirname}\\${fileBasenameNoExtension}.exe"
            ],
            "options": {
                "cwd": "${fileDirname}", // 指定任务的工作目录
                "env": {
                    "PATH": "C:/programs/msys2/ucrt64/bin;${env:PATH}" // 环境变量,将会在程序运行前进行设置
                },
            },
            "problemMatcher": [
                "$gcc"
            ],
            // 所以以上部分,就是在shell中执行 g++ -g -Wall -fexec-charset=GBK -finput-charset=UTF-8 ".cpp" -o ".exe"
            // 任务分组
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "调试器生成的任务。"
        },
        {
            "type": "shell",
            "label": "g++.exe Release", // 任务名称,与launch.json中对应,使用g++编译cpp文件,并在同目录下生成可执行文件
            "command": "g++",
            "args": [
                "-fdiagnostics-color=always",
                "-O3", // 优化等级3
                "-static", // 静态链接
                "-lpthread", // 链接pthread库
                //
                // "-fexec-charset=GBK", // 处理mingw中文编码问题
                // "-finput-charset=UTF-8", // 处理mingw中文编码问题
                //

                "${file}",
                "-o", // 指定输出文件名,不加该参数则默认输出a.exe,Linux下默认a.out
                "${fileDirname}\\${fileBasenameNoExtension}.exe"
            ],
            "options": {
                "cwd": "${fileDirname}", // 指定任务的工作目录
                "env": {
                    "PATH": "C:/programs/msys2/ucrt64/bin;${env:PATH}" // 环境变量,将会在程序运行前进行设置
                },
            },
            "problemMatcher": [
                "$gcc"
            ],
            // 所以以上部分,就是在shell中执行 g++ -g -Wall -fexec-charset=GBK -finput-charset=UTF-8 ".cpp" -o ".exe"
            // 任务分组
            "group": {
                "kind": "build",
            },
            "detail": "Release版本生成的任务。"
        },
    ],
    "version": "2.0.0"
}

mingw中文编码问题

最新版vscode会自动识别改变终端编码为utf-8,如果运行结果没有乱码,那么可以不用管这个问题。

乱码的主要原因是vscode默认使用的是utf-8编码,而 windows默认使用的是gbk编码。所以需要在vscode中配置一下。

整个过程是这样的:

我们代码的编码是UTF-8
把UTF-8编码的代码交给mingw,它也默认当做UTF-8处理(目前为止这是正确的)
mingw处理后生成的数据还是UTF-8编码(目前为止还是正确的)
把mingw处理后的数据(UTF-8编码)给cmd(目前为止也是正确的)
cmd按GBK编码处理它(UTF-8),这时出现错误,所以出现乱码

因此有两种解决方案,一个是将vscode的编码改为gbk,一个是将命令行的编码改为utf-8。

输出编码改为gbk

编译时使用GBK编码输出,然后再让命令行去显示。已经在配置文件中设置好选项,取消注释即可。

命令行编码改为utf-8

在新版中设置添加了选项Terminal › Integrated: Detect Locale,默认auto已经可以解决问题,但是如果不行,可以手动设置。

在 settings.json 中添加以下内容,手动设定终端编码:

  "terminal.integrated.defaultProfile.windows": "PowerShell",//默认终端,可选项为PowerShell,Command Prompt
    "terminal.integrated.profiles.windows": {
      "PowerShell": {
        "source": "PowerShell",
        "args": ["-NoExit", "/C", "chcp 65001"],
        "icon": "terminal-powershell"
      },
      "Command Prompt": {
        "path": [
          "${env:windir}\\Sysnative\\cmd.exe",
        "${env:windir}\\System32\\cmd.exe"
        ],
        "args": [
          "/K",
          "chcp 65001"
        ],
        "icon": "terminal-cmd"
      },

  },

或者修改终端的编码

powershell7:

在profile.ps1中添加以下内容

$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

cmd :

通过注册表修改编码:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe]
"FontSize"=dword:00140008
"CodePage"=dword:000003a8

不使用环境变量使用code runner

目前的解决方案是在powershell的配置文件中添加以下内容:

$Env:Path += ";C:/programs/msys2/ucrt64/bin "#添加mingw的路径

使用MinGW-w64编译的文件打开失败

解决方案:将dll文件复制到可执行文件所在的目录或使用静态编译(运行时选择Release)。

CMake 编译

VScode+MSVC+CMake搭建C++开发环境
Windows下VSCode+CMake搭建开发环境

参考链接

关于UTF-8、GBK编码以及编译时charset的指定的一些总结

愿编程不再乱码(含Qt)-根因深究

mingw控制台中文乱码

Make console windows fully UTF-8 by default on Windows, in line with the behavior on Unix-like platforms

/utf-8 (Set source and execution character sets to UTF-8)

在Visual C++中使用UTF-8格式代码文件

Visual Studio C++ 默认 UTF-8 编码及 *.editorconfig 统一代码格式 - Me伟 - 博客园 (cnblogs.com)

posted @ 2023-06-14 16:32  comsoi  阅读(841)  评论(0编辑  收藏  举报