사전 kotlinc
인터페이스

kotlinc

gabury1

kotlinc 는 코틀린으로 쓴 소스를 자바 가상 머신이 실행할 파일로 바꿔 주는 명령입니다. 터미널에서 소스 파일 이름을 넘겨 부르면 결과 파일을 만들어 놓습니다. 사람이 손으로 부릅니다. 빌드 도구가 대신 부르기도 합니다.

쉽고 빠른 이해

kotlinc 는 코틀린 소스를 자바 가상 머신이 읽는 파일로 바꿔 주는 명령입니다. kotlinc hello.kt -d out 처럼 부르면 out 밑에 실행할 파일이 놓입니다.

가상 머신은 코틀린 문법을 모릅니다. 소스를 그대로 넘기면 아무 일도 못 합니다. 미리 가상 머신이 아는 형태로 옮겨 두어야 실행이 됩니다.

어떻게 도는가:

  1. 넘겨받은 소스를 읽어 문법과 타입이 맞는지 봅니다
  2. 맞으면 가상 머신이 아는 명령어로 옮깁니다
  3. 옮긴 결과를 파일로 쓰거나 파일 하나로 묶습니다

대가가 있습니다. 명령을 부를 때마다 가상 머신이 새로 떠서 시작이 굼뜹니다. 결과 파일은 코틀린 표준 라이브러리가 있어야 돕니다. 그 라이브러리를 결과에 같이 넣거나, 실행할 때 어디 있는지 알려 줘야 합니다.

그래서 실무 빌드는 이 명령을 직접 부르지 않고 빌드 도구에 맡깁니다. 손으로 부르는 것은 파일 한두 장을 시험할 때입니다.

상세

kotlinc 는 코틀린 컴파일러를 터미널에서 부르는 명령입니다. 넘겨받은 .kt 소스를 읽어 JVM(Java Virtual Machine, 자바 가상 머신)이 실행할 형태로 옮깁니다. 그 형태가 바이트코드입니다.

바이트코드는 가상 머신 하나가 알아듣는 명령어 형식입니다. 그 명령어를 담는 파일이 클래스 파일입니다.

가상 머신은 코틀린 문법을 모릅니다. 소스를 그대로 넘기면 실행할 것이 없습니다. 그 사이를 메우는 것이 이 명령입니다.

자바 쪽의 javac 와 같은 노릇입니다. 읽는 언어만 다르고 내놓는 것은 같은 클래스 파일입니다. 그래서 kotlinc 가 만든 파일과 javac 가 만든 파일을 한 프로그램 안에 섞어 놓을 수 있습니다.

flowchart TD
    A["hello.kt · 코틀린 소스"] --> B["kotlinc"]
    B --> C["클래스 파일 · 바이트코드"]
    C --> D["자바 가상 머신"]
    E["코틀린 표준 라이브러리"] --> D

가상 머신은 클래스 파일과 라이브러리를 같이 읽어 프로그램을 돌립니다. 표준 라이브러리는 코틀린 코드가 기대는 함수 묶음입니다. kotlinc 가 만들지 않고 따로 딸려 옵니다.

그림의 아래쪽 절반이 kotlinc 가 손대지 않는 대목입니다. 컴파일은 파일을 만드는 데서 끝납니다. 그 파일을 돌리는 것은 java 명령의 몫입니다.

명령 하나가 하는 일은 세 단계입니다. 넘겨받은 소스를 읽어 문법이 맞는지 봅니다. 그다음 타입이 서로 맞는지 봅니다. 둘 다 통과하면 바이트코드로 옮깁니다. 옮긴 결과를 파일로 씁니다.

부르는 꼴

명령 뒤에 소스 파일을 늘어놓습니다. 결과를 어디에 쓸지는 -d 로 정합니다.

터미널
kotlinc hello.kt -include-runtime -d hello.jar
java -jar hello.jar

첫 줄은 소스 한 장을 컴파일해 JAR(Java ARchive, 자바 아카이브) 파일 하나로 묶는 명령입니다. JAR 은 클래스 파일 여럿을 한 파일로 묶은 것입니다. 자바 세계에서 프로그램을 나르는 기본 단위입니다. 둘째 줄은 그 묶음을 실행하는 명령입니다.

옵션은 여럿이지만 손으로 부를 때 쓰는 것은 대개 아래 넷입니다.

