CMake構建學習筆記16-使用VS進行CMake項目的開發(fā)
1. 概論
在之前的系列博文中,我們學習了如何構建第三方的依賴庫,也學習了如何去組建自己的CMake項目,尤其是學習了CMake的核心配置文件CMakeLists.txt如何編寫。長期以來,CMakeLists.txt這個文件都是C/C++項目額外編寫的,然后使用CMake指令或者GUI工具配置成Windows下的MSVC工程,或者Linux下的Makefile文件。這樣做雖然對比之前需要不同的平臺下要使用不同的工程有了長足的進步,但是還可以再進一步,那就是直接在IDE中使用CMake工程進行開發(fā),這樣無疑對C/C++程序開發(fā)的效率有質(zhì)的提升。
從Visual Studio 2017開始,Microsoft Visual Studio(簡稱VS)就開始支持CMake工程的導入。所謂CMake工程,指的就是不再需要建立傳統(tǒng)的MSVC項目,例如.sln或者.vcxproj工程文件,而是直接使用CMakeLists.txt作為工程配置文件來進行加載,進行進行構建和開發(fā)的工作。不僅是VS,目前其他IDE比如Visual Studio Code、Qt Creator、IntelliJ IDEA、 CLion都能直接支持CMake工程的導入。但是,作為初學者,筆者還是建議從Microsoft Visual Studio入手進行CMake項目的開發(fā),畢竟號稱宇宙第一的IDE不是白叫的。以筆者的觀點來看,Microsoft Visual Studio的確實有點重,編輯器也不是最美觀的,UI操作也不一定是最人性化的,但是其提供的調(diào)試功能卻是最優(yōu)秀且不可或缺的,尤其適合商業(yè)中的生產(chǎn)力環(huán)境。這里筆者就以Visual Studio 2019 為例,詳細講解一下如何進行CMake項目的開發(fā),以提升我們的C/C++程序開發(fā)效率。
2. 詳論
2.1 創(chuàng)建工程
啟動Visual Studio 2019,彈出的啟動頁面,如下圖1所示:

點擊右下方“創(chuàng)建新項目”按鈕,進入“創(chuàng)建新項目”頁面,如下圖2所示:

選擇“CMake項目”的模板,如果沒有看到可以搜索一下模板。點擊“下一步”按鈕,進入“配置新項目”頁面,如下圖3所示:

在“配置新項目”頁面填入項目名稱和位置,點擊“創(chuàng)建”按鈕,就進入了Visual Studio 2019的主要工作頁面,如下圖4所示:

2.2 加載工程
關閉Visual Studio 2019,模擬一下直接加載現(xiàn)有CMake工程的情況。再次啟動Visual Studio 2019,一般在圖1所示的啟動頁面中可以看到上次加載過的歷史記錄,點擊就可以再次進行加載了。但是如何沒有歷史記錄,就點擊“繼續(xù)但無需代碼”按鈕,直接進入主頁面。在菜單欄中依次選擇文件->打開->CMake按鈕,如下圖5所示:

此時會彈出“打開CMake項目”對話框,選中項目中的CMakeList.txt文件,CMake項目就是通過這個核心配置文件來打開的,如下圖6所示:

記住一定要通過這種方式打開CMakeList.txt文件才會打開CMake項目,如果直接將CMakeList.txt文件拖入到Visual Studio 2019主頁面中只會文本形式顯示CMakeList.txt。
2.3 配置文件
接下來再正式進行開發(fā)之前,我們需要先搞定一個配置文件CMakePresets.json。CMakeList.txt具有非常多的配置項,或者需要傳入的外部參數(shù),需要使用一個配置文件來進行管理。不過麻煩就麻煩在這里,CMakePresets.json是CMake 3.20引入的,是個相對較新的功能,Visual Studio 2019并沒有一開始就對接這個配置文件,而是使用自己設計的CMakeSettings.json文件作為CMake構建項目的配置。目前,這兩種配置文件Visual Studio 2019都支持,但是更推薦使用CMakePresets.json,因為更加標準化,符合CMake的規(guī)范,可以被多種IDE和構建工具識別和支持。
具體來說,如果程序主頁面,尤其是主頁面的工具欄與下圖7有所不同:

那么可以在菜單欄依次選擇工具->選項->CMake->常規(guī),勾選“首次使用CMake預設值進行配置、構建和測試”的單選框,如下圖8所示:

