?1.前言?
? ? ? ? 本来之前发文用的是CodeBlocks和cmake进行结合使用的,无奈在Mac上CodeBlocks竟然不更新了,纠结了许久是否继续使用CodeBlocks,但是想到在mac上不能使用CodeBlocks愉快地学习了。本文所有内容在Windows10上实践,所以Mac和Ubuntu得有空跑通再另说。
2.安装环境
? ? ? ? 此文章所用环境及版本为:
? ? ? ? (1) MinGW? ?v8.1.0
? ? ? ? (2) CMake? ?v3.21.2? ?
? ? ? ? (3) VS Code? ?v1.62.1 (系统安装模式)
? ? ? ? ? ? ? (插件:C/C++ v1.7.1,CMake v0.0.17,CMake Tools v1.9.1,clangd v0.1.13)
? ? ? ? (4) glad v3.3 (core)? ? ? ?
? ? ? ? (5) glfw v3.3.5
2.1安装MinGW
? 在Windows上安装mingw推荐安装32位和64位兼容的版本,因为你可能需要同时编译32位和64位的,如果只装其中一个版本,那就比较头疼。在这个下面网址下载MinGW-W64-install.exe进行在线安装,Version我这里选择8.1.0,Architecture因为我的是64位系统所以选择x86_64,Threads选择posix (通常我希望不只是编译win的,还可以Android的,所以选了这个),Exception选择sjlj(这个支持32位和64位的,seh是新的不支持32位,如果只编译64位你可以选择seh),然后安装就可以了。你也可以在页面直接选择下载解压,不过要自己配置环境变量。
MinGW-w64 - for 32 and 64 bit Windows - Browse /mingw-w64 at SourceForge.nethttps://sourceforge.net/projects/mingw-w64/files/mingw-w64/
? ? ? ? 我的安装路径在C:\mingw64,环境变量的Path配置如下:
2.2安装CMake
? ? ? ? 在cmake官网下载cmake-3.21.2-windows-x86_64.msi(可以根据最新版本自己选择),安装下一步到完成就好了(记得选择配置环境变量或者自己配置一下路径,跟上图C:\Program Files\CMake\bin一样指定到bin路径就可以)。Download | CMakehttps://cmake.org/download/
2.3安装VS Code及插件
? ? ? ? 我在这里选择了Windows->System installer->64bit下载安装。
? ? ? ? ?在VS Code左侧点选图中第四个(如果你的不是第四个请选择同样的图标进行点击),然后依次安装图中四个插件。特别注意的是在安装clangd插件的时候会弹出Download clangd server进行安装依赖,这里大概率会失败,请重试几次或者按照提示进行自己下载。这里自动下载安装的话会在settings.json自动配置clangd.path这个参数,如果自己下载的请自行添加指定到具体路径。
? ? ? ? ?另外需要特别的配置是勾选cmake-tools的导出compile_commands.json这个文件,这个文件用在clangd寻找依赖的时候用到的。通过CMake Tools右侧设置按钮点出的菜单选择Extension Settings,在弹出的界面上方输入export compile进行搜索,然后勾选第二张图所示。
? ? ? ? ?最后,附上我这里目前的配置和进行一些必要说明就可以了,有一些是我自己摸索出来的。这里需要特别说明的几个是:
(1)cmake.buildDirectory这个配置是我希望不同的编译选项编译到不同的路径,比如build/x86/Debug和build/X64/Release这些,在后面的cmake-variants.json中会配置后面的两个参数,如果你不是跟我一样用请自行修改一下。
(2)cmake.copyCompileCommands这个配置的是cmake配置完成后会在build/x86/Debug这样的路径下生成compile_commands.json这个文件,但是在后面的clangd.arguments?--compile-commands-dir这里我想要配置${workspaceFolder}/build/${variant:buildTarget}/${buildType}这种动态的参数是无效的,最终clangd解析出来的还是原样的字符串,所以这里只能写死到build文件夹了,所以cmake配置项目完成后拷贝这个文件到build文件夹即可,特别注意的是cmake.copyCompileCommands这个配置的值必须要指定到文件名称,就是路径/compile_commands.json这种格式才行。
(3)C_Cpp.intelliSenseEngine这个参数需要写死为Disable,因为我这里使用clangd进行代码提示,所以C/C++原本的提示功能需要禁止不然会有冲突。如果后面你要用回默认的那个代码提示,请删掉这个配置和删除clangd这个插件(吐槽一下,自带的代码提示啥玩意,垃圾!)。
(4)因为clangd在新版本移除了--clang-tidy的支持,所以我们需要自己在clangd的配置路径下创建config.yaml进行开启代码静态检查,你不需要可以不设置。比如路径为C:\Users\你的用户名\AppData\Local\clangd\config.yaml,内容为:
Diagnostics:
ClangTidy:
Add:
[
cppcoreguidelines*,
performance*,
bugprone*,
portabilit-*,
modernize*,
google*
]
Remove:
[
modernize-use-trailing-return-type
]
Index:
Background: Build
????????以下配置在settings.json进行设置,ctrl+shift+p后输入Open Settings进行查找,点击如下选项即可进行编辑。
{
// clangd路径,如果通过工具安装会配置,通过手动安装请修改这个的值
"clangd.path": "c:\\Users\\用户名\\AppData\\Roaming\\Code\\User\\globalStorage\\llvm-vs-code-extensions.vscode-clangd\\install\\13.0.0\\clangd_13.0.0\\bin\\clangd.exe",
// 开启自动配置
"cmake.configureOnOpen": true,
// cmake 编译生成文件的路劲
"cmake.buildDirectory": "${workspaceFolder}/build/${variant:buildTarget}/${buildType}",
// 拷贝cmake生成compile_commands.json到这个路径下的同名文件
"cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json",
/**********
* Clangd *
**********/
// 关闭 C/C++ 提供的 IntelliSenseEngine
"C_Cpp.intelliSenseEngine": "Disabled",
// Clangd 运行参数(在终端/命令行输入 clangd --help-list-hidden 可查看更多)
"clangd.onConfigChanged": "restart",
"clangd.arguments": [
// 全局补全(输入时弹出的建议将会提供 CMakeLists.txt 里配置的所有文件中可能的符号,会自动补充头文件)
"--all-scopes-completion",
// 启用 Clang-Tidy 以提供「静态检查」
"--clang-tidy",
// compelie_commands.json 文件的目录位置(相对于工作区,由于 CMake 生成的该文件默认在 build 文件夹中,故设置为 build)
"--compile-commands-dir=build",
// 建议风格:打包(bundled重载函数只会给出一个建议);反可以设置为detailed
"--completion-style=bundled",
/**
* Read user and project configuration from YAML files.
* Project config is from a .clangd file in the project directory.
* User config is from clangd/config.yaml in the following directories:
* Windows: %USERPROFILE%\AppData\Local
* Mac OS: ~/Library/Preferences/
* Others: $XDG_CONFIG_HOME, usually ~/.config
*
* 我所使用的配置:
* Diagnostics:
* ClangTidy:
* Add:
* [
* cppcoreguidelines*,
* performance*,
* bugprone*,
* portabilit-*,
* modernize*,
* google*
* ]
* Index:
* Background: Build
*/
"--enable-config",
// 默认格式化风格: 谷歌开源项目代码指南(可用的有 LLVM, Google, Chromium, Mozilla, Webkit, Microsoft, GNU 等)
"--fallback-style=Google",
// 启用这项时,补全函数时,将会给参数提供占位符,键入后按 Tab 可以切换到下一占位符,乃至函数末
"--function-arg-placeholders=true",
// 输入建议中,已包含头文件的项与还未包含头文件的项会以圆点加以区分
"--header-insertion-decorators",
// 允许补充头文件
"--header-insertion=iwyu",
// 让 Clangd 生成更详细的日志
"--log=verbose",
// pch优化的位置(memory 或 disk,选择memory会增加内存开销,但会提升性能)
"--pch-storage=memory",
// 输出的 JSON 文件更美观
"--pretty",
// 同时开启的任务数量
"-j=12"
],
// 自动检测 clangd 更新
"clangd.checkUpdates": true,
// clangd的snippets有很多的跳转点,不用这个就必须手动触发Intellisense了
"editor.suggest.snippetsPreventQuickSuggestions": false,
/********
* LLDB *
********/
// LLDB 指令自动补全
"lldb.commandCompletions": true,
// LLDB 指针显示解引用内容
"lldb.dereferencePointers": true,
// LLDB 鼠标悬停在变量上时预览变量值
"lldb.evaluateForHovers": true,
// LLDB 监视表达式的默认类型
"lldb.launch.expressions": "simple",
// LLDB 不显示汇编代码
"lldb.showDisassembly": "never",
// LLDB 生成更详细的日志
"lldb.verboseLogging": true,
}
3.编译搞起
? ? ? ? 在上面的配置和编译摸索了很久以后,终于在编译这一块有自己满意的一套了。这里附上我的github项目代码,这里主要以Test目录下的进行解释,后续这个项目会更新更多关于我个人学习opengl相关的学习代码。pananfly/OpenGLLearn: OpenGL learning codes. Base on glad and glfw, compile with cmake and gcc, edit on vscode ide. (github.com)https://github.com/pananfly/OpenGLLearn????????首先先解释下外面的libs文件夹的东西,我分出来是为了在后面的所有子模块如Test和Triangle等所使用的OpenGL或者其他库都是一样的,不用在自己子模块的文件夹下各自拷贝一份这个依赖。你可以下载后在VS Code进行open folder找到下载代码后的Test文件夹进行打开,打开后我们就可以看到如下的文件树,.vscode里配置的cmake编译的VS code配置信息,launch.json配置的是运行的一些参数,CMakeLists.txt是配置编译项目的设置,test.cpp是源代码。
? ? ? ? ?这里的cmake-variants.json是我自己新建的文件,没看到在哪里可以快速创建。launch.json可以通过Run->Add Configuration->选择(gdb) Launch进行添加,添加后修改program的值为${command:cmake.launchTargetPath},我觉得配置这个就够了,因为我们后面配置编译x64/x86、Debug/Release这么多不同的组合是不同的路径,我看了这个launchTargetPath是可以找到当前的编译路径的。cwd改为${workspaceFolder},这个好像不改也行,最后删除miDebuggerPath这个配置,我看Windows这里好像自动去找了(因为我配置了mingw的环境),Mac和Linux等我跑起来看看再补充有什么不同。
? ? ? ? ?最终的launch.json如下(提示一下,这里或者其他json配置文件,比如你敲"na"这个会自动提示出来name或者其他匹配的选项,或者你敲双引号开始就有提示了,这个挺nice):
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
? ? ? ? cmake-variants.json配置如下,这里的buildType就是Cmake Tool默认的,我自己加了buildTarget这个配置可以选择编译32位或者64位
{
"buildType": {
"default": "debug",
"description": "The build type.",
"choices": {
"debug": {
"short": "Debug",
"long": "Disable optimizations - include debug information.",
"buildType": "Debug"
},
"release": {
"short": "Release",
"long": "Optimize for speed - exclude debug information.",
"buildType": "Release"
}
}
},
"buildTarget": {
"default": "x64",
"description": "abi for 64 bit target build",
"choices": {
"x64": {
"short": "x64",
"long": "abi for 64 bit",
"settings": {
"CAMKE_BUILD_GENERATOR": "x64"
}
},
"x86": {
"short": "x86",
"long": "abi for 32 bit target build",
"settings": {
"CAMKE_BUILD_GENERATOR": "x86"
}
}
}
}
}
? ? ? ? 然后我们就可以在VS Code底下这个选项点击后弹出这些选项来选择编译哪个。这里说一个个人绕的坑,我在没有配置cmake-variants.json之前走了一大段弯路,我找到了tasks.json这个配置方式来进行编译模式的选择,但是最终都不是完美的,所以这个方式才是我觉得完美的终极方式,具体tasks.json你们可以在github上的Triangle/.vscode下查看,蹩脚又有很多限制,想知道的可以私聊我,也许你私聊我的时候过太久也许我已经不太记得了。
?接下来是CMakeLists.txt的内容,这里面都写了比较详细的注释,要说明的一点是我自定义了CAMKE_BUILD_GENERATOR这个变量是cmake-variants.json中配置的,在你选择哪个模式后会最终传到这里。
cmake_minimum_required(VERSION 3.10) # 设置支持最低Cmake版本
set(PROJECT_NAME_STR Test) # 设置项目名称为Test
project(${PROJECT_NAME_STR}) # set project name
if (Apple)
set (CMAKE_OSX_ARCHITECTURES i386)
set (CUDA_64_BIT_DEVICE_CODE OFF)
endif (Apple)
if (CMAKE_HOST_WIN32)
set(WINDOWS 1)
elseif(CMAKE_HOST_APPLE)
set(MACOS 1)
elseif(CMAKE_HOST_UNIX)
set(LINUX 1)
endif()
message("-- CMAKE_BUILD_TYPE : ${CMAKE_BUILD_TYPE}") # 输出从cmake运行传过来的buildType参数是什么,如Debug和Release等
message("-- CAMKE_BUILD_GENERATOR : ${CAMKE_BUILD_GENERATOR}") #输出从cmake运行传过来的buildGenerator参数是什么,如x86和x64等,这个参数是自定义的,如果不传默认编译64位(我当前系统64位)
if("${CAMKE_BUILD_GENERATOR}" MATCHES "^.*x86.*$") # 判断编译的版本
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") # -m32 32bit 指定为编译32位
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
if (CMAKE_HOST_WIN32)
set(GLFW_LINK_DIR ${PROJECT_SOURCE_DIR}/../libs/opengl/glfw/windows/static-ucrt) # 设置GLFW_LINK_DIR值为libs文件夹下windows平台对应的32位glfw依赖的库路径
elseif(CMAKE_HOST_APPLE)
set(GLFW_LINK_DIR ${PROJECT_SOURCE_DIR}/../libs/opengl/glfw/osx/lib-x86_64)
elseif(CMAKE_HOST_UNIX)
endif()
else() # default to link 64 bit lib
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64") # -m64 64bit
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64")
if (CMAKE_HOST_WIN32)
set(GLFW_LINK_DIR ${PROJECT_SOURCE_DIR}/../libs/opengl/glfw/windows/static-ucrt-w64)# 设置GLFW_LINK_DIR值为libs文件夹下windows平台对应的64位glfw依赖的库路径
elseif(CMAKE_HOST_APPLE)
set(GLFW_LINK_DIR ${PROJECT_SOURCE_DIR}/../libs/opengl/glfw/osx/lib-x86_64)
elseif(CMAKE_HOST_UNIX)
endif()
endif()
link_directories(${GLFW_LINK_DIR}) # 指定glfw3的链接路径
add_executable(${PROJECT_NAME_STR} test.cpp ${PROJECT_SOURCE_DIR}/../libs/opengl/glad/src/glad.c) # set source files 添加编译源文件
# 指定依赖的头文件路径
include_directories(
${PROJECT_SOURCE_DIR}/../libs/opengl/glfw/include
${PROJECT_SOURCE_DIR}/../libs/opengl/glad/include
)
target_link_libraries(${PROJECT_NAME_STR} glfw3) # 链接程序和glfw库
# copy lib 如果是windows,则拷贝依赖的glfw3.dll库到编译出来的工程exe同路径下,免得运行的时候找不到依赖的库
if(CMAKE_HOST_WIN32)
add_custom_command(TARGET ${PROJECT_NAME_STR}
POST_BUILD
COMMAND echo "copy dll files after make"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${GLFW_LINK_DIR}/glfw3.dll"
$<TARGET_FILE_DIR:${PROJECT_NAME_STR}>)
endif()
#add_library(testlib SHARED test.cpp)
#add_library(testa STATIC test.cpp)
? ? ? ? 接下来是运行的源码了,这里就是用了别人的代码进行测试开启一个窗口画了一个底色。
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <stdlib.h>
// 设置窗口尺寸
const unsigned int SCR_WIDTH = 400;
const unsigned int SCR_HEIGHT = 300;
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
int main()
{
// glfw: 初始化
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
// uncomment this statement to fix compilation on OS X
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw 创建窗口
GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Test<GLFW+GLAD>", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetKeyCallback(window, key_callback);
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// render loop
while (!glfwWindowShouldClose(window))
{
glClearColor(0.0f, 1.f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// glfw: swap buffers and poll IO events (keyspressed/released, mouse moved etc.)
glfwSwapBuffers(window);
// glfwPollEvents();
glfwWaitEvents();
}
// glfw: terminate, clearing all previously allocated GLFWresources.
glfwTerminate();
return 0;
}
? ? ? ? 关于CMake kits,因为我们配置了mingw的环境变量,所以会自动检测到GCC 8.1.0 x86_64-w64-mingw32这个选项,选这一个就好了,这个选项可以默认编译适合cmake的编译的东西因为它自动加了MinGW Makefiles这个配置,其他的我装了VS会生成VS项目相关的东西,这里不做讲解。点击底下如果所示位置就可以弹出所有的kits了,如果没有东西请选择一下Scan for kits跑一次查找。如果你自己要编辑这个kits的配置,ctrl+shift+p后搜索Edit User Local Kits进行修改,对应的文件路径为C:\Users\你的用户名\AppData\Local\CMakeTools\cmake-tools-kits.json。
? ? ? ? ?最后我们终于可以开始编译代码运行了。确认如下图1处选择了编译的选项后,确认图2处选择了GCC的kit后,点击图3处的build,再点击图4的三角形进行运行。
? ? ? ? ?好了,我们的程序跑起来了,结果如下:
?4.后记
? ? ? ? 这个VS Code自定义摸索挺折腾人的,不过经过一番折腾后,这些配置在登录微软账号的情况下是可以同步的,应该可以愉快地在Ubuntu和Mac上愉快地学习了。看到最后一个引用了没,后面试试通过VS Code CMake来搞NDK编译,希望简单的NDK项目可以不用开Android Studio那么麻烦了,搞起!
参考文章如下:
VSCode 配置 C/C++:VSCode + Clang + Clangd + LLDB + CMake + Git_tyKuGengty的博客-CSDN博客
VS Code + Cmake Tools, 搭建C/C++跨平台(NDK、iOS)开发环境 - 知乎 (zhihu.com)
|