Makefile 执行意外行为
Makefile executed unexpected behavior
我使用以下 Makefile 编译 C++ 文件,但发生了一些意外行为。环境是 MacOS X Mojave。 Makefile 如下:
CC=gcc
CXX=g++
CXXFLAGS=-std=c++11
RM=rm -f
all: clean sort_test ds_test
sort_test: data_structure sort .sort_test.o .sort_test
.sort_test: sort_test.o sort.o ds.o
$(CXX) $(CXXFLAGS) -o sort_test sort_test.o sort.o ds.o
.sort_test.o: sort_test.cpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o sort_test.o sort_test.cpp
sort: ../include/sort.hpp ../include/data_structure.hpp ../src/sort.cpp
$(CXX) $(CXXFLAGS) -c -o sort.o ../src/sort.cpp
data_structure: ../include/data_structure.hpp ../src/data_structure.cpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o ds.o ../src/data_structure.cpp
ds_test: data_structure .ds_test.o .ds_test
.ds_test: ds.o ds_test.o
$(CXX) $(CXXFLAGS) -o ds_test ds.o ds_test.o
.ds_test.o: ds_test.cpp ../include/io.hpp ../include/data_structure.hpp
$(CXX) $(CXXFLAGS) -c -o ds_test.o ds_test.cpp
clean:
$(RM) *.o sort_test ds_test
当我 运行 "make ds_test" 在同一目录下时,发生了一些奇怪的事情:
g++ -std=c++11 -c -o ds_test.o ds_test.cpp
g++ -std=c++11 -c -o ds.o ../src/data_structure.cpp
g++ -std=c++11 -c -o ds_test.o ds_test.cpp
g++ -std=c++11 -o ds_test ds.o ds_test.o
gcc ds_test.o data_structure .ds_test.o .ds_test -o ds_test
clang: error: no such file or directory: 'data_structure'
clang: error: no such file or directory: '.ds_test.o'
clang: error: no such file or directory: '.ds_test'
make: *** [ds_test] Error 1
此输出中的第一行和第五行绝对不是命令 "make ds_test",因为它应该只调用 "data_structure"、“.ds_test.o”和“.ds_test ”。
任何人,请解释为什么会发生这些额外的意外行为以及如何避免?谢谢!
你的 Makefile 有点奇怪。基本的 make 规则是这样的:
file-to-build: files-it-depends-on
command-to-build
当你写下这样的东西时:
.ds_test: ds.o ds_test.o
$(CXX) $(CXXFLAGS) -o ds_test ds.o ds_test.o
目标不是配方生成的文件。此外,您在没有适当扩展的情况下重命名事物(data_structure
与 ds.o
)。最后,您对同一事物使用不同的名称(同样是 data_structure
与 ds.o
)。如果您是从 C++ 和 make 开始,您可能应该避免所有这些花哨的东西。
你的 Makefile 失败的主要原因是因为 make 正在尝试构建一个名为 ds_test
的文件(这是你在键入 make ds_test
时所要求的)。 make 知道很多构建文件的方法。在这种特定情况下,它使用其默认规则,即使用 $(CC)
到 link 一起 ds_test.o
和所有其他文件 ds_test
取决于,即 data_structure
, .ds_test.o
和 .ds_test
.
如果您是新手,我建议您首先坚持其最基本的原则。类似于:
CC := gcc
CXX := g++
CXXFLAGS := -std=c++11
RM := rm -f
.PHONY: all clean
all: clean sort_test ds_test
sort_test: sort_test.o sort.o data_structure.o
$(CXX) $(CXXFLAGS) -o $@ $^
sort_test.o: sort_test.cpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
sort.o: ../src/sort.cpp ../include/sort.hpp ../include/data_structure.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
data_structure.o: ../src/data_structure.cpp ../include/data_structure.hpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
ds_test: data_structure.o ds_test.o
$(CXX) $(CXXFLAGS) -o $@ $^
ds_test.o: ds_test.cpp ../include/io.hpp ../include/data_structure.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o sort_test ds_test
解释:
$@
、$<
、$^
是make automatic variables,分别展开为目标、第一个前提和所有前提的列表。它们不仅方便,而且比在目标、先决条件和配方中重新键入相同的文件名更不容易出错。
.PHONY
是一个 special target,你可以用它发出信号,让哪些目标不是真实文件。
EDIT:将 LDLIBS
添加到 link C++ 对象文件,其中包含 gcc
和备用 linking 规则。
注意:由于 make 非常聪明,默认情况下知道如何编译和 link C++ 文件,您可以简化所有这些。特别是如果您还使用 VPATH
make variable:
CC := gcc
CXX := g++
CXXFLAGS := -std=c++11
LDLIBS := -lstdc++
RM := rm -f
EXEC := sort_test ds_test
.PHONY: all clean
all: clean sort_test ds_test
VPATH := ../src:../include
sort_test.o: io.hpp
sort.o: sort.hpp data_structure.hpp
data_structure.o: data_structure.hpp io.hpp
ds_test.o: io.hpp data_structure.hpp
sort_test: sort_test.o sort.o data_structure.o
ds_test: data_structure.o ds_test.o
clean:
$(RM) *.o $(EXEC)
注意:由于 make 将使用 gcc
到 link,我们必须将 -lstdc++
添加到 linker 标志 (LDLIBS
)。另一种选择是指定 linking 规则而不是让 make 使用默认值:
$(EXEC):
$(CXX) $(CXXFLAGS) -o $@ $^
请注意,在最后一种情况下,指定先决条件的规则和指定配方的规则是不同的。
我使用以下 Makefile 编译 C++ 文件,但发生了一些意外行为。环境是 MacOS X Mojave。 Makefile 如下:
CC=gcc
CXX=g++
CXXFLAGS=-std=c++11
RM=rm -f
all: clean sort_test ds_test
sort_test: data_structure sort .sort_test.o .sort_test
.sort_test: sort_test.o sort.o ds.o
$(CXX) $(CXXFLAGS) -o sort_test sort_test.o sort.o ds.o
.sort_test.o: sort_test.cpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o sort_test.o sort_test.cpp
sort: ../include/sort.hpp ../include/data_structure.hpp ../src/sort.cpp
$(CXX) $(CXXFLAGS) -c -o sort.o ../src/sort.cpp
data_structure: ../include/data_structure.hpp ../src/data_structure.cpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o ds.o ../src/data_structure.cpp
ds_test: data_structure .ds_test.o .ds_test
.ds_test: ds.o ds_test.o
$(CXX) $(CXXFLAGS) -o ds_test ds.o ds_test.o
.ds_test.o: ds_test.cpp ../include/io.hpp ../include/data_structure.hpp
$(CXX) $(CXXFLAGS) -c -o ds_test.o ds_test.cpp
clean:
$(RM) *.o sort_test ds_test
当我 运行 "make ds_test" 在同一目录下时,发生了一些奇怪的事情:
g++ -std=c++11 -c -o ds_test.o ds_test.cpp
g++ -std=c++11 -c -o ds.o ../src/data_structure.cpp
g++ -std=c++11 -c -o ds_test.o ds_test.cpp
g++ -std=c++11 -o ds_test ds.o ds_test.o
gcc ds_test.o data_structure .ds_test.o .ds_test -o ds_test
clang: error: no such file or directory: 'data_structure'
clang: error: no such file or directory: '.ds_test.o'
clang: error: no such file or directory: '.ds_test'
make: *** [ds_test] Error 1
此输出中的第一行和第五行绝对不是命令 "make ds_test",因为它应该只调用 "data_structure"、“.ds_test.o”和“.ds_test ”。 任何人,请解释为什么会发生这些额外的意外行为以及如何避免?谢谢!
你的 Makefile 有点奇怪。基本的 make 规则是这样的:
file-to-build: files-it-depends-on
command-to-build
当你写下这样的东西时:
.ds_test: ds.o ds_test.o
$(CXX) $(CXXFLAGS) -o ds_test ds.o ds_test.o
目标不是配方生成的文件。此外,您在没有适当扩展的情况下重命名事物(data_structure
与 ds.o
)。最后,您对同一事物使用不同的名称(同样是 data_structure
与 ds.o
)。如果您是从 C++ 和 make 开始,您可能应该避免所有这些花哨的东西。
你的 Makefile 失败的主要原因是因为 make 正在尝试构建一个名为 ds_test
的文件(这是你在键入 make ds_test
时所要求的)。 make 知道很多构建文件的方法。在这种特定情况下,它使用其默认规则,即使用 $(CC)
到 link 一起 ds_test.o
和所有其他文件 ds_test
取决于,即 data_structure
, .ds_test.o
和 .ds_test
.
如果您是新手,我建议您首先坚持其最基本的原则。类似于:
CC := gcc
CXX := g++
CXXFLAGS := -std=c++11
RM := rm -f
.PHONY: all clean
all: clean sort_test ds_test
sort_test: sort_test.o sort.o data_structure.o
$(CXX) $(CXXFLAGS) -o $@ $^
sort_test.o: sort_test.cpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
sort.o: ../src/sort.cpp ../include/sort.hpp ../include/data_structure.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
data_structure.o: ../src/data_structure.cpp ../include/data_structure.hpp ../include/io.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
ds_test: data_structure.o ds_test.o
$(CXX) $(CXXFLAGS) -o $@ $^
ds_test.o: ds_test.cpp ../include/io.hpp ../include/data_structure.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o sort_test ds_test
解释:
$@
、$<
、$^
是make automatic variables,分别展开为目标、第一个前提和所有前提的列表。它们不仅方便,而且比在目标、先决条件和配方中重新键入相同的文件名更不容易出错。.PHONY
是一个 special target,你可以用它发出信号,让哪些目标不是真实文件。
EDIT:将 LDLIBS
添加到 link C++ 对象文件,其中包含 gcc
和备用 linking 规则。
注意:由于 make 非常聪明,默认情况下知道如何编译和 link C++ 文件,您可以简化所有这些。特别是如果您还使用 VPATH
make variable:
CC := gcc
CXX := g++
CXXFLAGS := -std=c++11
LDLIBS := -lstdc++
RM := rm -f
EXEC := sort_test ds_test
.PHONY: all clean
all: clean sort_test ds_test
VPATH := ../src:../include
sort_test.o: io.hpp
sort.o: sort.hpp data_structure.hpp
data_structure.o: data_structure.hpp io.hpp
ds_test.o: io.hpp data_structure.hpp
sort_test: sort_test.o sort.o data_structure.o
ds_test: data_structure.o ds_test.o
clean:
$(RM) *.o $(EXEC)
注意:由于 make 将使用 gcc
到 link,我们必须将 -lstdc++
添加到 linker 标志 (LDLIBS
)。另一种选择是指定 linking 规则而不是让 make 使用默认值:
$(EXEC):
$(CXX) $(CXXFLAGS) -o $@ $^
请注意,在最后一种情况下,指定先决条件的规则和指定配方的规则是不同的。