【问题标题】:Issues with make execution ordermake 执行顺序的问题
【发布时间】:2016-09-11 19:25:35
【问题描述】:

这是我编写的一个 make 文件,当前目标是将目录中的所有 c++ 文件转换为目标文件。我的问题是它总是先执行 g++,然后再执行任何其他命令。

CC=g++
CPPFLAGS=`pkg-config --cflags --libs gtkmm-3.0`
SRCS=$(wildcard classes/source/*.cc)
PROGS=$(patsubst %.cc,%,$(SRCS))
CLASS_HEADERS=classes/
all: $(PROGS)
    mkdir -p build/release/objs 
%: %.cc
    $(CC) -I$(CLASS_HEADERS) -c $< -o build/release/objs/$(@F).o $(CPPFLAGS)

结果:

g++ -Iclasses/ -c classes/source/helloworld.cc -o build/release/objs/helloworld.o `pkg-config --cflags --libs gtkmm-3.0`
mkdir -p build/release/objs 

谢谢

【问题讨论】:

  • build/release/objs 提供另一个依赖目标,并将其放在$(PROGS) 之前。
  • all 的规则说:确保所有$(PROGS) 都是最新的;完成后,运行mkdir 将完成创建all 的工作。您需要更像all: objdir $(PROGS) 的东西,其中objdir 的规则可能是:objdir: ; mkdir -p build/release/objs(您可以使用换行符和制表符代替分号,尽管显示的符号实际上在单行上工作)。这只是@πάνταῥεῖ所说的更长的版本。
  • Jonathan Leffler 你已经解决了我的问题,并提供了一个很好的解释来帮助我更好地理解 make 是如何工作的。

标签: c++ terminal makefile


【解决方案1】:

最简单的解决方法是在使用目标目录之前始终发出mkdir。如果使用-p 选项,冗余执行此命令确实没有什么坏处。

%: %.cc
   mkdir -p build/release/objs
   $(CC) -I$(CLASS_HEADERS) -c $< -o build/release/objs/$(@F).o $(CPPFLAGS)

正如我对GNU make's -j option 的回答中所述:虽然它有时可能会起作用,但在现有的all 依赖项列表中简单地添加一个mkdir 目标作为初始依赖项是不正确的。原则上,这些可以按任何顺序执行(所以mkdir 不一定是第一个)。如果你想采用基于依赖的方法,你必须开始做更复杂的事情。例如递归使用 make:

all: do_mkdir
   $(MAKE) $(progs)

do_mkdir:
   mkdir -p build/release/objs

【讨论】:

    【解决方案2】:

    目标的配方在任何先决条件之后执行,因此当您制作all 时,make 将在运行mkdir 之前经过$(PROGS)

    build/release/objs 应该是目标文件的先决条件,因为除非目录存在,否则无法创建它们。该目录也应该是 order-only prerequisite,因为如果 dir 时间戳发生更改,您不希望重新制作每个目标文件。

    您的模式规则也是broken(参见2),而您使用了错误的flag variables。您也可以回收built-in implicit rule for compiling

    CXXFLAGS := $(shell pkg-config --cflags --libs gtkmm-3.0)
    CPPFLAGS := -Iclasses/
    SRCS     := $(wildcard classes/source/*.cc)
    OBJS     := $(SRCS:classes/source/%.cc=build/release/objs/%.o)
    
    .PHONY: all
    all: $(OBJS)
    
    $(OBJS): build/release/objs/%.o: classes/source/%.cc | build/release/objs
        $(COMPILE.cc) $(OUTPUT_OPTION) $<
    
    build/release/objs: ; mkdir -p $@
    

    旁注:由于您只编译 -libs gtkmm-3.0 可能不应该在标志中,因此您在链接时提供库。

    【讨论】:

    • @Russeree 如果回答了您的问题,请接受答案。
    【解决方案3】:

    可能的解决方案是为对象目录创建一个目标并将其放在构建目标之前:

    ......
    OBJ_DIR := build/release/objs
    
    all: create_obj_dir $(PROGS)
    
    create_obj_dir:
        mkdir -p  $(OBJ_DIR)
    
    %: %.cc
        $(CC) -I$(CLASS_HEADERS) -c $< -o $(OBJ_DIR)/$(@F).o $(CPPFLAGS)
    

    【讨论】:

    • 如果使用 -j 运行多个 make 线程,不一定能工作
    猜你喜欢
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-09
    • 1970-01-01
    • 2015-12-22
    相关资源
    最近更新 更多