본문 바로가기
320x100
320x100

프로그램을 작성하다보면 컴파일 타임, 런타임이란 용어들을 접하고...

컴파일, 런타임을 검색하다보면 링크, 빌드, 바인드 이런 용어들도 접하게 된다

 

그럼 이제부터 과연 이게 무엇인지에 대해 알아보자!

나중에 내가 주로 개발하는 언어인 Java와 TypeScript에 대해 말하긴 할것이고, Java는 C#과 많이 비교되는 언어지만..

C언어부터 예로 들어 시작해보겠다

 

Compile

- C언의 컴파일 과정

1. C언어로 프로그램을 만들기 위해선 .c 확장자를 갖고 있는 source file(소스파일)을 작성해야 한다

2. 컴파일을 거치기 전에 Preprocessing(전처리)과정을 거친다. 이 과정에서 #이 붙은 매크로나 전처리기를 해석하거나 해석하지 않거나 등을 선택하고 주석 등을 배제한다

3. 각 CPU 제조사(Intel, ARM)에 맞는 컴파일러가 source file을 compile하여 assembly code(어셈블리 코드)로 변환한다. 이때의 확장자는 GCC 기준으로 .s 또는 .S이다(두 개의 차이는 전처리기같은 매크로를 읽을 수 있는가 여부 등)

4. 컴퓨터는 0과 1밖에 알지 못하기에, 다시 assembly code는 어셈블러에 의해 binary code(바이너리 코드)로 변환된다. 이때의 확장자는 Windows는 .obj파일, Unix는 .o파일이 되며 오브젝트 파일이라고 부른다

- 여기까지가 컴파일 과정

5. 바이너리 코드는 각각 운영체제(Windows, Linux, Mac)에 맞는 실행 파일로 변환되어야 한다. 링커는 이 과정을 실행하고, 이 과정을 Linking이라고 하는데 오브젝트 파일과 Library들을 File들을 묶는 이 링킹을 거쳐서 executable file(실행 파일)이 만들어진다. 만들어진 실행 파일의 이름은 Windows기준으로 .exe또는 .dll이 된다

- 여기까지가 빌드 과정

링킹의 종류는 또 static linking, dynamic linking 등이 있다! 이 차이까지는 다루지 않겠다. 깊게 가면 OS타임이 되어버리니..ㅎㅎ

참고로 .dll은 Dynamic Link Library의 줄임말이다

https://coder-in-war.tistory.com/entry/OS-13-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5-Static-Linking-vs-Dynamic-Linking

 

[ OS ] 13. 메모리 관리 전략 - Static Linking vs Dynamic Linking

Static Linking vs Dynamic Linking 먼저 Linking (링킹)에 대해 이해를 해보자 링킹은, 프로그램을 빌드하는 과정 (즉 컴파일 과정에서 거치는 단계) 이뤄지는 과정이다. 이 전체를 크게 컴파일 과정이라고

coder-in-war.tistory.com

두개의 차이점을 잘 소개한 블로그가 있어 링크를 참조한다

 

- JAVA언의 컴파일 과정

자바는 C언어와는 조금 다른 컴파일 과정을 갖고 있다. 왜냐하면 JMV(Java Virtual Machine - 자바 가상 머신)위에서 바이트코드(목적 코드)가 런타임시 최종인 기계어 파일로 변환되어서 돌아가기 때문이다. 그럼 그 과정을 알아보자

1. Java언어로 프로그램을 만들기 위해선, .java 확장자를 갖고 있는 source file(소스파일)을 작성해야 한다

2. 자바 컴파일러(JAVAC)가 소스코드 파일을 읽어서 .class 확장자를 갖고 있는 byte code(바이트 코드)로 변환한다. byte code는 기계어가 아닌 어셈블리 언어형식이다. 또한 바이트 코드는 하드웨어가 처리하는 것이 아닌, 가상머신(소프트웨어)에 처리되는 언어이다

3. Class Loader에서 .class파일을 JVM에 lazy loading(.class 파일이 실행할때 메모리에 적재함)방식으로 로딩을 한다

(여기에서 loading, linking, Initializaiton을 한다)

자바에서는 링커가 따로 있지 않고, 클래스로더가 이 링킹을 대신한다고 한다

