12

Unix 平台上的 C++ 程序员使用什么方法来创建和管理 Makefile?

我为我的项目使用了手工制作的 Makefile,但它们不处理头文件更改和其他依赖项。我用谷歌搜索并在这里找到了一个很好的解决方案。

但是我在 sed 命令中遇到了一个问题-

    sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
        -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \

问题在于第三个表达式“-e's/ *\$$//'。它不起作用。它应该删除尾随反斜杠。我知道那里必须有双美元,因为这是Makefile 有人能告诉我这里有什么问题吗?

这是完整的 Makefile -

CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread

OBJS=file1.o file2.o
TARGET=testProg

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

%.o : %.cpp
        $(CC) -MMD -c -o $@ $< $(CFLAGS)
        @cp $*.d $*.P; \
            sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
                -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
            rm -f $*.d

-include $(OBJS:%.o=%.P)

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

all : $(TARGET)

除了这个问题的解决方案,我还想要一些提示/指向我的第一个问题。

4

12 回答 12

25

-Mgcc/g++ 可以通过一系列选项为您生成依赖项。以下通过指定如何在.depends给定源文件的情况下生成文件来工作。通过这样做-include $(DEPS)$(DEPS) 被识别为一个目标,并将在源文件更改时构建/重建。

CXX      = g++
CXXFLAGS = -Wall -O3
LDFLAGS  =

TARGET = testcpp
SRCS   = main.cc x.cc foo.cc
OBJS   = $(SRCS:.cc=.o)
DEPS   = $(SRCS:.cc=.depends)


.PHONY: clean all

all: $(TARGET)

$(TARGET): $(OBJS)
        $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)

.cc.o:
        $(CXX) $(CXXFLAGS) -c $< -o $@

%.depends: %.cc
        $(CXX) -M $(CXXFLAGS) $< > $@

clean:
        rm -f $(OBJS) $(DEPS) $(TARGET)

-include $(DEPS)
于 2009-10-02T16:35:58.087 回答
8
  1. 我也使用这种方法,不能高度赞扬它。我手工编写我的 makefile,并在新项目中大量重复使用它们。
  2. . 表达式 "s/ *\\$//" 将在 Make 的上下文之外工作。在 makefile 中它不起作用,因为 Make 在将结果交给 shell 之前会尝试解释 "$/"。所以你必须在makefile中使用“s/ *\\$$//”(注意额外的$),但这在Make的上下文之外不起作用(所以测试它有点痛苦)。



编辑:

我已经尝试过你的 makefile,并且 sed 语句似乎可以很好地删除尾随反斜杠。尝试一些更简单的方法,如下所示:

反斜杠:
    @echo " \\" > $@

测试:反斜杠
    @echo 没有 sed:
    @cat 反斜杠
    @echo 与 sed:
    @sed -e 's/ *\\$$//' < 反斜杠



编辑: 好的,现在我上瘾了。你能尝试这些实验并告诉我们结果吗?

将最后一个字符更改为 'z' : s/.$/z/
将尾部反斜杠更改为 'z' : s/\\$/z/
将尾部反斜杠更改为 'z' : sm\\$mzm
删除尾部反斜杠:s/\\$//
删除空格和尾部反斜杠:s/ *\\$//
使用“$”和“$$”在 Make 内部和外部尝试所有这些。
于 2009-09-30T21:50:43.747 回答
3

在 make 文件中,您在依赖项行上列出的任何内容都是依赖项头文件或包含的其他文件。

关于 make 的 BSD 教程 注意:您可以使用 GCC 的 -MM 开关自动生成头文件依赖信息。

于 2009-09-30T21:22:29.370 回答
2

我肯定错过了什么。为什么生成依赖文件对您不起作用?

于 2009-10-01T13:06:16.717 回答
1

在 Mozilla 的构建系统中,我们使用 GCC 的 -MD 开关来生成依赖文件: http : //mxr.mozilla.org/mozilla-central/source/configure.in#7134 然后我们使用名为 mddepend.pl 的脚本来检查对于删除的头文件,这样删除头只会导致重建,而不是错误: http: //mxr.mozilla.org/mozilla-central/source/config/rules.mk#2066 http://mxr.mozilla。 org/mozilla-central/source/build/unix/mddepend.pl

该脚本会生成一个包含所有依赖项的 .all.pp 文件,并foo.o: FORCE会因缺少的头文件而陷入额外的依赖项。然后,我们只需在下面的 rules.mk 中包含 .all.pp 文件。

于 2009-10-01T19:58:14.287 回答
1

makedepend实用程序安装在许多系统上,对于生成依赖关系信息非常有用。

下面是一个使用include指令(加上一点 Perl 魔法)来合并 makedepend 输出的 Makefile 示例:

# the name of the executable that we'll build
TARGET = foo_prog
# our .cc source files
SRCS = foo.cc main.cc

# the .o versions of our source files
OBJS := $(patsubst %.cc, %.o, $(filter %.cc, $(SRCS)))
# some flags for compiling
CXXFLAGS = -Wall -Werror

# In order to build $(TARGET), we first build each of the $(OBJS).
# Then we use the given command to link those $(OBJS) into our
# $(TARGET) executable.  $^ is a shortcut for $(OBJS).  $@ is a
# shortcut for $(TARGET).
#
# The default compile rule will compile each of the $(OBJS) for us.
$(TARGET): $(OBJS)
        $(CXX) $(CXXFLAGS) $^ -o $@

# Use "make clean" to remove all of the support files.
clean:
        rm -f $(OBJS) $(TARGET) Makefile.depend *~

# This automatically uses the 'makedepend' utility to add any
# dependencies that our source files have, namely .h files.  This way,
# if the .h files change, the code will be re-compiled.
include Makefile.depend
Makefile.depend: $(SRCS)
        makedepend -f- -Y $(SRCS) 2> /dev/null | \
        perl -p -e "s/(^.*?:)/Makefile.depend \1/" > Makefile.depend

如果两者都foo.cc依赖main.ccfoo.h,那么 的内容Makefile.depend将是:

Makefile.depend foo.o: foo.h
Makefile.depend main.o: foo.h

最终的结果是依赖信息 frommakedepend被作为一系列规则注入到 Makefile 中。它类似于为每个文件使用一个文件的方法.d.cc,但将依赖信息保存在一个文件中,而不是分散在各处。

于 2009-10-01T13:35:54.907 回答
1

我更喜欢使用 CMake,即使严格来说它并不是解决问题的方法。

它是一种项目描述语言,可为您生成 Makefile、Visual Studio 项目、Eclipse 项目、KDevelop 等。所有依赖项都为您完成:

CMakeLists.txt

add_executable(my_exe file1.c file2.c)
target_link_libraries(my_exe my_library)
add_subdirectory(lib)

在 lib/CMakeLists.txt

add_library(my_library file3.c file4.c)

这会从链接到 my_library 的 file1.c file2.c 创建一个 my_exe。我觉得这要简单得多。它还具有包发现之类的功能:

find_package(Qt4)
于 2009-09-30T22:13:57.013 回答
0

代替 sed 脚本,使用 gcc 的 -MT 选项来修改生成的依赖规则的目标。 这篇博文有更多信息。

于 2010-10-02T19:40:58.223 回答
0

我使用 BSD make (pmake?),它为我做了很多工作(我的语言是 C,但我认为这里没有区别)。这是我常见的“local.prog.mk”,我从不改变它:

.PHONY: tags .depend

# .depend depends only on $(SRCS) in bsd.dep.mk, so we can't track changes of
# header's own dependencies properly. so .depend is .PHONY target here.

CSTD    ?=c99
WARNS   ?=9
.if !empty(PC_LIST)
PC_CF   !=pkg-config --cflags $(PC_LIST)
PC_LD   !=pkg-config --libs   $(PC_LIST)
.endif
CFLAGS  +=$(PC_CF) -fgnu89-inline
.if !defined(NO_DEBUG)
CFLAGS  +=-O0 -ggdb3
.endif
LDFLAGS +=$(PC_LD)
CTAGS   =exctags

NO_MAN=
NO_OBJ=
CLEANFILES+=$(PROG).core

.include <bsd.prog.mk>
$(PROG): $(SUBDIR)
build: clean cleandepend depend all
run: $(PROG)
    ./$(PROG)

注意“bsd.prog.mk”包含——它处理所有、构建、依赖、清理目标。项目特定BSDmakefile的很简单:

.SILENT:

PROG    =hello
SRCS    =hello.c world.c
PC_LIST =gtk+-2.0 gnet-2.0

.include "../local.prog.mk"

proto:
    cproto -siv `pkg-config --cflags $(PC_LIST)` $(SRCS) > prototypes
CLEANFILES+=prototypes

每次插入/删除任何#include 指令时,我都会依赖。

于 2009-09-30T22:48:02.937 回答
0

您可以使用qmake为项目生成 Makefile,即使该项目未使用 Qt。

于 2009-09-30T21:46:36.587 回答
0

使用更现代的 GCC 版本,您可以添加 -MP 标志让 GCC 为标头本身生成空规则。

于 2013-07-22T14:08:09.280 回答
0

我发现在构建依赖文件时有用的重要提示是将依赖文件作为目标包含在生成的规则中:

file.d file.o : file.c header.h header2.h ...

因此make,如果源或任何标头发生更改,将重新生成依赖项。包括头文件的虚假目标(GCC -MP)应该允许在删除头文件时稳定构建 - 缺少所需的头文件仍然是编译错误,而不是 make 依赖错误。

假设依赖文件生成到与目标文件相同的目录中,以下内容应该适用于 Unix 上的 GCC:

-include $(OBJ:.o=.d)

$(OBJDIR)/%d : $(SRCDIR)/%.cpp
        mkdir -p $(@D)
        echo -n "$@ " > $@.tmp
        $(CXX) $(CPPFLAGS) -MM -MP -MT $(@:.d=.o) $< >> $@.tmp
        mv $@.tmp $@

(从记忆里)

于 2017-03-30T14:07:26.727 回答