Flat object file directory structure output with GNU Make

Mam mały projekt C++ używający GNU Make. Chciałbym móc włączyć następujące pliki źródłowe:

src/
  a.cpp
  b/
    b.cpp
  c/
    c.cpp

Do następującej struktury wyjściowej (w tym momencie nie przejmuję się duplikatami):

build/
  a.o
  b.o
  c.o

Do tej pory mam następujące, co niestety stawia .o i .d tuż obok każdego .cpp:

OBJS            :=      $(foreach file,$(SRCS),$(file).o)
DEPS            :=      $(patsubst %.o,%.d,$(OBJS))
sinclude $(DEPS)

$(OBJS) : %.o : %.cpp
        @echo Compiling $<
        $(CC) $(CC_FLAGS) $(INCS) -MMD -o $@ $<  

Znam $(notdir ...) funkcji, ale w tym momencie moje wysiłki, aby użyć go do filtrowania obiektów nie powiodły się. Czy ktoś może rzucić na to trochę światła? Informatyka wydaje się to całkiem rozsądne.

Author: Justicle, 2009-09-02

5 answers

Są co najmniej dwa sposoby, aby to zrobić. Po pierwsze (i co polecam) jest to, że możesz dodać katalog build do nazw docelowych (nawet jeśli używasz reguły wzorca). Na przykład:

$(OBJS) : build/%.o : %.cpp

Po drugie, możesz użyć zmiennej VPATH, aby powiedzieć make, aby przeszukał inny katalog pod kątem wymagań wstępnych. Jest to prawdopodobnie częściej (ponad) stosowane podejście. Ma co najmniej jedną poważną wadę, a to jest, jeśli pójdziesz z nim, a później napotkasz problemy z "duplikatami", nie ma sposobu, aby Rozwiąż problem. Przy pierwszym podejściu zawsze można dublować strukturę katalogów źródłowych pod katalogiem budowania, aby uniknąć kolizji duplikatów.

Edit: moja poprzednia odpowiedź była trochę krótka w odniesieniu do szczegółów, więc rozszerzę ją, aby pokazać, że to rzeczywiście działa zgodnie z reklamą. Oto kompletny przykład pracy Makefile, który wykorzystuje pierwszą technikę opisaną powyżej, aby rozwiązać problem. Po prostu wklej to do Makefile i uruchom make -- zrobi resztę i pokaże że to naprawdę działa.

Edit: nie mogę zrozumieć, jak uzyskać tak, aby zezwolić na znaki tabulacji w moim tekście odpowiedzi (zastąpiła je spacjami). Po skopiowaniu i wklejeniu tego przykładu musisz przekonwertować początkowe spacje w skryptach poleceń na karty.

BUILD_DIR := build

SRCS := \
    a.c \
    b.c \
    c.c \
    a/a.c \
    b/b.c \
    c/c.c

OBJS := ${SRCS:%.c=${BUILD_DIR}/%.o}

foo: ${OBJS}
    @echo Linking $@ using $?
    @touch $@

${BUILD_DIR}/%.o: %.c
    @mkdir -p $(dir $@)
    @echo Compiling $< ...
    @touch $@

${SRCS}:
    @echo Creating $@
    @mkdir -p $(dir $@)
    @touch $@

.PHONY: clean
clean:
    rm -f foo
    rm -f ${OBJS}

W szczególności zauważ, że istnieją pliki źródłowe o zduplikowanych nazwach (a.C i A/a.C, b.C i B/B.C, itp.) i że nie powoduje to żadnych problemów. Zauważ również, że nie ma zastosowania VPATH, który polecam aby uniknąć używania ze względu na jego nieodłączne ograniczenia.

 8
Author: Dan Moulding,
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-09-23 11:25:33
vpath %.cpp src src/b src/c

Następnie odwołaj się do plików źródłowych bez ich nazwy katalogu; Make przeszukuje vpath .

 2
Author: Jonathan Graehl,
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
2009-09-02 00:47:33

Tworzenie płaskiej struktury katalogów zgodnie z pierwotnym żądaniem.

Używa vpath do śledzenia plików źródłowych, ale wszystkie księgowania są wykonywane automatycznie z listy SRC.

SRC = a/a.c a/aa.c b/b.c
TARGET = done

FILES = $(notdir $(SRC) )
#make list of source paths, sort also removes duplicates
PATHS = $(sort $(dir $(SRC) ) )

BUILD_DIR = build
OBJ = $(addprefix $(BUILD_DIR)/, $(FILES:.c=.o))
DEP = $(OBJ:.o=.d)

# default target before includes
all: $(TARGET)

include $(DEP)

vpath %.c $(PATHS)

# create dummy dependency files to bootstrap the process
%.d:
    echo a=1 >$@

$(BUILD_DIR)/%.o:%.c
    echo $@: $< > $(patsubst %.o,%.d,$@)
    echo $< >$@

$(TARGET): $(OBJ)
    echo $^ > $@

.PHONY: clean
clean:
    del $(BUILD_DIR)/*.o
    del $(BUILD_DIR)/*.d
Sorry za brzydkie ale miałem tylko win box żeby go przetestować.
 1
Author: LarryH,
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
2009-11-26 09:14:44

To jest dla Win32 mingw32-make. to działa. Najważniejszą częścią jest

-mkdir $(patsubst %/,%,$(dir $@))

Dla win32. Musimy rozebrać trailling / dla win32.

GENERATED_DIRS = a b

# Dependency generator function
mkdir_deps =$(foreach dir,$(GENERATED_DIRS),$(dir)/.mkdir.done)

# Target rule to create the generated dependency.
# And create the .mkdir.done file for stop continuous recreate the dir
%/.mkdir.done: # target rule
    -mkdir $(patsubst %/,%,$(dir $@))
    echo $(patsubst %/,%,$(dir $@)) >$@

all: $(mkdir_deps)
    @echo Begin

clean:
    @echo Cleaning
 1
Author: lygstate,
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
2012-12-01 08:21:15

Może nie podoba Ci się to podejście, ale:

AUTOMAKE_OPTIONS =

Robi sztuczkę całkiem dobrze w Makefile.am mówię tylko, że nie musisz pisać wszystkiego ręcznie.

 0
Author: thiton,
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-09-23 11:29:55