<짧막한 lazy loading>

  • Loading(로딩) : 로드된 클래스 및 부모 클래스 정보, class interface enum 관련 여부, 변수 메서드 정보를 jvm 메모리(Heap 메모리, MetaSpace)에 올림 - loading
  • Verification(증명) : .class 파일이 자바 언어 명세, JVM 명세에 맞게 작성되었는지 검증한다. 실패시 런타임에러 (java.lang.VerifyError) - linking
  • Preparation(준비) : load된 메모리를 기본 값으로 초기화 하고, 클래스 변수를 위한 메모리에 할당함. - linking
  • resolution(해결) : 클래스의 constant pool 내의 symbolic reference를 direct reference로 변경함. - linking
  • Initialization(초기화) : static 변수들이 정의된 값으로 초기화됨. - bootstrap, extension, system/application loader 3종류가 존재

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

https://dev-nomad.com/87

https://mygumi.tistory.com/115

 

4. Runtime Engine에서 .class파일을 Interpreter/Just-In-Time 두개의 방식중 한가지 방식으로 기계어인 binary code로 번역해서 실행한다

<짧막한 interpreter way VS jit way>

  • 인터프리터 : (.class) 파일을 한줄씩 읽어 기계어로 변환함. 여러번 실행 할 경우 비효율적임.
  • Just-In-Time(JIT) :
    • 인터프리터의 비효율을 개선하기 위해 사용되는 컴파일 방식의 파트임.
    • JIT에서 해석된 코드는 메모리 Code Cache에 저장하여 사용함.
    • 인터프리터보다 실행시간이 길고, 캐싱되는데 자원이 사용되므로 반복되지 않는 코드는 인터프리터를 사용하는게 유리하다.

http://www.differencebetween.net/technology/communication-technology/difference-between-compiler-and-interpreter/

https://dev-nomad.com/87

 

JVM은 바이트코드를 읽어서 클래스 로더가 JVM 위에 올리면 실행엔진(인터프리터/JIT) 컴파일러가 해석하고 실행하는 역할을 한다

그렇기 때문에 운영체제체 상관없이 JVM위에서 모든 코드가 동작 되고, JVM이 런타임 환경에서 프로그램 메모리를 최적화하고 관리한다

 

C언어는 운영체제마다 다른 컴파일러(gcc, g++, visual c++)등이 존재하는데 반해, 자바는 JDK를 설치하면 JAVAC(Java Compiler)가 존재하며, javac 명령어로 실행이 가능하다

 

요약하면 컴파일 과정 안에 Link이 포함되어 있으며 Linking은 라이브러리와 실행 파일을 묶거나 어디 있는지 알려주는 연결파일을 설정하는 과정이라고 보면 된다

 

휴, 이제 겨우 Compile과 Link에 대한 설명이 끝났다....

글을 읽는건 금방인데 꽤 긴 시간동안 작성한것 같다

오개념을 전파하면 안되기때문에, 영어와 한글로 여러곳을 돌아다니며 찾았다

그럼 이제 나머지 Build, Run에 대한 설명과

Compile Time, RunTime 에 대한 차이 등을 설명 하겠다! 

 

Build

소프트웨어 빌드(software build)는 개발자가 소스코드로 작성한 것을 컴퓨터나 휴대폰에서 실행할 수 있는(standalone) 소프트웨어 가공물로 변환하는 과정을 말하거나 그에 대한 결과물을 일컫는다고 한다 - 위키 백과사전

Source code -> Executable File

 

C언어와 JAVA의 빌드 과정은 조금 차이가 있다

- C언어의 Build Steps

  • 전처리(Process) : .c, .cpp
  • 컴파일(Compile) : .s, .S
  • 어셈블(Assemble) : .o, .obj
  • 링크(Link) : .exe, .ddl

를 거친다

컴파일 + 링크 = 빌드라고 보면 된다

각 과정의 설명은 위에 적어놨다

 

JAVA언어의 Build Steps

  • 컴파일(Compile)
  • 패키징(Packaging)
  • 테스팅(Testing)
  • 배포(Distribution)

디테일하게 들어간다면

◾ validate - validate the project is correct and all necessary information is available
◾ compile - compile the source code of the project
◾ test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
◾ package - take the compiled code and package it in its distributable format, such as a JAR.
◾ integration-test - process and deploy the package if necessary into an environment where integration tests can be run
◾ verify - run any checks to verify the package is valid and meets quality criteria
◾ install - install the package into the local repository, for use as a dependency in other projects locally
◾ deploy - done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.

을 거친다

참고로 자바는 전처리 과정이 없다

https://stackoverflow.com/questions/20546659/how-to-provide-preprocessor-directives-in-java

 

How to provide preprocessor directives in Java

CHow can I correctly provide the following functionally from C# in Java? [C#] #define PRODUCTION //Change from sandbox to production to switch between both systems. #if SANDBOX using NetSuite....

stackoverflow.com

또한 Build Tool로는 Ant, Maven, Gradle이 있다

