2012-03-16 111 views
0

我有一个运行二进制文件生成cpp文件的makefile。然后我编译cpp文件并为每个cpp文件生成.o文件。如何强制重新生成makefile中的变量

问题是首先被调用的生成文件时,该文件夹是空的,因为二值尚未调用和

CPP_FILES=$(wildcard $(MY_DIR)/inc/output/*.cpp) 

将是一个空的变量。

所以我改了行,以

CPPFILES=$$(wildcard $(MY_DIR)/inc/output/*.cpp) 
OBJFILES=$$(patsubst $(MY_DIR)/*.cpp,$(MY_DIR)/*.o,$(CPPFILES)) 

//跑到二进制生成cpp文件

.SECONDEXPANSION: 
libEXP.so:$(CPPFILES),$(OBJFILES) 
     $(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) [email protected] 

二级扩展失败说外壳找不到通配符命令。
我在做什么错?

回答

3

您所遇到的问题是始终从最终目标BACKWARDS开始工作,然后再开始构建和解决先决条件。先从图书馆开始,然后看看它的先决条件是什么,然后看到那些先决条件是什么,然后是那些先决条件等等。

因此,当make扩展$(OBJFILES)值时,即使您延迟第二次扩展,仍然是.cpp文件尚未创建的情况。

你必须解释一下,有一条规则可以生成.cpp文件。一旦明白这一点,它会为你调用你的规则。尽管如此,您将无法使用通配符来确定要构建的.cpp文件,除非您想先执行一些操作,如先构建所有.cpp文件,然后递归调用make。

编辑:

你问为什么第二次膨胀没有工作。我在第一段中提到过,但可能不够清楚。制作经历两个阶段的处理。首先它读取makefile,其次它贯穿规则并构建事物。次要的扩展步骤会延迟分辨率,直到第二步......但在这种情况下这不会对您有所帮助。

你问make建立libEXP.so。为此,它需要扩展libEXP.so的先决条件,以便它知道目标依赖于什么。 这个是当第二次扩展执行时,但是在这里我们还没有建立任何.cpp文件,因为我们不知道我们需要它们,所以通配符扩展到什么都没有。 Make不会创建这些.cpp文件,直到它知道需要它们,并且它不知道它需要它们,直到它已经拥有它们,因此它可以生成列表。o libEXP.so的先决条件文件。这显然不会起作用:)

+0

嗨MadScientist,谢谢你解释,但这就是为什么我使用scendexpansion,如果它没有重新评估价值并坚持原来的价值,那该怎么办。有趣的是,如果我在CPPFILES定义中替换通配符行,通过shell命令“find $ MY_DIR -name”* .cpp“-type f”,正确地得到我的列表,但我仍然遇到patsubst命令的问题。如果secondexapnsion仅适用于shell函数,那么我想知道如何在secondexpansion上制作文档,并说它可以与patsubst一起使用。 – learningtocode 2012-03-19 22:43:22

+0

我想我真正要问的是有没有一种方法可以使用wildacrd函数,而不会抱怨找不到命令通配符。另外,可以递归解决这个问题,我认为先决条件列表中的变量是从读取阶段的所有包含makefile中读取的? – learningtocode 2012-03-19 23:55:42

+0

其实Madscienist是对的。我把这条规则放在一个makefile文件中,并将这行文件移动到另一个makefile .o文件和库中。我从第一个makefile递归地调用第二个makefile,并且它工作正常!我几乎已经放弃了。但我仍然不明白gnu中的这个例子如何使文档工作。反正非常感谢MadScientist和Eldar! – learningtocode 2012-03-21 00:26:06

0

离开CPPFILESOBJFILES像往常一样递归变量:

CPPFILES = $(wildcard $(MY_DIR)/inc/output/*.cpp) 
OBJFILES = $(CPPFILES:%.cpp=%.o) 

而推迟了它的扩展使用双美元如下:

.SECONDEXPANSION: 
libEXP.so: $$(OBJFILES) 
    $(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) [email protected] 

但我想这个问题是扩张在运行cpp文件生成器之前发生。你如何援引它?这是一条规则还是别的?

+0

埃尔达尔,感谢您的回复:请看看这个链接:http://www.gnu.org/software/make/manual /html_node/Secondary-Expansion.html。我遵循了patsubst的例子,该例子使用第二次扩展的方式来使用它。关于调用规则来运行二进制文件,我有一个名为exp的规则,它被定义为“exp:genCPP libEXP.so” – learningtocode 2012-03-19 19:07:56

+0

@learning,啊,我明白了,但它与我提出的代码具有几乎相同的效果。另请注意,使用并行Make('-j'选项)时,'exp:genCPP libEXP.so'可能无法正常工作。 呃,实际上,MadScientist已经解释了问题的原因。 – 2012-03-19 21:57:49

1

为了明确:你不应该在生成的文件上使用$(wildcard)。如果你想要一个“所有生成文件的列表”,$(wildcard)只会通过运气给你这个列表(如果所有的文件已经生成)。

如果生成器文件和生成的文件之间存在一对一的对应关系,那么可以在生成器文件上使用$(wildcard)并转换结果。

使用谷歌的协议缓冲区为例(它可以生成从的.cc文件.proto文件)

PROTOSS := $(wildcard *.proto) 
GENERATED_SOURCES := ${PROTOSS:.proto=.cc} 
GENERATED_HEADERS := ${PROTOSS:.proto=.h} 
0

我遇到过这种情况。我尝试了几层间接寻址(使用一个叫做罐头序列的罐头序列,它使用了wildcard),但是在执行生成文件的配方之前,make总是评估通配符。我的解决方案是编写一个Perl脚本来收集文件列表并执行我需要执行的操作,然后从makefile中调用脚本。我只希望我早点完成。我一直在想,我想避免引入额外的文件,但总的来说,使用脚本比使用非常重要的makefile配方容易得多,因此从一开始就可以节省大量时间。

0

另一种选择是在bash使用一个for循环:

target: prereqs 
    for file in files/*; do \ 
     ... \ 
    done