Создайте каталоги с помощью make-файла

Я - очень новое для make-файлов, и я хочу создать каталоги с помощью make-файла. Мой каталог проекта похож на это

+--Project  
   +--output  
   +--source  
     +Testfile.cpp  
   +Makefile  

Я хочу поместить все объекты и вывод в соответствующую выходную папку. Я хочу создать структуру папок, которая была бы похожа на это после компиляции.

+--Project
   +--output
     +--debug (or release)
       +--objs
         +Testfile.o
       +Testfile (my executable file)
   +--source
     +Testfile.cpp
   +Makefile

Я попробовал несколькими опциями, но не мог успешно выполниться. Помогите мне сделать каталоги с помощью make-файла. Я отправляю свой Make-файл для Вашего внимания.

#---------------------------------------------------------------------
# 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)

Заранее спасибо. Ведите меня, если я сделал какие-либо ошибки также.

90
задан Jabez 23 December 2009 в 05:58
поделиться

3 ответа

Это бы сработало - предполагая Unix-подобное окружение.

MKDIR_P = mkdir -p

.PHONY: directories

all: directories program

directories: ${OUT_DIR}

${OUT_DIR}:
        ${MKDIR_P} ${OUT_DIR}

Это должно было бы быть запущено в каталоге верхнего уровня - иначе определение ${OUT_DIR} должно было бы быть корректным относительно того, где оно запускается. Конечно, если вы будете следовать указаниям статьи Питера Миллера "Recursive Make Considered Harmful", то вы все равно будете запускать make в каталоге верхнего уровня.

Я сейчас играю с этим (RMCH). Нужна была небольшая адаптация к набору программного обеспечения, который я использую в качестве испытательного полигона. В наборе есть дюжина отдельных программ, собранных с исходными текстами, распределенными по 15 каталогам, некоторые из них - общие. Но с некоторой осторожностью это можно сделать. OTOH, это может быть неуместно для новичка.


Как отмечено в комментариях, перечислять команду 'mkdir' как действие для 'каталогов' неправильно. Как также отмечено в комментариях, есть и другие способы исправить ошибку 'don't know how to make output/debug', которая приводит к ошибке. Один из них - удалить зависимость от строки 'directories'. Это работает, так как 'mkdir -p' не генерирует ошибок, если все каталоги, которые он просит создать, уже существуют. Другой - показанный механизм, который будет пытаться создать каталог только в том случае, если он не существует. Версия 'as amended' - это то, о чем я думал прошлой ночью - но обе техники работают (и у обеих есть проблемы, если output/debug существует, но является файлом, а не каталогом)

.
79
ответ дан 24 November 2019 в 06:56
поделиться

На мой взгляд, каталоги не следует рассматривать в качестве мишеней вашего makefile ни в техническом, ни в конструктивном смысле. Вы должны создать файлы и если для создания файла требуется новый каталог, то тихо создайте каталог в рамках правила для соответствующего файла.

Если вы нацеливаетесь на обычный или "узорчатый" файл, просто используйте внутреннюю переменную make's внутреннюю переменную $(@D), что означает "каталог, в котором находится текущая цель" (ср. с $@ для цели). Например,

$(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)
128
ответ дан 24 November 2019 в 06:56
поделиться

, учитывая, что Вы новичок, я бы сказал пока не пытайтесь этого делать. это определенно возможно, но без надобности усложнит Ваш Makefile. придерживайтесь простых способов, пока Вам не станет удобнее делать make.

при этом один из способов собрать в каталог, отличный от исходного, это VPATH; я предпочитаю pattern rules

3
ответ дан 24 November 2019 в 06:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: