Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
622 views
in Technique[技术] by (71.8m points)

makefile - Flat object file directory structure output with GNU Make

I have a C++ small project using GNU Make. I'd like to be able to turn the following source files:

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

into the following output structure (I'm not concerned about duplicates at this point):

build/
  a.o
  b.o
  c.o

So far I have the following, which unfortunately puts the .o and .d right next to each .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 $@ $<  

I'm aware of the $(notdir ...) function, but at this point my efforts to use it to filter the objects has failed. Can anyone shed some light on this? It seems like fairly reasonable thing to do.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are at least two ways you can do this. First (and what I'd recommend) is you can add the build directory to the target names (even when using a pattern rule). For example:

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

Second, you can use the VPATH variable to tell make to search a different directory for prerequisites. This is probably the more commonly (over) used approach. It has at least one serious drawback, and that is if you go with it, and later run into problems with "duplicates", there's no way to solve the problem. With the former approach, you can always mirror the source directory structure underneath the build directory to avoid duplicates clashing.

Edit: My previous answer was a little short on detail, so I will expand upon it to show that this actually works as advertised. Here is a complete working example Makefile that uses the first technique described above to solve the problem. Simply paste this into a Makefile and run make -- it will do the rest and show that this does in fact work.

Edit: I can't figure out how to get SO to allow tab characters in my answer text (it replaced them with spaces). After copying and pasting this example, you'll need to convert the leading spaces in the command scripts into tabs.

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}

In particular, note that there are source files with duplicate names (a.c and a/a.c, b.c and b/b.c, etc) and that this doesn't cause any problems. Also note there is no use of VPATH, which I recommend to avoid using due to its inherent limitations.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...