【问题标题】:variable not updating when executing bash code in makefile在makefile中执行bash代码时变量不更新
【发布时间】:2021-05-19 12:31:44
【问题描述】:

我正在尝试编写一个包含一些 bash 命令的 makefile,以便从文件夹中收集 cpp 文件的名称。

SRC_FILES=""

CC = g++

CFLAGS = -g

gather-files:
    for var in $$(cd ./src && (ls -all *.cpp | awk '{print $$9}')); \
    do                                                              \
        SRC_FILES+="./src/"+"$(var) ";                              \
    done;                                                           \

game: gather-files
    $(CC) -c $(CFLAGS) $(SRC_FILES)

当我运行 ma​​ke game 命令时,SRC_FILESvar 变量似乎没有更新。
我错过了什么?
忽略比较不完整的g++命令,我只想知道如何让SRC_FILES变量包含src文件夹下所有cpp文件的名字。


这是ma​​ke game的输出:

g++ -c -g ""
clang: error: no input files

稍后编辑: 建议的解决方案:

SRC_FILES := $(wildcard src/*.cpp)

CC = g++

CFLAGS = -g

game: $(SRC_FILES)
    $(CC) -c $(CFLAGS) $(SRC_FILES)

【问题讨论】:

  • 请不要张贴文字图片。发布文本。
  • 相应地编辑了问题,现在可以复制和测试代码
  • 使用make 故意编译所有文件似乎与首先使用make 的一点相反。
  • Makefile 仍处于创建初期,问题仅在于我在其中编写的 shell 代码。我还是一个初学者,我不确定我明白你的意思。使用 make 的典型场景是什么?

标签: c++ bash makefile


【解决方案1】:

您正在混合使用 shell 命令和 makefile 命令。那是无效的。 整个 配方被发送到 shell 以在那里运行。一旦配方被展开(在调用 shell 之前发生一次),结果就不能包含任何 make 操作。

简而言之,从 shell中更改 make 变量是不可能的(从技术上讲,它可以做到,但这是一个非常糟糕的主意 (tm),所以不要这样做) > 食谱。

为什么不使用 GNU make 操作来代替?

SRC_FILES := $(wildcard src/*.cpp)

game: $(SRC_FILES)
        ...

当然,这是一种愚蠢的 makefile,因为如果任何源文件发生更改,它将重新编译所有源文件。您只需编写一个运行编译器的脚本即可获得等效的行为。

【讨论】:

  • 使用您建议的代码时确实有效。但是,我不确定我是否理解为什么这样做很愚蠢,请您详细说明一下吗?
  • makefile 的目标是执行最少的工作以可靠地产生您想要的结果。如果您只有几个源文件,并且需要几秒钟来重新编译它们并链接它们,那么每次都这样做并不是什么大问题。它不必考虑自上次编译以来哪些已更改:您总是重建所有内容。为此,您不需要 makefile:您可以只使用一个 shell 脚本来运行带有所有源文件的编译器。甚至是 shell 别名:您甚至不需要单独的脚本。
  • 但是,如果您有 5,000 个源文件,那么每当有任何更改时重新编译所有这些文件显然是对时间和资源的极大浪费。这就是 make 存在的原因:它允许您确定哪些源文件已更改,并且只重新编译 那些 文件,然后将所有先前编译的代码与那个新编译的文件链接。
【解决方案2】:

您的“最后一次编辑”仍然不理想,因为它每次都会构建一切。试试这样的:

SRC_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(SRC_FILES:.cpp=.o)
DEP_FILES := $(SRC_FILES:.cpp=.d)

#Important: this is =, not := 
DEP_FLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d

game: $(OBJ_FILES)
    $(CC) -o $@ $(OBJ_FILES)

# Pattern rule to build .o files
$(OBJ_FILES): %.o : %.cpp %.d
     $(CC) $(DEP_FLAGS) -c $(CFLAGS) $< -o $@

#dummy rule to prevent building .d files explicitly.
$(DEP_FILES):

include $(wildcard $(DEP_FILES))

至于它的作用——它首先用它找到的任何 cpp 文件填充SRC_FILES。然后它从该列表生成对象和依赖文件的列表。然后我们做一些神奇的依赖关系,描述为here——基本上,当你编译一个文件时,它会生成一个 .d 文件,其中包含它所依赖的所有头文件的列表,所以现在,如果有任何变化,make 知道重建 .c 文件。

然后有一个 static pattern rule 来构建所有 .o 文件,以及将它们全部链接到游戏的规则。最后但并非最不重要的一点是,它包括在您开始 make 时碰巧存在的 DEP_FILES

【讨论】:

    猜你喜欢
    • 2021-02-07
    • 2017-06-19
    • 1970-01-01
    • 2015-06-12
    • 2011-06-19
    • 1970-01-01
    • 2014-08-27
    • 1970-01-01
    • 2021-07-03
    相关资源
    最近更新 更多