2022-06-05 Makfile_이해

gcc

C언어의 컴파일 과정

  1. 전처리기 : #으로 시작하는 전처리 구문을 처리
gcc -E test.c -o test.i
Code language: CSS (css)
  1. 컴파일러 : 고급언어를 저급언어로 번역
gcc -S test.i -o test.s
Code language: CSS (css)
  1. 어셈블러 : 저급언어를 기계어로 번역
gcc -c test.s -o test.o
Code language: CSS (css)
  1. 링커 :
gcc test.o -o test.exe
Code language: CSS (css)

-o : 생성 된 파일의 이름을 지정

출처 : https://reakwon.tistory.com/52


make

지금부터 작성한 글은 아래 포스트를 많이 참고해서 작성했습니다.

출처 : https://bowbowbow.tistory.com/12#make-와-makefile

파일이 많으면 컴파일하기 힘들다.

컴파일 및 관리를 편하게 하기 위해서 Makefilemake를 이용한다.

Makefile에 컴파일 및 관리를 수행하는 방식을 규정하고 make 명령어로 실행한다.

Makefile의 구성

-목적파일(Target) : 명령어가 수행되어 나온 결과를 저장할 파일

-의존성(Dependency) : 목적파일을 만들기 위해 필요한 재료

-명령어(Command) : 실행 되어야 할 명령어들

-매크로(macro) : 코드를 단순화 시키기 위한 방법
CC = gcc // 매크로 정의

// 타겟 : 의존성 의존성
target1 : dependency1 denpendency2
	command1 // 명령어
	command2
target2 : dependency3 denpendency4
	command3
	command4
Code language: JavaScript (javascript)
매크로 정의 

목표파일 : 목표파일을 만들기 위해서 필요한 구성요소들 (dependency는 없어도 된다.)
(tab)목표 달성을 위한 명령1
(tab)목표 달성을 위한 명령2

길이가 긴 공백은 tab를 사용한다.


예시

//diary.h

#include<stdio.h>
void memo();
void calendar();
Code language: PHP (php)
//meno.c
#include "diary.h"
void memo(){
	printf("memo func \n");
}
Code language: PHP (php)
//calendar.c
#include "diary.h"
void calendar(){
	printf("calendar func \n");
}
Code language: PHP (php)
//main.c
#include"diary.h"
int main(void){
	memo();
	calendar();
	return 0;
}
Code language: PHP (php)

gcc 명령어 사용

gcc -c -o memo.o memo.c
gcc -c -o calendar.o calendar.c
gcc -c -o main.o main.c
gcc -o diary_exe main.o memo.o calendar.o

# 혹은

gcc -o diary_exe memo.c calendar.c main.c
Code language: CSS (css)

make 명령어 사용

vim Makefile

# 대문자 M 사용.
Code language: PHP (php)
diary_exe : memo.o calendar.o main.o
	gcc -o diary_exe memo.o calendar.o main.o

memo.o : memo.c
	gcc -c -o memo.o memo.c

calendar.o : calendar.c
	gcc -c -o calendar.o calendar.c

main.o : main.c
	gcc -c -o main.o main.c

clean :
	rm *.o diary_exe
Code language: CSS (css)

기본적으로 make 명령어를 사용하는 방법은 make [targetName]을 쉘에 입력한다.

$ make diary_exe
gcc -c -o calendar.o calendar.c
gcc -c -o main.o main.c
gcc -o diary_exe memo.o calendar.o main.o
$ make memo.o
gcc -c -o memo.o memo.c
$ make clean
rm *.o diary_exe

make clean : 현재 디렉터리에 있는 object 파일과 diary_exe를 지운다.

clean은 더미타겟으로 파일을 생성하지 않는 타겟이다.

$ make
gcc -c -o memo.o memo.c
gcc -c -o calendar.o calendar.c
gcc -c -o main.o main.c
gcc -o diary_exe memo.o calendar.o main.o

아무런 targetName 없이 make 명령을 입력했을때는 default target을 생성한다.

별도의 default target 지정 없으면 가장 상단에 위치한 target 파일을 생성한다.

default target을 지정하는 방법은 아래와 같다.

all : diary_exe

따로 가장 상단에 all이라는 타겟을 설정하고 의존성에 정말 우리가 필요한 타겟을 넣으면 된다.


Makefile 매크로

diary_exe : memo.o calendar.o main.o
	gcc -o diary_exe memo.o calendar.o main.o

memo.o : memo.c
	gcc -c -o memo.o memo.c

calendar.o : calendar.c
	gcc -c -o calendar.o calendar.c

main.o : main.c
	gcc -c -o main.o main.c

clean :
	rm *.o diary_exe
Code language: CSS (css)

Makefile을 더 단순하게 작성하기 위해서 중복되는 코드를 특정한 단어로 치환한다.

이 과정을 매크로라고 한다.

짧은 코드면 오히려 복잡하다고 느낄 수 있지만 코드가 길어지고 복잡해질수록 매크로를 사용했을 때 얻을 수 있는 효과가 크다.

사용할 수 있는 매크로 몇가지와 관용적으로 사용하는 변수 이름을 살펴보자.

OptionDesciption
$@해당 블록의 Target
$^해당 블록의 Dependencies 중 전체로 대치됨
$<해당 블록의 Dependencies 중 첫 번째로 대치됨
$*확장자가 없는 Target으로 대치됨
$?해당 블록의 Dependencies 중에 Target보다 새로운 파일들 목록으로 대치됨
VariablesDescription
CCC compiler, cc, gcc
CXXC++ compiler, g++
CFLAGSExtra flags to give to the C compiler
CXXFLAGSExtra flags to give to the C++ compiler
CPPFLAGSExtra flags to give to the C preprocessor
LDFAGSExtra flags to give to compilers when they are supposed to invoke linker
SRCSSource codes
OBJSObject codes
TARGETTarget file
.SUFFIXES확장자 규칙
INCInclude path

이외에도 사용자의 기호에 맞춰 매크로를 설정할 수 있다.

매크로 이름은 보통 대문자로 작성한다.

$(매크로 이름)로 매크로의 값을 참조할 수 있다.

diary_exe : memo.o calendar.o main.o
	gcc -o diary_exe memo.o calendar.o main.o

memo.o : memo.c
	gcc -c -o memo.o memo.c

calendar.o : calendar.c
	gcc -c -o calendar.o calendar.c

main.o : main.c
	gcc -c -o main.o main.c

