빌드 프로세스 Review 및 CI, CD

AUTHOR: SungwookLE
DATE: ‘21.9/4
REFERENCE: REF
CI/CD:Continuout Integration , Continuous Delivery, Continuous Deployment Youtube

한번 정리하는 과정을 통해, 모호한 것을 명확하게 짚고 넘어가보자.

1. Build란?

컴퓨터는 0과 1밖에 모른다(기계어). 우리가 작성하는 코드는 고급언어(사람들의 언어)를 사용하기 때문에 컴퓨터에게 실행시키기 위해선, 번역의 과정이 필요하다. (C, C++, Java 등 대부분 언어가 고급언어)
컴퓨터가 이해하는 언어를 기계어라고 하는데, 컴퓨터가 이해할 수 있는, 실행 가능한 파일로 만드는 과정을 빌드(Build)라고 한다.

image

정리하면, 우리가 만든 소스코드를 빌드라는 과정을 통해 실행 파일을 얻게 되는 것. 그 실행파일은 exe, exec 등 여러 종류가 있다. 이러한 실행 파일은 기계어(Machine Code) 라고 컴퓨터가 읽을 수 있는 이진코드로 이루어져 있다.

빌드는 번역과정(고급언어->기계어) + 엮어서 실행 파일로 만드는 과정이다.
진짜 러프하게 컴파일+링킹과정이 빌드인 것이다.

2. Build Process 종류

빌드과정은 언어에 따라 크게 3가지 방식으로 구분할 수 있는데, Compile 방식(C,C++), Interpreted(Python), Hybrid 방식이 있다.

table

2-1. Compile Type

Compile Type: (1) Preprocessing 전처리

