본문 바로가기
SWE/Linux

유닉스 리눅스 유틸리티 Make Makefile 기초 (2)

by S나라라2 2021. 12. 10.
반응형

2장 매크로

 

 

https://flower0.tistory.com/459

 

유닉스 리눅스 유틸리티 Make Makefile 기초 (1)

1장 컴파일, 실행, 디버그 타깃 make를 사용할 때 위 예제에서 나오는 program 같은 파일을 작업할 타깃(target)이라고 한다. target은 필요 항목(prerequisites) 또는 종속 항목(dependents)이라는 파일들을 기..

flower0.tistory.com

위 내용에 이어서 설명하고자 한다. 

이번 포스팅에서 설명할 내용을 맛보기로 보자면, 매크로를 사용하여 다음과 같이 코드 개선이 가능하다.

 

매크로 정의 방법

name = text string // 선언
$(name)				// 사용방법
${name}

name은 text string으로 치환된다.

 

참고로, 문자 하나로 이루어진 매크로 이름에는 괄호나 중괄호를 사용할 필요가 없다.

A = XYZ
$A
$(A)
${A}

위와 같이 사용하면 A는 XYZ로 치환된다.

 

예시1

// 매크로 정의
LIBS = -lx11
Objs = drawable.o plot_points.o root_data.o
CC = /usr/fred/cc
23 = "This is the (23)rd run"
OPT =
DEBUG_FLAG = #empty now, but assign -g for debugging
BINDIR = /usr/local/bin

// 매크로 사용
Plot: ${objs}
	${CC} -o plot ${DEBUG_FLAG} ${objs} ${LIBS}
    mv plot ${BINDIR}

make plot을 실행하면 명령은 다음과 같이 실행된다.

/usr/fred/cc -o plot drawable.o plot_points.o root_data.o -lx11
mv plot /usr/local/bin

 

예시2

SOURCE = ${MY_SRC} ${SHARED_SRC}
MY_SRC = parse.c search_file.c
SHARED_DIR = /usrs/b_proj/src
SHARED_SRC = ${SHARED_DIR}/depend.c

make 는 ${SOURCES}를 아래와 같이 평가한다.

parse.c search_file.c /users/b_proj/src/depend.c

 

위의 예시를 보면 알겠지만, 매크로를 정의하는 순서는 상관없다.

 

예시3

TEST_MACRO = test
TEST_MACRO = test2

all:
        @echo "${TEST_MACRO}";

make를 하면 결과로 'test2'가 출력된다.

즉, make는 항상 파일에서 마지막 정의만을 참조로 사용한다.

 

내장 매크로

make에서 내부적으로 정의된 매크로들이 있다. 

 

${CC} : C컴파일러. '$cc' 명령과 같다.

${CXX} : CPP 컴파일러. '$g++' 명령과 같다.

${LD} : 링커

${RM} : 삭제 명령어

 

이 외에도 아래 링크에서 더 확인할 수 있다.

https://www.tutorialspoint.com/makefile/makefile_macros.htm

 

 

내부에서 정의된 모든 매크로들을 표시하는 방법

$make -p

make에서 p옵션을 주면 다음과 같이 정의된 매크로들을 모두 보여준다.

 

명령 행에서 매크로 정의

// Makefile
all:
        @echo "${TEST_MACRO}";

 

 

makefile을 위와 같이 정의하였고, 명령행에서 매크로를 정의하여 전달할 수 있다.

$ make TEST_MACRO=test3

결과는 test3을 출력한다.

 

혹은 make 명령 이전에 매크로를 정의할 수도 있다. (본 셸과 콘셸에서만 가능)

$ TEST_MACRO=test3 make

위와 동일하게 test3을 출력한다.

 

셸 변수

변수 정의를 셸에서 입력한다면 다음과 같이 사용할 수 있다.

$ TEST_MACRO=test4; export TEST_MACRO
$ make

결과는 test4를 출력한다.

참고로 $export 명령을 통해 정의해놓은 변수를 확인할 수 있다. 그리고 시스템을 재부팅하면 사라진다.

 

(위의 예제는 본셸과 콘셸에서만 사용이 가능하고, C셸 사용자는 setenv 명령을 사용해야 한다.)

 

매크로 할당 우선순위

예를 들어, DIR 매크로를 makefile 안에서는 /usr/proj로 정의해두고, 현재 셸 환경에서는 /usr/proj/lib으로 정의해두었을 경우, make는 실제로 둘 가운데 어떤 정의를 사용할까?

 

make는 아래와 같은 우선순위를 매겨 사용한다.

1)make 명령 입력 시 make 명령 다음에 입력한 매크로

2)makefile의 매크로 정의

