Windows에서 규칙 작성

문제 신고 소스 보기

이 페이지에서는 Windows 호환 규칙 작성, 이동식 규칙 작성 시 발생하는 일반적인 문제 및 해결 방법을 중점적으로 설명합니다.

경로

문제:

  • 길이 제한: 최대 경로 길이는 259자(영문 기준)입니다.

    Windows는 더 긴 경로 (최대 32,767자)도 지원하지만 많은 프로그램은 최저값으로 빌드됩니다.

    작업 중에 실행하는 프로그램에 유의합니다.

  • 작업 디렉터리: 최대 259자(영문 기준)로 제한됩니다.

    프로세스는 259자(영문 기준)가 넘는 디렉터리로 cd할 수 없습니다.

  • 대소문자 구분: Windows 경로는 대소문자를 구분하지 않고, Unix 경로는 대소문자를 구분합니다.

    작업의 명령줄을 만들 때 이 점에 유의하세요.

  • 경로 구분자: 백슬래시 (\`), not forward slash (/`)입니다.

    Bazel은 / 구분자를 사용하여 Unix 스타일의 경로를 저장합니다. 일부 Windows 프로그램은 Unix 스타일 경로를 지원하지만 다른 프로그램은 지원하지 않습니다. cmd.exe에 내장된 일부 명령어에서는 이러한 명령어를 지원하지만 일부는 지원하지 않습니다.

    작업을 위한 명령줄 및 환경 변수를 만들 때는 항상 \` separators on Windows: replace/with` 를 사용하는 것이 가장 좋습니다.

  • 절대 경로: 슬래시 (/)로 시작하지 않습니다.

    Windows에서 절대 경로는 드라이브 문자로 시작합니다(예: C:\foo\bar.txt). 단일 파일 시스템 루트는 없습니다.

    규칙에서 경로가 절대 경로인지 확인하는 경우 이 점에 유의하세요. 절대 경로는 이동이 불가능한 경우가 많으므로 피해야 합니다.

해결 방법:

  • 경로를 짧게 유지합니다.

    긴 디렉터리 이름, 복잡하게 중첩된 디렉터리 구조, 긴 파일 이름, 긴 작업공간 이름, 긴 대상 이름은 사용하지 않습니다.

    이 모두가 작업 입력 파일의 경로 구성요소가 될 수 있으며 경로 길이 제한을 소진할 수 있습니다.

  • 짧은 출력 루트를 사용합니다.

    --output_user_root=<path> 플래그를 사용하여 Bazel 출력의 짧은 경로를 지정합니다. Bazel 출력 (예: D:\`), and adding this line to your.bazelrc` 파일)만을 위한 드라이브 (또는 가상 드라이브)를 만드는 것이 좋습니다.

    build --output_user_root=D:/
    

    또는

    build --output_user_root=C:/_bzl
    
  • 연결 지점을 사용하세요.

    연결 부분은 간단히 말해[1] 디렉터리 심볼릭 링크입니다. 정션은 쉽게 만들 수 있으며 긴 경로를 가진 디렉터리 (동일한 컴퓨터)를 가리킬 수 있습니다. 빌드 작업이 경로가 짧지만 타겟이 긴 연결을 생성하는 경우 짧은 경로 제한이 있는 도구는 정션된 디렉터리에 있는 파일에 액세스할 수 있습니다.

    .bat 파일 또는 cmd.exe에서 다음과 같은 정션을 만들 수 있습니다.

    mklink /J c:\path\to\junction c:\path\to\very\long\target\path
    

    [1]: 엄밀히 말하면 Junction은 심볼릭 링크가 아닙니다. 하지만 빌드 작업에서는 정션을 디렉터리 심볼릭 링크로 간주할 수 있습니다.

  • Actions / envvar의 경로에서 /을 `` 으로 바꿉니다.

    작업의 명령줄이나 환경 변수를 만들 때 경로를 Windows 스타일로 만듭니다. 예:

    def as_path(p, is_windows):
        if is_windows:
            return p.replace("/", "\\")
        else:
            return p
    

환경 변수

문제:

  • 대소문자 구분: Windows 환경 변수 이름은 대소문자를 구분하지 않습니다.

    예를 들어 Java에서 System.getenv("SystemRoot")System.getenv("SYSTEMROOT")의 결과는 동일합니다. (이는 다른 언어에도 적용됩니다.)

  • 밀폐성: 작업은 가능한 한 적은 수의 맞춤 환경 변수를 사용해야 합니다.

    환경 변수는 작업 캐시 키의 일부입니다. 작업에서 자주 변경되거나 사용자에게 맞춤설정되는 환경 변수를 사용하면 규칙의 캐시 가능성이 낮아집니다.

해결 방법:

  • 대문자 환경 변수 이름만 사용하세요.

    이 기능은 Windows, macOS, Linux에서 작동합니다.

  • 작업 환경을 최소화합니다.

    ctx.actions.run 사용 시 환경을 ctx.configuration.default_shell_env로 설정합니다. 작업에 더 많은 환경 변수가 필요한 경우 모든 환경 변수를 사전에 넣고 작업에 전달합니다. 예:

    load("@bazel_skylib//lib:dicts.bzl", "dicts")
    
    def _make_env(ctx, output_file, is_windows):
        out_path = output_file.path
        if is_windows:
            out_path = out_path.replace("/", "\\")
        return dicts.add(ctx.configuration.default_shell_env, {"MY_OUTPUT": out_path})
    

작업