clean :
	rm *.o diary_exeCode language: CSS (css)

  • CC, TARGET, OBJS 정의
    CC = gcc
    TARGET = diary_exe
    OBJS = memo.o calendar.o main.o
    
    all : $(Target)
    
    $(TARGET) : $(OBJS)
    	$(CC) -o $(TARGET) $(OBJS)
    
    memo.o : memo.c
    	$(CC) -c -o memo.o memo.c
    
    calendar.o : calendar.c
    	$(CC) -c -o calendar.o calendar.c
    
    main.o : main.c
    	$(CC) -c -o main.o main.c
    
    clean :
    	rm $(OBJS) $(TARGET)
    Code language: JavaScript (javascript)

    • $@, $^ 사용
      CC = gcc
      TARGET = diary_exe
      OBJS = memo.o calendar.o main.o
      
      all : $(Target)
      
      $(TARGET) : $(OBJS)
      	$(CC) -o $@ $^
      
      calendar.o : calendar.c
      	$(CC) -c -o $@ $<
      
      main.o : main.c
      	$(CC) -c -o $@ $<
      
      clean :
      	rm $(OBJS) $(TARGET)Code language: JavaScript (javascript)

      • %.o, %.c 사용
        CC = gcc
        TARGET = diary_exe
        OBJS = memo.o calendar.o main.o
        
        all : $(Target)
        
        $(TARGET) : $(OBJS)
        	$(CC) -o $@ $^
        
        %.o : %.c
        	$(CC) -c -o $@ $<
        
        clean :
        	rm $(OBJS) $(TARGET)Code language: JavaScript (javascript)

        많이 짧아졌다!

        %.o의 의미는 .o로 끝나는 어떤 파일을 의미한다.

        %.c는 .c로 끝나는 어떤 파일이고 앞선 %.o와는 확장자를 제외하고 같은 파일이름을 지녔을 것이다.

        마지막으로 주의할 점에대해 알아보자.

        clean :
        	rm $(OBJS) $(TARGET)Code language: JavaScript (javascript)

        만약 디렉토리내에 clean이라는 파일이 있으면 정상적으로 Makefile이 작동하지 않을 것이다.

        이때는 …

        clean :
        	rm $(OBJS) $(TARGET)
        
        .PHONY : cleanCode language: JavaScript (javascript)

        .PHONY : clean을 추가하면 된다.

        Phony는 ‘가짜의, 허위의’ 이라는 뜻이다.

        PHONY가 다수라면 옆에 띄어쓰고 열거하면 된다.

        .PHONY : a b c Code language: CSS (css)


        Makefile 보충

        :=, ?=+=는 뭐지?

        출처 : https://leehc257.tistory.com/67

        • = 사용
        T=A
        W=$(T)
        T=B
        
        run :
        	echo $(T)
        	echo $(W)Code language: JavaScript (javascript)
        // 결과
        $ make
        echo B
        B
        echo B
        BCode language: PHP (php)

        =T=A를 무시한다.

        =는 어디에서든 상관없이 나중에 작성된 T=B로 일관성을 유지한다.

        • := 사용
        T=A
        W:=$(T)
        T=B
        
        run :
        	echo $(T)
        	echo $(W)
        Code language: JavaScript (javascript)
        // 결과
        $ make
        echo B
        B
        echo A
        A
        Code language: PHP (php)

        :=T=A를 무시하지 않고 반영하는 것을 알 수 있다.

        실제 W가 정의된 시점의 TA를 반영했다.

        • += 사용
        T=A
        T+=B
        
        run :
        	echo $(T)
        Code language: JavaScript (javascript)
        // 결과
        $ make
        echo A B
        A B
        Code language: PHP (php)

        기존의 문자열에 이어쓰기하는 방식이다.

        • ?= 사용

        This is called a conditional variable assignment operator, because it only has an effect if the variable is not yet defined.

        변수가 정의되지않으면 변수의 값을 대입한다.


        $(OBJS:.o=.d)는 뭐지?

        $(OBJS:.o=.d) 부분은 OBJS 에서 .o 로 끝나는 부분을 .d 로 모두 대체한다는 뜻이다.


        Makefile 조건문

        //같은지 비교하고 싶다면 ifeq ~ else ~endif 사용.
        //equal
        
        ifeq ($(CC),gcc)
        Code language: JavaScript (javascript)
        //같지 않은지 비교하고 싶다면 ifneq ~ else ~ endif 사용.
        //not equal
        ifneq ($(CC),gcc)
        Code language: JavaScript (javascript)
        //매크로가 정의되었는지 되지 않았는지에 따라 Makefile을 다르게 구성하고 싶다면 
        //ifdef ~ else ~ endif 또는 ifndef ~ else ~ endif 사용.
        //define? not define?
        
        ifdef CC
        ifndef CC
        Code language: JavaScript (javascript)


        Makefile 함수

        $(shell 쉘 명령어)
        
        shell 명령에 대한 결과를 저장한다. $(변수명) <- 이 자리에 해당 결과가 들어가는 셈이다.
        Code language: JavaScript (javascript)

        이것말고도 엄청나게 많은 함수를 지원한다.

        필요하면 찾아서 사용하자.


        참고

        댓글 남기기