728x90

Makefile이 존재하는 이유는 무엇입니까?

Makefile은 큰 프로그램의 어느 부분을 다시 컴파일해야 하는지 결정하는 데 사용됩니다. 대부분의 경우 C 또는 C++ 파일이 컴파일됩니다. 다른 언어에는 일반적으로 Make와 유사한 목적을 수행하는 자체 도구가 있습니다. 변경된 파일에 따라 일련의 지침을 실행해야 하는 경우 프로그램 밖에서도 사용할 수 있습니다. 이 튜토리얼은 C/C++ 컴파일 사용 사례에 초점을 맞출 것입니다.

다음은 Make로 빌드할 수 있는 종속성 그래프의 예입니다. 파일의 종속성이 변경되면 파일이 다시 컴파일됩니다.

Make에는 어떤 대안이 있습니까?

인기 있는 C/C++ 대체 빌드 시스템은 SCons , CMake , Bazel  Ninja 입니다. Microsoft Visual Studio 와 같은 일부 코드 편집기 에는 자체 빌드 도구가 있습니다. Java의 경우 Ant , Maven  Gradle 이 있습니다. Go 및 Rust와 같은 다른 언어에는 자체 빌드 도구가 있습니다.

Python, Ruby 및 Javascript와 같은 해석 언어에는 Makefile과 유사한 것이 필요하지 않습니다. Makefiles의 목표는 변경된 파일을 기반으로 컴파일해야 하는 모든 파일을 컴파일하는 것입니다. 그러나 해석된 언어로 된 파일이 변경되면 아무 것도 다시 컴파일할 필요가 없습니다. 프로그램이 실행되면 가장 최신 버전의 파일이 사용됩니다.

Make의 버전과 종류

Make에는 다양한 구현이 있지만 이 가이드의 대부분은 사용 중인 버전에 관계없이 작동합니다. 그러나 Linux 및 MacOS의 표준 구현인 GNU Make를 위해 특별히 작성되었습니다. 모든 예제는 일부 난해한 차이점을 제외하고는 거의 동일한 Make 버전 3 및 4에서 작동합니다.

예제 실행

이 예제를 실행하려면 터미널과 "make"가 설치되어 있어야 합니다. 각 예에 대해 내용을 이라는 파일에 넣고 Makefile해당 디렉토리에서 명령을 실행합니다 make. 가장 간단한 Makefile부터 시작하겠습니다.

hello:
	echo "hello world"

다음은 위의 예를 실행한 결과입니다.

$ make
echo "hello world"
hello world

그게 다야! 조금 혼란스럽다면 Makefile의 기본 구조를 설명하는 단계와 함께 이 단계를 거치는 비디오가 있습니다.

 

메이크파일 구문

Makefile은 일련의 규칙 으로 구성됩니다 . 규칙은 일반적으로 다음과 같습니다.

targets: prerequisites
	command
	command
	command
  • 대상  공백으로 구분된 파일 이름입니다. 일반적으로 규칙당 하나만 있습니다.
  • 명령  일반적으로 대상을 만드는 데 사용되는 일련의 단계입니다. 공백이 아닌  문자로 시작해야 합니다.
  • 전제 조건  공백으로 구분된 파일 이름이기도 합니다. 이러한 파일은 대상에 대한 명령이 실행되기 전에 존재해야 합니다. 이를 종속성 이라고도 합니다.

초보자 예시

다음 Makefile에는 세 가지 개별 규칙 이 있습니다. 터미널에서 실행 하면 일련의 단계로 make blah호출되는 프로그램이 빌드됩니다 .blah

  • Make가 blah대상으로 주어졌으므로 먼저 이 대상을 검색합니다.
  • blah가 필요 하므로 대상 blah.o을 검색하십시오.blah.o
  • blah.o가 필요 하므로 대상 blah.c을 검색하십시오.blah.c
  • blah.c종속성이 없으므로 echo명령이 실행됩니다 .
  • 모든 종속성이 완료되었으므로 명령  cc -c실행 됩니다.blah.o
  • 모든 종속성이 완료되었으므로 top cc명령이 실행 됩니다.blah
  • 그게 다야 : blah컴파일 된 c 프로그램입니다
blah: blah.o
	cc blah.o -o blah # Runs third

blah.o: blah.c
	cc -c blah.c -o blah.o # Runs second

blah.c:
	echo "int main() { return 0; }" > blah.c # Runs first

이 메이크파일에는 이라는 단일 대상이 some_file있습니다. 기본 대상은 첫 번째 대상이므로 이 경우 some_file실행됩니다.

some_file:
	echo "This line will always print"

이 파일은 some_file처음으로 만들어지고 두 번째로 이미 만들어졌다는 것을 알 수 있습니다.make: 'some_file' is up to date.

some_file:
	echo "This line will only print once"
	touch some_file

여기에서 대상 some_file은 에 "의존"합니다 other_file. 를 실행 make하면 기본 대상( some_file, 첫 번째 대상이므로)이 호출됩니다. 먼저 종속성 목록을 살펴보고 오래된 항목이 있으면 먼저 해당 종속성에 대한 대상을 실행한 다음 자체적으로 실행합니다. 두 번째로 실행하면 두 대상이 모두 존재하기 때문에 두 대상이 모두 실행되지 않습니다.

some_file: other_file
	echo "This will run second, because it depends on other_file"
	touch some_file

other_file:
	echo "This will run first"
	touch other_file

some_file이것은 생성되지 않은 other_file에 의존 하기 때문에 항상 두 대상을 모두 실행합니다 .

some_file: other_file
	touch some_file

other_file:
	echo "nothing"

clean다른 대상의 출력을 제거하는 대상으로 자주 사용되지만 에서 특별한 단어는 아닙니다 make.

some_file: 
	touch some_file

clean:
	rm -f some_file

변수

변수는 문자열일 수 있습니다. 일반적으로 를 사용 :=하고 싶지만 =작동합니다. 변수 2편 을 참조하십시오 .

다음은 변수를 사용하는 예입니다.

files := file1 file2
some_file: $(files)
	echo "Look at this variable: " $(files)
	touch some_file

file1:
	touch file1
file2:
	touch file2

clean:
	rm -f file1 file2 some_file

${}또는 _$()

x := dude

all:
	echo $(x)
	echo ${x}

	# Bad practice, but works
	echo $x 

대상

모든 대상

여러 대상을 만들고 모두 실행하기를 원하십니까? 목표를 만드십시오 all.

all: one two three

one:
	touch one
two:
	touch two
three:
	touch three

clean:
	rm -f one two three

다중 대상

규칙에 대한 대상이 여러 개인 경우 각 대상에 대해 명령이 실행되며 대상 이름이 포함
$@된 자동 변수 입니다.

all: f1.o f2.o

f1.o f2.o:
	echo $@
# Equivalent to:
# f1.o:
#	 echo f1.o
# f2.o:
#	 echo f2.o

자동 변수 및 와일드카드

* 와일드카드

*and 모두 %Make에서는 와일드카드라고 하지만 완전히 다른 의미입니다. *일치하는 파일 이름을 찾기 위해 파일 시스템을 검색합니다. wildcard그렇지 않으면 아래에 설명된 일반적인 함정에 빠질 수 있으므로 항상 함수로 래핑하는 것이 좋습니다 .

# Print out file information about every .c file
print: $(wildcard *.c)
	ls -la  $?

*대상, 전제 조건 또는 wildcard기능에서 사용할 수 있습니다.

위험: *변수 정의에서 직접 사용되지 않을 수 있습니다 .

위험: 일치하는 파일이 없을 때 그대로 둡니다( 함수 *에서 실행되지 않는 한 ).wildcard

thing_wrong := *.o # Don't do this! '*' will not get expanded
thing_right := $(wildcard *.o)

all: one two three four

# Fails, because $(thing_wrong) is the string "*.o"
one: $(thing_wrong)

# Stays as *.o if there are no files that match this pattern :(
two: *.o 

# Works as you would expect! In this case, it does nothing.
three: $(thing_right)

# Same as rule three
four: $(wildcard *.o)

% 와일드카드

%정말 유용하지만 사용할 수 있는 다양한 상황 때문에 다소 혼란스럽습니다.

  • "일치" 모드에서 사용하면 문자열에서 하나 이상의 문자와 일치합니다. 이 경기를 스템이라고 합니다.
  • "교체" 모드에서 사용하면 일치하는 줄기를 가져와 문자열에서 교체합니다.
  • %규칙 정의 및 일부 특정 기능에서 가장 자주 사용됩니다.

사용되는 예는 다음 섹션을 참조하십시오.

자동 변수

많은 자동 변수 가 있지만 종종 몇 가지만 표시됩니다.

hey: one two
	# Outputs "hey", since this is the first target
	echo $@

	# Outputs all prerequisites newer than the target
	echo $?

	# Outputs all prerequisites
	echo $^

	touch hey

one:
	touch one

two:
	touch two

clean:
	rm -f hey one two

멋진 규칙

암시적 규칙

C 컴파일을 사랑하십시오. 그리고 사랑을 표현할 때마다 상황이 혼란스러워집니다. 아마도 Make에서 가장 혼란스러운 부분은 만들어지는 마술/자동 규칙일 것입니다. 이러한 "암시적" 규칙을 호출합니다. 나는 개인적으로 이 디자인 결정에 동의하지 않으며 사용을 권장하지 않지만 자주 사용되므로 알아두면 유용합니다. 다음은 암시적 규칙 목록입니다.

  • C 프로그램 컴파일: 다음 형식의 명령을 사용하여 n.o자동으로 만들어집니다 .n.c$(CC) -c $(CPPFLAGS) $(CFLAGS)
  • C++ 프로그램 컴파일: 다음 형식의 명령 n.o에서 자동으로 수행됩니다 n.cc.n.cpp$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)
  • 단일 개체 파일 연결: 명령을 실행하여 n자동으로 만들어집니다 .n.o$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)

암시적 규칙에서 사용하는 중요한 변수는 다음과 같습니다.

  • CC: C 프로그램을 컴파일하기 위한 프로그램; 기본cc
  • CXX: C++ 프로그램을 컴파일하기 위한 프로그램; 기본g++
  • CFLAGS: C 컴파일러에 제공할 추가 플래그
  • CXXFLAGS: C++ 컴파일러에 제공할 추가 플래그
  • CPPFLAGS: C 전처리기에 제공할 추가 플래그
  • LDFLAGS: 링커를 호출해야 할 때 컴파일러에 제공할 추가 플래그

컴파일을 수행하는 방법을 Make에게 명시적으로 알려주지 않고 이제 C 프로그램을 빌드할 수 있는 방법을 살펴보겠습니다.

CC = gcc # Flag for implicit rules
CFLAGS = -g # Flag for implicit rules. Turn on debug info

# Implicit rule #1: blah is built via the C linker implicit rule
# Implicit rule #2: blah.o is built via the C compilation implicit rule, because blah.c exists
blah: blah.o

blah.c:
	echo "int main() { return 0; }" > blah.c

clean:
	rm -f blah*

정적 패턴 규칙

정적 패턴 규칙은 Makefile에서 덜 쓰는 또 다른 방법이지만 더 유용하고 덜 "마법"이라고 말하고 싶습니다. 구문은 다음과 같습니다.

targets...: target-pattern: prereq-patterns ...
   commands

본질은 주어진 것이 ( 와일드 카드 를 통해 target) 일치 한다는 것입니다. 짝을 이룬 것을 줄기 라고 합니다 . 그런 다음 줄기는 대상의 전제 조건을 생성하기 위해 로 대체됩니다.target-pattern%prereq-pattern

