开发者

My makefile builds dependency files when not required - why?

I'm trying to create a generic makefile to build static libraries that my project uses. I've used the expertise on this site, as well as the GNU Make manual to help write the following makefile. It is working well apart from one annoying problem.

# Generic makefile to build/install a static library (zlib example)
ARC开发者_StackOverflowH      = linux
CFLAGS    = -O3 -Wall

# List of source code directories
SOURCES   = src test utils
# List of header files to install
INCLUDES  = src/zlib.h src/zconf.h
# Library to create
LIBNAME   = libz.a

############################################################

BUILD_DIR   = build/$(ARCH)

# Full path to the built library
TARGET      = $(BUILD_DIR)/$(LIBNAME)

prefix = ../..
exec_prefix = prefix
libdir = $(prefix)/lib/$(ARCH)
includedir = $(prefix)/include
INSTALL_PROGRAM = install -D
INSTALL_DATA = $(INSTALL_PROGRAM) -m 644

CFILES    := $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.c))
OBJECTS   := $(addprefix $(BUILD_DIR)/,$(CFILES:.c=.o))
DEPENDS   := $(OBJECTS:.o=.d)

.PHONY: all installdirs install uninstall clean

# Default
all: $(DEPENDS) $(TARGET)

# Build the dependency files
# (GNU Make Manual 4.14 Generating Prerequisites Automatically)
$(BUILD_DIR)/%.d: $(BUILD_DIR)
    @echo "build dep for $*.c as $@"
    @$(CC) -M $(CFLAGS) $*.c > $@.tmp
    @sed s~.*:~"$(BUILD_DIR)/$*.o $@:"~ $@.tmp > $@
    @rm $@.tmp

# Link all changed object files into static library
$(TARGET): $(OBJECTS)
    $(AR) -rc $(TARGET) $?

# Compile C source to object code
$(BUILD_DIR)/%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# Create the necessary directory tree for the build
$(BUILD_DIR):
    @for p in $(SOURCES); do mkdir -p $(BUILD_DIR)/$$p; done

# Create the necessary directory tree for installation
installdirs:
    @mkdir -p $(libdir)
    @mkdir -p $(includedir)

# Install the library and headers
install: all installdirs
    $(INSTALL_DATA) $(TARGET) $(libdir)
    for p in $(INCLUDES); do $(INSTALL_DATA) $$p $(includedir); done

# Remove the library and headers
uninstall: 
    rm -f $(libdir)/$(LIBNAME)
    for p in $(notdir $(INCLUDES)); do rm -f $(includedir)/$$p; done

# Remove all build files
clean:
    rm -fr $(BUILD_DIR)

# Pull in the dependencies if they exist
# http://scottmcpeak.com/autodepend/autodepend.html
-include $(DEPENDS)

The problem is that the dependency files are built when they don't need to be. e.g. make install shown below rebuilds the .d files before installing.

$make --version
GNU Make 3.81
$make
build dep for utils/utils.c as build/linux/utils/utils.d
build dep for test/test.c as build/linux/test/test.d
build dep for src/zutil.c as build/linux/src/zutil.d
...
{ continues on making the other .d files, then the .o files }
...
cc -O3 -Wall -c src/zutil.c -o build/linux/src/zutil.o
cc -O3 -Wall -c test/test.c -o build/linux/test/test.o
cc -O3 -Wall -c utils/utils.c -o build/linux/utils/utils.o
ar rc { ... .o files ... }

All good up to this point! But a 'make install' now will rebuild the .d files

$make install
build dep for utils/utils.c as build/linux/utils/utils.d
build dep for test/test.c as build/linux/test/test.d
build dep for src/zutil.c as build/linux/src/zutil.d
{ ... }
install -D -m 644 build/linux/libz.a ../../lib/linux
for p in src/zlib.h src/zconf.h; do install -D -m 644 $p ../../include; done

I tried to 'touch' the .d files when the objects are built, so the update time is newer than the .o files, but that had no effect. What's wrong with my makefile?


The problem is that you include the dependency files (whatever.d), and you also have a rule for building these files. So every time you use this makefile, no matter what target you specify, it will rebuild them, include them, and execute again.

Try this for an approach to dependency handling that solves this problem. Basically, you don't need a separate rule for foo.d, just make it a side effect of the foo.o rule (it takes some thought to realize that this will work).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