详解如何使用VSCode和CMake构建跨平台的CC++开发环境

详解如何使用VSCode和CMake构建跨平台的CC++开发环境

2023年7月26日发(作者:)

详解如何使⽤VSCode和CMake构建跨平台的CC++开发环境⽬录⼀、前⾔⼆、开发⼯具三、⽰例项⽬四、使⽤CMake4.1、如何引⼊⼀个第三⽅静态库4.2、动态库的加载问题4.3、utf-8编码格式的代码通过visualstudio编译报错问题4.4、可执⾏⽂件的⼯作⽬录问题4.5、如何修改Mac上动态库的加载路径五、利⽤VSCode的执⾏指定命令5.1、通过Ctrl+Shift+B执⾏CMake编译本地⼯程5.2、通过Ctrl+B构建与运⾏可执⾏⽂件六、利⽤VSCode的完成调试⼀、前⾔⽇前在学习制作的实战项⽬Breakout游戏时,希望能将这个⼩游戏开发成跨平台的,⽀持在多个平台运⾏。⼯欲善其事必先利其器,⾸先需要做的⾃然是搭建⼀个舒服的跨平台C/C++开发环境,所以这篇⽂章主要就是记录环境搭建的整个过程,踩到的⼀些坑,以及对应的解决办法。正⽂开始之前,先来阐述⼏个问题为什么选择使⽤VSCode实在⽤不习惯Visual Studio(也可能是⽤的太少了T▽T)代码编辑⽅⾯更喜欢⽤轻量级的编辑器,⽐如Sublime或者VSCodeVSCode确实⽐较强⼤好⽤,插件丰富为什么使⽤CMake通⽤的编译构建⼯具,跨平台的关键,⼀份代码,CMake可以针对不同的系统编译构建⽣成不同的项⽬⼯程源代码管理,编译更加⽅便(如果仅仅使⽤VSCode搭建开发环境,则每添加⼀个源⽂件,就要改动⼀下编译指令)最终实现的开发流程是怎样的VSCode编写代码快捷键Ctrl+Shift+B,调⽤CMake完成本地项⽬⽣成(Mac快捷键Command+Shift+B)快捷键Ctrl+B,完成项⽬的编译构建与运⾏(Mac快捷键Command+B)快捷键F5,完成项⽬的调试与运⾏(VSCode的F5调试运⾏,为了能够实现调试功能额外做了许多⼯作,所以启动会有些慢,因此在不需要调试的时候,直接使⽤Ctrl+B编译运⾏看效果会更快些)⼆、开发⼯具CMake与VSCodeCMake的获取,可以查看VSCode的获取,可以查看关于CMake与VSCode如何安装,⽐较简单,⽹上也有很多教程,这⾥就不详细介绍了VSCode插件推荐安装在VSCode的Extensions⾯板中搜索下⾯的插件名即可,记得看清作者名,不要下错啦插件插件名作者描述提供CMake语法的⾼亮显⽰以及代码段提⽰C/C++Microsoft提供C/C++的代码提⽰,跳转,调试等诸多功能,官⽅出品,基本是C/C++开发必备了CMaketwxs三、⽰例项⽬这⾥给出的⽂件⽬录情况,并不完整,但具有⼀定的代表性,不仅涉及源代码的编译,同样包含了静态库,动态库的加载,以及资源⽂件的读取等问题Breakout├── 3rd // 第三⽅库│ ├── glfw // ⼀个静态库⽬录│ ├── irrKlang-1.6.0 // ⼀个动态库⽬录│ └── // cmake⽂件├── resources // 资源⽬录│ ├── textures // 存放贴图⽂件│ └── shaders // 存放shader⽂件├── src // 源代码⽬录│ ├── game // 源代码⼦⽬录│ │ ├── game.h│ │ └── │ └──

