make - 2

2021. 8. 22. 16:20

make
 - 컴파일 도구, 컴파일을 위해 주어진 쉘명령어들을 조건에 맞게 실행하는 프로그램
 - 컴파일 작업 단순화를 위해 사용하며, 대규모/공동 프로젝트에서 많이 사용한다(기에는 개인들도 많이 사용한다)
 - 이전 컴파일한 내용이 있을 경우 수정된 파일들을 파알하여 수정된 내용들에 대해서만 컴파일 수행

  ** make 명령어 실행시 파일의 수정유무는 타임스탬프를 기반으로 판단한다
     (타임 스탬프의 변경유무를 통해 파일의 변경점을 판단)

make file
 -  컴파일 빌드 규칙을 기술한 파일
 - 컴파일 명령 및 쉘 명령어들로 구성되어 있으며, 소스파일 간의 의존성(dependency)을 명시한다
    : make가 makefile의 내용을 통해 파일 간의 종속성을 자동으로 파악하여 효율적 컴파일을 수행한다(쉘 스크립트와의 차이)


make 명령어 실행법
 - make [-f 파일명] [options] [targets]
    : makefile 미지정시, 현재경로의 makefile 혹은 Makefile을 사용하여 빌드한다
    : target 미지정시 all을 타겟으로 빌드한다

makefile 작성법
 - 구성
     타겟 : 의존성 목록
     (탭)쉘명령어
      -> 의존성 목록이 있어야 타겟을 컴파일 한다. 즉, 타겟을 위해 선행적으로 의존성 목록을 컴파일한다
      -> makefile는 탭문자 다음에 적힌 문자열을 명령문으로 판단한다

 - 묵시적으로 사용하는 타겟들
    all
     : 최종 타겟, 일반적으로 의존성 목록에 모든 빌드 타겟이 명시되어 있다
    clean
     : make 명령에 의해 생성된 파일들을 삭제하는 타겟

 - 주석
    #

 - 메크로
    변수 정의: 변수=값
    변수 사용: $(변수), ${변수}
    CC : 컴파일러 프로그램 명시
    CFLAGS : 컴파일 옵션 명시
    LDFLAGS : 링크를 위한 라이브러리 명시
   ** 컴파일은 소스파일로 목적파일 생성을 수행, 링크는 목적파일로 바이너리 파일 생성을 수행

 - 와일드 카드, 패턴
    % : *와 같음

   ** 아래의 패턴은 명령어 작성시 타겟과 의존성 목록을 가리킬 때 사용이 가능하다
    $@ : 타겟이름
    $< : 의존성 목록 중 첫번째 파일을 의미
    $^ : 의존성 목록 전체를 의미
    $? : 타겟보타 최신의 상태를 가지는 의존성 목록을 의미
    $+ : $^와 유사하나, 중복된 파일 이름들 까지 모두 포함


 - gcc 옵션
    ** gcc 옵션 참조
     - https://jayy-h.tistory.com/9

    -I : (대문자 i), 헤더파일 경로 지정
    -L : 라이브러리 경로 지정
    -l :(소문자 L), 참조할 라이브러리 이름을 명시
         ex) 라이브러리 이름이 libtest.a일 경우, gcc옵션 작성시에는 -ltest.a가 된다
             (라이브러리 이름작성시에는 lib로 시작해야하며, .a는 적적, .so는 동적라이브러리이다)

    -D : 매크로선언
    -g : 디버깅 정보 포함(디버깅 툴에서 디버깅 가능)
    -W : 컴파일이 가능하지만 존재하는 경고 출력
    -Wall : 컴파일시 발생하는 모든 경고 출력
    -c : 목적파일 생성
    -O : 최적화 레벨 지정
    -MD : 컴파일시 생성한 목적파일(메이크파일로 치면 타겟)을 만들기 위해 참조하는 소스파일(메이크파일로 치면 의존파일)과 헤더파일 목록의 정보를 "목적파일명.d"파는 이름으로 파일 생성
          (= 목적파일의 종속정을 검사하고 해당 내용을 "목적파일명.d" 파일에 생성 및 저장한다)

     * /usr/include/stdc-predef.h : gcc 컴파일러가 컴파일시 묵시적으로 참조하는 헤더파일
     ** 위의 .d파일을 사용하여 makefile작성시 종속목록 작성을 생략할 수 있다
        단, 처음 make 수행시에는 기존에 존재하는 .d파일이 없기 때문에 빌드시 어떠한 .d파일을 포함하지 않는다.
        즉, 그 다음  make수행시 .d가 포함된다
         ex) makefile에서 아래와 같이 정의
              include 목적파일명.d -> 특정 .d파일을 makefile에서 참조
              include $(OBJS:.o=.d) -> OBJS에 등록된 변수 값에서, .o를 .d로 치환. 이후 makefile이 목적파일에 대응하는 .d파일을 참조한다
              -include 목적파일명.d -> 특정 .d파일을 makefile에서 참조해되, 해당파일이 존재하지 않아도 관련오류 메세지를 출력하지 않는다


 - 함수사용
    $(wildcard 조건) : 조건에 맞는 파일목록을 추출
    $(notdir 파일목록) : 파일목록에서 경로를 제외한 파일이름만을 추출
    $(patsubst 현재패턴, 치환패턴, 대상) : '대상'에 정의된 파일목록 중 '현재 패턴'에 해당하는 파일들을 '치환패턴'으로 치환하여 결과 값 반환


 - 기타
    A = x 
      : x가 정의될 때까지 대기한 후 x값을 A에 저장
    A := x 
      : 해당 시점의 x변수의 값을 확인하여 A를 선언. 즉, x가 정의되지 않더라도 A를 선언(이 경우 A는 빈값을 가진다)
    .PHONY 
      : 'make 타겟' 명령어 실행 시, 조건에 관계없이 같이 정의된 타겟에 대한 명령어를 무조건 실행
      ex) makefile에서
          .PHONY : clean
          clean :
           rm -f $(OBJS) $(TARGETS)
           -> 타겟이나 목적파일이 없더라도 일단 해당 rm명령어 수행


** 멀티코어를 사용하여 make하기
  make -j 쓰레드개수
 - 컴파일 병렬수행 명령, 커널 컴파일과 같이 대용량 컴파일시 활용하면 시간이 절약된다
 - 쓰레드개수는 통상적으로 코어개수+1(혹은 코어개수의 120%수준으로)로 지정하여 수행하는 것이 가징 속도가 빠르다

 - 만약 리눅스 환경에서 코어개수를 모를 경우
  make -j $(nproc)
    - $(nproc)는 현재 시스템환경에서 사용가능한 코어개수를 의미


** 응용
  makefile에서
    .c.o:
     $(CC) -c -o $@ $<
  의미: makefile에 존재하는 c파일($<)을 o파일로 컴파일
   -> 인터넷을 찾아보니 .c.o는 구식 접미사 규칙(오래된 문법)으로서 같은 의미로는 %.o: %.c 이다 
      $<를 $^로 변경해도 문제가 없을 것으로 판단된다

'Study > utilities' 카테고리의 다른 글

vscode 배우기  (0) 2023.03.24
cmake - 3(강의정리)  (0) 2023.02.21
cmake - 2  (0) 2021.09.08
cmake - 1  (0) 2021.09.01
make - 1  (0) 2021.08.22

+ Recent posts