옵션 무엇을 정하나
-d 결과를 쓸 디렉토리나 JAR 파일 이름
-include-runtime 코틀린 표준 라이브러리를 결과 JAR 안에 같이 넣을지
-classpath 컴파일하는 동안 참조할 클래스 파일과 라이브러리를 찾을 곳
-script 넘긴 파일을 스크립트로 보고 바로 실행할지

표준 라이브러리를 함께 넘기는 두 방법

코틀린 코드는 자기 표준 라이브러리에 기대어 돕니다. 문자열을 자르는 함수도, 목록을 도는 함수도 그 라이브러리 안에 있습니다. 컴파일 결과만 들고 다른 기계로 가면 실행할 때 그 함수를 못 찾고 멈춥니다.

-include-runtime 은 라이브러리를 결과 JAR 안에 같이 넣습니다. 대신 결과 파일이 커집니다. 넣지 않았다면 실행할 때 클래스패스에 라이브러리를 얹어 줘야 합니다. 클래스패스는 가상 머신이 클래스 파일과 라이브러리를 찾아 뒤지는 목록입니다.

flowchart TD
    subgraph INC["-include-runtime 을 준다"]
        I1["JAR 하나 · 클래스 파일 + 표준 라이브러리"]
    end
    subgraph NOINC["안 준다"]
        O1["JAR · 클래스 파일만"]
        O2["표준 라이브러리 · 따로 있다"]
    end
    I1 --> R1["java -jar 로 바로 실행"]
    O1 --> R2["둘 다 클래스패스에 얹어야 실행"]
    O2 --> R2

위 묶음은 옮길 것이 파일 하나입니다. 아래 묶음은 파일 둘을 같이 옮기고 실행할 때 둘의 위치를 알려 줘야 합니다.

자바 소스를 같이 넘길 때

한 프로젝트에 코틀린 파일과 자바 파일이 섞여 있는 일은 흔합니다. 이때 컴파일러 둘이 다 필요합니다.

kotlinc 는 자바 소스 파일을 인자로 받기는 합니다. 다만 그 파일은 이름과 타입을 푸는 데만 읽습니다. 자바 파일에서 클래스 파일을 만들어 주지는 않습니다. 자바 쪽은 JDK(Java Development Kit, 자바 개발 키트)가 주는 javac 가 따로 컴파일해야 합니다.

flowchart TD
    K["코틀린 소스"] --> KC["kotlinc"]
    J["자바 소스"] --> JC["javac"]
    J -. 이름과 타입만 읽는다 .-> KC
    KC --> C1["클래스 파일"]
    JC --> C2["클래스 파일"]
    C1 --> R["한 프로그램"]
    C2 --> R

두 컴파일러가 각자 클래스 파일을 내놓습니다. 가상 머신은 그것들을 구분하지 않습니다. 코틀린에서 만든 클래스든 자바에서 만든 클래스든 실행할 때는 똑같이 다뤄집니다.

클래스 이름을 지어내는 규칙

코틀린은 파일 맨 위에 함수를 바로 적을 수 있습니다. 가상 머신에는 그런 것이 없습니다. 모든 코드가 클래스 안에 들어 있어야 합니다.

그래서 kotlinc 는 파일 이름을 가져다 클래스 이름을 지어냅니다. hello.kt 파일 맨 위에 적은 함수들은 HelloKt 라는 클래스의 메서드가 됩니다. 자바 코드에서 그 코틀린 함수를 부를 때 이 이름으로 부릅니다.

flowchart TD
    subgraph SRC["hello.kt · 코틀린 소스"]
        F["맨 위에 적은 함수들"]
    end
    subgraph CLS["HelloKt · 클래스 파일"]
        M["그 함수들이 된 메서드"]
    end
    SRC -- kotlinc --> CLS

파일 최상위에 있던 함수가 지어낸 클래스 안으로 들어갑니다. 자바 쪽에서 그 함수를 부를 때 클래스 이름이 앞에 붙는 까닭입니다.

이름이 어떻게 붙었는지 궁금하면 결과 파일을 javap 로 열어 볼 수 있습니다. javap 는 클래스 파일 안에 무엇이 들었는지 글로 찍어 주는 명령입니다.

컴파일이 실패할 때

오류는 파일 이름과 줄 번호를 달고 나옵니다. 어느 파일 몇째 줄에서 무엇이 안 맞는지가 한 줄로 찍힙니다.

