【问题标题】:How to properly use -MD flag in Makefile如何在 Makefile 中正确使用 -MD 标志
【发布时间】:2018-11-26 19:47:17
【问题描述】:

我正在尝试创建一个 Makefile,其中 make 只重新编译必要的 .cpp 文件。

默认情况下,如果我编辑 .cpp 效果很好,但是,当我编辑 .h 文件时,它只是忽略更改。

所以我读过-MD flag 和它的朋友-MP(用于避免键入 make 时出现错误)。

但是,我似乎无法让它工作,如果我使用-MMD,它工作得很好,但我也依赖系统包含,因为我也在编写一个随着项目发展的库。因此,如果我更新库头文件并重新安装库,在主项目中键入 make 应该会重新编译包含更改的头文件的文件。

当使用 -MMD 标志时,它 - 正如预期的那样 - 不会重新编译项目,但是,使用 -MD 标志时,它会重新编译所有内容。事实上,-MD 每次都会重新编译所有内容,即使没有任何变化。

这是重现问题的最小项目结构:

./Makefile:

all: build

re: clean build

build: build_lib install_lib build_client

build_lib:
    $(MAKE) -C lib
    $(MAKE) install -C lib

build_client:
    $(MAKE) -C client

install_lib:
    $(MAKE) install -C lib


.PHONY: clean
clean: clean_lib clean_client

clean_lib:
    $(MAKE) clean -C lib

clean_client:
    $(MAKE) clean -C client

./client/Makefile:

CC = g++
INC = -I../lib
CXXFLAGS = -Wall $(INC) -g -MD -MP
EXEC_NAME = ../test

src = $(shell find $(SOURCEDIR) -name '*.cpp')
obj = $(src:.cpp=.o)

LIBRARIES = -ltest_lib
LDFLAGS = -rdynamic $(LIBRARIES)

all: $(EXEC_NAME)

re: clean $(EXEC_NAME)

$(EXEC_NAME): $(obj)
    $(CC) -o $@ $^ $(LDFLAGS)
-include $(obj:.o=.d)

.PHONY: clean
clean:
    rm -f $(obj) $(EXEC_NAME)

./lib/Makefile:

.PHONY : clean

CXXFLAGS= -fPIC -g -Itest_lib/include -MMD -MP
LDFLAGS= -shared

SOURCES = $(shell find $(SOURCEDIR) -name '*.cpp')
HEADERS = $(shell find $(SOURCEDIR) -name '*.h')
OBJECTS=$(SOURCES:.cpp=.o)

TARGET=libtest_lib.so
INC_FOLDER=test_lib/include
CUR_DIR = $(shell pwd)

all: $(TARGET)

install:
    sudo rm -rf /usr/local/lib/libtest_lib.so && sudo ln -s $(CUR_DIR)/$(TARGET) /usr/local/lib/libtest_lib.so
    sudo rm -rf /usr/local/include/test_lib && sudo cp -r $(INC_FOLDER) /usr/local/include/test_lib

clean:
    rm -f $(OBJECTS) $(TARGET)

$(TARGET) : $(OBJECTS)
    $(CC) $(CFLAGS) $(OBJECTS) -o $@ $(LDFLAGS)
-include $(OBJECTS:.o=.d)

./client/main.cpp:

#include "bar.h"

int main()
{
    Bar b;

    b.sayHello();
    b.sayBye();

    return 0;
}

./client/bar.h

#ifndef __BAR__
#define __BAR__

#include <test_lib/foo.h>
#include <iostream>

struct Bar : public Foo
{
    Bar() {};
    ~Bar() {};

    void sayBye() const {
        std::cout << "Bye " << name << "..." << std::endl;
    };
};

#endif

./lib/test_lib/include/foo.h

#ifndef __FOO__
#define __FOO__

struct Foo
{
    const char *name;

    Foo(const char *name = "world");
    ~Foo();

    void sayHello() const;
};

#endif

./lib/test_lib/src

#include "foo.h"
#include <iostream>

Foo::Foo(const char *name) : name(name) {}
Foo::~Foo() {}

void Foo::sayHello() const
{
    std::cout << "Hello " << name << " !" << std::endl;
}

【问题讨论】:

  • 请发minimal reproducible example 仍然显示问题,您需要显示包含指令和文件夹结构的示例。
  • 鉴于此信息,我们情不自禁。我认为您可以自己调试。首先,找到生成的.d文件并查看它们。他们在正确的地方吗?那是针对每个srcdir/foo.c 是否有srcdir/foo.d 文件?内容看起来合理吗? .o 文件的目标名称是否正确?先决条件路径是否正确?如果这看起来不错,则运行make -d(将大量输出重定向到文件)。找到流程 make 决定重建样本.o。它会准确地告诉您哪些文件已过期。对吗?
  • @MadScientist make -d 确实在这里有所帮助。而且我了解这里发生了什么,请参阅我的编辑,实际上我每次都在重新安装库,因此它认为文件已根据其日期更改。我想我可以找到更新库的更好方法

标签: makefile


【解决方案1】:

问题是我一直在 /usr/local 中复制库头文件,因此文件变得更新,然后客户端认为库的每个头文件都已更改。

解决此问题的一个简单方法是在库 Makefile 中替换以下行:

sudo rm -rf /usr/local/include/test_lib &amp;&amp; sudo cp -r $(INC_FOLDER) /usr/local/include/test_lib

通过

sudo rm -rf /usr/local/include/test_lib &amp;&amp; sudo ln -s $(CUR_DIR)/$(INC_FOLDER) /usr/local/include/test_lib

附带说明,提供的示例缺少删除规则中的 .d 文件。

【讨论】:

    猜你喜欢
    • 2012-08-21
    • 1970-01-01
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-05-29
    • 2017-05-04
    • 1970-01-01
    • 2020-01-28
    相关资源
    最近更新 更多