작업 기반 빌드 시스템

<ph type="x-smartling-placeholder"></ph> 문제 신고 소스 보기 1박 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

이 페이지에서는 작업 기반 빌드 시스템과 작동 방식 및 복잡한 문제를 해결하는 데 도움이 됩니다. 셸 스크립트 후, 작업 기반 빌드 시스템은 빌딩의 논리적 발전입니다.

작업 기반 빌드 시스템 이해

작업 기반 빌드 시스템에서 작업의 기본 단위는 작업입니다. 각 태스크는 모든 종류의 로직을 실행할 수 있는 스크립트이며 이러한 작업을 종속 항목보다 먼저 실행되어야 합니다. 사용 중인 대부분의 주요 빌드 시스템 Ant, Maven, Gradle, Grunt 및 Rake와 같은 오늘날은 작업 기반입니다. 대신 셸 스크립트, 대부분의 최신 빌드 시스템에서는 엔지니어가 빌드 파일을 작성해야 함 확인할 수 있습니다

이 예시를 살펴보겠습니다. 개미 설명서:

<project name="MyProject" default="dist" basedir=".">
   <description>
     simple example build file
   </description>
   <!-- set global properties for this build -->
   <property name="src" location="src"/>
   <property name="build" location="build"/>
   <property name="dist" location="dist"/>

   <target name="init">
     <!-- Create the time stamp -->
     <tstamp/>
     <!-- Create the build directory structure used by compile -->
     <mkdir dir="${build}"/>
   </target>
   <target name="compile" depends="init"
       description="compile the source">
     <!-- Compile the Java code from ${src} into ${build} -->
     <javac srcdir="${src}" destdir="${build}"/>
   </target>
   <target name="dist" depends="compile"
       description="generate the distribution">
     <!-- Create the distribution directory -->
     <mkdir dir="${dist}/lib"/>
     <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
     <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
   </target>
   <target name="clean"
       description="clean up">
     <!-- Delete the ${build} and ${dist} directory trees -->
     <delete dir="${build}"/>
     <delete dir="${dist}"/>
   </target>
</project>

빌드 파일은 XML로 작성되며 빌드에 대한 몇 가지 간단한 메타데이터를 정의합니다. 작업 목록 (XML의 <target> 태그)과 함께 표시됩니다. (개미는 target작업을 나타내며 task라는 단어를 사용하여 명령어) 각 작업은 Ant가 정의한 가능한 명령 목록을 실행하고, 여기에는 디렉터리 생성 및 삭제, javac 실행, 살펴보겠습니다 이 명령어 집합은 사용자 제공에 의해 확장될 수 있습니다. 모든 종류의 논리를 커버할 수 있습니다. 또한 각 태스크는 종속 속성을 통해 종속됩니다. 이러한 종속 항목은 비순환 그래프를 형성하므로 Cloud CDN을 사용 설정합니다

종속 항목을 보여주는 아크릴 그래프

그림 1. 종속 항목을 보여주는 비순환 그래프

사용자는 Ant의 명령줄 도구에 작업을 제공하여 빌드를 수행합니다. 예를 들어 사용자가 ant dist를 입력하면 Ant는 다음 단계를 따릅니다.

  1. 현재 디렉터리에 이름이 build.xml인 파일을 로드하고 다음을 파싱합니다. 그림 1과 같은 그래프 구조를 만듭니다.
  2. 명령줄에 제공된 dist라는 작업을 찾습니다. compile라는 작업에 종속 항목이 있음을 발견합니다.
  3. compile라는 작업을 찾아 다음 항목에 종속 항목이 있음을 발견합니다. init라는 작업을 실행합니다.
  4. init라는 작업을 찾아 종속 항목이 없음을 발견합니다.
  5. init 작업에 정의된 명령어를 실행합니다.
  6. compile 작업에 정의된 명령어를 실행합니다. 이 모든 것이 주어진 경우 종속 항목이 실행됩니다
  7. dist 작업에 정의된 명령어를 실행합니다. 이 모든 것이 주어진 경우 종속 항목이 실행됩니다

결국 dist 작업을 실행할 때 Ant에서 실행되는 코드는 동일합니다. 다음 셸 스크립트에 추가합니다.

