Подтвердить что ты не робот

Как разместить объектные файлы в отдельном подкаталоге

У меня возникли проблемы с попыткой использовать make для размещения объектных файлов в отдельном подкаталоге, вероятно, очень простой метод. Я пытался использовать информацию на этой странице: http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types

Я получаю следующий вывод от make:

make: *** No rule to make target 'ku.h', needed by 'obj/kumain.o'.  Stop.

Однако ku.h является зависимостью, а не целью (хотя она, очевидно, включена в исходные файлы c). Когда я не пытаюсь использовать подкаталог для объектных файлов (то есть пропускаю части OBJDIR), он работает нормально. Почему заставляет думать, что ku.h является целью?

мой make файл такой: (стиль после чтения различных источников информации)

.SUFFIXES:
.SUFFIXES: .c .o

CC=gcc 
CPPFLAGS=-Wall
LDLIBS=-lhpdf
VPATH=%.c src
VPATH=%.h src
VPATH=%.o obj
OBJDIR=obj

objects= $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
  kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
  kushapes.o )

ku : $(objects)
  $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)

$(objects) : ku.h kudefines.h kuglobals.h kufns.h | $(OBJDIR)

$(OBJDIR):
  mkdir $(OBJDIR)

.PHONY: clean
clean :
  rm $(objects)

Изменение: я применил изменения, чтобы использовать директиву vpath. Моя версия была плохой смесью VPATH = xxx и vpath%.c xxx. Однако теперь я получаю другую проблему (которая была первоначальной проблемой до того, как я добавил неправильный vpath). Теперь это вывод:

    gcc  -o ku -lhpdf obj/kumain.o obj/kudlx.o obj/kusolvesk.o ..etc
    gcc: obj/kumain.o: No such file or directory
    gcc: obj/kudlx.o: No such file or directory
    gcc: obj/kusolvesk.o: No such file or directory
    gcc: obj/kugetpuz.o: No such file or directory
    gcc: obj/kuutils.o: No such file or directory
    gcc: obj/kurand.o: No such file or directory
    gcc: obj/kuASCboard.o: No such file or directory
    gcc: obj/kuPDFs.o: No such file or directory
    gcc: obj/kupuzstrings.o: No such file or directory
    gcc: obj/kugensud.o: No such file or directory
    gcc: obj/kushapes.o: No such file or directory
    make: *** [ku] Error 1

Похоже, что make не применяет неявное правило для объектного файла, хотя в руководстве говорится: "Неявные правила говорят make, как использовать обычные методы, чтобы вам не приходилось указывать их подробно, когда вы хотите их использовать. Например, есть является неявным правилом для компиляции C. Имена файлов определяют, какие неявные правила запускаются. Например, компиляция C обычно берет файл.c и создает файл.o. Так что make применяет неявное правило для компиляции C, когда видит эту комбинацию окончания имени файла. " а также "Поиск по каталогам, указанным в VPATH или с помощью vpath, также происходит при рассмотрении неявных правил (см. Использование неявных правил)".

Опять здесь "Например, когда файл foo.o не имеет явного правила, make рассматривает неявные правила, такие как встроенное правило для компиляции foo.c, если этот файл существует. Если такого файла нет в текущем каталоге, соответствующие каталоги ищутся. Если foo.c существует (или упоминается в make файле) в каком-либо из каталогов, применяется неявное правило для компиляции Си ".

Будем весьма благодарны за любую помощь в получении неявных правил для моего make файла.

Редактирование № 2: Благодаря Джеку Келли я сделал явное правило для компиляции файлов.c, так как не мог нигде пытаться использовать неявные правила. Также спасибо al_miro за информацию о vpath.

Вот рабочий макфайл:

.SUFFIXES:
.SUFFIXES: .c .o

CC=gcc 
CPPFLAGS=-Wall
LDLIBS=-lhpdf
OBJDIR=obj
vpath %.c src
vpath %.h src

objects = $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
  kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
  kushapes.o )

ku : $(objects)
  $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)

$(OBJDIR) obj/%.o : %.c ku.h kudefines.h kuglobals.h kufns.h 
  $(CC) -c $(CPPFLAGS) $< -o [email protected]

.PHONY : clean
clean :
  rm $(objects)
4b9b3361

Ответ 1

Поскольку вы используете GNUmake, используйте правило шаблона для компиляции объектных файлов:

$(OBJDIR)/%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o [email protected] $<

Ответ 2

Это файл makefile, который я использую для большинства моих проектов,

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

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

Он также скопирует все файлы из папки "resources" в папку bin, когда проект будет скомпилирован, который я обычно использую большую часть времени.

Чтобы предоставить кредит там, где это произошло, функция автозависимостей была основана в основном на странице Scott McPeak, которую можно найти ЗДЕСЬ, с некоторыми дополнительными изменениями/настройками для мои потребности.

Пример Makefile

#Compiler and Linker
CC          := g++-mp-4.7

#The Target Binary Program
TARGET      := program

#The Directories, Source, Includes, Objects, Binary and Resources
SRCDIR      := src
INCDIR      := inc
BUILDDIR    := obj
TARGETDIR   := bin
RESDIR      := res
SRCEXT      := cpp
DEPEXT      := d
OBJEXT      := o

