12

UnixプラットフォームのC++プログラマーは、Makefileを作成および管理するためにどのようなアプローチを使用しますか?

プロジェクトに手作りのMakefileを使用していましたが、ヘッダーファイルの変更やその他の依存関係を処理しません。私はグーグルで検索し、ここで良い解決策を見つけました。

しかし、私はここでsedコマンドで問題に遭遇しました-

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

問題は、3番目の式 "-e's / * \ $$ //'にあります。これは機能しません。末尾の円記号を削除することになっています。これは、の一部であるため、2ドル必要があることを理解しています。 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

gcc / g ++は、一連-Mのオプションを使用して依存関係を生成できます。.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が結果をシェルに渡す前に「$ /」を解釈しようとするため、機能しません。したがって、makefile内で "s / * \\ $$ //"(余分な$に注意)を使用する必要がありますが、これはMakeのコンテキスト外では機能しません(したがって、テストは少し面倒です)。



編集:

私はあなたのmakefileを試しましたが、そのsedステートメントは末尾のバックスラッシュをうまく削除しているようです。次のように、もっと簡単なことを試してください。

バックスラッシュ:
    @echo "\">> $ @

テスト:バックスラッシュ
    sedなしの@echo:
    @catバックスラッシュ
    @echo with 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

厳密には問題の解決策ではありませんが、私は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.cfile2.cからmy_exeが作成されます。これはもっと簡単だと思います。パッケージ検出などもあります。

find_package(Qt4)
于 2009-09-30T22:13:57.013 に答える
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.ccmain.cc依存している場合foo.h、の内容は次のMakefile.dependようになります。

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

最終結果は、からの依存関係情報がmakedepend一連のルールとしてMakefileに注入されることです。これは、ファイルごとにファイルを使用するアプローチに.d.cc似ていますが、依存関係情報をあちこちに散らばるのではなく、1つのファイルに保持します。

于 2009-10-01T13:35:54.907 に答える
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 に答える
0

プロジェクトがQtを使用していない場合でも、 qmakeを使用してプロジェクトのMakefileを生成できます。

于 2009-09-30T21:46:36.587 に答える
0

私はBSDmake(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

sedスクリプトの代わりに、gccの-MTオプションを使用して、生成された依存関係ルールのターゲットを変更します。 このブログ投稿には詳細があります。

于 2010-10-02T19:40:58.223 に答える
0

最新バージョンのGCCでは、-MPフラグを追加して、GCCにヘッダー自体の空のルールを生成させることができます。

于 2013-07-22T14:08:09.280 に答える
0

依存関係ファイルを作成するときに役立つと思ったヒントは、生成されたルールに依存関係ファイルをターゲットとして含めることです。

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

したがってmake、ソースまたはヘッダーのいずれかが変更された場合、依存関係が再生成されます。ヘッダーの偽のターゲット(GCC -MP)を含めると、ヘッダーが削除されたときに安定したビルドが可能になります。必要なヘッダーがない場合は、依存関係の作成エラーではなく、コンパイルエラーのままです。

依存関係ファイルがオブジェクトファイルと同じディレクトリに生成されると仮定すると、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 に答える