말 그대로 사전 처리라고 보면 되는데, 전처리 과정은 `전처리기(preprocessor)에 의해 소스코드에 포함 된 매크로나 지시자 같은 것을 포함시키는 과정이다.

소스코드의 중심(main)이 실행되기 전에 사전준비 하는 과정

image

책으로 비유하자면, 책에서 정의하는 인용, 목차 등 이미 정해져 있는 것들을 먼저 처리(정리)하여 이후에 일일이 다시 찾아 쓸 필요 없이 정리해두는 과정이다. 프로그래밍 언어로 보자면 C언어나 C++에서 #으로 시작하는 구문들(#include, #define 등)이다.

Compile Type: (2) Compilation 컴파일

compile 이라는 뜻이 번역하다라는 뜻이다. 컴파일을 소스코드를 실행파일로 만드는 것으로 생각할 수 있는데, 번역일 뿐이지, 아직은 컴퓨터가 실행할 수 있는 단계가 아니다. (외국어책을 번역만 해놓고 책으로 묶지 않으면 그 건 책이 아니라 그냥 번역만 한 종이일 뿐..) 어떤 언어로 번역하느냐, 컴파일 하는 프로그램을 컴파일러(compiler)라고 한다. C와 C++에서 gcc, g++ㄱ같은 프로그램이 컴파일러이다. 컴파일러가 컴파일 하면 바로 기계어로 번역되는 것은 아니고, 중간언어 또는 저수준 언어라고 하는 어셈블리어로 번역이 된다.
바로 기계어로 가지 않고 어셈블리어로 변환하는 이유는 사람이 알아보기 힘든 기계어(이진값)으로 가기전에 심볼릭(부호화) 처리된 중간단계 언어로 일단 번역을 함으로써 사람이 쳐다보면 어느정도 해석이 가능하게끔 만들어 둔것이다. 물론 심볼릭(부호화)은 이진값을 부호화해둔것이기 때문에 기계어와 구조는 1:1 매칭이 되기 때문에, 어셈블리어를 보고 번역될 기계어가 이렇게 생길 예정이고 하드웨어 메모리에는 이렇게 쓰여지겠구나, 내부가 이렇게 작동되게꾸나 하고 확인할 수 있다.
한마디로 인간이 기계어를 이해하기 위해 고급언어와 기계어 사이에 중간단계인 저수준 언어로 번역하는 것이다. C, C++ 모두 어셈블리어라는 저수준 언어로 번역된다.(물론 언어마다, 컴파일러마다 조금의 차이는 있다.)

Compile Type: (3) assemble 어셈블

컴파일을 거치면 중간언어(저수준 언어) 단계인 어셈블리어를 얻게 되는데, 이 어셈블리어를 기계어로 번역해주는 과정을 어셈블러(Assembler)라고 한다. 이렇게 CPU가 이해할 수 있는 언어로 번역된 파일을 보통 Object File이라고 한다.

참고로 Object(객체)란,
동작의 주체가 누군지 분류하여 동일성을 갖는 기능들을 하나의 묶음으로 만들어낸 하나의 실체 라고 정의할 수 있다.

어셈블리어에서 기계어로 번역된 Object File은 여러개의 연관된 파일을 빌드하면 링크단계 전까지는 각 파일별로 번역이 되기 때문에 그 번역된 파일 하나하나가 실행하는 최종 파일의 일부분으로서의 객체가 된다고 보면된다. 그래서 Object단어가 붙게되는 것이다.

그리고 컴파일과정을 여기까지 포함하기도 한다. 왜냐면,,, Compile이라는 단어 자체가 번역이라는 의미인데, 프로그래밍에서는 크게 두 가지로 해석할 수 있다. 좁은 의미로는 소스코드를 저수준 언어로 변환해주는 과정만을 생각할 수 있는데, 어셈블도 저수준 언어를 기계어로 바꿔주는 번역의 단계이기 때문에 Compilation + Assemble 까지 합쳐서 Compile 이라고 하기도 한다.

Compile Type: (4) linking 링크/링킹

컴파일(어셈블 포함) 과정을 통해 각 파일들이 기계어로 번역되었다면 하나로 연결해주는 과정이 필요하다. 각각의 Object File은 기계가 이해할 수 있는 번역본일 뿐 실행할 수 있는 파일은 아니다.
즉, Object File 들과 필요한 라이브러리를 연결 시켜주고 최종적으로 하나의 executable file(실행가능한 파일)로 만들어주는 과정이 링킹이다.

빌드: 전처리-컴파일-어셈블-링크 4단계를 살펴보았다. 좀 더 포괄적으로는 전처리-컴파일-어셈블을 컴파일 단계로 보기도 하니, 컴파일-링크의 단계를 살펴본 것이다. 즉, 빌드와 컴파일은 다르다는 것이다. 컴파일은 번역하는 단계로 소스코드를 목적 파일(Object File)로 만들어주는 과정이고, 그 결과물이 실행파일은 아니다. 컴파일 단계에 링크 과정을 거쳐야지만 실행가능한 파일이 생성되고 이것이 빌드이다. 컴파일+링크 = 빌드.

  • 컴파일 언어의 장점:
    1. 빌드가 완료된 실행가능한 파일은 실행 속도가 빠름
    2. 매번 번역할 필요 없이 실행 파일만 실행하면 되기 때문에 시간면에서 효율적
  • 컴파일 언어의 단점:
    1. 프로그램 수정시, 빌드과정 재수행 필요하므로 대규모 프로그램에서는 생산성 떨어짐
    2. 플랫폼에 매우 의존적이다.

단점 2번에 대해 설명하자면, 윈도우 실행파일을 맥OS에서 실행하지 못하는 상황을 생각하면 되는데, 2가지 이유가 있다. 먼저 어셈블리어의 경우 CPU 명령어 세트에 대해 1:1 매칭되는데, 다시 말해, CPU에 의존적이라는 것이다. CPU 명령 체게가 거의 비슷하기는 하나 완전히 같지는 않기 때문이다. 두번째로는 CPU가 이해할 수 있게 번역하여 최종 실행파일로 만들기 위해 링크작업이 필요한데, 이 과정에서 OS마다 서로 다른 라이브러리가 있어 링커는 해당 OS에서 요구하는 라이브러리를 연결하게 된다.

2-2. Interpreted Type

image

한 명령 단위로 해석하면서 즉시 실행하는 방법(동시 통역사). 컴파일 언어와 인터프리트 언어의 가장 큰 차이점은 바로 목적파일(Object File)을 생성하지 않고 바로 실행된다는 것이 가장 크다.
보통 이러한 인터프리터 언어에 가장 대표적인 언어는 자바스크립트, 파이썬 등이 있다. (정확히 말하면 절반은 맞고 절반은 틀림, 하이브리드 언어 참고)

소스코드의 한 명령 세트마다 기계어(Machine Code)로 번역하면서 바로바로 실행해주는 방식을 인터프리트라고한다. 이렇게 번역해주는 프로그램을 Interpreter(인터프리터)라고 한다. 즉, 각 운영체제에 맞는 해당 언어의 인터프리터만 설치한다면 어느 운영체제에서든 해당 언어를 사용하더라도 동일한 결과를 얻을 수 있다. 한마디로 플랫폼에 독립적이다. 또한 이렇게 컴파일 과정 없이 인터프리터를 통해 바로 결과를 볼 수 있기 때문에 프로그램 수정에 매우 유리하다.

소스코드 그 자체가 실행가능한 파일이 되는 것이라고 이해하면 된다. 소스코드르 번역해줄 수 있는 인터프리터가 있어야 하고,..

  • 인터프리트 언어의 장점
    1. 컴파일 과정 없이 바로 실행하기 때문에, 수정/디버깅에 유리. 개발속도 유리
    2. 각 플랫폼에 지원하는 인터프리터만 있다면 실행 가능하여 플랫폼에 독립적
  • 인터프리트 언어의 단점
    1. 빌드 되어있는 컴파일 언어 프로그램보다 실행시간이 느림
    2. 코드를 열면 다 보이기 때문에 보안에 좋지 않다.

2-3. Hybrid Type

컴파일 방식과 인터프리트 방식을 혼합한 방법으로 실행속도도 빠르면서 플랫폼 독립적인 무언가를 만들기 위함이다. 흔히 바이트 코드 언어(Byte Code Language)라고 하고, 가장 대표적인 언어가 Java(자바)이다.

책을 번역하는 과정에 비유해서 들어보자면, 세계적으로 가장 많이 쓰이는 언어는 영어이다. 그래서 프랑스어, 한국어 등등 다른 국가의 언어로 번역된 것을 1차적으로 영어로 번역을 해둔다. 그런 다음 영어로 번역된 것을 일본어로 번역하면 번역 가능한 사람이 많은 만큼 쉽고 빠르게 번역할 수 있다.
영어는 어디서든 대부분 쓰기 때문에 조금 번거롭더라도 중간 번역과정을 한번 거쳐두면 그 다음부터는 재사용을 하기도 쉽고, 다른 언어로 번역하기도 쉽다는 장점을 살린 것이 프로그래밍에서 하이브리드 방식이다. 어디서든 대부분 쓰일 수 있다는 것을 해석하면 플랫폼에 대해 독립적이라는 의미이다.

하이브리드 타입의 실행과정을 살펴보면, 먼저, 고급언어(Java)를 바이트 코드(bytecode)로 변환한다. 바이트 코드란 일종의 중간 언어라고 생각하면ㄷ 된다. 그리고 VM(Virtual Machine: 가상머신)이라는 프로그램에 의해 바이트코드를 기계어로 바꿔준다. 이 때 중요한 것은 바로 VM 인데, VM 은 하나의 프로그램이라고 생각하면 된다.

아주 쉽게 생각하면 프로그램을 VM이라는 가상머신에서 실행한다고 보면 된다. 즉, 각 플랫폼에 맞는 VM들이 만들어져 있다면 우리는 같은 소스코드를 어느 플랫폼에서든지 동일한 결과를 얻어낼 수 있다는 것이다.

image3

여기서 실행가능한 파일은 바이트 코드가 된다.
먼저 바이트코드(Byte Code)는 가상머신(Virtural Machine)이 이해할 수 있는 중간언어(intermediage language)라고 보면 된다. 앞선 비유에서 영어라고 보면 된다. 예로 들어 Java를 컴파일 하면, .class 파일이 생성된다. 또는 C#에서는 CIL(common intermediate language)라는 파일이 생성된다. 바이트코드는 기계어는 아니지만 어셈블리어처럼 기계에 조금 더 가까운 언어로 되어 있다.
다만 컴파일 언어의 object file과 차이가 있다면 컴파일 언어에서는 하드웨어에 의해 처리되는 기계어로 되어 있었다면, 바이트 코드 파일의 경우 하드웨어가 직접 처리하는 것이 아닌 소프트웨어(가상 머신)에 의해 처리된다는 것이다. 역으로 생각하자면 바이트코드는 해당 가상머신 전용 기계어라고 보면 된다.

바이트코드는 가상머신이 이해할 수 있는 코드로 되어 있다. 그리고 그 가상머신 안에는 인터프리터 같은 해석기가 있어 이들이 바이트코드를 해석하여 각 OS에 맞게 명령어를 해석하고 작동하는 하나의 프로그램이라고 보면 된다.

대표적인 VM은 Java Virtual Machine 인 JVM이 있다. 또한 C#의 경우는 .NET의 CLR이 있다. 이들의 장점은 VM(가상머신)이 해당 운영체제에 맞게 지원만 해준다면 플랫폼에 독집적으로 실행할 수 있다는 장점이 있따. 인터프리터와 같은 원리인 것이다. (물론 VM이 인터프리트만 하는 것이 아니라 최근에는 컴파일 방식과 혼용하여 구현되어 있다.)

즉, VM을 통해 ‘플랫폼에 독립적’인 장점을 갖고왔고, 초기 컴파일 단계를 통해 바이트코드로 기계어에 더 가까운 언어로 번역을 한 번 해놓았기 때문에 속도도 기존 인터프리터 언어에 비해 더 빠르다는 장점 또한 갖고 오게 되었다.

  • 하이브리드 언어의 장점
    1. 각 플랫폼에 지원하는 가상머신이 있다면 실행 가능하기 떄문에 플랫폼에 독립적
  • 하이브리드 언어의 단점
    1. 컴파일 언어처럼 하드웨어를 직접 제어하는 작업은 불가능

3. 정리

3가지 빌드과정을 살펴보았는데 C언어=컴파일 언어, Python=인터프리트 언어 이런식으로 생각하면 ‘절대’안된다.

어디까지나 ‘대표적인’언어일 뿐이지 1대 1로 매칭되는 개념이 아니라 빌드 과정의 구현의 차이일 뿐이다. 언어는 어디까지 언어고 이를 기계어로 바꾸는 수단은 매우매우 많다. 예를 들어 C나 C++전용 Interpreter를 사용하여 인터프리트처럼 사용할 수 있고, python코드를 자바 가상 머신(JVM)에서 실행하루 수 있도록 할 수도 있다.

4. CI, CD란?

개발 방법론을 말하는데, CI는 Continuous Integration 을 말하고 CD는 Continuous Delivery, Deployment 를 말한다. 어플리케이션 개발에서 배포까지 좀 더 자동화된 프로세스에 따른 개발 프로세스를 말한다.

  • CI 는 깃 메인 Repository에서 자주 Merge 함으로써 너무 오래동안 머지되지 않았을 경우 생기는 머지 충돌을 최소화 할 수 있다는 장점이 있다. 또한, 메인 Repository 에 머지될 때에, 머지 이후에 빌드는 문제없이 되는지 기존 프로그램에 버그를 발생하진 않는지 자동 테스트(유닛, 통합)를 수행시켜 문제 없게끔 한다. 생산성이 높다는 장점이 있고 자동화된 빌드,유닛테스트, 통합테스트를 통해 품질을 향상시킬 수 있고 자주 머지함으로써 문제 발생 시에 빠른 디버깅을 가능하게 함으로써 코드 품질을 높일 수 있기 때문이다.

  • CD 는 배포단계를 말하는데 Continuous Delivery는 테스트 엔지니어가 마지막 배포 단계에서 검증하고 배포(Release)하는 과정을 말하고, Continuous Deployment는 통합 테스트를 포함한 여러 검증단계를 자동화하여 자동적으로 고객에게 배포하는 과정(Release)을 말한다. 팀/회사마다 자동화 수준은 조금씩 차이가 있다.

끝.