Makefile 更改生成标志并重新编译

Makefile 更改生成标志并重新编译,makefile,gnu-make,Makefile,Gnu Make,我有一个make文件,其中有许多虚假目标,它们都使用不同的编译标志编译相同的代码 EXECUTABLE=ecis #debug build .PHONY: debug debug: FLAGS=-g debug: $(EXECUTABLE) #No optimization .PHONY: opt0 opt0: FLAGS= opt0: $(EXECUTABLE) #level 1 optimization .PHONY: opt1 opt1: FLAGS=-O1 opt1: $(EXEC

我有一个make文件,其中有许多虚假目标,它们都使用不同的编译标志编译相同的代码

EXECUTABLE=ecis

#debug build
.PHONY: debug
debug: FLAGS=-g
debug: $(EXECUTABLE)

#No optimization
.PHONY: opt0
opt0: FLAGS=
opt0: $(EXECUTABLE)

#level 1 optimization
.PHONY: opt1
opt1: FLAGS=-O1
opt1: $(EXECUTABLE)

#level 2 optimization
.PHONY: opt2
opt2: FLAGS=-O2
opt2: $(EXECUTABLE)

...

$(EXECUTABLE):$(FORTRAN_OBJECTS) $(CPP_OBJECTS)
    $(CPP) $(FLAGS) $(FORTRAN_OBJECTS) $(CPP_OBJECTS) -lgfortran -o $@
...
当我第一次使用一个build
makeopt2
选项运行makefile时,它运行得很好。 如果我随后想使用另一个构建选项运行make,比如说
makedebug
,它会声明目标是最新的。我理解它为什么这么做,make没有意识到标志改变了,所以就make而言,如果文件没有改变,就没有任何改变


也就是说,除了调用
makecleanall
(删除.o文件和可执行文件)之外,还有其他简单的方法吗?make是否有办法在更改编译时识别不同的标志?有没有其他途径可以让它“做正确的事情”?

下面是一个应该有效的示例:

.compile_flags: Makefile
        [ "`cat $@`" = '$(FLAGS)' ] || echo '$(FLAGS)' > $@

$(FORTRAN_OBJECTS) $(CPP_OBJECTS) $(EXECUTABLE): .compile_flags
另一种方法是为每个不同的基本目标生成对象文件和可执行文件到单独的子目录中。这样它们就不会重叠了。这还有一个额外的好处,即您不必为每种类型的构建重新编译世界(仅自上次构建以来)。但是,如果系统的其他部分希望在现在的位置运行,那么它会占用更多的磁盘空间,并可能导致其他问题

无法使用特定于目标的变量将内容放在其他目录中。最简单的方法是使用递归make的一个实例,如下所示:

EXECUTABLE=ecis

#debug build
.PHONY: debug
debug: FLAGS=-g

#No optimization
.PHONY: opt0
opt0: FLAGS=

#level 1 optimization
.PHONY: opt1
opt1: FLAGS=-O1

#level 2 optimization
.PHONY: opt2
opt2: FLAGS=-O2

debug opt0 opt1 opt2:
        $(MAKE) OUTDIR=obj_$@ FLAGS=$(FLAGS) obj_$@/$(EXECUTABLE)
...
FORTRAN_OBJECTS := $(addprefix $(OUTDIR)/,$(FORTRAN_OBJECTS))
CPP_OBJECTS := $(addprefix $(OUTDIR)/,$(CPP_OBJECTS))

$(OUTDIR)/$(EXECUTABLE):$(FORTRAN_OBJECTS) $(CPP_OBJECTS)
    $(CPP) $(FLAGS) $(FORTRAN_OBJECTS) $(CPP_OBJECTS) -lgfortran -o $@
...
并且,您必须为对象文件创建模式规则,如:

$(OUTDIR)/%.o : %.cpp
        ...

FORTRAN也是如此。

下面是一个应该可以使用的示例:

.compile_flags: Makefile
        [ "`cat $@`" = '$(FLAGS)' ] || echo '$(FLAGS)' > $@

$(FORTRAN_OBJECTS) $(CPP_OBJECTS) $(EXECUTABLE): .compile_flags
另一种方法是为每个不同的基本目标生成对象文件和可执行文件到单独的子目录中。这样它们就不会重叠了。这还有一个额外的好处,即您不必为每种类型的构建重新编译世界(仅自上次构建以来)。但是,如果系统的其他部分希望在现在的位置运行,那么它会占用更多的磁盘空间,并可能导致其他问题

