UE4命令列編譯工程入門
注:本文同步釋出於微信公眾號:stringwu的網際網路雜談UE4命令列編譯工程入門
0 背景
筆者是個UE4的小白,本文主要記錄了一個小白是如何從零UE4的基礎,一步步在命令列打出iOS的ipa包的嘗試過程,本文比較淺,適合小白做為UE4工程的入門資料(UE大神可自動忽略本文);
1構建流程
UE4工程的構建會涉及以以下幾個步驟:
- 編譯所有的原始碼;
- 將所需的內容轉化(cook)為目標平臺可使用的格式;
- 將編譯後的程式碼和經過
cook
的內容打包成一組可釋出的檔案,如apk,ipa等;
一般使用UAT(Unreal Automation Tool)
工具來通過一系列的指令碼程式來構建UE4專案,整個打包過程最重要的命令為BuildCookRun
BuildCookRun
打包命令最核心的幾個部分:
- 構建(Build) :將為所選擇的平臺編譯可執行的檔案;
- 烘培(Cook):通過在特殊模式下執行編輯器來轉化資源(把引擎使用的內容格式轉化為執行平臺可支援的內容格式);
- 暫存(Stage):通過將可執行檔案和內容複製到暫存區,它是開發目錄以外的獨立目錄;
- 打包(Package):將專案打包成平臺原生的分發格式;
- 部署(Deploy): 將構建版本部署到目標裝置;
- 執行(Run):該階段在目標平臺上啟動已封裝的專案;
1.1 Cook
UE引擎使用的資源以特定格式來儲存的,如png格式儲存紋理資料,wav格式儲存音訊,但UE引擎使用的內容格式可能沒有辦法在對應的目標執行平臺使用(如iOS,Android等),因此對於這些目標平臺來說,
必須要先轉化所有這些內容後,才能在對應的裝置上正常使用。
Cook
時有兩種模式可以供選擇
- 常規(by the cook):提前執行
cook
過程,這樣構建出的版本可一次性部署轉化後的資源,一般可在效能測試或可行性測試時使用該方法; - 動態(on the fly): 將
cook
過程推遲到遊戲被部署到對應平臺之後,這種方式只需要安裝可執行檔案和部分其他檔案,並在與轉化伺服器之間的通訊時按需請求,命令列使用的引數為-cookonthefly
2 打包方式
UE4工程可以通過兩種方式來進行打包:
- 通過編輯器的
File->Package Project->targetPlatform
選單來打出對應平臺的可執行的安裝包 - 通過
BuildCookRun
但不管是用哪種方式進行打包,都需要提前在專案設定
選單裡設定好對應平臺的配置(Project Setting->Platforms
);通過在編輯器選單進行打包的操作沒有其他特殊的邏輯,接下來著重來講一下通過BuildCookRun
命令來打包的過程與注意事項;
2.1BuildCookRun命令打包
一個最簡單的使用BookCookRun
命令來打包iOS
平臺上的安裝包示例:
sh [UE4Root]/Engine/Build/BatchFiles/RunUAT.sh BuildCookRun -project=ProjectName.uproject -clientconfig=Development -targetplatform=IOS
但筆者在剛從遠端拉下來的工程程式碼裡執行這個指令碼,發現這個命令會執行失敗,會報一些依賴的Plugin
找不到等錯誤,但為啥會失敗呢?明明也是按照官方文件和網上的操作教程來執行的。
在遇到這個問題後,筆者在本地做了若干的嘗試(更改指令碼的各種引數),發現引數的修改都不管用,直到發現如果在本地用UE
的編輯器開啟過這個工程時,這個命令就可以正常構建出iOS
的ipa
包時。
發現這個成功的case後,筆者就開始思考為啥用編輯器開啟過工程就可以成功呢?難道是編輯器要開啟工程時做了一些初始化的操作嗎?帶著這個疑問,筆者在經歷了幾次刪除工程又拉取工程的迷之操作後,發現用編輯器開啟一個新工程時,會經歷過一次rebuild
的操作,應該就是這個rebuild
操作幫忙做了一些初始化的工作。那rebuild
操作對應的命令列命令是什麼呢?
帶著這個疑問,筆者去搜索了一些文件,並在請教了一個有經驗的大佬,大佬指點說在構建前需要用引擎指令碼GenerateProjectFiles
重編一下整體工程,然後再執行構建的指令碼就可以,聽到這裡時,筆者心想原來這麼簡單的,於是就三下五除二,寫下了如下的構建指令碼
enginePath="/Users/Shared/Epic Games/UE_4.27/Engine/"
echo "${enginePath}"
echo $projectPath
#找到引擎在對應編譯平臺的指令碼
buildToolPath="${enginePath}Build/BatchFiles/Mac"
sh "${buildToolPath}/GenerateProjectFiles.sh" -project="${kk}/ProjectName.uproject"
sh "${enginePath}Build/BatchFiles/RunUAT.sh" BuildCookRun -nocompileeditor -nop4 -project="${projectPath}/ProjectName.uproject" -cook -clean -stage -archive -archivedirectory="${projectPath}/Binaries/" -package -clientconfig=Development -ue4exe=UE4Editor -pak -prereqs -nodebuginfo -targetplatform=IOS -build -utf8output
一頓操作猛如虎,結果卻依然是失敗的,但這次指令碼執行報的錯跟前面的不一樣了,報的錯為can not found ProjectName.module
,感覺有進步的空間。在嘗試在Google搜尋了關鍵的錯誤資訊後,找到一個回答是說引數沒帶對,不應該帶-nocompileeditor
的引數,筆者心想“那我去掉這個引數不就萬事大吉了嗎?“ 於是去掉了這個引數後,再次執行這個指令碼,發現還是指令碼執行錯誤,iOS
的包還是沒能打出來,不過在對比執行前後的工程目錄檔案裡,發現有個關鍵的變化,雖然想要的包沒有打出來,但Binaries
目錄下出現了一個Mac
的資料夾,而這個資料夾跟用UE4
的編輯器開啟工程時生成的一模一樣,看到這裡的時候,就心想,有了這個目錄不就是相當於用編輯器開啟過這個工程了嗎?那我再執行一個類似的命令是不是就可以成功了呢?於是修改了下關鍵的構建指令碼:
enginePath="/Users/Shared/Epic Games/UE_4.27/Engine/"
echo "${enginePath}"
projectPath=`pwd`
echo $projectPath
buildToolPath="${enginePath}Build/BatchFiles/Mac"
rm -df "${projectPath}/Binaries/"
sh "${buildToolPath}/GenerateProjectFiles.sh" -project="${kk}/ProjectName.uproject"
echo "GenerateProjectFiles project success*********************************"
sh "${enginePath}Build/BatchFiles/RunUAT.sh" BuildCookRun -nop4 -project="${projectPath}/ProjectName.uproject" -cook -stage -archive -archivedirectory="${projectPath}/Binaries/" -package -clientconfig=Development -ue4exe=UE4Editor -pak -prereqs -nodebuginfo -targetplatform=IOS -build -utf8output
echo "***********************************************************"
sh "${enginePath}Build/BatchFiles/RunUAT.sh" BuildCookRun -nocompileeditor -nop4 -project="${projectPath}/ProjectName.uproject" -cook -clean -stage -archive -archivedirectory="${projectPath}/Binaries/" -package -clientconfig=Development -ue4exe=UE4Editor -pak -prereqs -nodebuginfo -targetplatform=IOS -build -utf8output
echo "********************"
再次執行修改後的指令碼,發現可以成功執行,並正常生成了iOS
的ipa
包,這個指令碼的關鍵點為:
- 呼叫
GenerateProjectFiles
指令碼生成專案的一些依賴檔案; BuildCookRun
命令不帶-nocompileeditor
,執行類似於用編輯器開啟工程的編譯操作;BuildCookRun
命令帶-nocompileeditor
,執行構建安裝包的操作;
驗證發現指令碼打出來的包跟用編輯器的檔案選單裡的打包選項打出來的包沒區別後,就先用這個指令碼把專案的自動化跑起來了。但這個指令碼雖然可以正常執行,但一直感覺有點怪,畢竟執行了兩次BuildCookRun
命令,帶著這個疑問,筆者又繼續踏上了探索自動化編譯UE工程的路程(不斷在搜尋引擎中換搜尋關鍵字,看大家的一些思路)。
在看了很多國內很多類似的水文之後,終於找到了一個真正有價值的英文文章使用UAT自動化部署UE工程,這篇文章指出了自動化部署UE工程的關鍵步驟:
- 使用UBT(Unreal Build Tool)工具編譯對應工程的Editor;
- 使用UAT工具編譯對應工程,生成對應平臺的安裝包;
為什麼會需要先使用UBT
工具去編譯對應工程的Editor呢?因為僅僅使用UAT
工具去編譯工程的話,會因為工程缺少一些關鍵的依賴而編譯失敗,而UBT
工具會幫忙建立當前UE4
工程依賴的連結庫,在對應的連結庫建立成功後,再去執行工程的編譯邏輯。這也解釋了前面如果用編輯器開啟過UE4
工程後,BuildCookRun
命令就可以執行成功的的現象,反之則不行。
最終我們的指令碼就調整為:
#UE引擎的路徑
enginePath="/Users/Shared/Epic Games/UE_4.27/Engine/"
echo "${enginePath}"
projectPath=`pwd`
echo $projectPath
buildToolPath="${enginePath}Build/BatchFiles/Mac"
rm -df "${projectPath}/Binaries/"
#ProjectName為對應工程的名字
sh "${buildToolPath}/Build.sh" ProjectNameEditor Mac Development "${projectPath}/ProjectName.uproject" --WaitMutex
echo "***********************************************************"
sh "${enginePath}Build/BatchFiles/RunUAT.sh" BuildCookRun -nocompileeditor -nop4 -project="${projectPath}/ProjectName.uproject" -cook -clean -stage -archive -archivedirectory="${projectPath}/Binaries/" -package -clientconfig=Development -ue4exe=UE4Editor -pak -prereqs -nodebuginfo -targetplatform=IOS -build -utf8output
echo "********************"
#最終打出來的包在"${projectPath}/Binaries/IOS/"目錄下
附錄
BuilcCookRun
命令的一些引數解析
- build :執行編譯構建
- tagetplatform:打包的目標平臺,如IOS,Android,Mac,Win64等;
- nodebuginfo:不拷貝除錯資訊檔案到Stage目錄,也就是最終打出來的包中不包含除錯資訊;
- prereqs: 將所有依賴打包到一起
- pak:將資原始檔打包到pak檔案中;
- clientconfig:構建包的型別:
- Development
- Shipping:釋出包
- package :執行打包(Android->apk,iOS->ipa)
- archivedirectory: 歸檔目錄
- archive: 將構建結果歸檔
- stage :儲存構建過程中的中間結果
- clean: 在構建之前擦除intermediate資料夾,重新完整構建
- cook: 使用cook資源
- project: 需要打包的工程
- nop4 :禁用Perforce功能
- ForceDebugInfo :在非debug版本中加入debugwwyth