Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

TIL

2021 08 22 (일) Makefile 본문

2021/일일 기록

2021 08 22 (일) Makefile

ililillllllliilli 2021. 8. 22. 20:29

Makefile

Shell에서 컴파일을 할 때, make 명령어를 활용해서 컴파일을 할 수 있다. Makefile이 디렉토리에 있다면 해당 디렉토리에서 make 명령어만 치면 컴파일이 실행이 된다.

프로그램들과 달리 Shell에서 컴파일을 하려면 어떤 파일들을 컴파일 하고, 어떠한 방식으로 컴파일 할 지 직접 컴파일러에게 알려줘야 한다.

예를들어 아래와 같다.

$gcc a.c b.c

이 코드를 실행하면

$ls
main.c main.o

이처럼 main.o 파일이 생성된 것을 알 수 있다. 이 main.o 파일은 main.c 파일을 컴파일 한 어셈블리 코드가 담겨있는 파일 입니다.

여러 파일을 컴파일하는 경우 아래의 사진과 같이 진행된다고 보면 된다.

img

링킹(Linking)

링킹이 이름 그대로 링크 하는 작업 인 이유는 실제로 서로 다른 파일에 흩어져 있던 함수나 클래스들을 한 데 묶어서 링크해주는 작업이기 때문이다. 이 과정에서 main 함수 안에 foo 함수가 어디에 정의되어 있는지 위치를 찾고 제대로 된 함수를 호출할 수 있게 된다.

$gcc a.o b.o c.o -o test

여기서 -o 옵션은 뒤에오는 이름으로 실행파일을 만든다. 만약 이 옵션을 넣지 않는다면 디폴트로 a.out이라는 파일이 생긴다.

.c 파일을 .o파일로 변환하는 과정을 컴파일이라고 하고 만들어진 목적 파일들을 엮어서 실행파일로 만들어 주는 과정을 링킹이라고 한다.

이제 이러한 과정을 make를 이용해서 컴파일 해 볼 것이다.

make를 이용한 컴파일

make를 사용해서 컴파일 하기 위해서는 먼저 makefile이 있어야 한다.

makefile을 작성할 때 필요한 요소들을 살펴보자.

•목적파일(target)

명령어가 수행되어 나온 결과를 저장할 파일

•의존성(dependency)

목적 파일을 만들기 위해 필요한 재료

•명령어(recipes)

실행 되어야 할 명령어들

•매크로(macro)

코드를 단순화 시키기 위한 방법

Makefile의 기본 구조

아래의 Makefile을 보고 위의 요소들이 어떻게 작성되는지 살펴 보자.

img

Makefile의 작성 규칙

[target] : [dependency 1] [dependency 2] ...
                [command 1]
                [command 2]

•명령어(command)의 시작은 반드시 탭으로 시작한다.

•의존성(dependency)가 없는 목적파일(target)도 사용 가능하다.

make파일 직접 작성해보기

아래는 make파일 연습을 위한 기본적인 소스코드들이다.

# include <stdio.h>

void a();
void b();
#include "ab.h"

void a()
{
    printf("this is a.c\n");
}
#include "ab.h"

int main(void)
{
    a();
    b();
    return (0);
}
CC = gcc

test : a.o b.o main.o
    CC  a.o b.o main.o -o test

a.o : a.c
    CC -c a.c -o a.o

b.o : b.o
    CC -c b.c -o b.o

main.o : main.c
    CC -c main.c -o main.o

clean :
    rm -rf *.o
    rm -rf test
CC = gcc
CFLAGS = -Werror -Wall -Wextra 
TARGET = test

$(TARGET) : a.o b.o main.o
    $(CC) $(CFLAGS) a.o b.o main.o -o $(TARGET)

a.o : a.c
    $(CC) $(CFLAGS) -c a.c -o a.o

b.o : b.o
    $(CC) $(CFLAGS) -c b.c -o b.o

main.o : main.c
    $(CC) $(CFLAGS) -c main.c -o main.o

clean :
    rm -rf *.o
    rm -rf test
CC = gcc
CFLAGS = -Werror -Wall -Wextra
TARGET = test
OBJECTS = a.o b.o main.o

all : $(TARGET)

$(TARGET) : $(OBJECTS)
    $(CC) $(CFLAGS) $(OBJECTS) -o $(TARGET)

clean :
    rm -f $(OBJECTS) $(TARGET)
1.
gcc 컴파일러 사용
2.
오류들 출력
3.
최종 타겟 파일은 test
4.
OBJECTS로 정의할 파일들은 a.o b.o main.o
5.
all은 타겟이 여러개일 때 유용
6.
타겟 파일을 만들기 위해 OBJECT 들을 사용한다. 
( 단 OBJECT 파일이 없다면 OBJECT 파일과 이름이 동일한 C파일을 찾아 OBJECT파일을 생성한다. )
7.
gcc -Werror -Wall -Wextra a.o b.o main.o -o test 와 동일

TARGET names

make에서 자주 사용하는 가장 일반적인 Target names은 아래와 같다.

•all: the name of the default target

•check: runs tests, linters, and style enforcers

•clean: removes files created by all

•fclean: removes files created by all and target file

•re: call fclean and all

.PHONY target

포니 타겟은 실제 파일 이름을 나타내는 것이 아니다. 이것은 make 요청을 하는 경우에 실행되는 명령을 위한 목적으로 사용된다. 포니 타겟을 사용하는 이유는 두가지이다.

1) 동일한 이름의 파일이 있는 경우 출돌을 피하기 위해서

2) make의 성능 향상을 위해서

clean이라는 명령어를 보자. rm 명령은 clean 이라는 이름의 파일을 생성하지 않기 때문에, 그런 파일은 존재하지 않을 것이다. 그래서 rm 명령은 make clean 을 수행할 때, 매번 실행될 것이다.

하지만, 타겟 clean 은 다른 누군가가 디렉토리에 clean 이라는 이름의 파일을 생성하게 된다면, 작업을 멈추게 될 것이다. clean 파일은 이전에 존재하지 않았기 때문에, 필연적으로 최신이라고 간주될 것이다. 그리고 rm 명령은 실행되지 않을 것이다. 이러한 문제를 해결하기 위해서, 다음과 같이 특수 타겟 .PHONY를 사용해서, 해당 타겟을 명백하게 가짜로(phony) 선언할 수 있다.

.PHONY : clean

이렇게 되면 make clean명령은 clean이라는 파일이 존재하는지 여부와 상관 없이 무조건 명령을 수행할 것이다.

CC = gcc
CFLAGS = -Werror -Wall -Wextra
TARGET = test
SOURCES = a.c \
                    b.c \
                    main.c
OBJECTS = $(SOURCES: %.c=%.o)
INCLUDE = -I./

all : $(TARGET)

$(TARGET) : $(OBJECTS)
    $(CC) $(CFLAGS) $(OBJECTS) $(INCLUDE) -o $(TARGET)

clean :
    rm -f $(OBJECTS) $(TARGET)

참고

https://clarkgrubb.com/makefile-style-guide#phony-targets

https://modoocode.com/311

https://www.gnu.org/software/make/manual/html_node/index.html#SEC_Contents

'2021 > 일일 기록' 카테고리의 다른 글

2021 08 22 (일) - 백준 1149, 2193, 2579  (0) 2021.08.22
20210817 (화) - 이항정리, DP  (0) 2021.08.18
2021 08 12 (수) - 철권7 대회 조추첨 프로그램  (0) 2021.08.13
2021 08 01 (일)  (0) 2021.08.02
2021 08 02 (월) - gdb  (0) 2021.08.02
Comments