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만,fclean은find로 나머지 정리 — 방식 자체는 42 관례상 무방하나.o도find기반으로 통일하면 더 일관적스타일 후행 공백 일부 커맨드 줄 끝에 트레일링 스페이스 존재 가독성/코드 품질 질문: “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변경 근거 (번호별)
FUNCS리스트 하나로 6개 중복 룰을 정적 패턴 룰($(FUNCS): %: test_%.o $(LIBASM)) 하나로 축소.test_%.o: test_%.c패턴 룰로 오브젝트 파일 생성 로직 분리 →$<,$@자동 변수로 오타 여지 제거.$(LIBASM)을 prerequisite에 포함시켜libasm.a갱신 시 재링크되도록 수정..PHONY에 함수명 전체 등록 →all관련 버그(위 표 첫 행) 동시 해결.CC,CFLAGS를 변수로 분리해 컴파일러/플래그 교체 지점을 한 곳으로 통일.re타겟 추가(42 프로젝트 관례상 거의 필수).확인 필요:
$@가 함수명(strlen등)과 겹치는지 여부 — 정적 패턴 룰 안에서$@는 타겟 이름(strlen)을 가리키므로test_$@로 실행파일명을 만드는 구조입니다. 디렉토리 구조가test_strlen.c,test_strlen.o, 실행파일test_strlen이 맞는지만 확인해 주시면 됩니다.
나도 Makefile을 잘 쓰고 싶구나..
답글 남기기