일반적인 사용 사례는 .c파일을 .o파일로 컴파일하는 것입니다. 수동 방법 은 다음과 같습니다 .

objects = foo.o bar.o all.o
all: $(objects)

# These files compile via implicit rules
foo.o: foo.c
bar.o: bar.c
all.o: all.c

all.c:
	echo "int main() { return 0; }" > all.c

%.c:
	touch $@

clean:
	rm -f *.c *.o all

다음 은 정적 패턴 규칙을 사용하는 보다 효율적인 방법 입니다.

objects = foo.o bar.o all.o
all: $(objects)

# These files compile via implicit rules
# Syntax - targets ...: target-pattern: prereq-patterns ...
# In the case of the first target, foo.o, the target-pattern matches foo.o and sets the "stem" to be "foo".
# It then replaces the '%' in prereq-patterns with that stem
$(objects): %.o: %.c

all.c:
	echo "int main() { return 0; }" > all.c

%.c:
	touch $@

clean:
	rm -f *.c *.o all

정적 패턴 규칙 및 필터

나중에 기능을 소개하는 동안 기능을 사용하여 수행할 수 있는 작업을 미리 보여드리겠습니다.  filter함수는 올바른 파일을 일치시키기 위해 정적 패턴 규칙에서 사용할 수 있습니다. 이 예에서는 .raw및 .result확장을 구성했습니다.

obj_files = foo.result bar.o lose.o
src_files = foo.raw bar.c lose.c

.PHONY: all
all: $(obj_files)

$(filter %.o,$(obj_files)): %.o: %.c
	echo "target: $@ prereq: $<"
$(filter %.result,$(obj_files)): %.result: %.raw
	echo "target: $@ prereq: $<" 

%.c %.raw:
	touch $@

clean:
	rm -f $(src_files)

패턴 규칙

패턴 규칙이 자주 사용되지만 상당히 혼란스럽습니다. 두 가지 방법으로 볼 수 있습니다.

  • 자신의 암시적 규칙을 정의하는 방법
  • 더 간단한 형태의 정적 패턴 규칙

먼저 예제부터 시작하겠습니다.

# Define a pattern rule that compiles every .c file into a .o file
%.o : %.c
		$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

패턴 규칙은 대상에 '%'를 포함합니다. 이 '%'는 비어 있지 않은 모든 문자열과 일치하고 다른 문자는 자신과 일치합니다. 패턴 규칙의 전제 조건에서 '%'는 대상의 '%'와 일치하는 동일한 어간을 나타냅니다.

다음은 또 다른 예입니다.

# Define a pattern rule that has no pattern in the prerequisites.
# This just creates empty .c files when needed.
%.c:
   touch $@

이중 콜론 규칙

이중 콜론 규칙은 거의 사용되지 않지만 동일한 대상에 대해 여러 규칙을 정의할 수 있습니다. 이것이 단일 콜론이면 경고가 인쇄되고 두 번째 명령 세트만 실행됩니다.

all: blah

blah::
	echo "hello"

blah::
	echo "hello again"

명령 및 실행

명령 반향/음소거

@인쇄를 중지하려면 명령 앞에 추가하십시오.
make with를 실행하여 각 행 앞에 -s추가 할 수도 있습니다.@

all: 
	@echo "This make line will not be printed"
	echo "But this will"

명령 실행

각 명령은 새 셸에서 실행됩니다(또는 적어도 효과는 그대로임).

all: 
	cd ..
	# The cd above does not affect this line, because each command is effectively run in a new shell
	echo `pwd`

	# This cd command affects the next because they are on the same line
	cd ..;echo `pwd`

	# Same as above
	cd ..; \
	echo `pwd`

기본 셸

기본 쉘은 /bin/sh입니다. SHELL 변수를 변경하여 이를 변경할 수 있습니다.

SHELL=/bin/bash

cool:
	echo "Hello from bash"

-k, -i및 사용하여 오류 처리-

