我使用以下Makefile编译C ++文件,但是发生了一些意外行为。环境是MacOS X Mojave。 Makefile的格式为:
#include <iostream>
#include <cstdlib>
struct ListNode
{
int value;
ListNode* next = NULL;
~ListNode(){
if(this->next)
delete this->next;
}
};
void insertRecList(ListNode* list, int value)
{
if(list->next == NULL)
{
ListNode* end = new ListNode;
end->value = value;
list->next = end;
}
else
insertRecList(list->next, value);
}
void printList(ListNode* list)
{
std::cout << list->value << std::endl;
while(list->next != NULL)
{
list = list->next;
std::cout << list->value << std::endl;
}
}
ListNode * reverseList(ListNode* list)
{
ListNode* next;
ListNode* prev = NULL;
ListNode* cur = list;
while(cur != NULL)
{
if(cur->next == NULL)
{
cur->next = prev;
break;
}
else
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
}
std::cout << cur->value << " list:" << list->value << std::endl;
return cur;
}
void testLinkedList()
{
srand(time(NULL));
ListNode * nodes = new ListNode;
nodes->value = 99;
int val;
for(int i = 0; i < 5; i++)
{
val = rand() % 30 + 1;
insertRecList(nodes, i);
//insertList(&nodes, val);
}
printList(nodes);
nodes = reverseList(nodes);
printList(nodes);
delete nodes;
}
int main()
{
testLinkedList();
return 0;
}
当我在同一目录中运行“ make ds_test”时,发生了一些奇怪的事情:
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”永远不会出现此输出的第一行和第五行,因为它只应调用“ data_structure”,“。ds_test.o”和“ .ds_test”。 有人,请解释为什么会发生这些额外的意外行为以及如何避免这种情况?谢谢!
答案 0 :(得分:1)
您的Makefile有点奇怪。基本的制作规则如下:
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 ++开始制作的,则应该避免所有这些花哨的事情。
Makefile失败的主要原因是因为make试图构建名为ds_test
的文件(这是键入make ds_test
时要求的)。并了解许多构建文件的方法。在此特定情况下,它使用默认规则,该规则包含使用$(CC)
链接ds_test.o
和ds_test
依赖的所有其他文件,即data_structure
,{{1 }}和.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,分别扩展为目标,第一个必备条件和所有必备条件的列表。它们不仅方便,而且与在目标,先决条件和配方中重新键入相同的文件名相比,它们更容易出错。$^
是special target,您可以通过信号告知哪些目标不是真实文件。 编辑:添加了.PHONY
,以使用LDLIBS
和备用链接规则链接C ++对象文件。
注意:由于make确实很聪明,并且默认情况下知道如何编译和链接C ++文件,因此可以简化所有步骤。特别是如果您还使用VPATH
make variable:
gcc
注意:由于make将使用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)
进行链接,因此必须在链接器标志(gcc
)中添加-lstdc++
。另一种选择是指定链接规则,而不是使用默认值:
LDLIBS
请注意,在最后一种情况下,前提条件的指定规则和配方的指定规则不同。