无法使用特定于目标的变量将内容放在其他目录中。最简单的方法是使用递归make的一个实例,如下所示:

EXECUTABLE=ecis

#debug build
.PHONY: debug
debug: FLAGS=-g

#No optimization
.PHONY: opt0
opt0: FLAGS=

#level 1 optimization
.PHONY: opt1
opt1: FLAGS=-O1

#level 2 optimization
.PHONY: opt2
opt2: FLAGS=-O2

debug opt0 opt1 opt2:
        $(MAKE) OUTDIR=obj_$@ FLAGS=$(FLAGS) obj_$@/$(EXECUTABLE)
...
FORTRAN_OBJECTS := $(addprefix $(OUTDIR)/,$(FORTRAN_OBJECTS))
CPP_OBJECTS := $(addprefix $(OUTDIR)/,$(CPP_OBJECTS))

$(OUTDIR)/$(EXECUTABLE):$(FORTRAN_OBJECTS) $(CPP_OBJECTS)
    $(CPP) $(FLAGS) $(FORTRAN_OBJECTS) $(CPP_OBJECTS) -lgfortran -o $@
...
并且,您必须为对象文件创建模式规则,如:

$(OUTDIR)/%.o : %.cpp
        ...

FORTRAN也是如此。

如果您仅限于GNU make本身,您将很难实现您的目标。正如@MadScientist所建议的,你可以通过一些恶作剧基本上得到你想要的。约翰·格雷厄姆·卡明(John Graham Cumming)在他的老专栏“询问Make先生”中写了一个很好的解释:

如果您可以使用其他make实现,您可能会检查一下,这是一个为性能和可靠性而设计的gnumake的重新实现。它包括一个名为“分类账”的功能,它正好提供了这一功能


免责声明:我是Electric Make的架构师和首席开发者

如果您仅限于GNU Make本身,您将难以实现您的目标。正如@MadScientist所建议的,你可以通过一些恶作剧基本上得到你想要的。约翰·格雷厄姆·卡明(John Graham Cumming)在他的老专栏“询问Make先生”中写了一个很好的解释:

如果您可以使用其他make实现,您可能会检查一下,这是一个为性能和可靠性而设计的gnumake的重新实现。它包括一个名为“分类账”的功能,它正好提供了这一功能


免责声明:我是Electric Make的架构师和首席开发人员

这不是一个简单的方法,不。有很多方法可以做到这一点。例如,您可以将标志写入文件,然后使该文件成为所有编译规则的先决条件。该文件的配方应进行测试,以查看标志是否相同,如果相同,则不得更改文件的修改时间。如果MOD时间没有改变,将假定文件没有更新,并且不会考虑根据它过期的目标。如果标志不同,它应该用新的标志覆盖文件。@MadScientist:我编辑这个问题也是为了问是否有其他方法可以使它“做正确的事情”,这样就有解决问题的余地。谢谢你的初步想法。这不是一个简单的方法,不。有很多方法可以做到。例如,您可以将标志写入文件,然后使该文件成为所有编译规则的先决条件。该文件的配方应进行测试,以查看标志是否相同,如果相同,则不得更改文件的修改时间。如果MOD时间没有改变,将假定文件没有更新,并且不会考虑根据它过期的目标。如果标志不同,它应该用新的标志覆盖文件。@MadScientist:我编辑这个问题也是为了问是否有其他方法可以使它“做正确的事情”,这样就有解决问题的余地。谢谢你的初步想法。谢谢你链接到“询问Make先生”的文章。ElectricMake看起来很有趣,但现在我希望这个项目及其依赖项保持开源。这样做的原因是,我想从这个项目中获得一篇关于核仪器和方法的论文,如果其他科学家不得不使用linux系统工具上常见的东西,他们可能会感到恼火/不使用代码。谢谢你的意见。谢谢你链接到“询问Make先生”的文章。ElectricMake看起来很有趣,但现在我希望这个项目及其依赖项保持开源。这样做的原因是,我想从这个项目中获得一篇关于核仪器和方法的论文,如果其他科学家不得不使用linux系统工具上常见的东西,他们可能会感到恼火/不使用代码。不过,感谢您的输入。磁盘空间不是问题,除了构建以外,没有其他方法取决于.o文件的位置,因此您建议的第二种方法可能是更好的方法。我应该在.phony中设置一个目标文件夹吗