CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
.cpp.o:
$(CC) $(CFLAGS) $< -o $@
무엇을 $@
하고 $<
정확합니까?
답변
$@
생성되는 파일의 이름이며 $<
첫 번째 전제 조건 (일반적으로 소스 파일)입니다. GNU Make 매뉴얼 에서 이러한 모든 특수 변수 목록을 찾을 수 있습니다 .
예를 들어 다음 선언을 고려하십시오.
all: library.cpp main.cpp
이 경우 :
$@
~에 평가하다all
$<
~에 평가하다library.cpp
$^
~에 평가하다library.cpp main.cpp
답변
$@
및 $<
호출되는 자동 변수를 . 변수 $@
는 작성된 파일 이름 (예 : 대상)을 $<
나타내고 출력 파일을 작성하는 데 필요한 첫 번째 전제 조건을 나타냅니다.
예를 들면 다음과 같습니다.
hello.o: hello.c hello.h
gcc -c $< -o $@
여기서, hello.o
출력 파일입니다. 이것이 $@
확장되는 것입니다. 첫 번째 종속성은 hello.c
입니다. 그것이 $<
확장되는 것입니다.
-c
플래그는 생성 .o
파일을; man gcc
자세한 설명 은 참조하십시오 . 는 -o
만들 수있는 출력 파일을 지정합니다.
자세한 내용은 Linux Makefiles에 대한이 기사를 읽으십시오 .
또한 GNU make
매뉴얼을 확인할 수 있습니다 . Makefile을보다 쉽게 만들고 디버깅 할 수 있습니다.
이 명령을 실행하면 makefile 데이터베이스가 출력됩니다.
make -p
답변
에서 GNU의 메이크업, 제 3 판, P와 프로젝트 관리. 16 ( GNU Free Documentation License 하에 있음 ) :
자동 변수 는
make
규칙이 일치 한 후에 설정됩니다 . 대상 및 전제 조건 목록에서 요소에 대한 액세스를 제공하므로 파일 이름을 명시 적으로 지정할 필요가 없습니다. 코드 중복을 피하는 데 매우 유용하지만보다 일반적인 패턴 규칙을 정의 할 때 중요합니다.7 가지“핵심”자동 변수가 있습니다 :
$@
: 대상을 나타내는 파일 이름입니다.
$%
: 아카이브 멤버 스펙의 파일 이름 요소입니다.
$<
: 첫 번째 전제 조건의 파일 이름입니다.
$?
: 대상보다 최신 인 모든 전제 조건의 이름을 공백으로 구분합니다.
$^
: 모든 전제 조건의 파일 이름을 공백으로 구분합니다. 이 목록에는 편집, 복사 등과 같은 대부분의 용도에서 중복을 원하지 않기 때문에 중복 된 파일 이름이 제거되었습니다.
$+
:와 유사하게$^
, 이것은$+
중복 을 포함하는 것을 제외하고 공백으로 구분 된 모든 전제 조건의 이름입니다 . 이 변수는 중복 값이 의미가있는 링커에 대한 인수와 같은 특정 상황을 위해 만들어졌습니다.
$*
: 대상 파일 이름의 스템입니다. 줄기는 일반적으로 접미사가없는 파일 이름입니다. 패턴 규칙 외부에서의 사용은 권장하지 않습니다.또한 위의 각 변수에는 다른 제조사와의 호환성을 위해 두 가지 변형이 있습니다. 하나의 변형은 값의 디렉토리 부분 만 반환합니다. 이것은 심볼에 “D”를 추가하여 표시되는
$(@D)
,$(<D)
등의 다른 변형 반환 값의 파일 부. 이것은, 기호에 “F”를 추가로 표시됩니다$(@F)
,$(<F)
이러한 변형의 이름은 괄호로 묶어야합니다 둘 이상의 문자 길이 너무 있다는 등 참고. GNU make는 dir 및 notdir 함수에 대한보다 읽기 쉬운 대안을 제공합니다.
답변
$@
와는 $<
특별한 매크로입니다.
어디:
$@
대상의 파일 이름입니다.
$<
첫 번째 종속성의 이름입니다.
답변
메이크는 빌드 hello
중 하나가 있다면 실행을 main.cpp
, hello.cpp
, factorial.cpp
변경. 해당 사양을 달성 할 수있는 가장 작은 Makefile은 다음과 같습니다.
hello: main.cpp hello.cpp factorial.cpp
g++ -o hello main.cpp hello.cpp factorial.cpp
- 프로 : 매우 읽기 쉽다
- 단점 : 유지 관리의 악몽, C ++ 종속성의 중복
- 단점 : 효율성 문제, 하나만 변경된 경우에도 모든 C ++를 다시 컴파일
위의 내용을 개선하기 위해 편집 된 C ++ 파일 만 컴파일합니다. 그런 다음 결과 객체 파일을 서로 연결하면됩니다.
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
main.o: main.cpp
g++ -c main.cpp
hello.o: hello.cpp
g++ -c hello.cpp
factorial.o: factorial.cpp
g++ -c factorial.cpp
- 프로 : 효율성 문제 해결
- 죄수 : 새로운 유지 관리 악몽, 객체 파일 규칙의 오타 가능성
이를 개선하기 위해 모든 객체 파일 규칙을 단일 .cpp.o
규칙으로 바꿀 수 있습니다 .
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
.cpp.o:
g++ -c $< -o $@
- 찬성 : 짧은 makefile로 돌아가서 약간 읽기 쉽다.
여기에 .cpp.o
규칙을 구축하는 방법을 정의 anyfile.o
에서 anyfile.cpp
.
$<
이 경우 첫 번째 종속성과 일치합니다.anyfile.cpp
$@
이 경우 타겟과 일치합니다anyfile.o
.
Makefile에 존재하는 다른 변경 사항은 다음과 같습니다.
- 컴파일러를 g ++에서 C ++ 컴파일러로 쉽게 변경할 수 있습니다.
- 컴파일러 옵션을보다 쉽게 변경할 수 있습니다.
- 링커 옵션을보다 쉽게 변경할 수 있습니다.
- C ++ 소스 파일 및 출력을보다 쉽게 변경할 수 있습니다.
- 응용 프로그램 빌드를 시도하기 전에 모든 소스 파일이 있는지 확인하는 빠른 검사 역할을하는 기본 규칙 ‘all’이 추가되었습니다.
답변
소스를 컴파일하고 싶지만 다른 디렉토리에 객체가있는 경우 예를 들어 :
당신은해야합니다 :
gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...
그러나 대부분의 매크로에서 결과는 다음과 같이 모든 객체와 모든 소스가 뒤 따릅니다.
gcc -c -o <all OBJ path> <all SRC path>
그래서 이것은 아무것도 컴파일하지 않을 것입니다 ^^ 객체 파일을 다른 디렉토리에 넣을 수 없습니다 🙁
해결책은 이러한 특수 매크로를 사용하는 것입니다
$@ $<
이것은 SRC (src / file.c)의 각 .c 파일에 대해 .o 파일 (obj / file.o)을 생성합니다.
$(OBJ):$(SRC)
gcc -c -o $@ $< $(HEADERS) $(FLAGS)
그 뜻은 :
$@ = $(OBJ)
$< = $(SRC)
그러나 OBJ의 모든 라인의 INSTEAD 라인과 SRC의 모든 라인