프로그래밍 기본 (빌드 되는 과정)

프로그램을 작성하는 데에 여러 방식이 있다.

 

CPU가 직접 이해할 수 있는 기계어, 어셈블러 프로그램을 사용하는 어셈블리 언어, 가독성 및 이식성 문제를 해결하기 위해 나온 C, C++같은 고급 언어 등으로 프로그램을 직접 작성할 수 있다.

하지만 기계어를 제외한 나머지 언어들은 프로그램이 실행되기 전에 컴퓨터가 이해할 수 있는 기계어 형식으로 변환되어야 한다.

이때 필요한 것이 컴파일러이다.

 

 

 

 

 

컴파일러와 인터프리터

 

컴파일러는 소스코드를 읽고 이 코드를 다른 언어로 번역하는 프로그램이다. 

고급 언어 소스코드가 컴파일러에 의해 번역되고, 실행 가능한 파일 (exe) 이 생성된다.

그래서 컴파일된 프로그램의 장점으로, 컴파일된 프로그램을 배포할 때 소스 코드를 배포할 필요가 없다.(exe파일)

 

 

다음은 소스코드가 컴파일되는 과정이다.

 

 


 

 

컴파일러와 달리, 인터프리터는 먼저 실행 파일(exe)로 컴파일할 필요가 없다.

그냥 소스 코드의 명령을 직접 실행하는 프로그램이다.

 

인터프리터는 컴파일러보다 유연하지만, 프로그램이 실행될 때마다 interpreter 프로세스를 수행해야 하기 때문에 프로그램을 실행할 때 효율성이 떨어진다.

(컴파일러는 한번 exe로 만들고 나면 바로 실행 가능)

 

게다가 번역된 프로그램이 실행될 모든 컴퓨터에 인터프리터가 설치되어야 함을 의미한다.

 

 

다음은 인터프리터의 과정이다.

 

 

 

C, C++ 같은  대부분의 언어는 대부분 컴파일되거나 interpreted 될 수 있지만, 반면 Perl 및 Javascript와 같은 "스크립팅" 언어는 interpreted 되는 경향이 있다. Java 같은 일부 언어는 두 가지를 혼합하여 사용한다.

 

 

 

 

 

C++ 이전에 있던 C는 어떻게 개발되었을까

 

C는 시스템 프로그래밍 언어(운영 체제를 작성하는 데 사용되는 언어)로 개발하고자 만들어졌다.

 

이전의 많은 운영 체제는 어셈블리로 작성되었는데, 특정 CPU에서만 실행되는 프로그램을 만드는 어셈블리와 달리 C는 이식성이 뛰어나 다양한 종류의 컴퓨터에서 쉽게 컴파일할 수 있어서 도입 속도가 빨랐다. 

 

이와 같이 C를 만든 목적은 컴파일하기 쉽고, 효율적인 메모리 액세스가 가능하며, 효율적인 코드를 생성하고, 독립적인(다른 프로그램에 의존하지 않음) 최소한의 언어를 만드는 것 이었다.

 

 

 

1983년에 ANSI(American National Standards Institute)는 C에 대한 공식 표준을 확립하기 위해 위원회를 구성했다.

 

1989년(위원회는 모든 작업을 수행하는 데 시간이 오래 걸림), 이들은 일반적으로 ANSI C로 알려진 C89 표준을 완성하고 발표했다.

 

1990년 ISO(국제 표준화 기구)는 약간의 수정을 거쳐 ANSI C를 채택했다. 이 C 버전은 C90으로 알려져있다. 컴파일러는 결국 ANSI C/C90 규격이 되었고, 최대 이식성을 원하는 프로그램은 이 표준에 따라 코딩되었다.

 

 

 

 


 

 

 

 

 

C에서 확장한 C++ 프로그램의 개발 과정

 

위 과정을 풀어서 알아보자면

 

 

1단계: 무엇을 해결하고 싶은 지 문제를 설정

 

2단계: 설정한 문제를 어떻게 해결할 것인지 정한다. 

여기에서 해결 방법을 정할 때, 모듈화시키기 편한 상태로 제작하여 확장을 고려해야 한다.

 

3단계: 프로그램 작성

프로그램을 작성하려면 프로그래밍 언어에 대한 지식과, 프로그램을 작성하고 저장하기 위한 텍스트 편집기(IDE)가 필요하다.

 

4단계: 소스 코드 컴파일

컴파일러는 우선, 코드를 검사하여 C++ 언어의 규칙을 따르는지 확인한다. 그렇지 않은 경우 컴파일러는 오류(및 해당 줄 번호)를 제공하여 수정이 필요한 부분을 정확히 찾아내는 데 도움을 준다. 오류가 수정될 때까지 컴파일 프로세스도 중단된다.

다음으로, C++ 소스 코드를 object 파일이라는 기계어 파일로 변환한다.

개체 파일의 이름은 일반적으로 name.o 또는 name.obj 이다.

프로그램에 3개의 .cpp 파일이 있는 경우 컴파일러는 3개의 개체 파일을 생성한다.

 

 

 

5단계: obj 파일 및 라이브러리 연결

컴파일러가 하나 이상의 obj 파일을 생성한 후 링커 라는 다른 프로그램이 시작된다.

링커의 작업은 3가지다.

 

첫째, 컴파일러에서 생성된 모든 obj 파일을 가져와서 단일 실행 프로그램(.exe)으로 결합한다.

 

둘째, 위의 obj 파일 뿐만 아니라 라이브러리 파일도 링크할 수 있다. 라이브러리 파일은 다른 프로그램에서 사용할 수 있도록 "패키지"된 미리 컴파일된 코드 모음이다.

 

셋째, 모든 파일 간 종속성이 올바른지 확인한다.

예를 들어 하나의 .cpp 파일에서 무언가를 정의한 다음 이를 다른 .cpp 파일에서 사용하는 경우, 링커는 두 파일을 연결한다. 만약 해당 정의가 있는 항목에 대해 참조를 연결할 수 없으면, 링커 오류가 발생하고 연결 프로세스가 중단된다.

 

링커가 모든 개체 파일과 라이브러리의 연결을 완료하면(모든 것이 잘 진행된다는 가정 하에) exe 파일이 생성된다.

 

여러 단계가 관련되어 있기 때문에 빌드라는 용어는 소스 코드 파일을 실행할 수 있는 exe 파일로 변환하는 전체 프로세스를 나타낸다.

 

6단계 및 7단계: 테스트 및 디버깅

 

 

 

 

 

여기에서 컴파일러를 거치면 왜 obj파일을 생성하는걸까?

 

 

위에서 실행 파일을 생성하기 위해 프로그램의 각 코드 파일을 obj 파일로 컴파일한 다음 실행 파일로 링크하는 과정을 배웠다.

즉, 코드 파일이 컴파일되면 IDE는 obj 파일을 캐시할 수 있다.

이렇게 하면 프로그램이 나중에 다시 컴파일되는 경우, 수정되지 않은 코드 파일을 다시 컴파일할 필요가 없다.

결국 마지막으로 캐시된 개체 파일을 다시 사용할 수 있는 것이다. 비록 약간의 디스크 공간을 희생했지만, 컴파일 시간이 크게 단축될 수 있다.