오류가 하나라도 있으면 kotlinc 는 결과 파일을 만들지 않습니다. 대신 0 이 아닌 종료 코드를 남기고 끝냅니다. 종료 코드는 명령이 끝날 때 셸에 남기는 숫자입니다. 0 이면 성공, 그 밖이면 실패라는 뜻입니다. 빌드 도구는 이 숫자를 보고 다음 단계로 갈지 멈출지 정합니다.

경고는 다릅니다. 찍히기만 합니다. 컴파일은 끝까지 갑니다. 경고도 오류로 치고 싶으면 -Werror 를 줍니다. 그러면 경고가 난 컴파일도 결과 파일 없이 끝납니다.

flowchart TD
    A["문법 검사"] --> B["타입 검사"]
    B --> Q{"오류가 있나"}
    Q -- 예 --> F["결과 파일 없음 · 종료 코드 0 아님"]
    Q -- 아니오 --> W{"경고를 오류로 치나 · -Werror"}
    W -- 예 --> F
    W -- 아니오 --> S["결과 파일 나옴 · 종료 코드 0"]
    F --> STOP["빌드 도구가 멈춘다"]

검사 둘을 다 지나야 결과 파일이 나옵니다. -Werror 를 준 컴파일은 경고 하나만 있어도 오류와 같은 끝을 맞습니다.

부를 때마다 새로 뜨는 가상 머신

kotlinc 자신이 가상 머신 위에서 도는 프로그램입니다. 컴파일러도 클래스 파일로 배포됩니다. 명령은 그 클래스 파일을 띄우는 짧은 스크립트입니다.

그래서 명령을 부를 때마다 가상 머신이 새로 뜨고 컴파일러를 읽어 들입니다. 소스 한 줄을 고쳐 다시 부를 때도 이 준비 시간을 매번 냅니다. 실무 빌드가 kotlinc 를 직접 안 부르고 Gradle · Maven 같은 빌드 도구에 맡기는 까닭입니다. 빌드 도구는 컴파일러를 살려 둔 채 여러 번 시킵니다.

손으로 부르게 되는 때

빌드 도구가 잡고 있는 프로젝트에서 kotlinc 를 직접 부를 일은 드뭅니다. 손으로 부르는 때는 대개 셋입니다.

  • 파일 한두 장으로 문법이나 동작을 확인해 볼 때
  • 코틀린 스크립트 한 장을 -script 로 그때그때 실행할 때
  • 인자 없이 불러 대화형 셸을 띄우고 한 줄씩 쳐 볼 때

셋째의 대화형 셸을 REPL(Read-Eval-Print Loop, 읽고 계산해 찍는 되풀이)이라고 부릅니다. 한 줄을 받아 계산하고 결과를 찍는 것을 되풀이합니다. 파일을 만들지 않고 표현식 하나를 시험할 때 씁니다.

가상 머신 밖의 대상

kotlinc 가 내놓는 것은 가상 머신용 결과입니다. 코틀린 코드는 자바스크립트나 기계어로도 옮길 수 있습니다. 그 대상은 이 명령이 맡지 않습니다.

대상마다 명령이 따로 있습니다. 자바스크립트는 kotlinc-js, 기계어는 kotlinc-native 가 받습니다. 이름이 비슷해도 내놓는 결과는 다릅니다. 실행 환경을 정하는 것이 곧 명령을 고르는 일입니다.

관련 항목

kotlinc 를 사이에 둔 입력 언어와 출력 파일

코틀린 · 코틀린 스크립트 · 클래스 파일 · 바이트코드 · JAR · 표준 라이브러리

kotlinc 가 만든 파일을 실행하는 자바 실행 환경

JVM · JRE · JDK · 클래스패스 · 클래스 로더

같은 일을 하는 다른 컴파일러 명령

javac · scalac · groovyc · kotlinc-js · kotlinc-native

kotlinc 를 대신 불러 주는 빌드 도구

Gradle · Maven · 빌드 도구 · 증분 컴파일

kotlinc 안에서 소스가 거치는 단계

컴파일러 · 구문 분석 · 타입 검사 · 코드 생성 · 최적화

컴파일 결과를 열어 보는 도구

javap · 디컴파일러 · 상수 풀 · 디버깅 정보

kotlinc 가 실패를 알리는 방법

컴파일 오류 · 경고 · 종료 코드 · 표준 오류

다른 이름: kotlinc 명령