【问题标题】:Makefile for multiple source dirs and one target dir多个源目录和一个目标目录的 Makefile
【发布时间】:2013-12-07 10:54:03
【问题描述】:

我尝试编写一个 makefile,它在当前目录中搜索 lib 目录,编译每个目录的源代码并将目标文件放入单独的目标目录中。我不想拥有多个 makefile。

这个 makefile 会这样做:

SRCDIR  := $(shell ls -d lib_*/)

CC      := gcc
DB      := gdb
OBJDIR  := obj
CFLAGS  := -Wall -Werror -Wextra -pedantic -O3
LDFLAGS := #

# Rules
all:
    @ # create object directory
    @mkdir -p  $(OBJDIR)/ ;
    @ # go through all source dirs
    @for dir in $(SRCDIR); do \
        echo $$dir && \
        cd $$dir && \
        for n in $$(ls *.c); do \
            m=$${n%%.c}; \
            $(CC) -c \
               $(CFLAGS) \
               $(LDFLAGS) \
               -o ../$(OBJDIR)/$$m.o $$n;\
        done; \
        cd ..; \
    done

但是:makefile 编译每次运行的所有源。来源也没有任何变化。 makefile 是否可以识别是否有更改并仅编译更改的源?


这里是目录结构:

lib
 |-lib_one
 |  |-lib_one.c
 |  |-lib_one.h
 |
 |-lib_two
 |  |-lib_two.c
 |  |-lib_two.h
 |
 |-lib_n
 |  |-lib_n.c
 |  |-lib_n.h
 |
 |-obj
 |  |-lib_one.o
 |  |-lib_two.o
 |  |-
 |  |-lib_n.o
 |
 |-makefile

【问题讨论】:

    标签: c makefile


    【解决方案1】:

    如果你不关心头文件,你可以这样做:

    SRCS := $(wildcard */*.c)
    
    OBJDIR := obj
    
    OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SRCS)))
    
    all: $(OBJS)
        @:
    
    $(OBJDIR)/%.o: %.c
        $(CC) -c $(CFLAGS) -o $@ $<
    
    vpath %.c $(wildcard *)
    

    如果你关心明显的头文件(例如lib_one.c包含lib_one.h),那么你可以做一个简单的调整:

    $(OBJDIR)/%.o: %.c %.h
        $(CC) -c $(CFLAGS) -o $@ $<
    
    vpath %.c $(wildcard *)
    vpath %.h $(wildcard *)
    

    如果您有其他依赖项(例如 lib_n.c 包括 lib_one.h),您可以手动添加它们:

    lib_n.o: lib_one.h
    

    或者你可以使用Advanced Auto-Dependency Generation,但这是一种先进的技术,我建议你改天离开。

    【讨论】:

    • 我喜欢将目标目录放在目标部分 $(OBJDIR)/%.o 中的想法,但它与目标列表兼容:all: file1 file2 吗?
    • @Sandburg:是的,例如all: targdir/foo.o targdir/bar.o。要记住的重要一点是,目标应该是您尝试构建的文件的实际名称,否则您会遇到麻烦。
    【解决方案2】:

    您可以使用以下内容:

    SRCDIR  := $(shell ls -d lib_*/)
    
    CC      := gcc
    DB      := gdb
    OBJDIR  := obj
    CFLAGS  := -Wall -Werror -Wextra -pedantic -O3
    LDFLAGS := #
    
    # Rules
    all:
        @ # create object directory
        @mkdir -p  $(OBJDIR)/ ;
        @ # go through all source dirs
        @for dir in $(SRCDIR); do \
            echo $$dir && \
            cd $$dir && \
            for n in $$(ls *.c); do \
                m=$${n%%.c}; \
                if [ ! -e ../$(OBJDIR)/$$m.o ] || \
                    [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$n` ] || \
                    ([ -e $$m.h ] && [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$m.h` ]); then \
                    echo "Change detected, compiling $$n..."; \
                    $(CC) -c \
                        $(CFLAGS) \
                        $(LDFLAGS) \
                        -o ../$(OBJDIR)/$$m.o $$n;\
                fi; \
            done; \
            cd ..; \
        done
    

    以下行添加了对对象文件的检查以查看它们是否存在,如果存在,则将源修改时间与对象修改时间进行比较(类似于在 make 中重复 make 工作)。

     if [ ! -e ../$(OBJDIR)/$$m.o ] || [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$n` ] || ([ -e $$m.h ] && [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$m.h` ]); then 
    

    【讨论】:

    • 如果某些头文件被更改了怎么办?
    • 如果你这样做,我认为如果至少有一个文件比 lib 更新,则需要重建整个 lib 以确保安全......
    • 不,不会,我添加了对.h 文件的支持,但你是对的,这绝对不是要走的路,我建议 OP (@Alex44) 宁愿使用CMake 从头开始​​,而不仅仅是 make
    猜你喜欢
    • 2013-11-02
    • 1970-01-01
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多