Jak umieścić pliki obiektowe w osobnym podkatalogu

Mam problem z używaniem make do umieszczania plików obiektowych w osobnym podkatalogu, prawdopodobnie bardzo podstawowa technika. Próbowałem wykorzystać informacje zawarte na tej stronie: http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types

Otrzymuję następujące wyjście z make: make: * * * No rule to make target ku.h', needed by obj / kumain.o'. Przestań.

Jednak ku.h jest zależnością, a nie celem (choć oczywiście jest to #zawarte w c pliki źródłowe). Jeśli nie próbuję użyć podkatalogu dla plików obiektowych (tj. pominąć części OBJDIR) to działa dobrze. Po co myśleć ku.h jest celem?

Mój makefile jest taki: (styl jest po przeczytaniu różnych źródeł informacji)

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

Edytuj: Zastosowałem zmianę w celu użycia dyrektywy vpath. Moja wersja była złą mieszanką VPATH = xxx i vpath %.c xxx. jednak teraz mam inny problem (który był oryginalny problem, zanim dodałem zły vpath). To jest teraz wyjście:

    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

Wygląda na to, że make nie stosuje reguły implicit dla pliku obiektowego, chociaż instrukcja mówi "Ukryte zasady mówią, jak używać zwyczajowych technik, aby nie trzeba ich szczegółowo określać, gdy chcesz ich używać. Na przykład, istnieje ukryta Reguła dla kompilacji C. Nazwy plików określają, które reguły są uruchamiane. Na przykład kompilacja C zazwyczaj zajmuje a .plik c i tworzy a .plik o. Tak więc make stosuje zasadę implicit dla kompilacji C gdy widzi taką kombinację zakończeń nazw plików."a także" przeszukiwanie katalogów określonych w VPATH lub za pomocą vpath odbywa się również podczas rozpatrywania reguł ukrytych (patrz Using Implicit Rules)."

Ponownie tutaj " na przykład, gdy plik foo.o nie ma jawnej reguły, make uważa reguły niejawne, takie jak wbudowana reguła kompilacji foo.c Jeśli ten plik istnieje. Jeśli takiego pliku nie ma w bieżącym katalogu, wyszukiwane są odpowiednie katalogi. Jeśli foo.c istnieje (lub jest wspomniana w pliku makefile)w którymkolwiek z katalogów, stosowana jest domyślna reguła kompilacji C."

Każda pomoc w uzyskaniu ukrytych zasad do pracy dla mojego pliku makefile będzie bardzo mile widziana.

Edycja nr 2: Dzięki Jackowi Kelly ' emu wprowadziłem jednoznaczną zasadę kompilacji .pliki c, ponieważ nie mogłem się nigdzie dostać, próbując użyć ukrytych reguł. Również podziękowania dla al_miro za info o vpath.

Oto działający plik makfile:

.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 $@

.PHONY : clean
clean :
  rm $(objects)
Author: jww, 2011-03-03

6 answers

Ponieważ używasz GNUmake, użyj reguły wzorca do kompilacji plików obiektowych:

$(OBJDIR)/%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 58
Author: Jack Kelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-04 00:56:53

Jest to plik makefile, którego używam w większości moich projektów,

Umożliwia umieszczanie plików źródłowych, nagłówków i plików wbudowanych w podfoldery oraz podfoldery podfolderów i tak dalej, a automatycznie wygeneruje plik zależności dla każdego obiektu oznacza to, że modyfikacja nagłówków i plików wbudowanych spowoduje rekompilację plików zależnych.

Pliki źródłowe są wykrywane za pomocą polecenia Shell find, więc nie ma potrzeby jawnego określania, wystarczy zachować kodowanie do treści serca.

Skopiuje również wszystkie pliki z folderu 'resources', do folderu bin, gdy projekt jest skompilowany, co uważam za przydatne przez większość czasu.

Aby zapewnić kredyt tam, gdzie jest należny, Funkcja auto-zależności została oparta w dużej mierze na stronie Scotta Mcpeaka, którą można znaleźć tutaj, z dodatkowymi modyfikacjami / poprawkami dla moich potrzeb.

Przykład 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 $@)
    $(CC) $(CFLAGS) $(INC) -c -o $@ $<
    @$(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
 39
Author: Nicholas Hamilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-18 17:33:30

Linie VPATH są błędne, powinny być

vpath %.c  src
vpath %.h  src

Tj. bez kapitału i bez = . Jak to jest teraz, nie znajduje .plik h i uważa, że jest to cel do wykonania.

 22
Author: al_miro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-03 08:24:25

Ogólnie rzecz biorąc, albo musisz podać $(OBJDIR) po lewej stronie wszystkich reguł umieszczających pliki w $(OBJDIR), albo możesz uruchomić make z $(OBJDIR). {[3] } jest dla źródeł, nie dla obiektów.

Spójrz na te dwa linki, aby uzyskać więcej wyjaśnień i "sprytne" obejście.
 4
Author: Theo Belaire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-22 15:11:29

Poniższe rozwiązanie nie jest moim zdaniem miłe, ponieważ uwielbiam wbudowane zasady. Jednak GNU make nie wspiera czegoś takiego jak vpath dla katalogów wyjściowych. A wbudowane reguły nie mogą się zgadzać, ponieważ % in %.o pasowałoby obj/foo z obj/foo.o, pozostawiając make z wyszukiwaniem w vpath %.c src/ rzeczy takich jak src/obj/foo.c, ale nie src/foo.c.

Ale To jest tak blisko wbudowanych reguł, jak można uzyskać, a zatem według mojej najlepszej wiedzy najładniejsze rozwiązanie, które dostępny.

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

Wyjaśnienie: $(COMPILE.c) $(OUTPUT_OPTION) $< w rzeczywistości jest to sposób .c.o zaimplementowany, patrz http://git.savannah.gnu.org/cgit/make.git/tree/default.c nie jest to jednak możliwe.]}

Poza tym, jeśli $(OBJDIR) zawiera tylko automatycznie gerarowane pliki, możesz utworzyć je w locie z warunkiem tylko zamówienia, co nieco uprości regułę clean:

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

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

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

Wymaga to, aby dostępna była funkcja order-only, którą można sprawdzić za pomocą $(filter order-only, $(.FETAURES)). Sprawdziłem na Kubuntu 14.04 GNU make 3.81 i openSUSE 13.1 GNU make 3.82. Oba zostały zbudowane z włączoną tylko i jestem teraz zaskoczony, dlaczego Kubuntu 14.04 jest wyposażony w starszą wersję GNU make niż OpenSUSE 13.1. Tak czy inaczej, teraz ściągnę make 4.1:)

 2
Author: Christian Hujer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-06 12:19:05

Dla wszystkich pracujÄ ... cych z niejawnymi zasadami (i GNU MAKE). Oto prosty plik makefile, który obsługuje różne katalogi:

#Start of the makefile

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

OUTPUT_OPTION = -o objects/$@

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)

Przyjrzyjmy się bliżej (odnoszę się do bieżącego katalogu za pomocą curdir):

Ta linia jest używana do uzyskania listy używanych .o pliki, które są w curdir / src.

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

Poprzez zmienną wyjście jest ustawiane do innego katalogu (curdir / objects).

OUTPUT_OPTION = -o objects/$@
#OUTPUT_OPTION will insert the -o flag into the implicit rules

Aby upewnić się, że kompilator znajdzie obiekty w folderze nowe obiekty, do nazwy pliku zostanie dodana ścieżka.

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

to ma być Przykład i jest zdecydowanie pole do poprawy.

Aby uzyskać dodatkowe informacje skonsultuj się: zrób dokumentację. Patrz rozdział 10.2

Lub: Oracle: Programming Utilities Guide

 1
Author: A. Frank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-21 11:06:51