开发者

Why won't my project link without cleaning?

I am just getting started with makefiles, and I have written one for my project that has two targets. If I run a new make everything works fine. But if I don't clean after that, and I edit and save one source file, for example, and then I run make again, my project only compiles the source file I edited and then makes no attempt to link my sources into a new executable.

In other words: The first time I run make I get $(CC) -c <sourcefile> for each source, and then $(CC) -o <sourceobject1> <sourceobject2>... and everything works. But if I then go and edit a sourcefile, and try to make again, I just get $(CC) -c <editedsourcefile>, and no linking after that! At least make is not trying to compile all my source files again, but why isn't it linking me a new executable? Is this the expected behavior?

Bonus question: Is there a nicer way to move my object files into a subdirectory than sticking mv *.o at the top of my target rule? I have looked at this answer, 开发者_C百科but I didn't understand what was going on and couldn't figure out how to adapt it to my case with two targets.

Here is my makefile:

CC = clang++
OPTFLAGS = -O3 -flto -m64
CFLAGS = -Wall -c $(OPTFLAGS)
LFLAGS = -Wall $(OPTFLAGS)
MAKE = make
RM = \rm -f
TARGET-DIR = build
OBJ-DIR = $(TARGET-DIR)/obj
OBJS = $(addprefix $(OBJ-DIR)/, MCTS.o NodePool.o Node.o FastMath.o \
       Board.o Patterns.o FastSet.o FastHash.o FastHash2.o FastHashMap.o)
GTP-OBJS = $(addprefix $(OBJ-DIR)/, GtpPlayer.o)
GTP-TARGET = $(TARGET-DIR)/go-gtp
TEST-OBJS = $(addprefix $(OBJ-DIR)/, TestsMain.o MCTSTests.o NodePoolTests.o \
        NodeTests.o FastMathTests.o BoardTests.o FastSetTests.o \
        FastHashTests.o FastHash2Tests.o FastHashMapTests.o)
TEST-TARGET = $(TARGET-DIR)/go-test

.PHONY : all 
all : $(GTP-TARGET) $(TEST-TARGET)

$(GTP-TARGET) : $(GTP-OBJS) $(OBJS)
    mv *.o $(OBJ-DIR)
    $(CC) $(LFLAGS) $(GTP-OBJS) $(OBJS) -o $(GTP-TARGET)

$(OBJ-DIR)/GtpPlayer.o : GtpPlayer.hpp GtpPlayer.cpp mcts/MCTS.hpp
    $(CC) $(CFLAGS) GtpPlayer.cpp

$(OBJ-DIR)/MCTS.o : mcts/MCTS.hpp mcts/MCTS.cpp mcts/NodePool.hpp
    $(CC) $(CFLAGS) mcts/MCTS.cpp

$(OBJ-DIR)/NodePool.o : mcts/NodePool.hpp mcts/NodePool.cpp mcts/Node.hpp
    $(CC) $(CFLAGS) mcts/NodePool.cpp

$(OBJ-DIR)/Node.o : mcts/Node.hpp mcts/Node.cpp mcts/FastMath.hpp board/Board.hpp
    $(CC) $(CFLAGS) mcts/Node.cpp

$(OBJ-DIR)/FastMath.o : mcts/FastMath.hpp mcts/FastMath.cpp
    $(CC) $(CFLAGS) mcts/FastMath.cpp

$(OBJ-DIR)/Board.o : board/Board.hpp board/Board.cpp board/Patterns.hpp struct/FastSet.hpp struct/FastHash.hpp
    $(CC) $(CFLAGS) board/Board.cpp

$(OBJ-DIR)/Patterns.o : board/Patterns.hpp board/Patterns.cpp  struct/FastHash2.hpp struct/FastHashMap.hpp
    $(CC) $(CFLAGS) board/Patterns.cpp

$(OBJ-DIR)/FastSet.o : struct/FastSet.hpp struct/FastSet.cpp
    $(CC) $(CFLAGS) struct/FastSet.cpp

$(OBJ-DIR)/FastHash.o : struct/FastHash.hpp struct/FastHash.cpp
    $(CC) $(CFLAGS) struct/FastHash.cpp

$(OBJ-DIR)/FastHash2.o : struct/FastHash2.hpp struct/FastHash2.cpp
    $(CC) $(CFLAGS) struct/FastHash2.cpp

$(OBJ-DIR)/FastHashMap.o : struct/FastHashMap.hpp struct/FastHashMap.cpp
    $(CC) $(CFLAGS) struct/FastHashMap.cpp