Ant는 단순히 Build Tool이지만, Maven, Gradle은 의존관리까지 추가로 해준다

 

사실 Package 까지가 JAR, WAR, EAR등 JRE가 실행 가능한 압축 파일을 만드는 과정이다

JDK는 자바 개발 환경을 제공하는 Kit이고 실행파일을 자바환경 위에서 돌리려면 JRE가 필요하다(통상 JDK를 설치하면 같이 설치됨)

 

정확히는 패키징까지라고 보면 되는데, 관례상 빌드라고 검색하면 저런 일련의 과정들이 나오는것 같다..

https://stackoverflow.com/questions/2650168/building-vs-compiling-java

 

Building vs. Compiling (Java)

Thinking that the answer to this is pretty obvious but here it goes: When I am working on a small project for school (in java) I compile it. On my coop we are using ant to build our project. I

stackoverflow.com

 

그리고 또한 이 빌드 과정은 각기 언어 타입에 따라 달라지기도 하고, 달라지기도 하고, 다른 방식을 선택할 수도 있다

1. Compile Type

- 컴파일 언어: C, C++, Go, TypeScript

2. Interpreted Type

- 인터프리터 언어: Python, R, JavaScript, PHP

3. Hybrid Type

- 하이브리드 언어: Java, C#

 

빌드 과정은 컴파일 과정을 포함하고 있다고 했는데, 인터프리터 언어의 경우에는 소스코드를 통번역 하는 것이 아닌 한 명령 단위로 해석하면서 즉시실행하는 방법을 택하고, 목적 파일을 생성하지 않고 실행해주는 환경(Interpreter - 인터프리터)에서 곧 바로 실행이 가능하기 때문에 컴파일 과정을 거치지 않고 소스코드 자체를 곧바로 실행해준다. 컴파일 언어는 플랫폼에 종속적이고, 인터프리터 언어는 플랫폼에 독립적으로 실행이 가능하다

