-
Notifications
You must be signed in to change notification settings - Fork 87
使用VSCode开发CMake项目
本文以 WizNotePlus 项目为例,讲解如何配置 Visual Studio Code 以便开发基于 CMake 构建系统的 C++ 项目。
- C/C++ :提供语法提示、调试以及代码浏览等功能。
- C/C++ Clang Command Adapter :提供自动补全、语法诊断等功能。
打开命令面板,输入 C/C++: Edit Configurations (JSON) 以生成 ./.vscode/c_cpp_properties.json
文件,然后修改配置。
Linux:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"~/usr/Qt/5.14.2/gcc_64/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++11",
"intelliSenseMode": "gcc-x64",
"browse": {
"path": [
"${workspaceFolder}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
}
],
"version": 4
}
MacOS:
{
"configurations": [
{
"name": "MacOS",
"includePath": [
"${workspaceFolder}/**",
"~/Qt/5.15.2/clang_64/**"
],
"defines": [],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c11",
"cppStandard": "c++11",
"intelliSenseMode": "macos-clang-x64"
}
],
"version": 4
}
注意 includePath
很重要,需要指向 Qt 库。另外,不同编译工具链下某些设置需要修改,比如使用 VC 编译器需要将 intelliSenseMode
指定为 msvc-x64
,编译器地址设置可以删除,因为我们使用 CMake Tool 来自动检测工具链。这个设置文件主要用来提供语法检测。
注意:clang 版本可以根据你的需求自由选择。
首先安装 clang-6.0 :
sudo apt install clang-6.0
并在 ./.vscode/settings.json
中写入以下设置:
{
"clang.executable": "/usr/bin/clang-6.0"
}
- CMake :提供 CMake 语法高亮和提示功能。
- CMake Tools :提供 CMake 构建流程支持,也能为其他插件提供对语法诊断的支持。
CMake 的最佳实践是 out-of-source 构建,所以指定cmake.buildDirectory
为源码外的位置。
在 ./.vscode/settings.json
中写入以下设置:
{
"cmake.buildDirectory": "${workspaceRoot}/../build-WizNotePlus-VSCode",
"cmake.configureSettings": {
"CMAKE_PREFIX_PATH": "/home/altairwei/usr/Qt/5.14.2/gcc_64"
}
}
这里的 CMAKE_PREFIX_PATH
主要作为默认设置,我们可以在 cmake-variants.json
中定义几套适合不同 Qt 版本的设置。
这一步不是必需的,你也可以使用插件自动检测的 Kits
在 ./.vscode/cmake-kits.json
中写入 Kit :
[
{
"name": "GCC x64",
"compilers": {
"C": "/usr/bin/gcc",
"CXX": "/usr/bin/g++"
}
}
]
保存后在底部状态栏选择该 Kit 。
因为 CMake Tools 在 Configure 时不会定义 CMAKE_BUILD_TYPE
变量,导致 Configure 过程出现潜在的问题,所以我们可以通过 Variants 的功能来显示定义它。
在 ./.vscode/cmake-variants.json
中写入 Variants :
{
"buildType": {
"default": "Release",
"description": "WizNotePlus Option",
"choices": {
"Debug": {
"short": "Debug",
"long": "Build with debugging information",
"buildType": "Debug",
"settings": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
"Release": {
"short": "Release",
"long": "Optimize the resulting binaries",
"buildType": "Release",
"settings": {
"CMAKE_BUILD_TYPE": "Release"
}
}
}
}
}
另外,我们也可以设置不同 Qt 库,比如:
{
"buildType": {
"default": "Release",
"description": "WizNotePlus Option",
"choices": {
"Debug-Qt5.9": {
"short": "Debug-Qt5.9",
"long": "Build with debugging information",
"buildType": "Debug",
"settings": {
"CMAKE_BUILD_TYPE": "Debug",
"BUILD_TESTING": "ON",
"CMAKE_PREFIX_PATH": "/home/altairwei/usr/Qt/5.9.9/gcc_64"
}
},
"Debug-Qt5.12": {
"short": "Debug-Qt5.12",
"long": "Build with debugging information",
"buildType": "Debug",
"settings": {
"CMAKE_BUILD_TYPE": "Debug",
"BUILD_TESTING": "ON",
"CMAKE_PREFIX_PATH": "/home/altairwei/usr/Qt/5.12.8/gcc_64"
}
},
"Debug-Qt5.14": {
"short": "Debug-Qt5.14",
"long": "Build with debugging information",
"buildType": "Debug",
"settings": {
"CMAKE_BUILD_TYPE": "Debug",
"BUILD_TESTING": "ON",
"CMAKE_PREFIX_PATH": "/home/altairwei/usr/Qt/5.14.2/gcc_64"
}
},
"Debug-Qt5.15": {
"short": "Debug-Qt5.15",
"long": "Build with debugging information",
"buildType": "Debug",
"settings": {
"CMAKE_BUILD_TYPE": "Debug",
"BUILD_TESTING": "ON",
"CMAKE_PREFIX_PATH": "/home/altairwei/usr/Qt/5.15.0/gcc_64"
}
},
"Release": {
"short": "Release",
"long": "Optimize the resulting binaries",
"buildType": "Release",
"settings": {
"CMAKE_BUILD_TYPE": "Release"
}
}
}
}
}
注意:Qt 5.12 以后版本依赖于 OpenSSL v1.1
WizNotePlus 会用到 libQt5Network.so 模块,而该模块是以 OpenSSL v1.0 版本构建的。Ubuntu 18.04 平台系统自带 OpenSSL v1.1,因而运行程序时会出现网络错误的问题。WizNotePlus 项目通过 Conan 引入了 OpenSSL v1.0.2p 用以解决 libQt5Network.so 的依赖问题。
通过 readelf -d libQt5Network.so
可知该动态库的 RUNPATH 是 $ORIGIN
,看起来我们直接将 OpenSSL v1.0 相关动态库复制到 Qt5 库位置即可解决问题,但这毕竟比较麻烦。
我们注意到 Linux 下动态链接器的搜索顺序如下:
- RPATH - a list of directories which is linked into the executable, supported on most UNIX systems. It is ignored if RUNPATH is present.
- LD_LIBRARY_PATH - an environment variable which holds a list of directories
- RUNPATH - same as RPATH, but searched after LD_LIBRARY_PATH, supported only on most recent UNIX systems, e.g. on most current Linux systems
- /etc/ld.so.conf - configuration file for ld.so which lists additional library directories
- builtin directories - basically /lib and /usr/lib
这意味着我们直接利用环境变量 LD_LIBRARY_PATH
可以达到随意设置 OpenSSL v1.0 动态库放置位置的目的。我们可以通过 VSCode C/C++ 扩展的 launch.json
来设置每次调试时的环境变量。
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
// Resolved by CMake Tools:
"program": "${command:cmake.launchTargetPath}",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "LD_LIBRARY_PATH",
"value": "${config:cmake.buildDirectory}/lib:${config:cmake.buildDirectory}/bin"
}
],
"externalConsole": true,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
在 MacOS 上调试应用程序,可能出现找不到 dylib 的问题,因此我们需要使用 DYLD_LIBRARY_PATH
变量指向构建目录中包含缺失 dylib 的文件夹。相关 launch.json
配置:
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "cppdbg",
"request": "launch",
// Resolved by CMake Tools:
"program": "${command:cmake.launchTargetPath}",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [
{
// add the directory where our target was built to the PATHs
// it gets resolved by CMake Tools:
"name": "PATH",
"value": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
},
{
"name": "DYLD_LIBRARY_PATH",
"value": "${config:cmake.buildDirectory}/lib:${config:cmake.buildDirectory}/bin"
}
],
"externalConsole": false,
"MIMode": "lldb"
}
]
}
注意:wiznoteplus-build 镜像可能更新不及时,如有必要请根据 .ci/Dockerfile
自己构建镜像。
使用 VSCode C/C++ 的任务功能,在 ./.vscode
下新建 task.json
:
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"group": "build",
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"Mkdir"
],
"options": {
"env": {
"QT_INSTALL_PREFIX": "${config:qt.qtdir}"
}
},
"args": [
"${workspaceFolder}",
"${workspaceFolder}/_build"
],
"windows": {
"command": ".\\.ci\\build.ps1",
"options": {
"env": {
"CONAN_CMAKE_GENERATOR": "NMake Makefiles JOM"
}
}
},
"osx": {
"command": ".ci/build.sh"
},
"presentation": {
"reveal": "always",
"focus": true,
"panel":"shared"
},
"problemMatcher": []
},
{
"label": "Clean & Build",
"group": "build",
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"Clean",
"Build"
]
},
{
"label": "Mkdir",
"type": "shell",
"windows": {
"command": "mkdir -Force _build"
},
"osx": {
"command": "mkdir -p _build"
}
},
{
"label": "Clean",
"type": "shell",
"windows": {
"command": "rm -Force -Recurse _build"
},
"osx": {
"command": "rm -rf _build"
}
},
{
"label": "Update Translation",
"type": "shell",
"command": "python ${workspaceFolder}/script/update_translations.py",
"options": {
"env": {
"PATH": "${config:qt.qtdir}/bin;${env:PATH}"
}
}
},
{
"label": "Open Linguist",
"type": "shell",
"command": "linguist ${workspaceFolder}/i18n/wiznote_zh_CN.ts ${workspaceFolder}/i18n/wiznote_zh_TW.ts",
"options": {
"env": {
"PATH": "${config:qt.qtdir}/bin;${env:PATH}"
}
}
},
{
"label": "Translate",
"type": "shell",
"problemMatcher": [],
"dependsOrder": "sequence",
"dependsOn": [
"Update Translation",
"Open Linguist"
]
},
]
}