매크로 #
| = | 재귀 선언 가능 |
| := | 재귀 선언 안되나 자기 자신을 사용가능 |
| += | 공백을 하나 넣고 합친다 |
| ?= | 이미 있으면 선언하지 않는다 |
| % | wild card |
| $(findstring 찾을문자열, 대상문자열) | 찾으면 출력 |
| $(매크로명:패턴=치환문자열) | $(MY_STRING:.c=.o) |
| $(sort $(OBJECTS)) | 정렬한다. 중복되면 하나로 통합 |
순환 make #
sub_system:
cd sub;
$(MAKE)
성공시에 다음 문장 #
sub_system:
cd sub && rm *.* -rf
마지막 실행된 파일의 return 값 표시 #
옵션 #
| -f | 스크립트 파일명을 지정해준다 |
| -n | 실행할 목록을 표시만 해줌. 실행은 안 함 |
| -p | 이미 정의된 매크로 출력 |
| -s | -n 과 반대로 아무 표시도 없이 실행만 해줌 |
| -d | make 의 실행경로를 보여준다. debug |
| -t | 마치 make 된 것처럼 .o 나 실행파일의 시간을 현재 시간으로 맞춰준다 |
make -p | grep ^[[:alpha:]]*[[:space:]]*=[[:space:]] > premacro.txt
위 명령을 이용하면 현재 정의된 매크로 목록을 쉽게 볼 수 있다.
규칙 #
[결과] : [필요한 조건]
[필요한 조건이 만족될 때 결과를 만들어내는 방법]
간단한 예제 #
test : main.o read.o write.o
gcc -o test main.o read.o write.o
main.o : io.h main.c
gcc -c main.c
read.o : io.h read.c
gcc -c read.c
write.o: io.h write.c
gcc -c write.c
위와 같이 하면 test 라는 실행 파일이 만들어진다. 위의 조건을 보면 그냥 make 명령을 수행하면 test 파일을 필요로 한다. test 파일을 만들려면 main.o read.o write.o 파일이 존재해야 하고, 존재하면 gcc -o test maino read.o write.o 명령을 수행한다.
main.o 파일은 io.h main.c 파일이 존재해야 하고 존재한다면 gcc -c main.c 를 수행한다.... 나머지도 같은 규칙이다.
Makefile 을 만들어주는 파이썬 스크립트 #
다음은 내가 간단히 만들어 본 스크립트이다. 현재 디렉토리의 모든 .c, .cpp 파일을 검사해서 Makefile 을 만든다.
import glob
import os
def doMain():
files = glob.glob("*.*")
output = open("Makefile", "w")
tempTarget = "a.out"
output.write("# TARGET is execute filename\n")
output.write("TARGET = " + tempTarget + "\n")
output.write("COMPILER = g++\n")
output.write("COMPILER_OPTION = -W -Wall -g\n")
output.write("\n# ===== end of declaration var =====\n")
output.write("all: $(TARGET)\n")
output.write("\t@echo ------ [$(TARGET)] end of compile ------\n\n")
objs = []
compileStr = ""
for file in files:
filenameonly = os.path.splitext(file)[0]
fileextonly = os.path.splitext(file)[1]
if fileextonly == ".c" or fileextonly == ".cpp":
objs.append(filenameonly + ".o")
compileStr += (filenameonly + ".o: " + file)
if os.path.exists(filenameonly + ".h"):
compileStr += (" " + filenameonly + ".h")
compileStr += ("\n")
compileStr += ("\t$(COMPILER) $(COMPILER_OPTION) " + file + " -c -o " + filenameonly + ".o\n\n")
output.write("# To use pre-compiled header, uncomment below 3 line and make stdafx.h. If you use .c files, replace 'c++-header' with 'c-header'\n")
output.write("#stdafx.h.gch: stdafx.h\n")
output.write("#\t$(COMPILER) $(COMPILER_OPTION) -x c++-header stdafx.h -o stdafx.h.gch\n")
output.write("#PRECOMPILED = stdafx.h.gch\n")
output.write("# end of pre-compiled settings\n\n")
output.write("$(TARGET): $(PRECOMPILED) ")
for obj in objs:
output.write(" " + obj)
output.write("\n\t$(COMPILER) $(COMPILER_OPTION) -o $(TARGET)")
for obj in objs:
output.write(" " + obj)
output.write("\n\n")
output.write(compileStr)
output.write("clean:\n")
output.write("\trm -f *.o $(TARGET) $(PRECOMPILED)\n\n")
output.close()
if __name__ == "__main__":
doMain()
일반 #
SRC = $(wildcard *.c)
OBJECTS = $(SRC:.c=.o)
TARGET = run
all:$(TARGET)
$(TARGET): $(OBJECTS)
$(cc) -o $@ $^
$@ : target 파일 이름(확장자 포함)
$^ : target 의 종속 항목 리스트 전부
$? : target 보다 더 최근에 변경된 종속항목 파일