Makefile执行意外行为

时间:2018-11-13 04:18:03

标签: makefile g++ gnu-make

我使用以下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”。 有人,请解释为什么会发生这些额外的意外行为以及如何避免这种情况?谢谢!

1 个答案:

答案 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_structureds.o)。最后,您为同一事物使用不同的名称(再次data_structureds.o)。如果您是从C ++开始制作的,则应该避免所有这些花哨的事情。

Makefile失败的主要原因是因为make试图构建名为ds_test的文件(这是键入make ds_test时要求的)。并了解许多构建文件的方法。在此特定情况下,它使用默认规则,该规则包含使用$(CC)链接ds_test.ods_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

请注意,在最后一种情况下,前提条件的指定规则和配方的指定规则不同。