[ASM] 42 Libasm 과제를 해보아요~(3) strlen 검증


2026.07.03, 02:00


전편의 test_strlen.c를 조금 손봤다.
null 방어 해야하나 확인하고 싶어서

한줄씩 주석 풀어서 테스트하면 됩니다~

#include <stdio.h>
#include <string.h>

extern unsigned long ft_strlen(const char *str);

int main(void)
{
	char *tests[] = {"", "a", "hello", "42gyeongsan", "yuna", NULL};
	int fail = 0;

	int i = 0;
	for (; i < 5; ++i) {
		unsigned long mine = ft_strlen(tests[i]);	
		unsigned long libc = strlen(tests[i]);	
		printf("%15s -> mine=%2lu libc=%2lu %s\n", tests[i], mine, libc, mine == libc ? "OK" : "FAIL");
		if (mine != libc) fail = 1;
	}
	// printf("mine=%lu ", ft_strlen(tests[i]));
	// printf("libc=%lu ", strlen(tests[i]));
	return (fail);
}

자. 근데? 실행하려니까 좀 길어.

gcc -Wall -Wextra -Werror -c test_strlen.c -o test_strlen.o
gcc test_strlen.o ../libasm.a -o test_strlen          
./test_strlen

오, Makefile을 만들면 되겠구나!!

tests/ 폴더를 만들고, 그 안에 Makefile을 하나 더 만들어줍니다.

근데 fclean을 어떻게 써야 할까요?
test_*.c가 아닌 모든 test_*를 삭제하고 싶어. 어떻게 작성해?
이건 아니잖아.

rm -rf test_*

이렇다네요

find . -maxdepth 1 -name 'test_*' ! -name '*.c' -delete

-maxdepth 1: 현재 디렉토리만 (하위 디렉토리까지 뒤지지 않도록)
-name 'test_*': test_로 시작하는 것만 대상
! -name '*.c': .c 확장자는 제외
-delete: find가 찾은 것 바로 삭제

.

작성했는데, 너무 더러운 것 같아. 누더기 골렘이잔아…

이 Makefile을 더 Makefile 스럽게 수정해줘. Makefile로 하는 게 맞을까?

all: test_strlen

strlen:
    gcc -Wall -Wextra -Werror -c test_strlen.c -o test_strlen.o
    gcc test_strlen.o ../libasm.a -o test_strlen          
    ./test_strlen

strcpy:
    gcc -Wall -Wextra -Werror -c test_strcpy.c -o test_strcpy.o
    gcc test_strcpy.o ../libasm.a -o test_strcpy          
    ./test_strcpy

strcmp:
    gcc -Wall -Wextra -Werror -c test_strcmp.c -o test_strcmp.o
    gcc test_strcmp.o ../libasm.a -o test_strcmp          
    ./test_strcmp

write:
    gcc -Wall -Wextra -Werror -c test_write.c -o test_write.o
    gcc test_write.o ../libasm.a -o test_write          
    ./test_write

read:
    gcc -Wall -Wextra -Werror -c test_read.c -o test_read.o
    gcc test_read.o ../libasm.a -o test_read          
    ./test_read

strdup:
    gcc -Wall -Wextra -Werror -c test_strdup.c -o test_strdup.o
    gcc test_strdup.o ../libasm.a -o test_strdup          
    ./test_strdup

clean:
    rm -rf test_*.o

fclean: clean
    find . -maxdepth 1 -name 'test_*' ! -name '*.c' -delete

검토: Makefile 스럽지 않은 지점

항목문제근거
all 의존성all: test_strlen이 실행파일 test_strlen을 의존성으로 잡음. 룰 이름은 strlen인데 파일명 test_strlen을 걸었으므로, 해당 파일이 이미 존재하면 make가 “up to date”로 판단해 재빌드를 건너뜀make의 파일 기반 의존성 해석
.PHONY 부재strlen, strcpy 등 룰이 실제 파일이 아닌데도 선언이 없음. 우연히 동일 이름 파일이 없어서 지금은 동작하지만, 안전장치가 아님GNU Make Manual §4.6
반복 코드6개 룰이 함수 이름만 다를 뿐 완전히 동일한 패턴 → 정적 패턴 룰(static pattern rule) 하나로 대체 가능DRY 원칙
하드코딩된 gccCC 변수 없이 컴파일러 고정 → 크로스컴파일/툴체인 교체 불가Make 컨벤션(암묵적 변수)
CFLAGS 부재-Wall -Wextra -Werror가 각 룰에 중복 하드코딩변수화 미비
../libasm.a 미의존링크 대상이지만 prerequisite로 선언 안 됨 → libasm.a가 갱신돼도 make가 감지 못함의존성 그래프 불완전
실행 파일 생성 흔적각 룰이 .o, 실행파일을 만들지만 make의 자동 변수($@, $<) 미사용 → 오타 위험, 유지보수 비용 증가Make 관용구
clean/fclean 역할clean.o만, fcleanfind로 나머지 정리 — 방식 자체는 42 관례상 무방하나 .ofind 기반으로 통일하면 더 일관적스타일
후행 공백일부 커맨드 줄 끝에 트레일링 스페이스 존재가독성/코드 품질

질문: “Makefile로 하는 게 맞을까?”

네, 맞습니다. Make의 원래 목적(파일 갱신 시각 기반 재빌드)에는 딱 맞지 않지만, 42 계열 프로젝트에서 make strlen처럼 개별 테스트를 실행하는 phony target 패턴은 표준 관례입니다. 다만 그렇다면 .PHONY를 명시해서 “이건 파일이 아니라 커맨드 묶음”이라는 의도를 make에게 정확히 알려주는 것이 필수입니다. 지금 코드는 이 의도가 우연히 맞아떨어지는 상태입니다.

개선안

makefile

CC       = gcc
CFLAGS   = -Wall -Wextra -Werror
LIBASM   = ../libasm.a
FUNCS    = strlen strcpy strcmp write read strdup

.PHONY: all clean fclean re $(FUNCS)

all: $(FUNCS)

$(FUNCS): %: test_%.o $(LIBASM)
	$(CC) $< $(LIBASM) -o test_$@
	./test_$@

test_%.o: test_%.c
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	find . -maxdepth 1 -name 'test_*.o' -delete

fclean: clean
	find . -maxdepth 1 -name 'test_*' ! -name '*.c' -delete

re: fclean all

변경 근거 (번호별)

  1. FUNCS 리스트 하나로 6개 중복 룰을 정적 패턴 룰($(FUNCS): %: test_%.o $(LIBASM)) 하나로 축소.
  2. test_%.o: test_%.c 패턴 룰로 오브젝트 파일 생성 로직 분리 → $<, $@ 자동 변수로 오타 여지 제거.
  3. $(LIBASM)을 prerequisite에 포함시켜 libasm.a 갱신 시 재링크되도록 수정.
  4. .PHONY에 함수명 전체 등록 → all 관련 버그(위 표 첫 행) 동시 해결.
  5. CC, CFLAGS를 변수로 분리해 컴파일러/플래그 교체 지점을 한 곳으로 통일.
  6. re 타겟 추가(42 프로젝트 관례상 거의 필수).

확인 필요: $@가 함수명(strlen 등)과 겹치는지 여부 — 정적 패턴 룰 안에서 $@는 타겟 이름(strlen)을 가리키므로 test_$@로 실행파일명을 만드는 구조입니다. 디렉토리 구조가 test_strlen.c, test_strlen.o, 실행파일 test_strlen이 맞는지만 확인해 주시면 됩니다.

나도 Makefile을 잘 쓰고 싶구나..

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다