如何重写我的 makefile 以便重构我的项目目录?
How do I rewrite my makefile so that I can restructure the directories of my project?
我一直在开发一个完全用 C++ 编写的小游戏,使用 SDL 处理图形和音频。到目前为止,我所有的源文件和 headers 都位于与我的可执行文件相同的目录中,但我想将它们移动到 ./src 和 ./include 文件夹中。
但是,我真的很难理解 makefile 语法以及如何告诉编译器在哪里可以找到源文件和 header 文件。
如何告诉 makefile 在子目录中查找 source/headers/objects?我的 makefile 有 improvements/mistakes 吗?
这是我当前的 makefile:
OBJS = main.o Window.o Entity.o Player.o Tile.o BoundingBox.o\
MapReader.o Button.o Zombie.o Projectile.o Pathfinder.o
CPP = g++
CPPFLAGS = -c -g
LDFLAGS = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer -mwindows
ZombieAttack: $(OBJS)
$(CPP) -o ZombieAttack $(OBJS) $(LDFLAGS)
main.o: main.cpp
$(CPP) $(CPPFLAGS) main.cpp
Window.o: Window.cpp
$(CPP) $(CPPFLAGS) Window.cpp
Entity.o: Entity.cpp
$(CPP) $(CPPFLAGS) Entity.cpp
Player.o: Player.cpp
$(CPP) $(CPPFLAGS) Player.cpp
Tile.o: Tile.cpp
$(CPP) $(CPPFLAGS) Tile.cpp
BoundingBox.o: BoundingBox.cpp
$(CPP) $(CPPFLAGS) BoundingBox.cpp
MapReader.o: MapReader.cpp
$(CPP) $(CPPFLAGS) MapReader.cpp
Button.o: Button.cpp
$(CPP) $(CPPFLAGS) Button.cpp
Zombie.o: Zombie.cpp
$(CPP) $(CPPFLAGS) Zombie.cpp
Projectile.o: Projectile.cpp
$(CPP) $(CPPFLAGS) Projectile.cpp
Pathfinder.o: Pathfinder.cpp
$(CPP) $(CPPFLAGS) Pathfinder.cpp
clean:
del *.o
我正在使用 mingw 进行编译和 mingw32-make
如果您希望二进制文件位于最高级别的目录中,而 .h / .cpp 文件位于该目录的子目录中,您可以简单地在您希望访问的文件前加上 target directory/filename
例如:
MapReader.o: MapReader.cpp
$(CPP) $(CPPFLAGS) MapReader.cpp
变成
MapReader.o: src/MapReader.cpp
$(CPP) $(CPPFLAGS) src/MapReader.cpp
一般来说,最好在发布到 SO 之前尝试自己解决问题。然后,当您遇到无法解决的问题时,您应该具体询问该问题,而不是像这样宽泛的问题。
不过,过年了!!
首先,make 与编译器不是一回事。仅教 make 在哪里可以找到您的文件是不够的,您还必须教编译器在哪里可以找到您的文件。如果您打算将 header 文件放在源目录之外的其他目录中,那么您必须为编译器提供选项,告诉它在哪里可以找到这些 headers。仅仅告诉 make 在哪里可以找到它们对编译器没有任何帮助。
其次,除非你真的有紧迫的需要,否则你应该使用 standard variables 来处理 C++ 编译器(CXX
而不是 CPP
)和它的标志(CXXFLAGS
而不是 CPPFLAGS
)。您也不应该将选择输出类型的选项 (-c
) 放入通用标志变量中:这应该进入规则。最后,您应该确保区分 LDFLAGS
和 link 之间的区别,LDFLAGS
是 linker 的标志,LDLIBS
是 link 的库。在这里,您将 link 的所有库放入 LDFLAGS
.
第三,您可以尽可能使用automatic variables来减少重复。
第四,您可以使用可以正确构建 C++ 文件的 pattern rule. In fact, GNU make provides default pattern rules 来大大简化您的 makefile,如果您像上面那样使用正确的变量,那么您甚至不必定义自己的变量。
这是原始 makefile 的一个版本,修复了上述变量并使用内置规则减少重复:
OBJS = main.o Window.o Entity.o Player.o Tile.o BoundingBox.o \
MapReader.o Button.o Zombie.o Projectile.o Pathfinder.o
CXX = g++
CXXFLAGS = -g
LDFLAGS = -mwindows
LDLIBS = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer
ZombieAttack: $(OBJS)
$(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS)
clean:
del *.o
如果所有文件都在同一个目录中,那么该 makefile 的性能应该与您的原始 makefile 完全一样。
现在,如果你想移动一些东西,那么你需要先向编译器解释在哪里可以找到你的 headers,方法是在编译行中添加一个 -I
选项。如果您的 header 现在位于 include
子目录中,您可以这样做:
CXXFLAGS = -g -Iinclude
现在,如果您愿意将 object 文件与源文件放在同一目录中,那么您可以更改上面的 makefile 以告诉 make 在何处构建它们,如下所示:
BASE_OBJS = main.o Window.o Entity.o Player.o Tile.o BoundingBox.o \
MapReader.o Button.o Zombie.o Projectile.o Pathfinder.o
SRC = src
OBJS = $(addprefix $(SRC)/,$(BASE_OBJS))
加上上述更改,它应该可以正常工作。
如果你想把 object 文件放在源文件以外的其他目录中,那么你将无法再使用 make 的 built-in 规则,因为 make 不知道你想放在哪里放东西,所以你必须编写自己的模式规则。
我一直在开发一个完全用 C++ 编写的小游戏,使用 SDL 处理图形和音频。到目前为止,我所有的源文件和 headers 都位于与我的可执行文件相同的目录中,但我想将它们移动到 ./src 和 ./include 文件夹中。
但是,我真的很难理解 makefile 语法以及如何告诉编译器在哪里可以找到源文件和 header 文件。
如何告诉 makefile 在子目录中查找 source/headers/objects?我的 makefile 有 improvements/mistakes 吗?
这是我当前的 makefile:
OBJS = main.o Window.o Entity.o Player.o Tile.o BoundingBox.o\
MapReader.o Button.o Zombie.o Projectile.o Pathfinder.o
CPP = g++
CPPFLAGS = -c -g
LDFLAGS = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer -mwindows
ZombieAttack: $(OBJS)
$(CPP) -o ZombieAttack $(OBJS) $(LDFLAGS)
main.o: main.cpp
$(CPP) $(CPPFLAGS) main.cpp
Window.o: Window.cpp
$(CPP) $(CPPFLAGS) Window.cpp
Entity.o: Entity.cpp
$(CPP) $(CPPFLAGS) Entity.cpp
Player.o: Player.cpp
$(CPP) $(CPPFLAGS) Player.cpp
Tile.o: Tile.cpp
$(CPP) $(CPPFLAGS) Tile.cpp
BoundingBox.o: BoundingBox.cpp
$(CPP) $(CPPFLAGS) BoundingBox.cpp
MapReader.o: MapReader.cpp
$(CPP) $(CPPFLAGS) MapReader.cpp
Button.o: Button.cpp
$(CPP) $(CPPFLAGS) Button.cpp
Zombie.o: Zombie.cpp
$(CPP) $(CPPFLAGS) Zombie.cpp
Projectile.o: Projectile.cpp
$(CPP) $(CPPFLAGS) Projectile.cpp
Pathfinder.o: Pathfinder.cpp
$(CPP) $(CPPFLAGS) Pathfinder.cpp
clean:
del *.o
我正在使用 mingw 进行编译和 mingw32-make
如果您希望二进制文件位于最高级别的目录中,而 .h / .cpp 文件位于该目录的子目录中,您可以简单地在您希望访问的文件前加上 target directory/filename
例如:
MapReader.o: MapReader.cpp
$(CPP) $(CPPFLAGS) MapReader.cpp
变成
MapReader.o: src/MapReader.cpp
$(CPP) $(CPPFLAGS) src/MapReader.cpp
一般来说,最好在发布到 SO 之前尝试自己解决问题。然后,当您遇到无法解决的问题时,您应该具体询问该问题,而不是像这样宽泛的问题。
不过,过年了!!
首先,make 与编译器不是一回事。仅教 make 在哪里可以找到您的文件是不够的,您还必须教编译器在哪里可以找到您的文件。如果您打算将 header 文件放在源目录之外的其他目录中,那么您必须为编译器提供选项,告诉它在哪里可以找到这些 headers。仅仅告诉 make 在哪里可以找到它们对编译器没有任何帮助。
其次,除非你真的有紧迫的需要,否则你应该使用 standard variables 来处理 C++ 编译器(CXX
而不是 CPP
)和它的标志(CXXFLAGS
而不是 CPPFLAGS
)。您也不应该将选择输出类型的选项 (-c
) 放入通用标志变量中:这应该进入规则。最后,您应该确保区分 LDFLAGS
和 link 之间的区别,LDFLAGS
是 linker 的标志,LDLIBS
是 link 的库。在这里,您将 link 的所有库放入 LDFLAGS
.
第三,您可以尽可能使用automatic variables来减少重复。
第四,您可以使用可以正确构建 C++ 文件的 pattern rule. In fact, GNU make provides default pattern rules 来大大简化您的 makefile,如果您像上面那样使用正确的变量,那么您甚至不必定义自己的变量。
这是原始 makefile 的一个版本,修复了上述变量并使用内置规则减少重复:
OBJS = main.o Window.o Entity.o Player.o Tile.o BoundingBox.o \
MapReader.o Button.o Zombie.o Projectile.o Pathfinder.o
CXX = g++
CXXFLAGS = -g
LDFLAGS = -mwindows
LDLIBS = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer
ZombieAttack: $(OBJS)
$(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS)
clean:
del *.o
如果所有文件都在同一个目录中,那么该 makefile 的性能应该与您的原始 makefile 完全一样。
现在,如果你想移动一些东西,那么你需要先向编译器解释在哪里可以找到你的 headers,方法是在编译行中添加一个 -I
选项。如果您的 header 现在位于 include
子目录中,您可以这样做:
CXXFLAGS = -g -Iinclude
现在,如果您愿意将 object 文件与源文件放在同一目录中,那么您可以更改上面的 makefile 以告诉 make 在何处构建它们,如下所示:
BASE_OBJS = main.o Window.o Entity.o Player.o Tile.o BoundingBox.o \
MapReader.o Button.o Zombie.o Projectile.o Pathfinder.o
SRC = src
OBJS = $(addprefix $(SRC)/,$(BASE_OBJS))
加上上述更改,它应该可以正常工作。
如果你想把 object 文件放在源文件以外的其他目录中,那么你将无法再使用 make 的 built-in 规则,因为 make 不知道你想放在哪里放东西,所以你必须编写自己的模式规则。