2017-05-12 7 views
0

私は、次のメイクファイルを持っている:ここ延期評価

CC ?= gcc 
LD := gcc 

CFLAGS := -Wall -Wextra -Werror -Wfatal-errors 
LDFLAGS := 
LIBRARIES := m c 
INCLUDEDIRS := . 
LIBS = $(addprefix -l,$(LIBRARIES)) 
INCLUDES = $(addprefix -I,$(INCLUDEDIRS)) 

SRC := $(wildcard *.c) 
TARGET = $(TARGETDIR)/test 
OBJDIR = $(TARGETDIR)/obj/ 
OBJ = $(addprefix $(OBJDIR),$(SRC:%.c=%.c.o)) 

.SUFFIXES: 
.SUFFIXES: .c.o 

.PHONY: all debug i7avx i7avx-debug 

all: TARGETDIR := generic 
all: CFLAGS += -O3 
all: LDFLAGS += -s 
all: $(TARGET) 

debug: CFLAGS += -Og 
debug: TARGETDIR := generic/dbg 
debug: $(TARGET) 


$(OBJDIR): 
    @mkdir -p $(OBJDIR) 

$(OBJ): | $(OBJDIR) 

$(OBJDIR)%.c.o : %.c 
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o [email protected] 

$(TARGET) : $(OBJ) 
    $(LD) $(LDFLAGS) -o [email protected] $^ $(LIBS) 

特別なことは、出力ディレクトリは、ターゲットに依存していることです。 現在のところ、allとdebugのみが定義されていますが、アーキテクチャ全体をサポートし、ターゲットごとに出力ディレクトリを定義することが考えられます。

問題:これは機能しません。これを実行すると、TARGETDIR変数があまりにも遅く展開されたことを意味します。私は本当の変数と自動変数を交換する場合 、それは仕事のことを行います

$(OBJ): | $(OBJDIR) 

$(OBJDIR)%.c.o : %.c 
    $(CC) $(CFLAGS) $(INCLUDES) -c $(SRC) -o $(OBJ) 

$(TARGET) : $(OBJ) 
    $(LD) $(LDFLAGS) -o $(TARGET) $(OBJ) $(LIBS) 

このランニング:すっごく

cc -Wall -Wextra -Werror -Wfatal-errors -O3 -I. -c main.c -o generic/obj/main.c.o 
gcc -s -o generic/test generic/obj/main.c.o -lm -lc 

を、どのように私はTARGETDIRが定義された後autmatic変数を展開することができますか?

+1

このメイクファイルには、大きくて小さい問題がいくつかあります。そのため、徹底的な回答が長くなることがあります。自動変数を有効にしようとしているのですか、または期待どおりに機能していない理由を理解していますか? (それらは別の目標です)。 – Beta

+0

Makefileに批評を書いてもらえれば、私はそれに完全に気づくでしょう。理想的な答えは、実際の問題に対する解決策です。私は、1つのMakefileを使って複数の異なるフォルダで複数の異なるアーキテクチャでコンパイルできるようにしたいと考えています。私はこれがなぜ機能しないのか分かりました(ターゲットと依存関係は直ちに評価されるので、$ ^、$ @ etcetaはTARGETDIRが設定される前に設定されます)。現在私は、BashがTARGETDIR変数を設定し、makeを呼び出すMake/Bashソリューションに傾いています。 – Cheiron

答えて

0

Makeはワイルドカードを非常にうまく扱いますが、これはずっと簡単な問題です。

これはそのままですが、最適な解決策はrecursive Makeです。これに

all: $(TARGET) 

debug: $(TARGET) 

:ただ、これを変更

all debug:          
    $(MAKE) $(TARGET) TARGETDIR=$(TARGETDIR) CFLAGS+='$(CFLAGS)' LDFLAGS=$(LDFLAGS) 
0

まず、それが動作しない理由:あなたは、ターゲット固有の変数を使用しているが、それらはでのみ利用可能です

ルールの評価中ではなく、ターゲットレシピのコンテキスト(ここではマニュアルを引用しています): MakeはまずMakefileを読み、$(OBJDIR)$(TARGET)のルールを評価します(この時点では$(TARGETDIR)はまだ定義されていません)。これはallを更新しようとします。この時点で$(TARGETDIR)allのターゲット固有の値に設定します(これは2番目の例の理由ですが、毎回再構築する必要がある理由を説明しています)。

私は(私は実際にすぐに同じようなことを行う上で計画しています)あなたが何をしようとして達成するためにいくつかのヒントを持っていることがあります。

あなたがビルドごとに一つのルールを生成するためにeval関数を使用することができます/ Archiのは、次のように:

#define TARGET_RULE 
$(TARGET) : $(OBJ) 
    $$(RECIPE) 
#endif 
$(foreach TARGETDIR, $(BUILD_LIST), $(eval $(TARGET_RULE)) 

$$は、それがルールの評価時に、拡張されるのを避けるために、レシピのために必要とされる)

また、あなたがしているターゲットのためだけのルールやルールを定義することができるはずです現在ビルド中(nそれが顕著なperf違いを作り出すかどうか確かめてください)。