make를 실행할 때 추가 -k하면 오류가 발생하더라도 계속 실행됩니다. Make의 모든 오류를 한 번에 보고 싶을 때 유용합니다. 오류를 억제하려면 명령 앞에
추가 하십시오 . 모든 명령에 대해 이러한 일이 발생하도록 하려면 추가하십시오 .-
-i

one:
	# This error will be printed but ignored, and make will continue to run
	-false
	touch one

make를 방해하거나 죽이는 것

참고만: ctrl+c만들면 방금 만든 새 대상이 삭제됩니다.

make의 재귀적 사용

makefile을 재귀적으로 호출하려면 make 플래그를 대신 전달하고 자체적으로 영향을 받지 않기 때문에 $(MAKE)대신 special을 사용하십시오.make

new_contents = "hello:\n\ttouch inside_file"
all:
	mkdir -p subdir
	printf $(new_contents) | sed -e 's/^ //' > subdir/makefile
	cd subdir && $(MAKE)

clean:
	rm -rf subdir

재귀 메이크에 내보내기 사용

내보내기 지시문은 변수를 가져와서 sub-make 명령에 액세스할 수 있도록 합니다. 이 예에서는 coolysubdir의 makefile이 사용할 수 있도록 내보냅니다.

참고: 내보내기는 sh와 구문이 동일하지만 관련이 없습니다(기능이 비슷함).

new_contents = "hello:\n\\techo \$$(cooly)"

all:
	mkdir -p subdir
	echo $(new_contents) | sed -e 's/^ //' > subdir/makefile
	@echo "---MAKEFILE CONTENTS---"
	@cd subdir && cat makefile
	@echo "---END MAKEFILE CONTENTS---"
	cd subdir && $(MAKE)

# Note that variables and exports. They are set/affected globally.
cooly = "The subdirectory can see me!"
export cooly
# This would nullify the line above: unexport cooly

clean:
	rm -rf subdir

셸에서도 변수를 실행하려면 변수를 내보내야 합니다.

one=this will only work locally
export two=we can run subcommands with this

all: 
	@echo $(one)
	@echo $$one
	@echo $(two)
	@echo $$two

.EXPORT_ALL_VARIABLES모든 변수를 내보냅니다.

.EXPORT_ALL_VARIABLES:
new_contents = "hello:\n\techo \$$(cooly)"

cooly = "The subdirectory can see me!"
# This would nullify the line above: unexport cooly

all:
	mkdir -p subdir
	echo $(new_contents) | sed -e 's/^ //' > subdir/makefile
	@echo "---MAKEFILE CONTENTS---"
	@cd subdir && cat makefile
	@echo "---END MAKEFILE CONTENTS---"
	cd subdir && $(MAKE)

clean:
	rm -rf subdir

할 인수

make에서 실행할 수 있는 멋진 옵션 목록이 있습니다 . 체크 아웃 --dry-run, --touch, --old-file.

여러 대상을 만들 수 있습니다. 즉 , 목표를 make clean run test실행 한 다음 , 를 차례로 실행합니다 .cleanruntest

변수 Pt. 2

풍미 및 변형

변수에는 두 가지 유형이 있습니다.

  • 재귀(사용 ) - 명령이 정의 될 때가 아니라 명령이 사용될= 때만 변수를 찾습니다 .
  • 단순히 확장(사용 :=) - 일반 명령형 프로그래밍처럼 - 지금까지 정의된 항목만 확장됩니다.
# Recursive variable. This will print "later" below
one = one ${later_variable}
# Simply expanded variable. This will not print "later" below
two := two ${later_variable}

later_variable = later

all: 
	echo $(one)
	echo $(two)

단순히 확장( :=)을 사용하면 변수에 추가할 수 있습니다. 재귀 정의는 무한 루프 오류를 제공합니다.

one = hello
# one gets defined as a simply expanded variable (:=) and thus can handle appending
one := ${one} there

all: 
	echo $(one)

?=아직 설정되지 않은 경우에만 변수를 설정합니다.

one = hello
one ?= will not be set
two ?= will be set

