Makefile构建最佳实践及相关技术问题咨询
Hey David, let's break down your Makefile questions one by one—glad you're diving into optimizing your Othello build setup!
问题1:clean目标无法正常工作的原因是什么?
There are a few common culprits when a clean target fails to behave as expected:
- You have a file named
clean: Make treats targets as files by default. If a file namedcleanexists in your directory, Make will think it's up-to-date and skip running the cleanup commands. Fix this by markingcleanas a phony target with.PHONY: cleanat the top of your Makefile. - Incorrect paths or wildcards: If your
.ofiles are in a subdirectory (likesrc/), yourrm *.ocommand won't find them. Use explicit paths (e.g.,rm src/*.o) or define variables for your object file directory to keep it consistent. Also, Make's wildcards work differently than shell wildcards—use$(wildcard *.o)to reliably match existing object files. - Missing
-fflag inrm: If some files don't exist,rmwill throw an error and stop the cleanup. Adding-fforcesrmto ignore non-existent files, so your clean target runs to completion:rm -f *.o othello. - Unnecessary dependencies: If you added dependencies to your
cleantarget (likeclean: othello), Make will only runcleanifothellois newer than thecleantarget (or the phony flag is set). Keepcleandependency-free so it runs whenever you callmake clean.
问题2:归档.o文件和可执行文件是否属于标准最佳实践?有没有更优实现方案?
Archiving .o object files isn't typically a standard best practice—here's why and what to do instead:
.ofiles are intermediate build artifacts. Make is designed to track dependencies and rebuild only what's necessary, so keeping them around helps with incremental builds, but archiving them adds unnecessary bloat. If you need to share your build, other developers can just recompile from source (assuming you've shared all your code).- For executable files, archiving can make sense if you're distributing the game to others who don't want to compile it themselves—but you should avoid including
.ofiles here.
Better approaches:
- Use a dedicated build directory: Create a
build/folder with subdirectories likebuild/objfor.ofiles andbuild/binfor your executable. This keeps your source directory clean and makes cleanup trivial (justrm -rf build/). Define variables in your Makefile to manage these paths, e.g.:OBJ_DIR := build/obj BIN_DIR := build/bin EXEC := $(BIN_DIR)/othello - Package only what's needed for distribution: If you want to share the game, package the executable along with any game assets (like sprites, config files) into a compressed archive (e.g.,
othello-game.tar.gz). You can add adisttarget to automate this:dist: $(EXEC) mkdir -p dist/othello cp $(EXEC) assets/ dist/othello/ tar -czf othello-game.tar.gz dist/othello/ rm -rf dist/ - Save debug artifacts if needed: If you want to preserve build artifacts for debugging (with symbols), keep the executable compiled with
-gand archive that, but skip the.ofiles—they don't add much value once the executable is built.
问题3:关于构建环节自动运行可执行文件的实现
Since you mentioned wanting to run the executable as part of the build process, the easiest way is to add a run phony target that depends on your executable. This ensures Make only runs the game if the build succeeds:
.PHONY: run run: $(EXEC) ./$(EXEC)
If you want to pass command-line arguments to the game, you can use a variable to make it flexible:
run: $(EXEC) ./$(EXEC) $(ARGS)
Then run it with:
make run ARGS="--debug --level hard"
This keeps your build targets modular—you can build without running, or run with one command after a successful build.
内容的提问来源于stack exchange,提问作者David Wisniewski

