注:本文同步發布於微信公眾號: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