all: 
	echo $(one)
	echo $(two)

줄 끝의 공백은 제거되지 않지만 시작 부분의 공백은 제거됩니다. 단일 공백으로 변수를 만들려면 다음을 사용하십시오.$(nullstring)

with_spaces = hello   # with_spaces has many spaces after "hello"
after = $(with_spaces)there

nullstring =
space = $(nullstring) # Make a variable with a single space.

all: 
	echo "$(after)"
	echo start"$(space)"end

정의되지 않은 변수는 실제로 빈 문자열입니다!

all: 
	# Undefined variables are just empty strings!
	echo $(nowhere)

+=추가하는 데 사용

foo := start
foo += more

all: 
	echo $(foo)

문자열 대체 는 변수를 수정하는 정말 일반적이고 유용한 방법이기도 합니다. Text Functions  Filename Functions 도 확인하십시오 .

명령줄 인수 및 재정의

를 사용하여 명령줄에서 가져온 변수를 재정의할 수 있습니다 override. 여기에서 우리는 make를 실행했습니다.make option_one=hi

# Overrides command line arguments
override option_one = did_override
# Does not override command line arguments
option_two = not_override
all: 
	echo $(option_one)
	echo $(option_two)

명령 목록 및 정의

"define"은 실제로 명령 목록일 뿐입니다. 함수가 되는 것과는 아무 관련이 없습니다. 예상대로 각각이 별도의 셸에서 실행되기 때문에 명령 사이에 세미콜론을 사용하는 것과는 약간 다릅니다.

one = export blah="I was set!"; echo $$blah

define two
export blah=set
echo $$blah
endef

# One and two are different.

all: 
	@echo "This prints 'I was set'"
	@$(one)
	@echo "This does not print 'I was set' because each command runs in a separate shell"
	@$(two)

대상별 변수

특정 대상에 대해 변수를 할당할 수 있습니다.

all: one = cool

all: 
	echo one is defined: $(one)

other:
	echo one is nothing: $(one)

패턴별 변수

특정 대상 패턴 에 대한 변수를 할당할 수 있습니다.

%.c: one = cool

blah.c: 
	echo one is defined: $(one)

other:
	echo one is nothing: $(one)

Makefile의 조건부

조건부 if/else

foo = ok

all:
ifeq ($(foo), ok)
	echo "foo equals ok"
else
	echo "nope"
endif

변수가 비어 있는지 확인

nullstring =
foo = $(nullstring) # end of line; there is a space here

all:
ifeq ($(strip $(foo)),)
	echo "foo is empty after being stripped"
endif
ifeq ($(nullstring),)
	echo "nullstring doesn't even have spaces"
endif

변수가 정의되어 있는지 확인

ifdef는 변수 참조를 확장하지 않습니다. 무언가가 정의되어 있는지 확인합니다.

bar =
foo = $(bar)

all:
ifdef foo
	echo "foo is defined"
endif
ifdef bar
	echo "but bar is not"
endif

$(메이크플래그)

findstring이 예에서는 및 를 사용하여 make 플래그를 테스트하는 방법을 보여줍니다 MAKEFLAGS. 이 예제를 실행 make -i하여 echo 문을 출력하는지 확인하십시오.

bar =
foo = $(bar)

all:
# Search for the "-i" flag. MAKEFLAGS is just a list of single characters, one per flag. So look for "i" in this case.
ifneq (,$(findstring i, $(MAKEFLAGS)))
	echo "i was passed to MAKEFLAGS"
endif

기능

첫 번째 기능

함수 는 주로 텍스트 처리를 위한 것입니다. $(fn, arguments)또는 를 사용하여 함수를 호출합니다 ${fn, arguments}. call 내장 기능 을 사용하여 직접 만들 수 있습니다 . Make에는 상당한 양의 내장 함수 가 있습니다.

bar := ${subst not, totally, "I am not superman"}
all: 
	@echo $(bar)

공백이나 쉼표를 바꾸려면 변수를 사용하십시오.