$(TEST-TARGET) : $(TEST-OBJS) $(OBJS)
    mv *.o $(OBJ-DIR)
    $(CC) $(LFLAGS) $(TEST-OBJS) $(OBJS) -o $(TEST-TARGET)

$(OBJ-DIR)/TestsMain.o : test/TestsMain.cpp test/MCTSTests.hpp test/NodePoolTests.hpp \
          test/NodeTests.hpp test/FastMathTests.hpp test/BoardTests.hpp \
          test/FastSetTests.hpp test/FastHashTests.hpp test/FastHash2Tests.hpp test/FastHashMapTests.hpp
    $(CC) $(CFLAGS) test/TestsMain.cpp

$(OBJ-DIR)/MCTSTests.o : test/MCTSTests.hpp test/MCTSTests.cpp mcts/MCTS.hpp
    $(CC) $(CFLAGS) test/MCTSTests.cpp

$(OBJ-DIR)/NodePoolTests.o : test/NodePoolTests.hpp test/NodePoolTests.cpp
    $(CC) $(CFLAGS) test/NodePoolTests.cpp

$(OBJ-DIR)/NodeTests.o : test/NodeTests.hpp test/NodeTests.cpp
    $(CC) $(CFLAGS) test/NodeTests.cpp

$(OBJ-DIR)/FastMathTests.o : test/FastMathTests.hpp test/FastMathTests.cpp
    $(CC) $(CFLAGS) test/FastMathTests.cpp

$(OBJ-DIR)/BoardTests.o : test/BoardTests.hpp test/BoardTests.cpp
    $(CC) $(CFLAGS) test/BoardTests.cpp

$(OBJ-DIR)/FastSetTests.o : test/FastSetTests.hpp test/FastSetTests.cpp
    $(CC) $(CFLAGS) test/FastSetTests.cpp

$(OBJ-DIR)/FastHashTests.o : test/FastHashTests.hpp test/FastHashTests.cpp
    $(CC) $(CFLAGS) test/FastHashTests.cpp

$(OBJ-DIR)/FastHash2Tests.o : test/FastHash2Tests.hpp test/FastHash2Tests.cpp
    $(CC) $(CFLAGS) test/FastHash2Tests.cpp

$(OBJ-DIR)/FastHashMapTests.o : test/FastHashMapTests.hpp test/FastHashMapTests.cpp
    $(CC) $(CFLAGS) test/FastHashMapTests.cpp

