Windows에서 규칙 작성

문제 신고 소스 보기 Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

이 페이지에서는 Windows 호환 규칙 작성, 휴대용 규칙 작성의 일반적인 문제, 몇 가지 해결 방법을 중점적으로 설명합니다.

경로

문제:

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

    Windows에서도 더 긴 경로 (최대 32,767자)를 지원하지만 많은 프로그램은 하한선을 사용하여 빌드됩니다.

    작업에서 실행하는 프로그램에 대해 이 점을 유의하세요.

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

    프로세스는 259자(영문 기준)를 초과하는 디렉터리에 cd할 수 없습니다.

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

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

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

    Bazel은 / 구분자를 사용하여 Unix 스타일로 경로를 저장합니다. 일부 Windows 프로그램은 유닉스 스타일 경로를 지원하지만 그렇지 않은 프로그램도 있습니다. 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]: 엄밀히 말해 연결은 심볼릭 링크가 아닙니다. 하지만 빌드 작업을 위해 연결을 디렉터리 심볼릭 링크로 간주할 수 있습니다.

  • 작업 / envvars의 경로에서 /를 `` 로 바꿉니다.

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

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

환경 변수

문제:

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

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

  • Hermeticity: 작업은 맞춤 환경 변수를 최대한 적게 사용해야 합니다.

    환경 변수는 작업의 캐시 키의 일부입니다. 작업에서 자주 변경되거나 사용자별로 맞춤설정된 환경 변수를 사용하면 규칙을 캐시하기가 더 어려워집니다.

해결 방법:

  • 환경 변수 이름은 대문자만 사용합니다.

    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는 유닉스 계열 시스템에서 널리 사용되지만 Windows에서는 사용할 수 없는 경우가 많습니다. Bazel 자체가 Bash (MSYS2)에 점점 더 덜 의존하고 있으므로 향후 사용자는 Bazel과 함께 MSYS2를 설치할 가능성이 줄어들 것입니다. Windows에서 규칙을 더 쉽게 사용하려면 작업에서 Bash 명령어를 실행하지 마세요.

  • 줄 끝: Windows는 CRLF (\r\n)를 사용하고 유닉스 계열 시스템은 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 파일은 실행할 수 없습니다. 빈 스크립트가 필요한 경우 스크립트에 공백 1개를 입력합니다.

  • 원칙적으로 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:를 사용합니다. 원칙적으로 핸들을 최대한 빨리 닫으려고 합니다.