마지막으로 Java는 컴파일을 거치지만, 바이너리 코드인 목적 파일을 만들지 않고, 그 중간의 언어인 바이트 코드(.class)로 만들어서 해석 또는 실행을 Interpreter인 VM(자바로 치면 JVM, JRE)에 맡기기 때문에, 컴파일 + 인터프리터를 함께 갖고 있어서 하이브리드 언어라고 하는 것이다(C#의 경우 닷넷 - .NET)

 

글이 좀 장황했지만, 이해한 내용을 정리하면 컴파일 언어는 목적 파일을 만들면서, 컴파일 과정을 거친다. 인터프리터 언어는 컴파일 과정 없이 곧바로 인터프리터에 의해 실행된다. 하이브리드는 컴파일 과정을 거쳐서 실행 과정을 독립의 VM에 맡긴다

참고로 꼭 이 프로그래밍 언어가 ㅇㅇ 언어이다 정해진 것은 없다고 한다!!

-> 무슨 언어는 컴파일 타입이다, 이런 방식의 결론내는 것은 좋지 않다고 본다

예를 들어 Javascript의 경우 WebAssembly 과정을 거치게 할 수도 있고, 플랫폼에 따라 엔진 내부(현대의 Chrome V8 등등)에서 JIT등을 통해 컴파일 과정을 거치기도 한다

또한 Python을 JVM위에서 실행할 수도 있거나, C++을 인터프리터를 통해서 해석이 가능하다

여담이지만, 내가 최근에 개발하고 있는 TypeScript도 컴파일 과정과 AST 과정을 거쳐서 .js파일이 만들어지고, 그 과정에서 문법적 오류를 잡아줄 수 있어서 너무너무 좋은 것 같다!

 

Run

마지막으로 런, 런타임 환경에 대해서 작성해보려고 한다. 인터프리터 언어의 경우 곧바로 실행되기 때문에, 런타임 환경에서 에러를 잡아야 한다. 그렇기 때문에 JS에서 곧바로 디버깅을 하기 어렵다고 생각한다

사실 Run을 서두에 적은 것은, CompileTime, RunTime의 차이점과 이 때 발생하는 에러들을 적기 위해서이다

현대의 모든 라이브러리들은 대체로 Compile time에 프로그래머의 실수를 잡을 수 있도록 개발되고 개선되는 것 같다

그리고 개발자는 사람이라는 것에 명심하며, 항상 실수하는 것을 염두하고 컴파일 타임에 IDE가 에러를 알려주도록 하는 방식으로 하는 것이 유지보수를 하고, 실수를 줄이기 위해 좋을 것이다

예를 들면 Mybatis를 사용시 Namespace를 적거나, 단순 파일명으로 String으로 접근하는 방식 - QueryID, 보다는 Interface로 접근하는 방식이 사용하지 않는 Query등을 알려주기도하고, string이 아니기때문에 query - method를 매핑할때 오류가 없다

비슷하게 Querydsl도 컴파일타임에 오류를 잡아주기때문에 복잡한 쿼리 등을 오류 없이 개발할 수 있게 도와주는 좋은 라이브러리다

또한 Lombok은 Annotation Processor(어노테이션 전처리기)라고 하며, 컴파일 타임때 AST에 따라 동적으로 바이트 코드를 추가해준다

여러가지 Mapper의 비교를 한 글을 본 적이 있었는데, MapStruct는 컴파일 타임 시점에 매핑을 하고, ModelMapper는 런타임 시점에 Reflection을 통해서 매핑을 시켜준다고 한다

< 이런차이점을 알려면 런타임을 아는 것은 중요하다고 생각한다

마지막으로 토비의 스프링 책에서 개발자는 RuntimeException또는 이것을 상속받는 예외만을 throw 해야 한다는 내용을 봤다

우리는 Error(에러)가 아닌, 실행중에 발생할 수 있는 Exception(예외)를 처리해야 하는 것이다

 

- Run Time

  컴파일 과정을 마친 응용 프로그램이 사용자에 의해서 실행되어 지는 '때'를 의미한다

- Run Time Error

  프로그램 실행 중에, 의도치 않은 예외상황으로 인하여 프로그램 실행 중에 발생하는 오류 형태

- Compile Time

  기계어 코드로 번역하면서, 실행 가능한 프로그램이 되는 '때'를 의미한다(빌드 이전 과정)

- Compile Time Error

  소스코드가 컴파일 되는 과정 중에 발생하는 오류들로, 프로그램이 성공적으로 컴파일되지 못하는 상황에 발생하고, 문제가 발생하는 원인 코드를 알려준다

 

* 런타임 에러의 종류

  • 0 나누기 오류(Division By Zero)
  • NULL Pointer Exception(널 참조 오류) - 메모리에 올라와있지 않은 변수나 함수를 참조하려고 할때 발생
  • 메모리 부족 오류

* 컴파일타임 에러의 종류

  • Syntax Error(문법 오류)
  • Type Check Error(타입 체크 오류)

+ 추가

Binding Time(바인딩 타임)

- Bind

이름(a name)에 변수나 함수 등에 코드, 클래스 등을 실제로 연결하는 것

- Binding Time

  이름(name)에 속성이나 값이 연결되는 시점

  Attribute와 Entity의 결합

- Binding Time의 종류

  1. 언어 디자인 시점

  2. 언어 구현 시점

  3. 프로그램 작성 시점

  4. 컴파일 시점

  5. 링크 시점

  6. 로드 시점

  7. 실행 시점

- Static Binding VS Dynamic Binding

여기에 위에서 설명한 컴파일러 언어와 인터프리터 언어의 차이점이 쓰인다

각 언어마다 static, dynamic 바인딩 둘다 쓰이지만..

컴파일러 언어가 binding에 대한 결정을 조금 일찍 내린다(Static Binding이 더 많다)

순수한 인터프리터 언어는 프로그램을 실행할 때마다 바인딩을 결정한다(Dynamic Binding이 더 많다)

빠른 바인딩 시점(대부분의 컴파일 언어) => 높은 효율성

느린 바인딩 시점(대부분의 인터프리터 언어) => 높은 유연성

인터프리터 언어는 실행 시간에 type checking을 하기 위한 비용이 든다

 

바인딩의 시점은 각 언어의 타입에 따라 다르지않을까 생각한다!(Binding Time의 종류에 나와있다)

다음 글은 JAVA쪽으로 넘어가서 Ant, Maven, Gradle의 차이점과 빌드파일의 차이점에 대한 얘기를 해볼까 한다..!!

 

참고

https://chayan-memorias.tistory.com/130

https://code-lab1.tistory.com/64

 

+ 심심해서 찾아본 실행 파일들 종류

https://fileinfo.com/filetypes/executable

 

Executable File Formats

Executable Files Executable files contain code that is run when the file is opened. Windows programs, Mac OS X applications, scripts, and macros are all considered executable files. Since these file types run code when opened, unknown executable files, suc

fileinfo.com

https://www.microfocus.com/documentation/visual-cobol/vc50/EclWin/HHBUCHCOMP03.html

 

Executable File Formats

You must compile your program to an executable before it can be run or debugged. This topic summarizes the different types of executable file that the Micro Focus COBOL Compiler can produce. It also gives recommendations to help you choose which file forma

www.microfocus.com

320x100

댓글