makefile + source codes

김도현 KimDohyun·2024년 10월 8일
0
post-thumbnail

지난번에 제출하신 두개의 소스코드 과제 별로 컴파일을 수행할 수 있는 makefile을 제출해주세요.

소스코드 별로 디렉토리를 만들어서 (src1과 src2) 해당 디렉토리별로 소스코드를 저장하고 이를 컴파일하기 위한 makefile을 압축하여 제출해주세요.

수업에서 배운 mk2 예제를 참조해서 작성해주세요.

세 번째 과제는 makefile을 작성하는 것이다.

첫 번째 과제의 소스 코드 read.c 와 두 번째 과제의 소스 코드 my_cp.c 를 사용하여 이번 과제를 수행한다.

개요

read.cmy_cp.c 는 각각 gcc -o read read.cgcc -o my_cp my_cp.c 명령으로 컴파일했다. 이는 직접 명령어로 프로그램을 컴파일하는 방법으로 즉시 실행이 가능하며 간단한 수정 후 바로 컴파일할 수 있다.

하지만 각각의 컴파일 명령어를 기억해야 하기 때문에 복잡한 프로젝트에서는 관리가 어렵고 수정하지 않은 파일도 다시 컴파일하게 될 수도 있는 단점이 존재한다.

Makefile은 위와 같은 컴파일 명령을 자동화한 형태다. 자동으로 빌드 과정을 관리하기 때문에 소스 파일이 많거나 복잡한 프로젝트에서도 자동으로 컴파일이 가능하며 어떤 파일이 변경되었는지를 추적하여 수정된 파일만 다시 컴파일할 수 있다.

이번 과제에서는 두 개의 프로그램을 각각의 Makefile로 컴파일을 자동화하여 빌드 과정을 관리한다.



디렉토리 구조

Projects/
├── src1/
│   ├── read.c
│   ├── test.txt
│   └── read_mk
└── src2/
    ├── my_cp.c
    ├── src_file
    ├── dst_file
    └── cp_mk

위 구조를 토대로 코드를 작성한다.



작업 폴더 생성

mkdir src1
mkdir src2

기존 파일 이동

이전에 작성했던 두 개의 소스코드는 Projects 라는 프로젝트 디렉토리에 위치해 있으므로 read.cmy_cp.c 를 방금 생성한 src1, src2 로 각각 이동시킨다.

mv read.c src1
mv my_cp.c src2

read.c

read.c 소스 코드는 test.txt를 읽고 출력하는 프로그램이다. 따라서 실행하려면 test.txt 파일이 작업 디렉토리에 위치해 있어야 하기 때문에 마찬가지로 src1에 이동시킨다.

mv test.txt src1

my_cp.c

my_cp.c 소스 코드는 사용자로부터 복사할 파일(src_file)과 복사 후 생성될 파일(dst_file)을 전달받아 실행하는 복사 프로그램이다. 따라서 실행하려면 src_file과 dst_file 파일이 작업 디렉토리에 위치해 있어야 하기 때문에 src2에 이동시킨다.

mv src_file src2
mv dst_file src2


Makefile

read.c makefile 생성 후 작성

  • read.c를 컴파일 할 makefile인 read_mk를 src1 폴더에 생성한다.
vim read_mk
  • read_mk에 들어갈 소스 코드를 작성한다.
CC = gcc
CFLAGS = -Wall

SRC = read.c
TARGET = read

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

코드 설명

CC = gcc : 컴파일러로 GCC 사용
CFLAGS = -Wall : 컴파일 시 모든 경고 활성화
SRC = read.c : 컴파일할 소스 파일은 read.c
TARGET = read : 컴파일 후 생성될 실행 파일 이름은 read
$(TARGET): $(SRC) : SRC(read.c)에 의존하는 TARGET(read)을 생성
$(CC) $(CFLAGS) -o $(TARGET) $(SRC) : gcc 컴파일러를 사용하여 read.c를 컴파일하고 결과물을 read라는 이름의 실행 파일로 출력