└── // cmake⽂件四、使⽤CMake本⽂仅着重介绍为了完成⽰例项⽬开发,解决特定问题⽽使⽤的⼀些cmake语句cmake的所有语句都写在中,cmake会根据该⽂件中的配置完成最终的编译,构建,打包,测试等⼀系列任务⼀个简单的如下所⽰,完整的⽂件可以查看# cmake最低版本号要求cmake_minimum_required (VERSION 2.8)# 设置PROJECT_NAME变量set(PROJECT_NAME Breakout)# 设置⼯程名project (${PROJECT_NAME})# 查找当前⽬录下的所有源⽂件并存⼊DIR_SRCS变量aux_source_directory(src DIR_SRCS)# 添加⼀个可编译的⽬标到⼯程add_executable (${PROJECT_NAME} ${DIR_SRCS})如何编译⼀个⽂件夹下的所有源代码在开发过程中,由于架构设计或是为了便于管理与查找,源⽂件⼀般会根据不同的功能存放在不同的⽂件夹中,⽂件夹中⼜可能嵌⼊⽂件夹,所以需要⼀条语句能够获取所有的源⽂件进⾏编译,⽽不⽤每新创建⼀个源⽂件,就修改⼀次编译指令# 递归列出所有源⽂件file (GLOB_RECURSE SOURCE_FILES *.cc)# 添加⼀个可编译的⽬标到⼯程add_executable (${PROJECT_NAME} ${SOURCE_FILES})上⾯这条file命令会递归列出所有.cc⽂件,并存⼊SOURCE_FILES变量,然后将SOURCE_FILES表⽰的所有.cc⽂件添加到⽬标即可,从⽽解决多源⽂件编译问题4.1、如何引⼊⼀个第三⽅静态库为了不重复造轮⼦,开发中不可避免的要引⼊其他第三⽅库。正常情况下,这个第三⽅库也会是⼀个CMake⼯程(或是库的开发者直接提供已经编译好的库)以⽰例项⽬引⼊的库为例1.添加submodule引⼊glfw(glfw正好是github上的⼀个开源项⽬),或是直接将第三⽅库的源码放到⾃⼰的⽬录中2.使⽤add_subdirectory命令,将glfw所在的⽂件夹添加到编译的任务列表中# 保证glfw dir被编译add_subdirectory (${GLFW_DIR})3.将glfw的头⽂件⽬录添加到头⽂件搜索路径中# 添加头⽂件搜索路径include_directories (${GLFW_DIR}/include)4.链接glfw库,target_link_libraries命令⽤来链接⽬标与库⽂件,第⼀个参数就是我们的构建⽬标,后⾯可以跟多个参数,来表⽰链接多个库# 添加链接库target_link_libraries (${PROJECT_NAME} glfw)4.2、动态库的加载问题以引⼊的irrKlang库为例,它并不是⼀个开源项⽬,不过好在它提供了已经在多个平台上编译好的库,所以我们需要根据不同的平台来设置引⼊不同的库⽂件1.利⽤find_package引⼊外部依赖包,它可以帮我们找到官⽅预定义的许多依赖包模块,当未在官⽅预定义的依赖中找到时,会再查找⽂件,执⾏该⽂件从⽽找到XXX库。# IrrKlangfind_package (IrrKlang REQUIRED)2.先新建⽂件,由它来负责具体的irrKlang库加载。部分语句如下所⽰,主要是根据当前平台的不同,设置不同的头⽂件路径,库路径,库所在⽬录等变量。⽤到的find_library语句可以实现直接根据库的base name(即不需要lib,so等),找到对应的库,并存⼊IRRKLANG_LIBRARY变量find_path(IRRKLANG_INCLUDE_DIR NAMES irrKlang.h PATHS "${3RD_DIR}/irrKlang-1.6.0/include")IF(WIN32) # win32平台 if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") message(STATUS "Using MSVC") set (IRRKLANG_LIB_DIR "${3RD_DIR}/irrKlang-1.6.0/lib/Win32-visualStudio") set (IRRKLANG_BIN_DIR "${3RD_DIR}/irrKlang-1.6.0/bin/Win32-visualStudio") find_library(IRRKLANG_LIBRARY NAMES irrKlang PATHS ${IRRKLANG_LIB_DIR}) elseif("${CMAKE_CXX_COMPILED_ID}" STREQUAL "GNU") message(STATUS "Using GCC") set (IRRKLANG_LIB_DIR "${3RD_DIR}/irrKlang-1.6.0/lib/Win32-gcc") set (IRRKLANG_BIN_DIR "${3RD_DIR}/irrKlang-1.6.0/bin/Win32-gcc") find_library(IRRKLANG_LIBRARY NAMES libirrKlang.a PATHS ${IRRKLANG_LIB_DIR}) endif()elseif(APPLE) # mac平台 set (IRRKLANG_BIN_DIR "${3RD_DIR}/irrKlang-1.6.0/bin/macosx-gcc") find_library(IRRKLANG_LIBRARY NAMES PATHS "${3RD_DIR}/irrKlang-1.6.0/bin/macosx-gcc")elseif(UNIX AND NOT APPLE) # 等同于linux平台 set (IRRKLANG_BIN_DIR "${3RD_DIR}/irrKlang-1.6.0/bin/inux-gcc") find_library(IRRKLANG_LIBRARY NAMES IrrKlang PATHS "${3RD_DIR}/irrKlang-1.6.0/bin/linux-gcc")endif()3.将找到的irrKlan头⽂件添加到头⽂件搜索路径中include_directories (${IRRKLANG_INCLUDE_DIR})4.链接irrKlang库# 添加链接库target_link_libraries (${PROJECT_NAME} glfw ${IRRKLANG_LIBRARY})4.3、utf-8编码格式的代码通过visual studio编译报错问题跨平台的代码,⼀般使⽤utf-8编码格式的代码,更加通⽤,也可以保证在MacOS或者Linux平台上的正常编译。但是visual studio默认编译⽂件的编码是utf-8 with bom,在没有中⽂的情况下,直接编译是没有问题的,然⽽当源⽂件含有中⽂时(⽐如中⽂注释),则可能会出现异常,报⼀些莫名其妙的语法错误。解决办法是通过CMake语句通知MSVC编译时采⽤utf-8编码# 设置MSVC编译编码add_compile_options("$<$:/source-charset:utf-8>")4.4、可执⾏⽂件的⼯作⽬录问题当编译构建⽣成可执⾏⽂件后,我们希望可以直接通过命令⾏命令启动可执⾏⽂件来查看效果。但是由于⼯作⽬录的问题,可能会导致出现资源⽂件找不到,或者库加载失败问题对于visual studio⼯程,可以通过CMake语句设置其⼯作⽬录,但是这个⼯作⽬录仅在通过visual studio调试启动时才会⽣效,但对于直接启动可执⾏⽂件的情况仍然是没⽤的# 设置⼯作⽬录set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY

${CMAKE_SOURCE_DIR}/resources)所以只能将资源⽂件⽬录放置到可执⾏⽂件所在⽬录下,以保证⼀定能加载到需要的资源,这可以通过CMake的⾃定义命令实现# 复制资源⽂件到⼯作⽬录add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources $/resources)这条语句的功能是在编译结束后,将指定的资源⽬录复制到⽣成的可执⾏⽂件所在的⽬录。同样的,对于⼀些动态库,⽐如dylib,dll等也需要复制,不过注意最好在编译前就将它们复制到⽬标⽬录,使⽤PRE_BUILD指明命令执⾏的时机# 复制库到⼯作⽬录add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${IRRKLANG_BIN_DIR} $)4.5、如何修改Mac上动态库的加载路径在Mac上启动可执⾏⽂件时,⼀直遇到⼀个动态库⽆法加载的报错dyld: Library not loaded: /usr/local/lib/ Referenced from: ... Reason: image not found这是由于在编译⽣成动态库时,可以指定动态库的加载路径,⽐如我们引⼊的libirrklang库默认会到/usr/local/lib⽬录下查找dylib⽂件简单的解决⽅式,⾃然是通过install命令,将⽂件安装到/usr/local/lib⽬录下,不过为了不“污染”其他⽬录,更希望可执⾏⽂件加载的是我们放置在其所在⽬录下的⽂件。为了实现这个⽬标,我们添加下⾯的CMake语句if(APPLE) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND install_name_tool -change /usr/local/lib/ @executable_path/ ${PROJECT_NAME} )endif()判断如果是Mac平台,则通过add_custom_command调⽤install_name_tool命令,来修改应该应⽤程序对动态库的查找路径。其中的@executable_path就表⽰可执⾏⽂件所在⽬录五、利⽤VSCode的执⾏指定命令CMake的配置⽂件已经基本准备完毕了,接下来就是怎样结合VSCode更⽅便的调⽤CMake的问题了5.1、通过Ctrl+Shift+B执⾏CMake编译本地⼯程Ctrl+Shift+B是VSCode调⽤task的默认快捷键,task定义在.vscode⽬录下的⽂件中,⼀般使⽤task来完成编译等任务,VSCode提供了丰富的参数配置,我们可以利⽤它完成很多⾃定义任务定义⼀个task,执⾏cmake ..命令,完成本地项⽬的编译⽣成。Linux会⽣成Makefile,MacOS⽣成Makefile或Xcode⼯程,Windows下⽣成Visual Studio⼯程。注意这⾥的..表⽰的是上层⽬录,因为我们会在项⽬根⽬录下新建⼀个build⽂件夹,然后在这个⽂件夹内完成⼀系列的编译⼯作,这样cmake⽣成的中间⽂件都在build⽬录,不会“污染”开发⽬录(将build⽬录加⼊.gitignorej即可忽略CMake所产⽣的所有中间⽂件),在编译出问题的时候也可以直接删除buidl⽬录重新编译{ "label": "cmake", // task的名字 "type": "shell", "command": "cmake", "args": [ // "-DCMAKE_BUILD_TYPE=${input:CMAKE_BUILD_TYPE}", ".." ], "options": { "cwd": "build" // 表⽰当前执⾏⽬录build⽂件夹 }, "group": "build", "presentation": { // ⼀些控制台显⽰配置 "echo": true, "reveal": "always",

