Rust 프로젝트의 GiitHub Actions에서 increamental build 기술 수행

Rust의 구축 시간은 프로그램 언어에서 비교적 긴 편이지만,incremental build을 잘 사용할 수 있다면 구축 시간을 단축할 수 있습니다.로컬에서 개발할 때 아무것도 원하지 않아도 incremental build이 되지만 CI에서 incremental build를 진행하기 위해서는 많은 노력이 필요합니다.이 글은 그 기교를 소개한다.

TL;DR


  • actions/cachegit-restore-mtime 명령을 조합하면 CI를 통해incremental build를 진행할 수 있습니다.
  • release build로incremental을 구축하려면on에incremental flag를 덮어써야 합니다.
  • Rust 프로젝트 캐시 설정


    Giithub Actionsactions/cache에서 절차를 사용하면 구축 시 자산을 캐시하고 구축 시간을 단축할 수 있다.
    일반적인 Rust 프로젝트 설정은 다음과 같습니다.
    - uses: actions/cache@v2
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    
    ref: https://github.com/actions/cache/blob/main/examples.md#rust---cargo
    이 설정을 사용하면 외부 의존 Crate 구문을 건너뛸 수 있지만 창고의 코드 구문은 완전합니다.일정 규모 이상의 프로젝트라면 이 구축 기간이 상당히 길어져 문제가 될 수 있다.
    Rust의 구축과 관련된 생성물은 모두 target 이하에서 생성됩니다. 위의 설정은 starget 이하를 완전히 캐시하는 것입니다.incremental build이 작동하지 않는 것은 이상합니다.왜 캐시만 있으면 완전한 구축이 될까요?

    시간 문제


    실제로 Rust는 파일의 mtime 타임 스탬프 (최종 업데이트 시간) 를 보고 재구성인지 캐시를 사용하는지 판단합니다.이것은 이미 구축된 코드를 바탕으로 특정 파일에서 터치 재구축을 하면 터치 파일의 재구축은 실행을 통해 확인할 수 있다.
    한편, github actions에서clone 창고에 있을 때 실제 파일의 시간 스탬프는 저장되지 않았다.이것은 원래git파일 타임 스탬프가 저장되지 않았습니다.이었기 때문에 당연한 것이다.즉, github actions가 실행될 때마다 Repository 내의 모든 파일의 업데이트 시간은 이 작업 내clone 시간으로 바뀐다.
    github actions에서 모든 파일의 업데이트 시간 (mtime) 은 clone 이후의 시간입니다. 그 시간은 당연히 이전에 구축된 캐시 시간보다 업데이트됩니다.모든 소스 코드의 업데이트 시간은 캐시 업데이트 시간보다 새롭기 때문에 캐시를 사용할 수 없고 모든 구축이 실행됩니다.

    mtime 복원(git-restore-mtime)


    그러면 파일의 업데이트 시간 스탬프를 구축 사이에 완벽하게 일치시킬 수 있는 방법이 없다면, 사실 매우 편리한 스크립트가 있다.바로 git-restore-mtime입니다.이 스크립트는git의commiit 로그에서 그 파일이 마지막으로 제출된 시간에 mtime를 강제로 수정합니다.구축하기 전에 이 동작을 실행하면github actions에서increamental build을 실행할 수 있습니다.
    이 스크립트를 창고에 복사하고 다음 절차에 따라 실행하면 제출 기록을 기반으로 하는 mtime를 복구할 수 있습니다.(ptyhon 스크립트이기 때문에 필요에 따라 setup-ptyhon 절차 등도 함께 사용하세요)
    - name: Install Python
      uses: actions/setup-python@v2
    - name: Restore mtime
      run: python ./git-restore-mtime.py
    
    이외에git의commiithistory에서 mtime를 회복하기 위해git의모든history가 필요합니다.fetch의 모든history를 사용하려면 다음과 같이 actions/checkkout 옵션을 사용하여shallow clone을 무효화해야 합니다.
    - name: Clone repository
      uses: actions/checkout@v2
      with:
        fetch-depth: 0 # 0 にすると全履歴を fecth するようになります。
    
    (history가 너무 긴 창고라면 전부가 아니더라도 충분한 값으로 만들면 충분하다.)
    이상의 설정은github actions에서incremental build도 작용할 수 있습니다.

    보충1:release 소개


    CI에서 release profile로 구축 테스트를 진행하는 경우가 있다고 생각합니다.release 프로필의 경우 기본increamental 모드가 비활성화되었습니다(ref:https://doc.rust-lang.org/cargo/reference/profiles.html#release. 따라서release 프로필에서increamentalbuild을 사용하려면 로고를 진실에 명확하게 덮어야 합니다.
    구성 파일의 기본값을 변경할 수 있다면 카고.toml로 다음 내용을 덮어쓸 수 있습니다.
    [profile.release]
    incremental = true
    
    기본 행동을 바꾸지 않고 CI에서만 incremental build을 사용하려면 CARGO_INCREMENTAL 환경 변수를 설정하면 로고를 덮어쓸 수 있습니다.
    jobs:
      build:
        env:
          CARGO_INCREMENTAL: 1
    

    보충2:mac 중 캐치 파손 문제


    GiitHub Action의 Mac runner에 표준으로 설치된 BSD tar가 일부 파일(libserde derive.dylib 등)을 올바르게 압축하거나 압축하지 못하는 것으로 알려진 문제actions/cache#403
    위의 issue에서 논의한 바와 같이 이 문제를 피하기 위해서는 다음과 같이 설정된 GNUtar를 설치해야 한다.
    # Work around https://github.com/actions/cache/issues/403 by using GNU tar
    # instead of BSD tar.
    - name: Install GNU tar 
      if: matrix.os == 'macos-latest'
      run: |
        brew install gnu-tar
        echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
    
    matrix.os == 'macos-latest'의 부분은 각자의 환경에 따라 개작하십시오.)
    위의 설정에 GNUtar를 설치하면 actions/cache는 자동으로 GNUtar를 선택하여 GNUtar로 압축과 해동을 합니다.
    앞으로 표준 GNUtar는 Mac runner에 설치될 것이다. 상술한 문제는 자연적으로 해결될 것 같지만 모든 Mac 이미지가 변경된 것은 아니다. 필자의 환경(denoland/deno)에서 위의 업무 복습이 필요하다.

    총결산


    git-restore-mtime 스크립트를 사용하여github actions에서increamental build를 사용하는 설정을 소개합니다.

    좋은 웹페이지 즐겨찾기