👀 의존하다? 의존성이란?
Makefile에서 “의존한다”는 것은 타겟(Target)을 생성하기 위해 필요한 파일들을 의미하며, 의존성 파일이 변경되었을 때만 다시 컴파일한다.

→ "SRC(read.c)에 의존하는 TARGET(read)"은 read 실행 파일을 생성하려면 read.c 소스 파일이 필요하다는 뜻

디렉토리 확인


빌드 전 src1 디렉토리를 ls 명령어로 검사한 결과 맨 처음 작성한 디렉토리 구조와 동일하게 모든 파일이 위치해 있는 것을 확인할 수 있다.
(빌드 후 실행을 이미 한 상태에서 캡처를 해 버려서 사진 상에는 실행 파일이 이미 존재한다 ㅎ)

my_cp.c makefile 생성 후 작성

  • my_cp.c를 컴파일 할 makefile인 cp_mk를 src2 폴더에 생성한다.
vim cp_mk
  • cp_mk에 들어갈 소스 코드를 작성한다.
CC = gcc
CFLAGS = -Wall

SRC = my_cp.c
TARGET = my_cp

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

디렉토리 확인


빌드 전 src2 디렉토리 또한 ls 명령어로 검사한 결과 맨 처음 작성한 디렉토리 구조와 동일하게 모든 파일이 위치해 있는 것을 확인할 수 있다.



빌드(+ 컴파일)

read_mk 빌드

make -f read_mk


직접 명령어 gcc -o read read.c 와 동일하게 컴파일되었다.

cp_mk 빌드

make -f cp_mk


직접 명령어 gcc -o my_cp my_cp.c 와 동일하게 컴파일되었다.

👀 -Wall은 왜 추가됐지?
→ 아까 Makefile에 CFLAGS = -Wall을 추가했기 때문

-Wall 옵션은 소스 코드를 컴파일할 때 일반적인 경고 메시지(warning messages)를 출력하며, 이 옵션을 사용하면 잠재적인 문제를 미리 발견하고 수정할 수 있는 장점이 있다.


위 사진은 Makefile의 read_mk 파일을 빌드하면서 발생한 구문 오류(Syntax error)이다. &(CC) 부분에서 & 기호가 잘못 사용되었고, 이를 셸이 인식하지 못하면서 구문 오류가 발생했다.

이렇게 구문 오류는 직접적으로 컴파일을 실패하게 만들지만 -Wall 옵션은 코드 내에서 발생할 수 있는 경고를 출력해 줌으로써 수정할 수 있도록 도와준다.



최종 결과

read 실행 전 테스트

read_mk 파일이 성공적으로 빌드되어서 컴파일에 성공하고 잘 실행되는지를 확인하기 위해 test.txt의 내용을 확인한다.

cat test.txt

Hello World! 가 출력된다. 만약 생성된 read 파일이 잘 실행된다면 같은 텍스트가 출력될 것이다.

실행

./read


test.txt와 동일하게 Hello World! 가 출력되는 것을 보아 정상적으로 동작하는 것을 확인할 수 있다.

my_cp 실행 전 테스트

cp_mk 파일이 성공적으로 빌드되어서 컴파일에 성공하고 잘 실행되는지를 확인하기 위해 src_file과 dst_file의 내용을 확인한다.

cat src_file
cat dst_file

각각 다른 텍스트가 출력되는 것을 확인할 수 있다. 만약 my_cp 파일이 잘 실행된다면 dst_file의 내용도 src_file과 같은 This is Test 가 출력되어야 한다.

실행

./my_cp src_file dst_file

두 파일 모두 This is Test 가 출력되는 것을 보아 정상적으로 동작하는 것을 확인할 수 있다.

제출

scp -P 2022 -r pu2rile@서버 주소:/home/pu2rile/Projects/src1 .
scp -P 2022 -r pu2rile@서버 주소:/home/pu2rile/Projects/src2 .

해당 코드로 원격 디렉토리 카피 후 src1와 src2를 압축해서 제출한다.

끝.

0개의 댓글

관련 채용 정보