GitLab 的 C++ CI/CD 腳本:使用 PowerShell


之前已經在《GitLab 簡單的 C++ 專案腳本範例》這篇文章裡面,大概整理了一下 Heresy 這邊針對自己的 C++ 專案、撰寫出來的 GitLab CI 自動建置的腳本了。

不過,當時在 Windows 平台下,Heresy 是使用「Windows Batch」(CMD)這個 shell 來進行操作的。

但是,GitLab 官方其實有說,從 11.11 開始,就將「Windows Batch executor」設定為棄用(deprecated),並將於 13.0 時移除(預計時間是 2020/06/22);而取而代之的,GitLab 將使用 PowerShell 來作為 Windows 上預設的 shell。(參考

而這篇記錄,就是簡單地記錄一下 Heresy 把之前 cmd 的 script、改寫成 PowerShell 版本的紀錄。


Runner

理論上,Windows 上如果用最新版的 GitLab Runner 來設定一台新的 GitLab Runner,在選擇 shell 模式的情況下,預設就會是使用 PowerShell 來執行了。

而針對既有的 GitLab Runner 呢,則就需要手動去修改設定了。

修改的方法,基本上就是以純文字檔編輯器去開啟「config.toml」(在 Windows 環境應該會跟 gitlab-runner.exe 在一起),然後找到「runners」的區段,加入「shell」的設定了。

官方文件中,也有提供對應的範例:

...
[[runners]]
  name = "shell executor runner"
  executor = "shell"
  shell = "powershell"
...

在修改完後,只要再讓 GitLab Runner 重新執行,就可以讓修改生效了。

要重新執行 gitlab-runner.exe 的話,只要用系統管理者權限,執行

.\gitlab-runner.exe restart

就可以了。


.gitlab-ci.yml

在 yaml 腳本的部分,由於流程沒有變,所以大致上都可以沿用之前的腳本。

但是,有兩個地方必須要針對更換 shell 做對應的修改:

  • 切換字碼
  • 設定 Visual C++ 的環境

切換字碼

首先,在切換字碼的部分,在使用 cmd 作為 shell 的時候,只要執行「CHCP 65001」就可以了。但是這個指令在 PowerShell 下,似乎不能解決問題。

後來查了一下資料,最後是採用下面的指令:

[System.Console]::OutputEncoding = [System.Console]::InputEncoding = 
[System.Text.Encoding]::UTF8

透過這個指令,可以把 console 輸入、輸出的編碼都設定成 UTF-8;如此一來 GitLab 抓到的紀錄就能正常顯示中文了。

(這個指令哪抄來的已經忘了 ^^")


Visual C++ 環境變數

在設定 Visual C++ 需要的環境變數的時候,微軟提供的是一個 batch 檔,所以當使用 cmd 做 shell 的時候,只要執行

'call "c:\progra~2\MICROS~1\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'

就可以了。

但是這樣的指令在 PowerShell 一樣是沒有用的。

後來又找了好一陣子資料,最後是決定參考《How to use vcvars64.bat from Powershell?》這串討論裡面,Tyler Denniston 所提供的腳本:

if ($env:APPVEYOR_BUILD_WORKER_IMAGE -eq "Visual Studio 2015") {
  cmd.exe /c "call `"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd`" /x64 && call `"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat`" x86_amd64 && set > %temp%\vcvars.txt"
} else {
  cmd.exe /c "call `"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat`" && set > %temp%\vcvars.txt"
}

Get-Content "$env:temp\vcvars.txt" | Foreach-Object {
  if ($_ -match "^(.*?)=(.*)$") {
    Set-Content "env:\$($matches[1])" $matches[2]
  }
}

他的概念就是先把本來 vcvars64.bat 要設定的環境變數,輸出成一個名為 vcvars.txt 的純文字檔,然後再透過 PowerShell 的 script 來讀取他,並透過 Set-Content 來設定環境變數。

這邊針對這個腳本,則可以在簡化一點,把前面判斷的部分拿掉,會更為簡單。


最後,如果只看「build-windows」 這個工作的話,他的腳本就變成:

.powershell_encoding:
  before_script:
  - "[System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8" # Set as UTF-8

build-windows:
  stage: build
  extends: .powershell_encoding
  variables:
    GIT_SUBMODULE_STRATEGY: none
  script:
  - git submodule sync --recursive
  - git submodule update --recursive --init --remote external
  - cmd.exe /c "call `"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat`" && set > vcvars.txt" # Generate VC env-settings
  - Get-Content "vcvars.txt" | Foreach-Object { if ($_ -match "^(.*?)=(.*)$") { Set-Content "env:\$($matches[1])" $matches[2] } } # Apply VC env settings
  - msbuild.exe /m /property:Configuration=Release
  tags:
  - msvc

目前這個腳本在 Heresy 這邊是可以正常運作的。
不過,當然他還有很多改善空間。

目前想到之後還可以、或是可能需要修改的地方,包括了:

  • 編譯出來的檔案要怎麼傳遞給測試階段。
    感覺上,應該比較適合用 cache 來做?(參考

  • 目前 Visual C++ 的環境變數設定的 bat 檔是寫死的,但是根據 GitLab Runner 裝的版本的不同,路徑可能會不一樣;所以在有多台不同配置的 runner 的情況下,有可能會出現找不到檔案的問題。
    目前想到的解法,是在 Runner 上把路徑設定成一個特別的環境變數,在執行腳本的時候就透過環境變數去取得路徑。

  • 在 GitLab 12 的時候,針對 CI/CD 的 job log 加入了折疊/展開的功能(參考)。
    他基本上是預設就可以直接用的,但是個人總覺得他的摺起來的方法和想像的不太一樣?這部分還不知道有沒有辦法手動進行控制。

廣告

對「GitLab 的 C++ CI/CD 腳本:使用 PowerShell」的想法

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.