更改Makefile标志时如何强制重新编译?

问题描述 投票:0回答:4

我正在编译一些具有依赖关系的项目,因此我不必每次都重新编译,但是当我将 -Dsome_flags 添加到我的 CFLAGS 时,它不会重新编译。

dep: $(CPPS)
    $(CC) $(CFLAGS) $(INC) -M $(CPPS) > dep

我添加到我的 CFLAS -DDEBUG_FLAG 中,它迫使我执行 make clean 并 make 而不是 make。

c++ c gcc g++
4个回答
6
投票

它不会重新编译,因为你没有将 makefile 本身列为依赖项。

dep: $(CPPS) Makefile
    $(CC) $(CFLAGS) $(INC) -M $(CPPS) > dep

也就是说,如果您从命令行输入 make 标志(例如

CFLAGS=-O3 make all
),
make
无法检测到您已更改这些标志并强制进行完整构建。


3
投票

在我看来,最简单的就是先做一个

make clean
,然后做一个
make
。当然,这是假设您希望由于编译器标志的更改而重新编译所有源文件。但你似乎不喜欢这个方法。

如果你想修改makefile,你可以将你的makefile的名称添加到编译源文件的每条规则中,例如:

    somefile.o : somefile.cpp <makefile_name>
            $(CC) -c $(CFLAGS) somefile.cpp -o somefile.o

    %.o : %.c <makefile_name> 
            $(CC) -c $(CFLAGS) somefile.cpp -o somefile.o

考虑到项目的规模以及涉及的规则数量,执行

make clean; make
可能是最简单、最快的方法。然而,一如既往,你里程我的范围。

仅值我的 0.02 美元,希望有帮助 T.


2
投票

Makefile 根据其拥有的数据查找更改。您的 Makefile 声明唯一的依赖项是在 $(CPPS) 下定义的。

dep: $(CPPS)
    $(CC) $(CFLAGS) $(INC) -M $(CPPS) > dep

因此 make 仅跟踪给定列表(即 $(CPPS))内的更改。所以解决办法是:

dep: $(CPPS) Makefile
    $(CC) $(CFLAGS) $(INC) -M $(CPPS) > dep

对于完整但不复杂的示例,这是我的 helloworld 程序的 Makefile:

OBJS = helloworld.o
default: hw

%.o: %.c Makefile
    gcc -c $< -o $@

hw: $(OBJS)
    gcc $(OBJS) -o $@

clean:
    -rm -f $(OBJS) hw

每次我更改 makefile 时,它都会重新编译! :)


0
投票

我在寻找同一问题的答案时遇到了这个问题,但我决定想要完整的答案,而不是“仅仅依赖于 Makefile”,所以这是我编写的一般实现。

假设您从一个看起来像这样的 Makefile 开始(我添加了一个 BUILD_DIR 变量和 all/clean 目标来充实 OP 示例):

################
# Setup:

BUILD_DIR := build


################
# Basic targets:

all: dep $(CPPS)
    @echo "make all"        # E.g. some build commands...

clean:
    @echo "make clean"      # E.g. some cleanup commands
    @rm -rf "$(BUILD_DIR)"  # Etc. ...

dep: $(BUILD_DIR) $(BUILD_DIR)/dep

################
# Build details:

$(BUILD_DIR):
    mkdir -p "$(BUILD_DIR)"

$(BUILD_DIR)/dep: $(CPPS) Makefile
    echo $(CC) $(CFLAGS) $(INC) -M $(CPPS) > "$(BUILD_DIR)/dep"

.PHONY: all clean dep

现在,您想要修改此 Makefile,使其依赖于使用的任何构建选项,因此您在“Setup”部分中引入一个新的中间文件(保存在构建目录中,可能与所有其他构建工件一起保存):

# Stores the last options used for compilation:
CC_OPT_FILE := $(BUILD_DIR)/cc_options

您需要一种有条件地调用“干净”目标的方法;我选择修改“clean”配方,将清理代码移至 make 变量以实现可重用性(注意:MAKE_CLEAN 包含空格、NOT 制表符):

MAKE_CLEAN =                                            \
  echo "make clean"      # E.g. some cleanup commands   \
  rm -rf "$(BUILD_DIR)"  # Etc. ...
clean:
    @$(MAKE_CLEAN)

现在,您在“基本目标”之后添加一个部分,以将选项保存到 cc_options 文件,检查中间工件是否已更改,如果是,则强制进行干净构建[注意,您可以在其中包含尽可能多的 shell 变量选项根据需要归档,例如$(CPPFLAGS)、$(CXXFLAGS)、$(LDFLAGS) 等;另请注意,此块中使用了空格、NOT 制表符]:

###########################################
# Do clean build if compile options change:

# Usage: $(call MK_CC_OPT_FILE,<outfile>)
MK_CC_OPT_FILE =                        \
  mkdir -p "$(dir $(1))" &&             \
  echo "$(CFLAGS)" > "$(1)" &&          \
  echo "$(INC)" >> "$(1)" # Etc. ...
ifeq ($(findstring clean, $(MAKECMDGOALS)),)    # "clean" target NOT requested?
  $(shell $(call MK_CC_OPT_FILE,$(CC_OPT_FILE).tmp))  # Make tmp options file
  ifeq ($(.SHELLSTATUS),0)    # Success?
    $(shell cmp --silent -- "$(CC_OPT_FILE)" "$(CC_OPT_FILE).tmp")
  endif
  ifneq ($(.SHELLSTATUS),0)   # Options differ (or couldn't write file/etc.)?
    $(warning ***** CC options changed: forcing clean target)
    _ := $(shell $(MAKE_CLEAN))     # [Note: dummy assignment is required here!]
    ifneq ($(.SHELLSTATUS),0)
      $(error MAKE_CLEAN failed)
    endif
  endif
endif
$(shell $(call MK_CC_OPT_FILE,$(CC_OPT_FILE)))  # Save curr opts for next time

就是这样!现在,每当构建命令使用的任何选项发生更改时,Makefile 都会在继续构建之前执行干净的 make。唯一的要求是 CC_OPT_FILE 包含 Makefile 传递给编译器或链接器的任何选项标志,您可以在其他目标配方中找到这些选项并根据需要添加到 MK_CC_OPT_FILE。

© www.soinside.com 2019 - 2024. All rights reserved.