저는 makefiles를 처음 접했고 makefile을 사용하여 디렉토리를 만들고 싶습니다. 내 프로젝트 디렉토리는 다음과 같습니다.
+--Project
+--output
+--source
+Testfile.cpp
+Makefile
모든 개체와 출력을 각 출력 폴더에 넣고 싶습니다. 컴파일 후 다음과 같은 폴더 구조를 만들고 싶습니다.
+--Project
+--output
+--debug (or release)
+--objs
+Testfile.o
+Testfile (my executable file)
+--source
+Testfile.cpp
+Makefile
몇 가지 옵션을 시도했지만 성공하지 못했습니다. make 파일을 사용하여 디렉토리를 만들도록 도와주세요. 나는 당신의 고려를 위해 내 Makefile을 게시하고 있습니다.
#---------------------------------------------------------------------
# Input dirs, names, files
#---------------------------------------------------------------------
OUTPUT_ROOT := output/
TITLE_NAME := TestProj
ifdef DEBUG
TITLE_NAME += _DEBUG
else
ifdef RELEASE
TITLE_NAME += _RELEASE
endif
endif
# Include all the source files here with the directory tree
SOURCES := \
source/TestFile.cpp \
#---------------------------------------------------------------------
# configs
#---------------------------------------------------------------------
ifdef DEBUG
OUT_DIR := $(OUTPUT_ROOT)debug
CC_FLAGS := -c -Wall
else
ifdef RELEASE
OUT_DIR := $(OUTPUT_ROOT)release
CC_FLAGS := -c -Wall
else
$(error no build type defined)
endif
endif
# Put objects in the output directory.
OUT_O_DIR := $(OUT_DIR)/objs
#---------------------------------------------------------------------
# settings
#---------------------------------------------------------------------
OBJS = $(SOURCES:.cpp=.o)
DIRS = $(subst /,/,$(sort $(dir $(OBJS))))
DIR_TARGET = $(OUT_DIR)
OUTPUT_TARGET = $(OUT_DIR)/$(TITLE_NAME)
CC_FLAGS +=
LCF_FLAGS :=
LD_FLAGS :=
#---------------------------------------------------------------------
# executables
#---------------------------------------------------------------------
MD := mkdir
RM := rm
CC := g++
#---------------------------------------------------------------------
# rules
#---------------------------------------------------------------------
.PHONY: all clean title
all: title
clean:
$(RM) -rf $(OUT_DIR)
$(DIR_TARGET):
$(MD) -p $(DIRS)
.cpp.o:
@$(CC) -c $< -o $@
$(OBJS): $(OUT_O_DIR)/%.o: %.cpp
@$(CC) -c $< -o $@
title: $(DIR_TARGET) $(OBJS)
미리 감사드립니다. 저도 실수를했다면 안내 해주세요.
답변
이것은 유닉스와 같은 환경을 가정하여 그렇게 할 것입니다.
MKDIR_P = mkdir -p
.PHONY: directories
all: directories program
directories: ${OUT_DIR}
${OUT_DIR}:
${MKDIR_P} ${OUT_DIR}
이것은 최상위 디렉토리에서 실행되어야합니다. 그렇지 않으면 $ {OUT_DIR}의 정의가 실행되는 위치에 상대적으로 정확해야합니다. 물론 Peter Miller의 ” Recursive Make Thoughmful “문서 의 칙령을 따른다면 어쨌든 최상위 디렉토리에서 make를 실행하게 될 것입니다.
나는 지금이 (RMCH)를 가지고 놀고있다. 테스트 그라운드로 사용중인 소프트웨어 제품군에 약간의 적응이 필요했습니다. 이 제품군에는 15 개의 디렉토리에 분산 된 소스로 구축 된 12 개의 개별 프로그램이 있으며, 일부는 공유됩니다. 그러나 약간의주의를 기울이면 가능합니다. OTOH, 초보자에게는 적합하지 않을 수 있습니다.
주석에서 언급했듯이 ‘디렉토리’에 대한 작업으로 ‘mkdir’명령을 나열하는 것은 잘못되었습니다. 주석에서 언급했듯이 ‘출력 / 디버그를 만드는 방법을 모릅니다’오류를 수정하는 다른 방법이 있습니다. 하나는 ‘디렉토리’줄에 대한 종속성을 제거하는 것입니다. 이것은 ‘mkdir -p’가 생성하도록 요청 된 모든 디렉토리가 이미 존재하는 경우 오류를 생성하지 않기 때문에 작동합니다. 다른 하나는 표시된 메커니즘으로, 디렉토리가없는 경우에만 생성을 시도합니다. ‘수정 된’버전은 내가 어젯밤 염두에 두었던 것입니다.하지만 두 기술 모두 작동합니다 (출력 / 디버그가 존재하지만 디렉토리가 아닌 파일 인 경우 둘 다 문제가 있습니다).
답변
제 생각에, 디렉토리는 기술적 또는 디자인 적 측면에서 Makefile의 대상으로 간주되어서는 안됩니다. 당신은 만들어야합니다 파일 및 파일 생성은 새로운 디렉토리를 필요로하는 경우 다음 조용히 관련 파일에 대한 규칙 내에서 디렉토리를 생성합니다.
일반 또는 “패턴 화 된”파일을 대상으로하는 경우 make
‘s 내부 변수 $(@D)
를 사용하십시오. 이는 “현재 대상이 상주하는 디렉토리”(대상의 경우 cmp. $@
)를 의미합니다. 예를 들면
$(OUT_O_DIR)/%.o: %.cpp
@mkdir -p $(@D)
@$(CC) -c $< -o $@
title: $(OBJS)
그런 다음 효과적으로 동일한 작업을 수행합니다. 모두를위한 디렉토리를 생성 $(OBJS)
하지만 덜 복잡한 방식으로 수행합니다.
다양한 애플리케이션에서 동일한 정책 (파일은 대상, 디렉토리는 절대로 사용되지 않음)이 사용됩니다. 예를 들어 git
개정 제어 시스템은 디렉토리를 저장하지 않습니다.
참고 : 사용하려는 경우 편의 변수를 도입하고 make
의 확장 규칙을 활용하는 것이 유용 할 수 있습니다 .
dir_guard=@mkdir -p $(@D)
$(OUT_O_DIR)/%.o: %.cpp
$(dir_guard)
@$(CC) -c $< -o $@
$(OUT_O_DIR_DEBUG)/%.o: %.cpp
$(dir_guard)
@$(CC) -g -c $< -o $@
title: $(OBJS)
답변
또는 KISS.
DIRS=build build/bins
...
$(shell mkdir -p $(DIRS))
Makefile이 구문 분석 된 후 모든 디렉토리가 생성됩니다.
답변
make
in 및 off 자체는 파일 대상과 동일하게 디렉토리 대상을 처리합니다. 따라서 다음과 같은 규칙을 작성하는 것은 쉽습니다.
outDir/someTarget: Makefile outDir
touch outDir/someTarget
outDir:
mkdir -p outDir
유일한 문제는 디렉토리 타임 스탬프가 내부 파일에 수행되는 작업에 따라 달라진다는 것입니다. 위의 규칙의 경우 다음과 같은 결과가 나타납니다.
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
이것은 확실히 당신이 원하는 것이 아닙니다. 파일을 터치 할 때마다 디렉토리도 터치합니다. 그리고 파일이 디렉토리에 의존하기 때문에 파일이 오래되어 다시 빌드되어야합니다.
그러나 make에게 디렉토리의 타임 스탬프를 무시하도록 지시 하여이 루프를 쉽게 끊을 수 있습니다 . 이는 디렉토리를 주문 전용 전제 조건으로 선언하여 수행됩니다.
# The pipe symbol tells make that the following prerequisites are order-only
# |
# v
outDir/someTarget: Makefile | outDir
touch outDir/someTarget
outDir:
mkdir -p outDir
이것은 올바르게 다음을 산출합니다.
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
make: 'outDir/someTarget' is up to date.
TL; DR :
디렉터리를 만드는 규칙을 작성합니다.
$(OUT_DIR):
mkdir -p $(OUT_DIR)
그리고 내부의 물건에 대한 대상은 디렉토리 주문에만 의존합니다.
$(OUT_DIR)/someTarget: ... | $(OUT_DIR)
답변
수락 된 솔루션을 포함한 모든 솔루션에는 각각의 의견에 명시된 몇 가지 문제가 있습니다. 조나단 – 레플러 @에 의해 허용 대답은 이미 꽤 좋은 그러나 전제 조건이 반드시 (중 순서에 건설되지 않도록 효력을지지 않습니다 make -j
예를 들어). 그러나 단순히 directories
전제 조건을에서 all
로 이동하면 program
AFAICT가 실행될 때마다 재 구축 이 유발됩니다. 다음 솔루션에는 해당 문제가 없으며 AFAICS가 의도 한대로 작동합니다.
MKDIR_P := mkdir -p
OUT_DIR := build
.PHONY: directories all clean
all: $(OUT_DIR)/program
directories: $(OUT_DIR)
$(OUT_DIR):
${MKDIR_P} $(OUT_DIR)
$(OUT_DIR)/program: | directories
touch $(OUT_DIR)/program
clean:
rm -rf $(OUT_DIR)
답변
빌드 할 파일을 정의하고 디렉토리를 자동으로 생성 할 수있는 상당히 합리적인 솔루션을 찾았습니다. 먼저 ALL_TARGET_FILES
makefile이 빌드 될 모든 파일의 파일 이름을 보유 하는 변수 를 정의 하십시오. 그런 다음 다음 코드를 사용하십시오.
define depend_on_dir
$(1): | $(dir $(1))
ifndef $(dir $(1))_DIRECTORY_RULE_IS_DEFINED
$(dir $(1)):
mkdir -p $$@
$(dir $(1))_DIRECTORY_RULE_IS_DEFINED := 1
endif
endef
$(foreach file,$(ALL_TARGET_FILES),$(eval $(call depend_on_dir,$(file))))
작동 방식은 다음과 같습니다. depend_on_dir
파일 이름을 가져 와서 파일이 포함 된 디렉토리에 종속되는 규칙을 생성 하는 함수 를 정의한 다음 필요한 경우 해당 디렉토리를 생성하는 규칙을 정의합니다. 그런 다음 각 파일 이름과 결과 에이 기능을 사용 foreach
합니다 .call
eval
를 지원하는 GNU make 버전이 필요합니다 eval
.이 버전은 3.81 이상이라고 생각합니다.