#Flags, Libraries and Includes
CFLAGS      := -fopenmp -Wall -O3 -g
LIB         := -fopenmp -lm -larmadillo
INC         := -I$(INCDIR) -I/usr/local/include
INCDEP      := -I$(INCDIR)

#---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
SOURCES     := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS     := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))

#Defauilt Make
all: resources $(TARGET)

#Remake
remake: cleaner all

#Copy Resources from Resources Directory to Target Directory
resources: directories
    @cp $(RESDIR)/* $(TARGETDIR)/

#Make the Directories
directories:
    @mkdir -p $(TARGETDIR)
    @mkdir -p $(BUILDDIR)

#Clean only Objecst
clean:
    @$(RM) -rf $(BUILDDIR)

#Full Clean, Objects and Binaries
cleaner: clean
    @$(RM) -rf $(TARGETDIR)

#Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))

#Link
$(TARGET): $(OBJECTS)
    $(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIB)

#Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
    @mkdir -p $(dir [email protected])
    $(CC) $(CFLAGS) $(INC) -c -o [email protected] $<
    @$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
    @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
    @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
    @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
    @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp

#Non-File Targets
.PHONY: all remake clean cleaner resources

Ответ 3

Строки VPATH неверны, они должны быть

vpath %.c  src
vpath %.h  src

то есть. а не капитала и без =. Как и сейчас, он не находит файл .h и считает, что это цель.

Ответ 4

В общем, вам либо нужно указать $(OBJDIR) в левой части всех правил размещения файлов в $(OBJDIR), либо вы можете запустить make из $(OBJDIR). VPATH предназначен для источников, а не для объектов.

Взгляните на эти две ссылки для более подробного объяснения и "умного" обходного пути.

Ответ 5

Следующее решение, на мой взгляд, не очень приятно, так как мне очень нравятся встроенные правила. Однако GNU make не поддерживает что-то вроде vpath для выходных каталогов. И встроенные правила не могут совпадать, так как % в %.o будет соответствовать obj/foo obj/foo.o, оставив make с поиском в vpath %.c src/ для таких вещей, как src/obj/foo.c, но не src/foo.c > .

Но это как можно ближе к встроенным правилам, которые вы можете получить, и поэтому, насколько мне известно, самое приятное решение, которое доступно.

$(OBJDIR)/%.o: %.c
        $(COMPILE.c) $(OUTPUT_OPTION) $<

Объяснение: $(COMPILE.c) $(OUTPUT_OPTION) $< на самом деле реализовано .c.o, см. http://git.savannah.gnu.org/cgit/make.git/tree/default.c (и это даже упоминается в руководстве)

Кроме того, если $(OBJDIR) будет содержать только автоматически загруженные файлы, вы можете создать его "на лету" с предварительным условием для заказа, что упростит чистое правило:

$(OBJDIR):
        mkdir -p $(OBJDIR)

$(OBJDIR)/%.o: %.c | $(OBJDIR)
        $(COMPILE.c) $(OUTPUT_OPTION) $<

.PHONY: clean
clean:
        $(RM) -r $(OBJDIR)

Для этого требуется доступность только для функций, которые вы можете проверить, используя $(filter order-only, $(.FETAURES)). Я проверил Kubuntu 14.04 GNU make 3.81 и OpenSUSE 13.1 GNU make 3.82. Оба были построены только с поддержкой заказа, и теперь я озадачен тем, почему Kubuntu 14.04 поставляется со старой версией GNU make, чем OpenSUSE 13.1. Anyways, собираюсь скачать make 4.1 сейчас:)

Ответ 6

Для всех тех, кто работает с неявными правилами (и GNU MAKE). Вот простой make файл, который поддерживает разные каталоги:

#Start of the makefile

VPATH = ./src:./header:./objects

OUTPUT_OPTION = -o objects/[email protected]

CXXFLAGS += -Wall -g -I./header

Target = $(notdir $(CURDIR)).exe

Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))



all: $(Target)

$(Target): $(Objects)
     $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))


#Beware of -f. It skips any confirmation/errors (e.g. file does not exist)

.PHONY: clean
clean:
     rm -f $(addprefix objects/,$(Objects)) $(Target)

Давайте посмотрим ближе (я буду ссылаться на текущий каталог с curdir):

Эта строка используется для получения списка используемых файлов .o, которые находятся в curdir/src.

Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))
#expands to "foo.o myfoo.o otherfoo.o"

Через переменную вывод устанавливается в другую директорию (curdir/objects).

OUTPUT_OPTION = -o objects/[email protected]
#OUTPUT_OPTION will insert the -o flag into the implicit rules

Чтобы убедиться, что компилятор находит объекты в папке с новыми объектами, путь добавляется к имени файла.

$(Target): $(Objects)
     $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))
#                                    ^^^^^^^^^^^^^^^^^^^^    

Это подразумевается как пример, и есть определенная возможность для улучшения.

За дополнительной информацией обращайтесь: Сделайте документацию. См. Главу 10.2

Или: Oracle: Руководство по программированию программ