.PHONY : clean
clean : 
    $(RM) $(OBJ-DIR)/*.o

.PHONY : distclean
distclean :
    $(MAKE) clean
    $(RM) $(GTP-TARGET) $(TEST-TARGET)

.PHONY : again
again:
    $(MAKE) distclean
    $(MAKE) $(GTP-TARGET)
    $(MAKE) $(TEST-TARGET)

.PHONY : tar
tar: 
    tar cfv $(GTP-TARGET).tar $(GTP-OBJS) $(OBJS)
    tar cfv $(TEST-TARGET).tar $(TEST-OBJS) $(OBJS)

Example output:

$ make
clang++ -Wall -c -O3 -flto -m64 GtpPlayer.cpp
clang++ -Wall -c -O3 -flto -m64 mcts/MCTS.cpp
clang++ -Wall -c -O3 -flto -m64 mcts/NodePool.cpp
clang++ -Wall -c -O3 -flto -m64 mcts/Node.cpp
clang++ -Wall -c -O3 -flto -m64 mcts/FastMath.cpp
clang++ -Wall -c -O3 -flto -m64 board/Board.cpp
clang++ -Wall -c -O3 -flto -m64 board/Patterns.cpp
clang++ -Wall -c -O3 -flto -m64 struct/FastSet.cpp
clang++ -Wall -c -O3 -flto -m64 struct/FastHash.cpp
clang++ -Wall -c -O3 -flto -m64 struct/FastHash2.cpp
clang++ -Wall -c -O3 -flto -m64 struct/FastHashMap.cpp
mv *.o build/obj
clang++ -Wall -O3 -flto -m64 build/obj/GtpPlayer.o build/obj/MCTS.o build/obj/NodePool.o build/obj/Node.o build/obj/FastMath.o build/obj/Board.o build/obj/Patterns.o build/obj/FastSet.o build/obj/FastHash.o build/obj/FastHash2.o build/obj/FastHashMap.o -o build/go-gtp
clang++ -Wall -c -O3 -flto -m64 test/TestsMain.cpp
clang++ -Wall -c -O3 -flto -m64 test/MCTSTests.cpp
clang++ -Wall -c -O3 -flto -m64 test/NodePoolTests.cpp
clang++ -Wall -c -O3 -flto -m64 test/NodeTests.cpp
clang++ -Wall -c -O3 -flto -m64 test/FastMathTests.cpp
clang++ -Wall -c -O3 -flto -m64 test/BoardTests.cpp
clang++ -Wall -c -O3 -flto -m64 test/FastSetTests.cpp
clang++ -Wall -c -O3 -flto -m64 test/FastHashTests.cpp
clang++ -Wall -c -O3 -flto -m64 test/FastHash2Tests.cpp
clang++ -Wall -c -O3 -flto -m64 test/FastHashMapTests.cpp
mv *.o build/obj
clang++ -Wall -O3 -flto -m64 build/obj/TestsMain.o build/obj/MCTSTests.o build/obj/NodePoolTests.o build/obj/NodeTests.o build/obj/FastMathTests.o build/obj/BoardTests.o build/obj/FastSetTests.o build/obj/FastHashTests.o build/obj/FastHash2Tests.o build/obj/FastHashMapTests.o build/obj/MCTS.o build/obj/NodePool.o build/obj/Node.o build/obj/FastMath.o build/obj/Board.o build/obj/Patterns.o build/obj/FastSet.o build/obj/FastHash.o build/obj/FastHash2.o build/obj/FastHashMap.o -o build/go-test

Now if I edit and save Board.cpp for example and run make again, I get this:

$ make
clang++ -Wall -c -O3 -flto -m64 board/Board.cpp

What happened to the linking command? I want a new target!


It won't link because the newer obj files are not in OBJ_DIR but in wherever they are before they are moved (current directory?). Make looks at the executable and the object files and correctly concludes that the executable is newer than the object files in OBJ_DIR.

Make the compiler generate them in OBJ_DIR in the first place (use -o) or move the mv command to each of the rules generating the object files (not recommended) so that the after running the rule, the obj file in OBJ_DIR is updated.


Outputting my object files to the desired directory with $(CC) -o $@ (and removing the mv *.o commands in my target rules) solves my problem. Everything links as expected now.

Thanks to Greg and sarnold who explained how to do this in the comments.

My makefile now looks like this:

CC = clang++
CFLAGS = -Wall -O3 -flto -m64
MAKE = make
RM = \rm -f
TARGET-DIR = build
OBJ-DIR = $(TARGET-DIR)/obj
OBJS = $(addprefix $(OBJ-DIR)/, MCTS.o NodePool.o Node.o FastMath.o \
       Board.o Patterns.o FastSet.o FastHash.o FastHash2.o FastHashMap.o)
GTP-OBJS = $(addprefix $(OBJ-DIR)/, GtpPlayer.o)
GTP-TARGET = $(TARGET-DIR)/go-gtp
TEST-OBJS = $(addprefix $(OBJ-DIR)/, TestsMain.o MCTSTests.o NodePoolTests.o \
        NodeTests.o FastMathTests.o BoardTests.o FastSetTests.o \
        FastHashTests.o FastHash2Tests.o FastHashMapTests.o)
TEST-TARGET = $(TARGET-DIR)/go-test

.PHONY : all 
all : $(GTP-TARGET) $(TEST-TARGET)

$(GTP-TARGET) : $(GTP-OBJS) $(OBJS)
    $(CC) $(CFLAGS) $^ -o $@

$(OBJ-DIR)/GtpPlayer.o : GtpPlayer.cpp
    $(CC) -c $(CFLAGS) $< -o $@

$(OBJ-DIR)/%.o : mcts/%.cpp
    $(CC) -c $(CFLAGS) $< -o $@

$(OBJ-DIR)/%.o : board/%.cpp
    $(CC) -c $(CFLAGS) $< -o $@

$(OBJ-DIR)/%.o : struct/%.cpp
    $(CC) -c $(CFLAGS) $< -o $@

$(TEST-TARGET) : $(TEST-OBJS) $(OBJS)
    $(CC) $(CFLAGS) $^ -o $@

$(OBJ-DIR)/%.o : test/%.cpp
    $(CC) -c $(CFLAGS) $< -o $@

.PHONY : clean
clean : 
    $(RM) $(OBJ-DIR)/*.o

.PHONY : distclean
distclean :
    $(MAKE) clean
    $(RM) $(GTP-TARGET) $(TEST-TARGET)

.PHONY : again
again:
    $(MAKE) distclean
    $(MAKE) $(GTP-TARGET)
    $(MAKE) $(TEST-TARGET)

.PHONY : tar
tar: 
    tar cfv $(GTP-TARGET).tar $(GTP-OBJS) $(OBJS)
    tar cfv $(TEST-TARGET).tar $(TEST-OBJS) $(OBJS)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