21

includeディレクティブを特定のターゲットにのみ使用したい。makefileが不必要に生成されることを意味するため、ターゲットが不要なときに他のmakefileを実行したくありません。

では、ターゲットを条件とするincludeディレクティブを条件付きで使用する方法はありますか?または、どういうわけか、includeディレクティブをターゲットの前提条件にします。

これが私がこれまでに持っているものです:

# Flags

INCDIR = $(CURDIR)/include
CFLAGS = -Wall -Wno-overflow -Wno-uninitialized -pedantic -std=c99 -I$(INCDIR) -O3
LFLAGS = -flat_namespace -dynamiclib -undefined dynamic_lookup

# Directory names

# Set vpath search paths

vpath %.h include
vpath %.c src
vpath %.o build
vpath %.d build

# Get files for the core library

CORE_FILES = $(wildcard src/*.c)
CORE_OBJS = $(patsubst src/%.c, build/%.o, $(CORE_FILES))
CORE_DEPS = $(CORE_OBJS:.o=.d)

# Core library target linking

core : $(CORE_OBJS) | bin
    $(CC) $(LFLAGS) -o bin/libcbitcoin.2.0.dylib $(CORE_OBJS)

# Include header prerequisites (How to do only for "core" target?)

include $(CORE_DEPS)

# Makefiles for header dependencies. 

$(CORE_DEPS): build/%.d: src/%.c | build
    rm -f $@; \
    $(CC) -I$(INCDIR) -MM $< -MT '$(@:.d=.o) $@' > $@

# Objects depend on directory

$(CORE_OBS) : | build

# Create build directory

build:
    mkdir build

# Create bin directory

bin:
    mkdir bin

# Core Compilation

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@

# Depencies require include/CBDependencies.h as a prerequisite

build/CBOpenSSLCrypto.o: include/CBDependencies.h

# Crypto library target linking

crypto : build/CBOpenSSLCrypto.o -lcrypto -lssl | bin
    $(CC) $(LFLAGS) -o bin/libcbitcoin-crypto.2.0.dylib build/CBOpenSSLCrypto.o -lcrypto -lssl

# Crypto library compile

build/CBOpenSSLCrypto.o: dependencies/crypto/CBOpenSSLCrypto.c
    $(CC) -c $(CFLAGS) $< -o $@

#Clean

clean:
    rm -f $(CORE_OBJS) $(CORE_DEPS) build/CBOpenSSLCrypto.o

「crypto」には「.d」ファイルを含める必要はありませんが、「core」(デフォルトの目標)には含める必要があります。

助けてくれてありがとう。

4

3 に答える 3

19

Makeは手続き型言語ではないので、それを穀物に反するものとして扱う。makefileのスケーリングは難しく、微妙なバグにつながる可能性があります。

クリーンで効率的でスケーラブルなTomTromeyによるより良い方法があります。秘訣は、オブジェクトファイルと同じ手順で依存関係ファイルを作成できることを理解することです。依存関係は、オブジェクトがいつ再構築されるかをMakeに通知するだけです。Makeはオブジェクトをビルドする必要があることを認識しているため、最初にオブジェクトをビルドするときにそれらは必要ありません。また、依存関係が変更された場合、それはソース内の何かまたは古い依存関係が変更されたことが原因である可能性があるため、Makeはオブジェクトを再構築する必要があることを再度認識します。(これは明らかではないので、少し混乱する可能性があります。)

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM -MF build/$*.d $<

-include build/*.d

もう1つ問題があります。依存関係を削除するようにコードを変更し、そのファイルも削除すると、古い依存関係リストが引き続き見つからないファイルを要求するため、再構築できなくなります。 。洗練されたソリューションは、依存関係ファイルを処理して、各前提条件(ヘッダーなど)をコマンドなしでそれ自体でターゲットにし、必要なときに再構築されると想定できるようにすることです。

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM -MF build/$*.d $<
    @cp build/$*.d build/$*.P
    @sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
            -e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d;
    @rm build/$*.P

より大雑把な方法ですが、ほぼ確実に、ヘッダーとソースにキャッチオールルールを設定することです。

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM -MF build/$*.d $<

%.cc %.h:

編集:

新しいコマンドを分解するには:

このオプションは、前処理やコンパイルではなく、オブジェクトファイルのルール-MMを生成するようにgccに指示します。makeデフォルトでは、前処理された出力を送信する場所にルールを送信します。これは通常、stdoutです。

とともに使用される-MFオプションは-MM、出力ファイルを指定します。だから-MM -MF build/$*.d私たちが望むところにルールを置きます。

したがって、次の2つのコマンドは(ほとんどの場合)同等です。

    $(CC) -MM -MF build/$*.d $<

    $(CC) -MM $< > build/$*.d

(どちらも少し複雑になり、実際には問題のポイントではないため、オプション-I$(...)を使用する可能性を省略しました。)-MMD

于 2012-11-18T15:26:12.487 に答える
3

MAKECMDGOALSを使用できます。

ifeq (core,$(MAKECMDGOALS))
include $(CORE_DEPS)
endif

もちろん、ifneq (,$(findstring core,$(MAKECMDGOALS)))複数のターゲットの可能性がある場合に使用できます。

注:これは「迅速で汚い」解決策です。これを一般的な方法にすべきではないというベータ版に同意します(多くのmakefileで実行すると、これは厄介になる可能性があります...)。

ジョン

于 2012-11-17T23:16:33.603 に答える
1

良い答えが何であるかについてのガイドラインを破るのは仕方がありません。

元の質問に対する私の答えは私の意見です。ターゲットに依存するルールを含めることはできません。すべてのルールは、ターゲットが考慮される前に処理されます。これはmakeの制限です(私は推測します)。繰り返しになりますが、良い点はMAKECMDGOALSですが、これはmakeユーティリティ自体の単なるハックではありませんか?

ベータ版からの回答は合理的で正統なものですが、それが最善の方法であったとしても、それをクリーンとは言えません。makeが以前に特定のターゲットを処理したことがなく、適切なbuild/*。d依存関係ファイルがそこにない場合は機能しません。

于 2012-12-02T12:55:45.610 に答える