3)현재 셸 환경 변수.

여기에는 사용자가 make 명령 행에 입력할 때 명령 바로 앞에 입력한 매크로도 포함된다. (본셸과 콘셸에만 해당)

4.make의 내장(기본) 정의

 

위의 우선순위는 다음과 같이 테스트를 해볼 수 있다.

// makefile
TEST_MACRO = insideMake

all:
        @echo "${TEST_MACRO}";
// 환경변수 정의
$ TEST_MACRO="environment variable"; export TEST_MACRO
// make 명령어와 함께 매크로 정의
$ make TEST_MACRO="command macro"

 

결과는 "command macro"를 출력한다.

 

그러나 여기에서 make 명령어 앞에 매크로 정의를 한다면 결과는 달라진다.

$ TEST_MACRO="command macro" make

결과는 insideMake를 출력한다.

 

억지로 환경 변수에 매크로를 우선적으로 참고하는 방법

e옵션을 주면 makefile보다 환경변수의 매크로를 우선적으로 참고한다.

$ make -e

위 명령어에 따라 바뀐 우선순위는 아래와 같다.

1) make 명령 입력 시 make 명령 다음에 입력한 매크로

2) 현재 셸 환경 변수.

여기에는 make 명령행에 입력할 때 명령 바로 앞에 입력한 매크로도 포함된다.(본셸과 콘셸만)

3)기술 파일의 매크로 정의

4)makefile의 매크로 저으이

5)make의 내장(기본) 정의

 

make 밖으로 나와 셸 스크립트를 활용하는 방법 - 래퍼 스크립트

위와 같이 매크로가 여러가지 방법으로 선언될 수 있기 때문에 래퍼 스크립트를 활용하여 매크로를 확인하여 make를 실행시키는 방법이 있다. 이 방법은 현업에서 유용하게 사용된다.

 

//make_local.sh
if
	TEST z "$PROJECT_TREE"
then
	PROJECT_TREE=usr/local; export PROJECT_TREE
fi
make $*

사용자가 PROJECT_TREE를 정의했는지 확인한다. 정의했다면 스크립트는 아무런 조처없이 종료한다. 

반면 정의되지 않은 경우, PROJECT_TREE는 사용자가 선택한 기본값을 취한다.

마지막 줄이 make를 실행시키면서 명령 행에서 모든 인수들을 전달한다.

 

make_local 실행시키기

$ make_local source_stream

 

매크로 문자열 치환

예제1

SRC = def.s redraw.c calc.c #매크로 정의
ls ${SRC:.c=.o} # 기술 파일 명령 내리면
calc.o defs.o redraw.o # 마치 이들 파일들이 존재하는 것처럼 결과를 출력한다.

make는 {SRC}를 평가하고, 콜론 뒤에 따라오는 문자열을 찾은 다음 등호 기호 뒤의 문자열을 치환한다.

이 기능을 이용하면 확장자만 또는 마지막에 첨부된 문자만 다른 여러 파일로 이뤄진 그룹들을 쉽게 관리할 수 있다.

 

예제2

SRC = defs.c redraw.c calc.c
FINAL_OBJS = ${SRC:.c=.o}
DEBUG_OBJS = ${SRC:.c=_dbg.o}

 

문자열 치환 예외 상황

LITTER = xyz xyzabc abcxyz
	echo ${LITTER:xyz=DEF}

결과는 다음과 같이 출력한다.

DEF xyzabc abcDEF

문자열 치환은 매크로의 마지막 부분이나 공백 문자 바로 앞까지만 적용이 가능하기 때문이다.

 

 

내부적으로 정의되어 있는 macro

$@ : 현재 target 이름 (명령행에서만 의미를 지닌다)

$$@ : 현재 target의 이름 (종속행에서만 의미를 지닌다)

$< : 현재 target 보다 최근에 변경된 필요 항목 리스트 (확장자 규칙에서만 사용가능)

$* : 현재 target보다 최근에 변경된 현재 필요 항목의 이름 (확장자 제외). (확장자 규칙에서만 사용 가능).

$% : 현재의 타깃이 라이브러리 모듈일 .o 파일에 대응되는 이름

 

예제1.

CMDS = cat dd echo date cccmp comm ar ld chown
${CMDS} : $$@.c
	${CC} -O $? -o $@

 

예제2.

/temp/target : /usr/local/c/test.c

${@F} : 현재 target 파일 부분 (target)

${<F} : 현재 필요 항목의 파일 부분 (test.c)

${@D} : 현재 target 디렉토리 부분 (/temp)

${<D} : 현재 필요 항목의 디렉토리 부분 (/usr/local/c)

 

 

매크로 활용 예제

반응형