./createTimestamp.sh
mkdir build/
javac src/* -d build/
mkdir -p dist/lib/
jar cf dist/lib/MyProject-$(date --iso-8601).jar build/*

구문이 제거되면, buildfile과 빌드 스크립트는 실제로 크게 다르지 않습니다 하지만 이렇게 함으로써 이미 많은 것을 얻었습니다. 우리는 다른 디렉터리에서 새 빌드 파일을 생성하고 이들을 함께 링크할 수 있습니다. 쉽게 임의의 복잡한 방법으로 기존 작업에 의존하는 새 작업을 추가합니다. 단일 작업의 이름을 ant 명령줄 도구에 전달하기만 하면 됩니다. 실행해야 하는 모든 것을 결정합니다.

Ant는 원래 2000년에 출시된 오래된 소프트웨어입니다. 기타 도구 Maven과 Gradle은 그 사이에 Ant를 개선했으며 기본적으로 외부 IP 주소 자동 관리와 같은 종속 항목, XML 없이 더 깔끔한 문법을 제공합니다. 그러나 이러한 새로운 기능의 특성은 엔지니어가 빌드 스크립트를 작성할 수 있으며 원칙에 입각하여 모듈식으로 접근하여 작업 수행에 필요한 도구를 제공합니다. 이들 간의 종속 항목을 관리할 수 있습니다

작업 기반 빌드 시스템의 어두운 측면

이러한 도구를 사용하면 기본적으로 엔지니어가 모든 스크립트를 작업으로 정의할 수 있기 때문에 매우 강력해서 상상할 수 있는 거의 모든 것을 할 수 있습니다. 공유할 수 있습니다. 하지만 이러한 힘에는 단점이 수반되고 작업 기반 빌드 시스템은 빌드 스크립트가 더 복잡해짐에 따라 작업하기가 더 어려워집니다. 이 이러한 시스템의 문제는 실제로 컴퓨터에 너무 많은 전력을 공급하여 시스템에 충분한 전원이 부족할 수 있습니다. 시스템이 이 문제를 스크립트가 수행하는 작업은 매우 보수적이어야 하므로 성능이 저하됩니다. 빌드 단계를 예약하고 실행하는 방식에 중점을 둡니다 또한 시스템에는 확인하기 위해 각 스크립트가 제 역할을 하고 있는지 확인해야 하기 때문에 디버깅이 필요한 또 다른 문제가 생깁니다.

빌드 단계 병렬화 어려움

최신 개발 워크스테이션은 매우 강력하며 여러 빌드 단계를 동시에 실행할 수 있습니다. 하지만 작업 기반 시스템은 필요한 것처럼 보이는 경우에도 작업 실행을 병렬화할 수 없는 경우가 많음 있습니다. 작업 A가 작업 B와 C에 종속되어 있다고 가정해 보겠습니다. 태스크 B와 C이므로 서로 종속되지 않는 경우 이들을 동시에 실행하는 것이 안전한가요? 작업 A에 더 빨리 도달하려면 어떻게 해야 할까요? 아마도, 아무 것도 터치하지 않으면 동일한 리소스를 사용할 수 있습니다 그렇지 않을 수도 있습니다. 둘 다 동일한 파일을 사용하여 동시에 실행하면 충돌이 발생합니다. 없음 이러한 충돌을 야기하거나 위험을 감수해야 하기 때문에 (드물지만 디버그하기 매우 어려운 빌드 문제를 초래하거나) 전체 빌드가 단일 프로세스의 단일 스레드에서 실행되도록 제한할 수 있습니다. 이는 강력한 개발자 머신의 엄청난 낭비일 수 있으며 빌드를 여러 머신에 배포할 가능성을 배제합니다.

증분 빌드 수행의 어려움

좋은 빌드 시스템을 사용하면 엔지니어가 전체 코드베이스를 다시 빌드할 필요가 없다는 것을 깨닫게 되었습니다. 있습니다. 이는 빌드 시스템이 느리고 빌드 단계를 병렬화하는 것이 좋습니다 하지만 안타깝게도 여기에도 작업 기반 빌드 시스템이 어렵습니다. 태스크는 모든 것을 할 수 있으므로 일반적으로 이미 적용되었는지 확인할 수 있는 방법은 없습니다. 많은 작업 소스 파일 세트를 가져와서 컴파일러를 실행하여 바이너리 따라서 기본 소스 파일이 확인할 수 있습니다 하지만 추가 정보가 없으면 시스템은 이러한 내용을 말할 수 없습니다. 변경되었을 수 있는 파일을 다운로드하거나 각 실행마다 다를 수 있는 타임스탬프를 기록합니다. 보장 정확성을 높이기 위해 시스템은 일반적으로 각 빌드 중에 모든 작업을 재실행해야 합니다. 다소 유용함 증분 빌드를 사용하려면 엔지니어가 작업을 재실행해야 하는 조건으로 인해 발생할 수 있습니다. 일부 경우에는 가능하지만 종종 보이는 것보다 훨씬 까다로운 문제입니다. 예를 들어 파일을 다른 파일에 직접 포함할 수 있도록 하는 C++처럼 변경사항을 감시해야 하는 전체 파일 세트를 결정하는 것은 불가능합니다. 소스 코드를 생성합니다. 엔지니어는 종종 지름길을 택하고, 이러한 단축키는 작업 결과가 나오지 않게 되어 적절하지 않은 경우에도 재사용됨 이런 일이 자주 발생하면 엔지니어는 새로운 상태를 얻기 위해 모든 빌드 전에 깨끗하게 실행하는 습관을 들이고, 초기에 증분 빌드의 목적을 완전히 무력화하기 위해 있습니다. 작업을 재실행해야 할 때를 파악하는 일은 놀라울 정도로 미묘하며 작업이 인간보다 기계가 더 잘 처리합니다.

스크립트 유지관리 및 디버깅이 어려움

마지막으로, 작업 기반 빌드 시스템이 적용하는 빌드 스크립트는 다루기 어려웠죠. 빌드 스크립트는 빌드 중인 시스템과 같은 코드이며 버그를 쉽게 숨길 수 있습니다. 다음은 작업 기반 빌드 시스템:

  • 작업 A는 특정 파일을 출력으로 생성하기 위해 작업 B에 종속됩니다. 소유자 다른 태스크가 그것에 의존한다는 것을 깨닫지 못해서 출력을 생성할 수 있습니다 이는 다른 사용자가 감지할 때까지 감지할 수 없습니다. 작업 A를 실행하려고 했지만 실패했음을 발견합니다.
  • 작업 A는 작업 B에 종속되며, 이는 작업 B에 종속되며, 이는 작업 B에 종속되어 특정 파일을 태스크 A에 필요한 출력으로 만듭니다. 작업 B의 소유자 더 이상 작업 C에 의존할 필요가 없다고 판단하여 작업 B는 작업 C에 전혀 신경 쓰지 않아도 A는 실패합니다.
  • 새로운 작업의 개발자는 실수로 머신이 실행 중인 작업, 즉 툴의 위치나 특정 환경 변수입니다 작업이 사용자 컴퓨터에서 작동하지만 실패함 발생할 수 있습니다.
  • 작업에는 파일 다운로드와 같은 비확정적인 구성요소가 포함됩니다. 빌드에 타임스탬프를 추가할 수 있습니다 이제 사람들은 결과를 얻지 못할 수 있습니다. 즉, 엔지니어들이 항상 서로의 실패를 재현하고 고칠 수 있는 것은 장애 또는 장애를 방지합니다
  • 여러 종속 항목이 있는 작업은 경합 상태를 일으킬 수 있습니다. 작업 A인 경우 작업 B와 작업 C에 모두 종속되며 작업 B와 C는 모두 파일, 작업 A는 작업 B와 C 중 어느 것이 무엇인지에 따라 다른 결과를 얻습니다. 완료되어야 합니다.

이러한 성능, 정확성 또는 문제를 해결할 범용적인 방법은 유지관리 문제에 대해 살펴봤습니다 감사합니다. 엔지니어가 빌드 중에 실행되는 임의의 코드를 작성할 수 있기 때문에 시스템은 항상 신속하게 빌드를 실행할 수 있는 정보가 부족해서 있습니다. 문제를 해결하려면 이를 시스템에 되돌려 주고 작업을 실행하는 것이 아니라 아티팩트를 생성하는 것처럼 시스템의 역할을 수행합니다.

이 접근 방식으로 Blaze와 같은 아티팩트 기반 빌드 시스템을 만들었습니다. Bazel이 있습니다