comma := ,
empty:=
space := $(empty) $(empty)
foo := a b c
bar := $(subst $(space),$(comma),$(foo))

all: 
	@echo $(bar)

첫 번째 인수 이후에 인수에 공백을 포함하지 마십시오. 그것은 문자열의 일부로 보일 것입니다.

comma := ,
empty:=
space := $(empty) $(empty)
foo := a b c
bar := $(subst $(space), $(comma) , $(foo))

all: 
	# Output is ", a , b , c". Notice the spaces introduced
	@echo $(bar)

문자열 대체

$(patsubst pattern,replacement,text)다음을 수행합니다.

"텍스트에서 패턴과 일치하는 공백으로 구분된 단어를 찾아 이를 대체 단어로 대체합니다. 여기서 패턴은 단어 내의 임의의 수의 문자와 일치하는 와일드카드 역할을 하는 '%'를 포함할 수 있습니다. 대체에 '%'도 포함되어 있으면, '%'는 패턴의 '%'와 일치하는 텍스트로 대체됩니다. 패턴 및 대체의 첫 번째 '%'만 이러한 방식으로 처리되고 이후의 '%'는 변경되지 않습니다." ( GNU 문서 )

대체 참조 $(text:pattern=replacement)는 이에 대한 약어입니다.

접미사만 대체하는 또 다른 속기가 있습니다 $(text:suffix=replacement). . %여기에는 와일드카드가 사용 되지 않습니다 .

참고: 이 약어에 공백을 추가하지 마십시오. 검색 또는 대체 용어로 표시됩니다.

foo := a.o b.o l.a c.o
one := $(patsubst %.o,%.c,$(foo))
# This is a shorthand for the above
two := $(foo:%.o=%.c)
# This is the suffix-only shorthand, and is also equivalent to the above.
three := $(foo:.o=.c)

all:
	echo $(one)
	echo $(two)
	echo $(three)

foreach 함수

foreach 함수는 다음과 같습니다 $(foreach var,list,text). 단어 목록(공백으로 구분)을 다른 목록으로 변환합니다. var목록의 각 단어에 설정되고 각 단어에 text대해 확장됩니다.
이렇게 하면 각 단어 뒤에 느낌표가 추가됩니다.

foo := who are you
# For each "word" in foo, output that same word with an exclamation after
bar := $(foreach wrd,$(foo),$(wrd)!)

all:
	# Output is "who! are! you!"
	@echo $(bar)

if 함수

if첫 번째 인수가 비어 있지 않은지 확인합니다. 그렇다면 두 번째 인수가 실행되고, 그렇지 않으면 세 번째 인수가 실행됩니다.

foo := $(if this-is-not-empty,then!,else!)
empty :=
bar := $(if $(empty),then!,else!)

all:
	@echo $(foo)
	@echo $(bar)

통화 기능

Make는 기본 기능 생성을 지원합니다. 변수를 생성하여 함수를 "정의"하지만 매개변수 , 등을 사용합니다 $(0). $(1)그런 다음 특수 call함수를 사용하여 함수를 호출합니다. 구문은 $(call variable,param,param). $(0)는 변수이고 $(1), $(2)등은 매개변수입니다.

sweet_new_fn = Variable Name: $(0) First: $(1) Second: $(2) Empty Variable: $(3)

all:
	# Outputs "Variable Name: sweet_new_fn First: go Second: tigers Empty Variable:"
	@echo $(call sweet_new_fn, go, tigers)

쉘 함수

shell - 이것은 셸을 호출하지만 줄 바꿈을 공백으로 바꿉니다!

all: 
	@echo $(shell ls -la) # Very ugly because the newlines are gone!

다른 특징들

Makefile 포함

include 지시문은 make에게 하나 이상의 다른 makefile을 읽도록 지시합니다. 다음과 같은 makefile makefile 행입니다.

include filenames...

