Developer Document

Embedded Software 개발을 하면서 습득한 내용을 적은 시니어 개발자들의 글

코 독 코 독 CoderDocument

Embedded SW 기초

컴파일러 & 크로스 컴파일

뜨요르 2024. 6. 15. 16:40

컴파일러란?

인간의 언어에 가까운 소스코드(maic.c)를 컴퓨터가 이해할 수 있는 기계어로 변환하는 과정으로 컴파일된 파일을 Object File(main.o)이라고 부른다.

컴파일러의 종류로는 gcc, g++ clang 등이 존재한다.

 

컴파일 과정

컴파일 과정

  • 전처리 (Pre-processing) 과정

전처리기를 통해 소스코드 파일(*.c)을 전처리된 파일 (.*i)으로 변환하는 과정이다.

주석을 제거하고, #include 지시문을 만나면 해당 헤더 파일을 찾아 헤더 파일에 있는 모든 내용을 복사해 소스코드에 삽입, =

#define 지시문에 정의된 매크로를 저장하고 해당 내용을 치환한다.

  • 컴파일 (Compilation) 과정

컴파일러를 통해 전처리된 파일(*.i)을 어셈블리어 파일(*. s)로 변환하는 과정

  • 어셈블리 (Assembly) 과정

어셈블러를 통해 어셈블리어 파일(*.s)을 오브젝트 파일(*. o)로 변환하는 과정

오브젝트 파일이란 사람이 알아볼 수 없는 기계어로 작성된 코드를 오브젝트 코드라고 부른다. 그리고 오브젝트 코드로 구성된 파일을 오브젝트 파일이라고 하며 특정 파일 포맷을 가짐

  • 링킹 (Linking) 과정

링커를 통해 오브젝트 파일(*.o)를 묶어 실행파일로 만드는 과정

이 과정에서 오브젝트 파일들과 프로그램에서 사용하는 라이브러리 파일들을 링크하여 하나의 실행 파일로 만듦

 

gcc 컴파일

명령어 설명
gcc 파일명(*.c) Default로 out 파일이 생성됨(*.out 이라는 파일이 생성되며 실행 가능)
gcc -c 파일명(*.c) 오브젝트 파일을 생성함(*.o라는 오브젝트 파일이 생성됨)
gcc -c 오브젝트파일명(*.o) 파일명(*.c)
gcc -o 실행파일명(*.out) 오브젝트_파일명(*.o)
실행 파일을 만듦
gcc -o 실행파일 파일명(*.c) 실행 파일을 만듦 (바로 위 2줄을 간략화한 것)
(소스 파일 컴파일 > 오브젝트 파일 생성 > 실행 파일 생성 > 오브젝트 파일 삭제)

 

gcc 옵션

옵션 설명
-Wall 모든 모호한 코딩에 대해 경고를 보냄
-W 합법적이지만 모호한 코딩에 대해 경고를 보냄
-W -Wall 아주 사소한 모호성에 대해서도 경고를 보냄
-w(소문자) 모든 에러 메시지를 출력 하지 않음
-Werror 경고를 오류로 표시, 모든 경고를 컴파일을 중단하는 에러로 취급해서 경고 하나만 나와도 컴파일 중단
-Wextra -Wall에 의해 활성화되지 않는 추가적인 Warning flags를 활성화
-O2 최적화 레벨 2로 설정 (대부분의 최적화를 시도)
-E 전처리 과정의 결과를 화면에 보이는 옵션 (전처리 과정 중 발생한 오류 검증)
-S cc1으로 전처리된 파일을 어셈블리 파일로 컴파일까지만 수행하고 멈춤 (*.s)
-D [메크로상수명]=[값] 매크로 상수를 정의하기 위한 옵션
ex) BUFFER_SIZE  매크로 상수 값 20으로 설정 : gcc -D BUFFER_SIZE=20
-l(소문자L) 라이브러리 이름을 지정
-L 추가 라이브러리 디렉토리를 지정
-I(대문자i)  추가 헤더 파일이 있는 디렉토리를 지정
-c as에 의한 어셈블까지만 수행하고 링크는 수행하지 않음
-o 출력 파일명을 지정할 때 사용
-g 디버깅을 위한 정보를 컴파일 하면서 생성
-v gcc가 컴파일을 어떤 식으로 수행하는지 화면에 출력
--save-temps 컴파일 과정에서 생성되는 중간 파일인 전처리 파일(*.i)과 어셈블리 파일(*.s)을 지우지 않고,
현재 디렉토리에 저장 (오류 분석에 사용)

 

링커 옵션

옵션 설명
libc printf, open, close, read, write 등 잘 알려진 POSIX 함수를 담은 C 라이브러리, 항상 기본으로 링크됨
libm cos, sin, exp, log 같은 수학 함수, 링크 [-lm]
libpthread pthread_ 로 시작하는 모든 POSIX 스레드 함수들, 링크 [-lpthread]
librt 공유 메모리와 비동기 I/O를 포함하는 POSIX 실시간 확장
libdl 동적 라이브러리, runtime에 동적으로 so파일을 메모리에 loading 하여 실행하기 위한 함수들, 링크 [-ldl]

크로스 컴파일러란?

