node-gyp的作用我已經不想贅述了,這里給一個我之前文章的鏈接:cnblogs看這里,知乎看這里。本文主要從源碼入手,介紹node-gyp查找VisualStudio的過程
為了方便我們研究node-gyp的源碼,我們隨意創建一個node項目,然后我們npm install node-gyp,安裝node-gyp這個包來開始我們源碼探索之路吧。
E:\Projects\node-gyp-demo> npm init
...
package name: (gyp-demo)
version: (1.0.0)
...
npm install node-gyp@latest // 安裝最新的node-gyp
安裝完成后,在項目/node_modules/node-gyp中,已經有了我們需要的node-gyp的js腳本代碼:
那么,我們應該怎么入手呢?這里需要再次提到node-gyp的處理過程,主要分為兩個步驟:
- configure
gyp首先根據C/C++源碼目錄下的binding.gyp文件+操作系統(Windows、macOS以及Linux)+編譯構建工具(Windows下的VS,macOS以及Linux下的make)來決定生成什么樣的項目結構(Windows下的sln以及vcxproj、macOS以及Linux下的make項目)這一步是configure配置過程,不會進行源碼的編譯,僅僅是生成能夠作為對應平台下對應編譯工具輸入的項目結構。
- build
生成項目結構以后,執行build過程調用對應的編譯工具完成編譯任務。
所以,我們首先查看lib/configure.js文件,試着從源碼中探索一下。進入configure.js,一下就可以看到我們期望的東西(圖片頂部顯示了js代碼位置):
如果當前進程平台是win32
(Windows操作系統標識),則會引入模塊find-visualstudio
。暫時停止閱讀configure.js的代碼,直接上我們的主角:find-visualstudio.js
find-visualstudio.js
在該文件中定義了一個名為VisualStudioFinder
的類,查找的過程就是執行創建該類的一個實例,並調用實例的一個名為findVisualStudio
的方法。該方法被定義在該類的原型里:
對於該函數來說,主要分為了三個步驟:
- 對於參數msvs_version的處理
- 對於環境變量VSINSTALLDIR的處理
- 查找各個版本的VS
對於步驟1和2,我們暫時不進行解析,主要解析步驟3。因為絕大多數開發者就卡在這個步驟,導致安裝需要原生編譯的node模塊失敗。對於步驟3來說,我們不難看出處理的過程是優先查找本地的vs2017以及更高的版本,然后是vs2015,最后是vs2013,所以開發者Windows機器上沒有安裝VS或者是不在源碼中支持的范圍都一定會報錯,提示VS找不到。我們首先解析findVisualStudio2017OrNewer
這個函數,然后解析findVisualStudio2015
和findVisualStudio2013
,對於后兩個,實際上最終都是相同的邏輯,后面會提到。
findVisualStudio2017OrNewer
該函數的簽名表示,這個函數是通過調用PowerShell腳本來獲取關於VS2017或是更高版本VS的安裝信息。
那么這段代碼的運行情況到底如何呢?我們將該段代碼單獨拿出來,並將Find-VisualStudio.cs
拷貝到運行目錄下來Debug它。
上圖中,我模擬了node-gyp中查詢VS2017以上版本的函數,通過Debug方式斷點調試:
ps
變量值為:C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe
,即為Windows下對應的最初版本的PowerShell。cs文件不再贅述,我們也不對CSharp代碼解讀了。代碼的最后就是執行弄得的chile_process模塊中的execFile
函數,通過傳入可執行程序的完整路徑已經執行參數,完成外部程序調用。
而在這一步當中,如果執行出現了異常就會導致node-gyp的執行過程出現異常,進而導致需要原生編譯的模塊無法完成安裝等。為了方便開發人員進行在Windows上查找VS2017以及以上版本,我把這段代碼和CSharp代碼提取出來,放在了github倉庫(w4ngzhen/node-gyp-find-vs-check),讀者如果出現了問題,可以直接下載腳本和CSharp代碼進行環境的確認。
當然,有些讀者的機器還是VS2015或者VS2013等版本,我們繼續分析。
findVisualStudio2015/2013
通過源碼可以知道,最終都調用了方法:findOldVS
,並且還知道,nodejs的主版本大於等於9時,根本不會查找VS了。接下來我們查看方法findOldVs
:
對於該段代碼,其實一點也不難理解,就是根據注冊表上對應的鍵去查找的VS的安裝路徑(PS:好像又學習到了VS的安裝路徑可以從注冊表里面查看呢!)對於該段代碼,本人不提供demo代碼幫助查詢了。有興趣的讀者可以自己提取代碼,模擬調用。