이것은 -M소스를 기반으로 Makefile을 생성하는 것과 같은 컴파일러 플래그를 사용할 때 특히 유용합니다. 예를 들어, 일부 c 파일에 헤더가 포함된 경우 해당 헤더는 gcc가 작성한 Makefile에 추가됩니다. Makefile Cookbook 에서 이에 대해 더 자세히 설명합니다.

vpath 지시문

vpath를 사용하여 일부 전제조건 세트가 존재하는 위치를 지정하십시오. 형식은 0개 이상의 문자와 일치하는 를 vpath <pattern> <directories, space/colon separated>
<pattern>가질 수 있습니다 . VPATH 변수를 사용하여 전역적으로 이 작업을 수행할 수도 있습니다. %

vpath %.h ../headers ../other-directory

some_binary: ../headers blah.h
	touch some_binary

../headers:
	mkdir ../headers

blah.h:
	touch ../headers/blah.h

clean:
	rm -rf ../headers
	rm -f some_binary

여러 줄

백슬래시("\") 문자는 명령이 너무 길 때 여러 줄을 사용할 수 있는 기능을 제공합니다.

some_file: 
	echo This line is too long, so \
		it is broken up into multiple lines

.위조품

대상에 추가하면 .PHONYmake가 가짜 대상을 파일 이름과 혼동하는 것을 방지할 수 있습니다. 이 예에서 파일 clean이 생성되면 make clean이 계속 실행됩니다. .PHONY사용하기 좋지만 나머지 예제에서는 간단하게 하기 위해 건너뛸 것입니다.

some_file:
	touch some_file
	touch clean

.PHONY: clean
clean:
	rm -f some_file
	rm -f clean

.delete_on_error

명령이 0이 아닌 종료 상태를 반환하면 make 도구는 규칙 실행을 중지하고 전제 조건으로 다시 전파합니다.
DELETE_ON_ERROR규칙이 이러한 방식으로 실패하면 규칙의 대상이 삭제됩니다. 이것은 PHONY와 같이 이전의 대상뿐만 아니라 모든 대상에 대해 발생합니다. make 가 역사적인 이유가 아니더라도 항상 이것을 사용하는 것이 좋습니다.

.DELETE_ON_ERROR:
all: one two

one:
	touch one
	false

two:
	touch two
	false

메이크파일 요리책

중간 규모의 프로젝트에 잘 작동하는 정말 유용한 Make 예제를 살펴보겠습니다.

이 makefile의 깔끔한 점은 자동으로 종속성을 결정한다는 것입니다. C/C++ 파일을 src/폴더에 넣으면 됩니다.

# Thanks to Job Vranish (https://spin.atomicobject.com/2016/08/26/makefile-c-projects/)
TARGET_EXEC := final_program

BUILD_DIR := ./build
SRC_DIRS := ./src

# Find all the C and C++ files we want to compile
# Note the single quotes around the * expressions. Make will incorrectly expand these otherwise.
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')

# String substitution for every C/C++ file.
# As an example, hello.cpp turns into ./build/hello.cpp.o
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)

# String substitution (suffix version without %).
# As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d
DEPS := $(OBJS:.o=.d)

# Every folder in ./src will need to be passed to GCC so that it can find header files
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))

# The -MMD and -MP flags together generate Makefiles for us!
# These files will have .d instead of .o as the output.
CPPFLAGS := $(INC_FLAGS) -MMD -MP

# The final build step.
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
	$(CC) $(OBJS) -o $@ $(LDFLAGS)

# Build step for C source
$(BUILD_DIR)/%.c.o: %.c
	mkdir -p $(dir $@)
	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

# Build step for C++ source
$(BUILD_DIR)/%.cpp.o: %.cpp
	mkdir -p $(dir $@)
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@


.PHONY: clean
clean:
	rm -r $(BUILD_DIR)

# Include the .d makefiles. The - at the front suppresses the errors of missing
# Makefiles. Initially, all the .d files will be missing, and we don't want those
# errors to show up.
-include $(DEPS)

원문 출처 : https://makefiletutorial.com/

728x90
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기
반응형