"focus": false, "panel": "shared", "showReuseMessage": true, "clear": true }, // Use the standard MS compiler pattern to detect errors, warnings and infos "problemMatcher": "$msCompile", "dependsOn":["mkbuild"] // 依赖的任务,在本任务执⾏前先执⾏mkbuild任务}在cmake ..命令执⾏前,先通过task执⾏mkdir新建build⽂件夹。其中通过windows参数,区分不同平台设置不同的参数{ "label": "mkbuild", "type": "shell", "command": "mkdir", // 调⽤的命令 "args": [ // 命令参数 "-p", "build" ], "windows":{ // windows平台使⽤mkdir -Force build新建⽂件夹 "args": [ "-Force", "build" ] }, "group": "build", "presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": true, "clear": true }, // Use the standard MS compiler pattern to detect errors, warnings and infos "problemMatcher": "$msCompile",}当按下Ctrl+Shift+B时,VSCode将弹出所有可执⾏的task,选择执⾏cmake task即可。由于定义了依赖(dependsOn),在cmak task执⾏前,将⾃动先执⾏mkbuild task5.2、通过Ctrl+B构建与运⾏可执⾏⽂件在启动可执⾏⽂件前,先通过cmake --build .构建⽣成可执⾏⽂件{ "label": "compile", "type": "shell", "command": "cmake --build .", "options": { "cwd": "build" }, "group": "build", "presentation": { // Reveal the output only if unrecognized errors occur. "reveal": "always", "clear": true }, // Use the standard MS compiler pattern to detect errors, warnings and infos "problemMatcher": "$msCompile" }在可执⾏⽂件⽣成后,通过task启动可执⾏⽂件。其中的${workspaceFolderBasename}是VSCode的内置变量,表⽰⼯程名。更多的内置变量介绍可以查看{ "label": "run", "type": "shell", "command": "./${workspaceFolderBasename}", "group": "build", "presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": true, "clear": true }, "options": { "cwd": "build"

}, "windows":{ "options": { "cwd": "build/Debug" // windows visual studio项⽬会默认多⽣成Debug/Release⽬录 }, }, // Use the standard MS compiler pattern to detect errors, warnings and infos "problemMatcher": "$msCompile", "dependsOn":["compile"] // 在run任务执⾏前先执⾏compile任务,确保修改的代码⽣效}通过Ctrl+B直接调⽤run任务。由于编译运⾏这个任务经常要⽤到,如果依然通过Ctrl+Shift+B弹出所有任务,再进⼀步选择就会有些⿇烦,所以定义⼀个快捷键(读者可以⽤同样的⽅法设置⾃⼰喜欢的快捷键)来直接运⾏run任务打开VSCode快捷键设置在弹出的界⾯中输⼊“run build task”搜索,并修改其快捷键点击右上⾓的翻转按钮,进⼊快捷键⽂件配置在打开的⽂件中,为刚配置的快捷键添加参数,告诉它直接启动名字叫“run”的task{ "key": "ctrl+b", "command": "k", "args" : "run"}六、利⽤VSCode的完成调试VSCode通过.vscode⽬录下的实现对多个平台多种语⾔的调试⽀持通过F5完成项⽬的调试与运⾏配置⽂件以⽀持C/C++项⽬的调试{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: /fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Launch Debug", //名称 "type": "cppdbg", //调试类型,除使⽤msvc进⾏调试外,均为该类型 "request": "launch", "program": "${workspaceFolder}/build/${workspaceFolderBasename}", //指定C/C++程序位置 "args": [], //指定运⾏参数 "stopAtEntry": false, "cwd": "${workspaceFolder}/build", //指定⼯作⽬录 "preLaunchTask": "compile", //在调试前会先调⽤这个task编译构建程序 "environment": [], "externalConsole": false, "osx": { //macOS的特定配置 // "miDebuggerPath": "/Applications//Contents/Developer/usr/bin/lldb-mi", //修改使⽤的lldb-mi,⼀般不需要修改 "MIMode": "lldb" //指定使⽤lldb进⾏调试 }, "linux": { //linux的特定配置 "MIMode": "gdb", //指定使⽤gdb调试 "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] }, "windows": { //windows的特定配置 "type": "cppvsdbg", //指定使⽤msvc进⾏调试 "program": "${workspaceFolder}/build/Debug/${workspaceFolderBasename}.exe", //指定C/C++程序位置 } } ]}F5是VSCode调试运⾏的默认快捷键,不需要额外配置,启动调试后的界⾯如下所⽰通过使⽤本地⼯具完成调试由于cmake在windows平台会默认⽣成Visual Stduio⼯程,所以也可以直接打开⽣成的解决⽅案,通过Visual Studio进⾏调试Mac平台可以使⽤cmake .. -GXcode命令指定⽣成XCode⼯程,然后通过XCode进⾏调试以上就是详解如何使⽤VSCode和CMake构建跨平台的C/C++开发环境的详细内容,更多关于VSCode CMake构建跨平台 C/C++开发环境的资料请关注其它相关⽂章!

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1690367924a339126.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信