최근 로봇이란 새로운 분야를 접하게 되면서, build라는 당연하고도 당연한 과정에 대해서 다시 한번 생각하게 되었다. 왜냐하면 ros 내부에서는 catkin(cmake 기반의 빌드 도구)를 사용했기 때문이다.![]
In software development, a build is the process of converting source code files into standalone software artifacts that can be run on a computer, or the result of doing so.
-from Wikipedia [Software Build]
그런데 이 빌드라는 과정이 프로그램이 실행되는 플랫폼, 사용되는 언어에 따라서 달라진다.그러나 공통적인 부분은 번역이 일어난다는 점이다. 언어에는 고수준과 저수준이 있다. 그래서 고수준의 언어를 저수순으로 번역하면서 종국에는 내가 사용하는 플랫폼이 이해하는 기계어로까지 번역시켜야 한다. (여기서 주목하고 싶은 점은 플랫폼도 사용하는 언어가 있다는 것이다.)
그래서 내가 앞으로 사용해야 할 Python, C, C++가 Linux에서 어떻게 Build 되는지 살펴보자.
C언어의 빌드 과정을 보면 나머지 언어의 빌드 과정을 이해하는데 도움이 된다.
왜냐하면 가장 기본적이기 때문이다. 또한 컴퓨터 구조와 연관된 부분이 언어 수준에서 추상화 되어 있지 않아 컴퓨터 구조를 이해하는데도 도움이 된다.
또한 빌드 과정 중에서 컴파일러나 인터프리터가 플랫폼에 대한 정보를 알고 있어야 한다. 왜냐하면 번역하고자 하는 언어가 무엇인지 알고 있어야 하기 때문이다. 아까도 말했듯이 플랫폼은 자신만의 언어가 있다.
c++은 c언어에 객체지향 개념이 추가된 언어이다. 그래서 기본적인 개념이 크게 다르지 않다는게 특징이다.
파이썬은 위의 컴파일 언어들과 다르게 인터프리터 언어이다. 인터프리터 언어의 가장 큰 특징은 곧바로 인터프리터에 의해서 바로 실행된다는 점이다. 그리고 플랫폼 중립적인 성격이 있어서 위의 언어들과 다르게 플랫폼에 대해서 신경 쓰지 않아도 된다. 그래서 리눅스에서 작성한 코드도 곧바로 다른 플랫폼에서 실행시킬 수 있다.
공통적으로 내가 빌드 과정 중에 어떤 프로그램이 사용되었는지 명시하였는데, 이는 빌드 과정 중에 로그를 이해할 때 도움이 된다.
우리는 지금까지 언어가 어떻게 빌드되는지 언어마다 다른 과정을 살펴보았다.
그리고 이런 빌드를 도와주는 빌드 자동화 도구가 있다. 바로 make이다.
위에서 본 과정은 하나의 소스 코드를 빌드하는 과정을 나타낸 것이다. 그러나 만약 프로젝트가 커져서 여러 개의 소스 코드를 빌드해야 하는 경우 어떻게 해야 할까? 빌드 자동화 도구가 없다면 빌드를 n번 반복해야 한다. 따라서 프로젝트의 크기가 커져서 여러 번 반복되는 빌드와 신경써야 할 옵션들을 하나의 스크립트로 작성하여 이런 빌드 과정을 자동화 한다.
이것이 바로 make를 gcc, g++와 같은 빌드 명령어 대신에 사용하는 이유이다.
(즉, 프로젝트가 커진다면 make를 써서 빌드한다!)
위에서 말한 빌드 과정을 스크립트화 한 파일이다. 간단한 예시를 통해 이해한다.
파일 구조는 다음과 같이 가정한다
main.c: 메인 소스 파일
util.c: 유틸리티 함수들이 있는 소스 파일
util.h: util.c에 대한 헤더 파일
# Compiler to use
CC = gcc
# Compiler flags
CFLAGS = -Wall -g
# Object files
OBJ = main.o util.o
# Target executable
TARGET = myprogram
# Default rule
all: $(TARGET)
# Link object files to create the target executable
$(TARGET): $(OBJ)
$(CC) $(CFLAGS) -o $(TARGET) $(OBJ)
# Compile main.c to produce main.o
main.o: main.c util.h
$(CC) $(CFLAGS) -c main.c
# Compile util.c to produce util.o
util.o: util.c util.h
$(CC) $(CFLAGS) -c util.c
# Clean rule to remove object files and the target executable
clean:
rm -f $(OBJ) $(TARGET)
이 makefile을 사용하면 다음과 같은 명령어가 가능하다
make: myprogram을 빌드. (기본 타겟은 all)
make clean: 빌드 과정에서 생성된 오브젝트 파일과 실행 파일을 삭제
이렇게 하면 main.c나 util.c 파일이 변경될 때마다 전체 프로그램을 수동으로 컴파일할 필요 없이 make 명령어 하나로 쉽게 빌드할 수 있다.
그러나 make에도 문제는 있다.
gcc, g++ 명령어는 단일 빌드 과정을 자동화 해주어 도움을 주지만, 프로젝트가 커져 여러 소스 코드를 빌드해야 하는 경우 그 과정이 반복되고 복잡해지는 문제가 있었다.
make는 이런 반복되고 복잡한 빌드 과정을 스크립트로 작성하여 한번에 실행할 수 있도록 도움을 준다. 즉, 빌드의 단위를 단일 소스 코드에서 프로젝트 단위로 확장시켜준다. 그러나 이런 make도 플랫폼이 변경되는 경우에 수정해줘야 하는 메타 데이터들이 있다. 즉, make는 플랫폼 종속적인 문제가 있다.
cmake는 make의 플랫폼 종속적인 문제를 해결하기 위해 나왔다. 처음에도 이야기 했듯이 플랫폼에도 사용하는 언어가 있다. 칩셋의 종류, 운영체제의 종류에 따라서 프로그램 빌드 과정 중에 생성된 아티펙터들의 내용이 달라질 수 있다. 그렇게 된 경우에는 빌드된 파일을 다른 플랫폼에서 실행하는 경우 실행되지 않는다.
cmake는 이런 플랫폼과 관련된 메타 데이터를 스크립트에 작성해두고, 이를 바탕으로 Makefile 파일을 생성한다. 그리하여 플랫폼에 적합한 빌드 스크립트를 작성하여 플랫폼 독립적으로 빌드가 가능하게끔 해준다.
위에서 말한 플랫폼과 관련한 메타 데이터를 스크립트화 시켜둔 파일을 말한다.
간단한 예시로 이해해보자.
# CMake 최소 버전을 지정
cmake_minimum_required(VERSION 3.10)
# 프로젝트 이름과 사용할 언어를 지정
project(MySimpleProject VERSION 1.0 LANGUAGES CXX)
# C++ 표준을 지정
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 실행 파일을 만들기 위한 소스 파일을 지정
add_executable(MySimpleProject main.cpp)
# 필요한 라이브러리가 있다면 이렇게 링크할 수 있습니다.
# target_link_libraries(MySimpleProject SomeLibrary)
이 CMakeLists.txt 파일은 다음을 수행한다
빌드명령어
mkdir build # 빌드 파일을 저장할 디렉터리 생성
cd build # 디렉터리로 이동
cmake .. # 상위 디렉터리의 CMakeLists.txt 파일을 기반으로 설정 생성
make # make 명령으로 빌드 수행
위의 과정을 통해 플랫폼 독립적이며, 프로젝트 단위의 빌드 자동화 과정을 거쳐서 하나의 프로젝트를 빌드 시킬 수 있다.
https://easy-study-note.tistory.com/9
https://hsunnystory.tistory.com/112
https://en.wikipedia.org/wiki/List_of_build_automation_software
https://medium.com/swlh/a-brief-introduction-to-build-systems-1e45cb1cf667
https://dobby-the-house-elf.tistory.com/109
다음 글에서는 catkin에 대해서 알아본다!!
(사실 이게 핵심이었는데.. 하다보니 내용이 길어져서 따로 쓴다.)