Go에서 바이너리(Binary)란 Go 프로그램이 실행 가능한 독립적인 기계어 파일로 컴파일 된 결과물을 의미한다.
Go는 C/C++처럼 컴파일 언어로서, 다른 언어들과 달리 실행에 필요한 모든 요소를 포함한 단일 바이너리(single binary) 파일을 생성하기 때문에, 별도의 런타임이나 의존성 없이 어느 환경에서든 쉽게 배포하고 실행할 수 있다.
"싱글 바이너리"라는 말은 보통 그 프로그램을 실행할 때 별도의 런타임(예:JVM, Node.js, Python 인터프리터)이나 외부 라이브러리를 따로 설치하지 않아도, 그 실행 파일 하나만 있으면 곧바로 실행된다는 뜻이다.
예를 들어, 실행 파일 하나면, 추가로 "자바 런타임 깔아라", "npm 설치해라"같은게 필요 없다는 뜻이다. (전제 : 필요한 코드와 라이브러리를 정적 링크하거나, 최소한 OS에 기본으로 있는것만 사용)
Go, Rust는 보통 싱글 바이너리로, 배포하기가 쉽다. 주의할 것은 싱글바이너리가 외부서비스(DB, Redis)까지 없다는 뜻은 아니다. 그건 서비스 의존성이고, 런타임 의존성과는 다른 개념!
작성한 .go 소스코드를 go build로 기계어 실행파일로 변환하면 바이너리 실행파일이 생성된다. 이 실행 파일은 OS와 CPU 아키텍쳐에 맞는 순수 기계어 코드이기 때문에, 별도의 런타임 의존성이 필요 없는 것이다.
그러면 더 자세히 go build 명령어에 대해서 알아보자.
go build
기본적인 go build 명령어는 해당 디렉토리에 있는 Go 소스 파일을 컴파일하여 실행 파일을 생성한다.
이 명령어는 현재 디렉토리의 main 패키지를 찾아 컴파일하고, 디렉토리에 바이너리 파일을 생성한다
go build main.go
이 명령어는 main.go이라는 파일만 컴파일하여 바이너리를 생성한다.
go build -o myApp
-o 플래그를 사용하면 생성할 실행 파일의 이름을 지정할 수 있다.
go build
외부 모듈을 사용하는 프로젝트라면, Go 프로젝트 루트에 go.mod 파일이 존재할 것이고, 이 경우 go build 명령어를 사용하면 자동으로 go.mod에서 필요한 의존성을 확인하고 해당 모듈들을 포함한 상태로 빌드를 수행하다. 필요한 모듈들이 다운로드 되지 않았을 경우 자동으로 다운로드하여 빌드가 진행된다.
Go는 크로스 컴파일을 매우 쉽게 지원하는데, 환경 변수 GOOS와 GOARCH를 설정하여 다른 운영체제나 아키텍쳐용으로 빌드를 할 수 있다.
GOOS=windows GOARCH=amd64 go build -o myApp.exe
GOOS=linux GOARCH=amd64 go build -0 myApp
go build -gcflags "-N -l"
-gcflags 플래그를 사용하면 최적화를 비활성화하고 디버깅을 위한 추가 정보를 포함한 바이너리를 생성한다.
go build -ldflags "-s -w"
-ldflags 플래그를 사용하면 디버그 정보를 포함하지 않은채로 바이너리를 생성한다. 따라서 파일 크기가 줄어든다.
go build -trimpath
-trimpath 플래그를 사용하면 빌드 환경의 로컬 정보를 제거한 채로 바이너리를 생성한다. 사용자 이름 등 포함된 로컬 PC에서의 경로 정보 유출을 방지한다.
-ldflags, -trimpath 이 두개의 옵션을 지정하면, 파일 사이즈는 작아지고, 불필요한 정보가 남지 않기 때문에, 릴리스시에는 꼭 붙이기를 권장한다.
빌드가 완료되면, 생성된 실행 파일을 확인할 수 있는데, 터미널에서 ls 명령어를 사용하면 파일을 확인하거나 해당 디렉토리에서 실행 파일을 실행할 수 있다.