문제:

  • 실행 출력: 모든 실행 파일에는 실행 확장자가 있어야 합니다.

    가장 일반적인 확장자는 .exe (바이너리 파일) 및 .bat (일괄 스크립트)입니다.

    셸 스크립트 (.sh)는 Windows에서 실행할 수 없으므로 ctx.actions.runexecutable로 지정할 수 없습니다. 파일에 포함할 수 있는 +x 권한도 없으므로 Linux에서처럼 임의의 파일을 실행할 수 없습니다.

  • Bash 명령어: 이동성을 위해 작업에서 직접 Bash 명령어를 실행하지 마세요.

    Bash는 Unix와 유사한 시스템에서 널리 사용되지만 Windows에서는 종종 사용할 수 없습니다. Bazel 자체는 Bash (MSYS2)에 대한 의존도가 낮으므로 향후 사용자는 Bazel과 함께 MSYS2를 설치할 가능성이 낮아집니다. Windows에서 규칙을 더 쉽게 사용하려면 작업 중에 Bash 명령어를 실행하지 마세요.

  • 행 끝자리: Windows는 CRLF (\r\n)를 사용하고 Unix 유사 시스템은 LF (\n)를 사용합니다.

    텍스트 파일을 비교할 때는 이 점을 염두에 두시기 바랍니다. Git 설정, 특히 체크아웃하거나 커밋할 때 줄 끝 부분에 유의하세요. Git의 core.autocrlf 설정을 참고하세요.

해결 방법:

  • Bash 없이 목적에 맞게 설정된 규칙 사용

    native.genrule()는 Bash 명령어의 래퍼이며 파일 복사 또는 텍스트 파일 쓰기와 같은 간단한 문제를 해결하는 데 자주 사용됩니다. Bash에 의존하지 않고 bazel-skylib에 필요에 맞게 만들어진 규칙이 있는지 확인하세요. Windows에서 빌드/테스트할 때 Bash에 종속되지 않습니다.

    빌드 규칙 예는 다음과 같습니다.

    • copy_file()(소스, 문서): 파일을 다른 곳에 복사하고 필요에 따라 실행 파일로 만듭니다.

    • write_file()(소스, 문서): 원하는 줄 끝 (auto, unix 또는 windows)을 사용하여 텍스트 파일을 작성하고 필요에 따라 실행 파일 (스크립트인 경우)으로 만듭니다.

    • run_binary()(소스, 문서): 주어진 입력 및 예상 출력을 빌드 작업으로 사용하여 바이너리 (또는 *_binary 규칙)를 실행합니다(ctx.actions.run의 빌드 규칙 래퍼입니다).

    • native_binary()(소스, 문서): 네이티브 바이너리를 *_binary 규칙으로 래핑합니다. 이 규칙은 bazel run하거나 run_binary()tool 속성 또는 native.genrule()tools 속성에 사용할 수 있습니다.

    테스트 규칙의 예:

    • diff_test()(소스, 문서): 두 파일의 콘텐츠를 비교하는 테스트

    • native_test()(소스, 문서): *_test 규칙에 네이티브 바이너리를 래핑합니다. bazel test할 수 있습니다.

  • Windows에서 사소한 일에 .bat 스크립트를 사용하는 것이 좋습니다.

    .sh 스크립트 대신 .bat 스크립트로 사소한 작업을 해결할 수 있습니다.

    예를 들어 아무 작업도 하지 않거나, 메시지를 출력하거나, 수정된 오류 코드와 함께 종료되는 스크립트가 필요하다면 간단한 .bat 파일만으로 충분합니다. 규칙에서 DefaultInfo() 제공자를 반환하는 경우 executable 필드는 Windows에서 이 .bat 파일을 참조할 수 있습니다.

    macOS와 Linux에서는 파일 확장자가 중요하지 않으므로 셸 스크립트의 경우에도 항상 .bat을 확장자로 사용할 수 있습니다.

    .bat 파일은 실행할 수 없습니다. 빈 스크립트가 필요하면 공백을 하나 작성합니다.

  • Bash를 원칙 방식으로 사용합니다.

    Starlark 빌드 및 테스트 규칙에서 ctx.actions.run_shell을 사용하여 Bash 스크립트와 Bash 명령어를 작업으로 실행합니다.

    Starlark 매크로에서 Bash 스크립트와 명령어를 native.sh_binary() 또는 native.genrule()에 래핑합니다. Bazel은 Bash를 사용할 수 있는지 확인하고 Bash를 통해 스크립트 또는 명령어를 실행합니다.

    Starlark 저장소 규칙에서 Bash를 완전히 피합니다. 현재 Bazel은 저장소 규칙에서 원칙적인 방식으로 Bash 명령어를 실행하는 방법을 제공하지 않습니다.

파일 삭제

문제:

  • 열린 상태에서는 파일을 삭제할 수 없습니다.

    열려 있는 파일은 삭제할 수 없으며 (기본적으로 삭제하려고 하면 '액세스 거부' 오류가 발생합니다.) 파일을 삭제할 수 없다면 실행 중인 프로세스에서 계속 열려 있는 파일을 유지할 수 있습니다.

  • 실행 중인 프로세스의 작업 디렉터리는 삭제할 수 없습니다.

    프로세스에는 작업 디렉터리에 대한 열린 핸들이 있으며 프로세스가 종료될 때까지 디렉터리를 삭제할 수 없습니다.

해결 방법:

  • 코드에서 파일을 빠르게 닫아 보세요.

    Java에서는 try-with-resources를 사용합니다. Python에서는 with open(...) as f:를 사용합니다. 원칙적으로 가능한 한 빨리 핸들을 닫으세요.