컴파일러가 실행되는 플랫폼이 아닌 다른 플랫폼에서 실행 가능한 코드를 생성할 수 있는 기계어로 번역해 주는 작업을 말한다.

즉, 다른 플렛폼에서(windows, Mac) 다른 플랫폼의(Android, IOS, Embedded) 실행 파일을 만들어 주는 컴파일러를 가리켜 크로스 컴파일러 라고 한다.

 

크로스 컴파일 종류

  • x86, AMD64 binary 코드 (컴파일러 gcc)
  • ARM 32 binary 코드 (컴파일러 arm-linux-gnueabi-gcc)
  • ARM 64 binary 코드 (컴파일러 aarch64-linux-gnu-gcc)

Makefile로 컴파일러를 통해 컴파일을 하면 링크 파일이 나온다. 해당 링크파일을 아래 명령어로 치면 x86-64로 나오는 것을  볼 수 있다. 보통 임베디드 리눅스는 ARM을 많이 사용한다. 크로스 컴파일러를 통해 ARM으로 바꿔보려고 한다.

#file {link file}
# iperf3 example
file iperf3

./Configure

configure 스크립트에서 받는 옵션

옵션 설명
--build 내가 지금 작업하고 있는 컴파일 시스템. 코딩 작업을 하고있는 호스트
--host 빌드하고 나서 실행파일이 실행될 시스템을 명시. 컴파일 결과물이 돌아갈 환경
--target 빌드된 파일이 실행됐을 때 내놓을 바이너리 포맷
--prefix 컴파일 후 실행파일 디렉터리 설정을 위한 옵션
-static 컴파일에 필요한 정적 라이브러리 설정 옵션
--with-zlib 컴파일에 필요한 zlib 라이브러리 경로지정 옵션
--with-ssl-dir 컴파일에 필요한 openSSL 라이브러리 경로지정 옵션
--cross-compile-prefix 크로스 컴파일 수행에 필요한 관련 컴포넌트에 추가할 접두어 지정

 

configure 스크립트 파일에 설정 옵션을 아래와 같이 적용하면 환경설정을 수행한다.

configure는 autoconf라는 툴을 이용해서 만들어진 자동화된 빌드스크립트이고, 여기에 빌드할 프로젝트에 대한 설정을 해주어야 하며, 설정이 끝나면 모든 설정을 포함한 Makefile이 생성되기 때문에 단순히 make명령만을 통해서 빌드를 수행할 수 있다.

./configure ac_cv_func_malloc_0_nonnull=yes  ac_cv_type_bool=yes ac_cv_sizeof_bool=1  CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ --host=arm  CFLAGS=-static CXXFLAGS=-static

 

빌드 스크립트 대신 환경변수를 설정하고 나서 configure에 build와 host설정 후 make로 옵션을 지정할 수 도 있다.

$ export CROSS_COMPILE=arm-none-linux-gnueabi-
$ export CC=${CROSS_COMPILE}gcc
$ export CPP=${CROSS_COMPILE}cpp
$ export CXX=${CROSS_COMPILE}g++
$ export LD=${CROSS_COMPILE}ld
$ export AR=${CROSS_COMPILE}ar

$ configure --build=arm-none-linux-gnueabi \
            --host=armv9-none-linux-gnueabi
            
$ make CFLAGS=-static CXXFLAGS=-static

 

해당 내용을 설정 후 file 명령어로 확인하면 ARM으로 변경된 것을 볼 수 있다.

 

Makefile

Makefile에 아래 내용을 추가하게 되면 크로스 컴파일이 실행된다.

CROSS_COMPILE := /bin/arm-linux-gnueabihf-

AR              := $(CROSS_COMPILE)ar
AS              := $(CROSS_COMPILE)as
LD              := $(CROSS_COMPILE)ld
NM              := $(CROSS_COMPILE)nm
CC              := $(CROSS_COMPILE)gcc -mcpu=cortex-a53 -march=armv8-a+crc -mbranch-protection=standard -fstack-protector-strong --sysroot=$(SYSROOT_DIR)
GCC             := $(CROSS_COMPILE)gcc -mcpu=cortex-a53 -march=armv8-a+crc -mbranch-protection=standard -fstack-protector-strong --sysroot=$(SYSROOT_DIR)
CPP             := $(CROSS_COMPILE)cpp -mcpu=cortex-a53 -march=armv8-a+crc -mbranch-protection=standard -fstack-protector-strong --sysroot=$(SYSROOT_DIR)
CXX             := $(CROSS_COMPILE)g++ -mcpu=cortex-a53 -march=armv8-a+crc -mbranch-protection=standard -fstack-protector-strong --sysroot=$(SYSROOT_DIR)
FC              := $(CROSS_COMPILE)gfortran
RANLIB          := $(CROSS_COMPILE)ranlib
READELF         := $(CROSS_COMPILE)readelf
STRIP           := $(CROSS_COMPILE)strip
OBJCOPY         := $(CROSS_COMPILE)objcopy
OBJDUMP         := $(CROSS_COMPILE)objdump

 

'Embedded SW 기초' 카테고리의 다른 글

Makefile  (0) 2024.06.25
WiFi  (0) 2024.06.17
git 기초 명령어  (0) 2024.06.14
Peripheral과의 통신 - 3. I2C  (0) 2024.06.13
리눅스 명령어 & rootfs  (0) 2024.06.13