點擊工具欄的配置下拉菜單,選擇“管理配置”按鈕,如下圖9所示:

此時Visual Studio 2019就會自動創(chuàng)建CMakeSettings.json配置文件,如下圖10所示:

從這個文件可以看到默認的windows-default配置其實是Debug模式,我們可以將其增加一個RelWithDebInfo模式,也就是Release帶調(diào)試信息模式,CMakePresets.json具體的內(nèi)容為:
{
"version": 2,
"configurePresets": [
{
"name": "linux-default",
"displayName": "Linux Debug",
"description": "面向適用于 Linux 的 Windows 子系統(tǒng)(WSL)或遠程 Linux 系統(tǒng)。",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Linux" ] },
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" }
}
},
{
"name": "windows-default",
"displayName": "Windows x64 Debug",
"description": "面向具有 Visual Studio 開發(fā)環(huán)境的 Windows。",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
},
"vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Windows" ] } }
},
{
"name": "RelWithDebInfo",
"displayName": "Windows x64 RelWithDebInfo Shared Library",
"description": "面向具有 Visual Studio 開發(fā)環(huán)境的 Windows。",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
},
"vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Windows" ] } }
}
]
}
添加這段配置并Ctrl+S保存之后,工具欄的配置下拉菜單就會多了RelWithDebInfo這個選項,將其選中,如下圖11所示:

注意,有的時候因為兩種配置方式的沖突問題,會導致一些異常現(xiàn)象,比如工具欄的配置菜單不太一樣。如果遇到這種情況可以推出Visual Studio 2019,清理工程的中間生成文件,再重新加載工程試試。
2.4 工程配置
再接下來的步驟不要急著去編寫源代碼文件,要先完成CMakeLists.txt的編寫。新建工程的CMakeLists.txt會有一段默認的內(nèi)容,如下所示:
# CMakeList.txt: ZipTest 的 CMake 項目,在此處包括源代碼并定義
# 項目特定的邏輯。
#
cmake_minimum_required (VERSION 3.8)
project ("ZipTest")
# 將源代碼添加到此項目的可執(zhí)行文件。
add_executable (ZipTest "ZipTest.cpp" "ZipTest.h")
# TODO: 如有需要,請?zhí)砑訙y試并安裝目標。
如果我們學習過上一篇博文的話就會理解這段配置代碼文件,推薦讀者復習一下。這里要說的關鍵是,在修改CMakeLists.txt文件之后,需要Ctrl+S保存一下,Visual Studio 2019就會自動進行工程配置,可以在輸出窗口看到一些輸出信息:
1> 已為配置“RelWithDebInfo”啟動 CMake 生成。
1> 環(huán)境設置:
1> CommandPromptType=Native
1> DevEnvDir=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\
1> ExtensionSdkDir=C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs
1> Framework40Version=v4.0
1> FrameworkDir=C:\windows\Microsoft.NET\Framework64\
1> FrameworkDIR64=C:\windows\Microsoft.NET\Framework64
1> FrameworkVersion=v4.0.30319
1> FrameworkVersion64=v4.0.30319
1> HTMLHelpDir=C:\Program Files (x86)\HTML Help Workshop
1> IFCPATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\ifc\x64
1> IGCCSVC_DB=AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAggkwNDDGDkq0HFOUjEsXQAQAAAACAAAAAAAQZgAAAAEAACAAAADxjk35GiqLjZDHeYjx5dq8wxmbU7aEbBW9J68TO/bzIwAAAAAOgAAAAAIAACAAAADdM3gyHGrxXOwEEyHmxfe9ocZnP6CM0OTQGZYVZKgQWmAAAAC8xGVDuFoU062/gozauvaMPUmsT8FAuEXoLnI9lTwHVT6XWpjF7lVBoYB+vxo1dgIUAtW0nl1wZSUg9KRxmYpIicPPLm7B+twKXEdbaDMIu55E10uazKjjvoHY/4KYu+tAAAAAoK95FWIYAE3f+YLjfb3S77+ZMJXFw69cRlxyTYekzkyfOFdUcCY94ahV+XHEgao2y8e/zT+q2zHU0SqXho0LDQ==
1> INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\ATLMFC\include;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\include;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\cppwinrt
1> LIB=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\ATLMFC\lib\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\lib\x64;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.22000.0\ucrt\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.22000.0\um\x64
1> LIBPATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\ATLMFC\lib\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\lib\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\lib\x86\store\references;C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.22000.0;C:\Program Files (x86)\Windows Kits\10\References\10.0.22000.0;C:\windows\Microsoft.NET\Framework64\v4.0.30319
1> NETFXSDKDir=C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\
1> Path=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCPackages;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Team Tools\Performance Tools\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\devinit;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\\MSBuild\Current\Bin;C:\windows\Microsoft.NET\Framework64\v4.0.30319;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\windows\system32;C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;C:\windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\Program Files\HP\OMEN-Broadcast\Common;C:\Program Files\CMake\bin;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\TortoiseGit\bin;C:\Work\3rdparty\bin;C:\SoftWare\Qt\Qt5.12.5\5.12.5\msvc2017_64\bin;C:\File\MyGitHub\GISBasic\3rdParty\bin;C:\Program Files\dotnet\;C:\Work\eGova3rdParty\protobuf\bin;C:\Program Files\Java\jdk1.8.0_271\bin;C:\Program Files\KTX-Software\bin;C:\SoftWare\sonar-scanner-msbuild;C:\Program Files\Cppcheck;C:\SoftWare\sonar-scanner-msbuild\sonar-scanner-4.7.0.2747\bin;C:\SoftWare\apache-ant-1.10.8\bin;C:\Program Files (x86)\pcsuite\;C:\SoftWare\apache-maven-3.6.2\bin;C:\Program Files\7-Zip;C:\Program Files\Git\cmd;C:\SoftWare\nvm;C:\Program Files\nodejs;C:\SoftWare\Python\Python311\Scripts\;C:\SoftWare\Python\Python311\;C:\Users\Charlee\AppData\Local\Microsoft\WindowsApps;C:\Program Files\Microsoft VS Code\bin;C:\Users\Charlee\AppData\Local\GitHubDesktop\bin;C:\Users\Charlee\AppData\Roaming\npm;C:\SoftWare\nvm;C:\Program Files\nodejs;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\Linux\bin\ConnectionManagerExe
1> PROMPT=$P$G
1> UCRTVersion=10.0.22000.0
1> UniversalCRTSdkDir=C:\Program Files (x86)\Windows Kits\10\
1> VCIDEInstallDir=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\
1> VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\
1> VCToolsInstallDir=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\
1> VCToolsRedistDir=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Redist\MSVC\14.29.30133\
1> VCToolsVersion=14.29.30133
1> VS160COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\
1> VSCMD_ARG_app_plat=Desktop
1> VSCMD_ARG_HOST_ARCH=x64
1> VSCMD_ARG_no_logo=1
1> VSCMD_ARG_TGT_ARCH=x64
1> VSCMD_DEBUG=5
1> VSCMD_VER=16.11.29
1> VSINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\
1> WindowsLibPath=C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.22000.0;C:\Program Files (x86)\Windows Kits\10\References\10.0.22000.0
1> WindowsSdkBinPath=C:\Program Files (x86)\Windows Kits\10\bin\
1> WindowsSdkDir=C:\Program Files (x86)\Windows Kits\10\
1> WindowsSDKLibVersion=10.0.22000.0\
1> WindowsSdkVerBinPath=C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\
1> WindowsSDKVersion=10.0.22000.0\
1> WindowsSDK_ExecutablePath_x64=C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\
1> WindowsSDK_ExecutablePath_x86=C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\
1> __devinit_path=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\devinit\devinit.exe
1> __DOTNET_ADD_64BIT=1
1> __DOTNET_PREFERRED_BITNESS=64
1> __VSCMD_PREINIT_PATH=C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\windows\system32;C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;C:\windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\Program Files\HP\OMEN-Broadcast\Common;C:\Program Files\CMake\bin;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\TortoiseGit\bin;C:\Work\3rdparty\bin;C:\SoftWare\Qt\Qt5.12.5\5.12.5\msvc2017_64\bin;C:\File\MyGitHub\GISBasic\3rdParty\bin;C:\Program Files\dotnet\;C:\Work\eGova3rdParty\protobuf\bin;C:\Program Files\Java\jdk1.8.0_271\bin;C:\Program Files\KTX-Software\bin;C:\SoftWare\sonar-scanner-msbuild;C:\Program Files\Cppcheck;C:\SoftWare\sonar-scanner-msbuild\sonar-scanner-4.7.0.2747\bin;C:\SoftWare\apache-ant-1.10.8\bin;C:\Program Files (x86)\pcsuite\;C:\SoftWare\apache-maven-3.6.2\bin;C:\Program Files\7-Zip;C:\Program Files\Git\cmd;C:\SoftWare\nvm;C:\Program Files\nodejs;C:\SoftWare\Python\Python311\Scripts\;C:\SoftWare\Python\Python311\;C:\Users\Charlee\AppData\Local\Microsoft\WindowsApps;C:\Program Files\Microsoft VS Code\bin;C:\Users\Charlee\AppData\Local\GitHubDesktop\bin;C:\Users\Charlee\AppData\Roaming\npm;C:\SoftWare\nvm;C:\Program Files\nodejs
1> __VSCMD_script_err_count=0
1> HOMEPATH=\Users\Charlee
1> DriverData=C:\Windows\System32\Drivers\DriverData
1> COMPUTERNAME=LAPTOP-K38HMG48
1> CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
1> POSTGIS_GDAL_ENABLED_DRIVERS=ENABLE_ALL
1> ProgramW6432=C:\Program Files
1> OneDrive=C:\Users\Charlee\OneDrive
1> __PSLockDownPolicy=0
1> RegionCode=APJ
1> DEVECOSTUDIO_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\devecostudio.vmoptions
1> VisualStudioEdition=Microsoft Visual Studio Enterprise 2019
1> WEBIDE_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\webide.vmoptions
1> ServiceHubLogSessionKey=3AFDCD75
1> PROCESSOR_REVISION=b701
1> PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 183 Stepping 1, GenuineIntel
1> PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
1> PkgDefApplicationConfigFile=C:\Users\Charlee\AppData\Local\Microsoft\VisualStudio\16.0_36d14652\devenv.exe.config
1> JETBRAINS_CLIENT_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\jetbrains_client.vmoptions
1> PROJ_LIB=C:\Program Files\PostgreSQL\16\share\contrib\postgis-3.4\proj
1> CURL_CA_BUNDLE=C:\Program Files\PostgreSQL\16\ssl\certs\ca-bundle.crt
1> TMP=C:\Users\Charlee\AppData\Local\Temp
1> DATAGRIP_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\datagrip.vmoptions
1> TEMP=C:\Users\Charlee\AppData\Local\Temp
1> LOCALAPPDATA=C:\Users\Charlee\AppData\Local
1> PUBLIC=C:\Users\Public
1> eGova3rdParty=C:\Work\3rdparty
1> GDAL_DATA=C:\Program Files\PostgreSQL\16\gdal-data
1> PSModulePath=C:\Program Files\WindowsPowerShell\Modules;C:\windows\system32\WindowsPowerShell\v1.0\Modules
1> ProgramData=C:\ProgramData
1> JAVA_HOME=C:\Program Files\Java\jdk1.8.0_271
1> USERDOMAIN=LAPTOP-K38HMG48
1> platformcode=M7
1> PROCESSOR_LEVEL=6
1> NUMBER_OF_PROCESSORS=32
1> PHPSTORM_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\phpstorm.vmoptions
1> STUDIO_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\studio.vmoptions
1> VSAPPIDDIR=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\
1> ProgramFiles(x86)=C:\Program Files (x86)
1> FPS_BROWSER_USER_PROFILE_STRING=Default
1> CommonProgramFiles=C:\Program Files (x86)\Common Files
1> VS140COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\
1> USERDOMAIN_ROAMINGPROFILE=LAPTOP-K38HMG48
1> VisualStudioDir=C:\Users\Charlee\Documents\Visual Studio 2019
1> IGCCSVC_DB=AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAggkwNDDGDkq0HFOUjEsXQAQAAAACAAAAAAAQZgAAAAEAACAAAADxjk35GiqLjZDHeYjx5dq8wxmbU7aEbBW9J68TO/bzIwAAAAAOgAAAAAIAACAAAADdM3gyHGrxXOwEEyHmxfe9ocZnP6CM0OTQGZYVZKgQWmAAAAC8xGVDuFoU062/gozauvaMPUmsT8FAuEXoLnI9lTwHVT6XWpjF7lVBoYB+vxo1dgIUAtW0nl1wZSUg9KRxmYpIicPPLm7B+twKXEdbaDMIu55E10uazKjjvoHY/4KYu+tAAAAAoK95FWIYAE3f+YLjfb3S77+ZMJXFw69cRlxyTYekzkyfOFdUcCY94ahV+XHEgao2y8e/zT+q2zHU0SqXho0LDQ==
1> GISBasic=C:\File\MyGitHub\GISBasic\3rdParty
1> VSLS_SESSION_KEEPALIVE_INTERVAL=0
1> MAVEN_HOME=C:\SoftWare\apache-maven-3.6.2
1> ProgramFiles=C:\Program Files (x86)
1> RUBYMINE_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\rubymine.vmoptions
1> APPCODE_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\appcode.vmoptions
1> FPS_BROWSER_APP_PROFILE_STRING=Internet Explorer
1> VSSKUEDITION=Enterprise
1> OnlineServices=Online Services
1> ThreadedWaitDialogDpiContext=-4
1> IDEA_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\idea.vmoptions
1> WEBSTORM_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\webstorm.vmoptions
1> GOLAND_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\goland.vmoptions
1> NVM_SYMLINK=C:\Program Files\nodejs
1> NVM_HOME=C:\SoftWare\nvm
1> SESSIONNAME=Console
1> VisualStudioVersion=16.0
1> SystemRoot=C:\windows
1> CommonProgramW6432=C:\Program Files\Common Files
1> ZES_ENABLE_SYSMAN=1
1> LOGONSERVER=\\LAPTOP-K38HMG48
1> VSAPPIDNAME=devenv.exe
1> USERPROFILE=C:\Users\Charlee
1> MSBuildLoadMicrosoftTargetsReadOnly=true
1> QtMsBuild=C:\Users\Charlee\AppData\Local\QtMsBuild
1> POSTGIS_ENABLE_OUTDB_RASTERS=1
1> VSLANG=2052
1> RIDER_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\rider.vmoptions
1> APPDATA=C:\Users\Charlee\AppData\Roaming
1> HOMEDRIVE=C:
1> DATASPELL_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\dataspell.vmoptions
1> GATEWAY_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\gateway.vmoptions
1> CLION_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\clion.vmoptions
1> JETBRAINSCLIENT_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\jetbrainsclient.vmoptions
1> USERNAME=Charlee
1> PROCESSOR_ARCHITEW6432=AMD64
1> EFC_20336=1
1> PROCESSOR_ARCHITECTURE=x86
1> OS=Windows_NT
1> ComSpec=C:\windows\system32\cmd.exe
1> PYCHARM_VM_OPTIONS=C:\SoftWare\ideaI-windows\2023\vmoptions\pycharm.vmoptions
1> SystemDrive=C:
1> windir=C:\windows
1> ALLUSERSPROFILE=C:\ProgramData
1> 命令行: "C:\windows\system32\cmd.exe" /c "%SYSTEMROOT%\System32\chcp.com 65001 >NUL && "C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2019\ENTERPRISE\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe" -G "Ninja" -DCMAKE_BUILD_TYPE:STRING="RelWithDebInfo" -DCMAKE_INSTALL_PREFIX:STRING="C:/Work/ZipTest/out/install/RelWithDebInfo" -DCMAKE_MAKE_PROGRAM="C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2019\ENTERPRISE\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\Ninja\ninja.exe" "C:\Work\ZipTest" 2>&1"
1> 工作目錄: C:/Work/ZipTest/out/build/RelWithDebInfo
1> [CMake] -- Configuring done
1> [CMake] -- Generating done
1> [CMake] -- Build files have been written to: C:/Work/ZipTest/out/build/RelWithDebInfo
1> 已提取 CMake 變量。
1> 已提取源文件和標頭。
1> 已提取代碼模型。
1> 已提取工具鏈配置。
1> 已提取包含路徑。
1> CMake 生成完畢。
這個配置工程的步驟一定不能少,且要保證看到“CMake生成完畢”的提示。如果生成中斷的話,可以在輸出日志中看到出錯的地方并進行修改。本質(zhì)上來說,CMakeLists.txt只是個文本文件而已,要通過這一步將構建的環(huán)境準備好,生成一些緩存文件和中間文件,從而便于構建工具鏈識別進行下一步作業(yè)。
2.5 調(diào)試執(zhí)行
在保證CMake配置工程完畢之后,就可以進行調(diào)試運行了。這一步的功能就無縫對接MSVC項目了,例如編輯代碼,F(xiàn)7生成,F(xiàn)5調(diào)試,Ctrl+F5執(zhí)行,F(xiàn)9斷點,F(xiàn)10逐過程調(diào)試以及F11逐語句調(diào)試。不過有一點要注意,就是要選擇啟動項,不然可能無法運行項目。具體可以在工具欄的選擇啟動項下拉菜單中,如下圖12所示:

我們當然要選中ZipTest.exe這個目標,不過一定要注意,只有當CMake生成完畢以后才會出現(xiàn)這個選項。如果沒有這個選項,那就說明之前的CMake生成沒有成功。
另外一個很實用的功能是,在CMake生成成功以后,可以切換到CMake目標項目。具體通過“解決資源管理器視圖”的工具欄上的“在解決方案和可用視圖之間切換”按鈕進入,如下圖13所示:

這個視圖看起來有點像MSVC工程了,比文件夾視圖簡潔介多了。更重要的是由這個視圖的右鍵菜單功能更實用一點,比如“設為啟動項”按鈕也可以實現(xiàn)上面的選擇啟動項功能。另外還有“添加”功能,與MSVC項目的“添加”功能類似,可以新建源代碼文件加入到CMake工程中。不過這個功能是通過修改CMakeList.txt文件來實現(xiàn)的,讀者可以自己試用一下。

其實筆者感覺這個CMake目標視圖是想像MSVC工程一樣,集成更多的常用GUI操作的功能,使得開發(fā)編程的效率更高。不過目前這些還只是半成品,比如這個“添加”功能是可以實現(xiàn)源代碼文件的添加了,但是對應修改CMakeList.txt的內(nèi)容不一定是我們想要的,關于這一點讀者可以試用一段時間之后再領會。目前很多常用的IDE功能還是需要我們自己編輯CMakeList.txt文件來實現(xiàn),盡管如此,已經(jīng)可以幫助我們提升很大一部分開發(fā)效率了。
3. 項目案例
默認的Hello CMake案例還是太簡單了,我們還是將上一篇的調(diào)用libzip壓縮文件和文件夾的案例用上。項目目錄如下:
ZipTest
│ main.cpp
│ CMakeLists.txt
| CMakePresets.json
main.cpp的內(nèi)容如下:
#include <zip.h>
#include <filesystem>
#include <fstream>
#include <iostream>
using namespace std;
void CompressFile2Zip(std::filesystem::path unZipFilePath,
const char* relativeName, zip_t* zipArchive) {
std::ifstream file(unZipFilePath, std::ios::binary);
file.seekg(0, std::ios::end);
size_t bufferSize = file.tellg();
char* bufferData = (char*)malloc(bufferSize);
file.seekg(0, std::ios::beg);
file.read(bufferData, bufferSize);
//第四個參數(shù)如果非0,會自動托管申請的資源,直到zip_close之前自動銷毀。
zip_source_t* source =
zip_source_buffer(zipArchive, bufferData, bufferSize, 1);
if (source) {
if (zip_file_add(zipArchive, relativeName, source, ZIP_FL_OVERWRITE) < 0) {
std::cerr << "Failed to add file " << unZipFilePath
<< " to zip: " << zip_strerror(zipArchive) << std::endl;
zip_source_free(source);
}
} else {
std::cerr << "Failed to create zip source for " << unZipFilePath << ": "
<< zip_strerror(zipArchive) << std::endl;
}
}
void CompressFile(std::filesystem::path unZipFilePath,
std::filesystem::path zipFilePath) {
int errorCode = 0;
zip_t* zipArchive = zip_open(zipFilePath.generic_u8string().c_str(),
ZIP_CREATE | ZIP_TRUNCATE, &errorCode);
if (zipArchive) {
CompressFile2Zip(unZipFilePath, unZipFilePath.filename().string().c_str(),
zipArchive);
errorCode = zip_close(zipArchive);
if (errorCode != 0) {
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
std::cerr << zip_error_strerror(&zipError) << std::endl;
zip_error_fini(&zipError);
}
} else {
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
std::cerr << "Failed to open output file " << zipFilePath << ": "
<< zip_error_strerror(&zipError) << std::endl;
zip_error_fini(&zipError);
}
}
void CompressDirectory2Zip(std::filesystem::path rootDirectoryPath,
std::filesystem::path directoryPath,
zip_t* zipArchive) {
if (rootDirectoryPath != directoryPath) {
if (zip_dir_add(zipArchive,
std::filesystem::relative(directoryPath, rootDirectoryPath)
.generic_u8string()
.c_str(),
ZIP_FL_ENC_UTF_8) < 0) {
std::cerr << "Failed to add directory " << directoryPath
<< " to zip: " << zip_strerror(zipArchive) << std::endl;
}
}
for (const auto& entry : std::filesystem::directory_iterator(directoryPath)) {
if (entry.is_regular_file()) {
CompressFile2Zip(
entry.path().generic_u8string(),
std::filesystem::relative(entry.path(), rootDirectoryPath)
.generic_u8string()
.c_str(),
zipArchive);
} else if (entry.is_directory()) {
CompressDirectory2Zip(rootDirectoryPath, entry.path().generic_u8string(),
zipArchive);
}
}
}
void CompressDirectory(std::filesystem::path directoryPath,
std::filesystem::path zipFilePath) {
int errorCode = 0;
zip_t* zipArchive = zip_open(zipFilePath.generic_u8string().c_str(),
ZIP_CREATE | ZIP_TRUNCATE, &errorCode);
if (zipArchive) {
CompressDirectory2Zip(directoryPath, directoryPath, zipArchive);
errorCode = zip_close(zipArchive);
if (errorCode != 0) {
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
std::cerr << zip_error_strerror(&zipError) << std::endl;
zip_error_fini(&zipError);
}
} else {
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
std::cerr << "Failed to open output file " << zipFilePath << ": "
<< zip_error_strerror(&zipError) << std::endl;
zip_error_fini(&zipError);
}
}
int main() {
//壓縮文件
// CompressFile("C:/Data/Builder/Demo/view.tmp",
// "C:/Data/Builder/Demo/view.zip");
//壓縮文件夾
CompressDirectory("C:/Data/Builder/Demo", "C:/Data/Builder/Demo.zip");
return 0;
}
CMakeLists.txt的內(nèi)容如下:
# 輸出cmake版本提示
message(STATUS "The CMAKE_VERSION is ${CMAKE_VERSION}.")
# cmake的最低版本要求
cmake_minimum_required (VERSION 3.9)
# 工程名稱、版本、語言
project (ZipTest VERSION 0.1 LANGUAGES CXX)
# cpp17支持
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找依賴庫
find_package(libzip REQUIRED)
# 將源代碼添加到此項目的可執(zhí)行文件。
add_executable (${PROJECT_NAME} "main.cpp")
# 鏈接依賴庫
target_link_libraries(${PROJECT_NAME} PRIVATE libzip::zip)
CMakePresets.json的內(nèi)容如下:
{
"version": 2,
"configurePresets": [
{
"name": "linux-default",
"displayName": "Linux Debug",
"description": "面向適用于 Linux 的 Windows 子系統(tǒng)(WSL)或遠程 Linux 系統(tǒng)。",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Linux" ] },
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" }
}
},
{
"name": "windows-default",
"displayName": "Windows x64 Debug",
"description": "面向具有 Visual Studio 開發(fā)環(huán)境的 Windows。",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
},
"vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Windows" ] } }
},
{
"name": "RelWithDebInfo",
"displayName": "Windows x64 RelWithDebInfo Shared Library",
"description": "面向具有 Visual Studio 開發(fā)環(huán)境的 Windows。",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
},
"vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Windows" ] } }
}
]
}
請務必注意,我們這里使用的是CMake比較推薦和比較新的目標鏈接機制來引入libzip庫,關于這一點請務必復習上一篇博文的內(nèi)容。這里要說的是如果find_package(libzip REQUIRED)失敗,那么可能需要指定依賴庫的安裝目錄,具體是在CMakePresets.json文件中的RelWithDebInfo配置中增加CMAKE_PREFIX_PATH,筆者這里使用的GISBasic環(huán)境變量指向的目錄。至于libzip如何構建安裝?可以參考本系列之前的博文。
{
"name": "RelWithDebInfo",
"displayName": "Windows x64 RelWithDebInfo Shared Library",
"description": "面向具有 Visual Studio 開發(fā)環(huán)境的 Windows。",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CMAKE_PREFIX_PATH": "$env{GISBasic}",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [
"Windows"
]
}
}
}
4. 總結
好了,使用Visual Studio 2019進行CMake項目的開發(fā)的步驟和注意事項就是以上內(nèi)容了。其實筆者也很想使用Visual Studio 2022甚至更新的版本來進行CMake項目的開發(fā),不過受限于工作的環(huán)境沒有進行升級。如果有試用的讀者歡迎進行留言,看看與Visual Studio 2019對比有哪些區(qū)別或者提升。

浙公網(wǎng)安備 33010602011771號