13

要するに、さまざまなディレクトリからソースをコンパイルし、オブジェクト ファイルを現在のディレクトリに配置したいと考えています。

たとえば、次のファイルがあります。

test.c
../../lib1/boot.c
../../lib2/startup.c
../common/utils.c

(いくつかのファイル .s (アセンブリ) と .cpp もありますが、これが重要でないことを願っています)。

現在のディレクトリに配置したいすべてのオブジェクトファイル:

test.o
boot.o
startup.o
utils.o

そして、そのようなルールをメイクファイルに記述する方法がわかりません。

例えば、

%o.: %.c

からmake構築するルールが見つからないため、現在は機能しません。構築するルールのみを見つけることができます。boot.o../../lib1/boot.c../../lib1/boot.o../../lib1/boot.c

私はこれを使用しようとしました:

%o.: %.c
 (my compilation line, for example "gcc -c $^ -o $@")
%o.: ../../lib1/%.c
 (my compilation line)
%o.: ../../lib2/%.c
 (my compilation line)
%o.: ../common/%.c
 (my compilation line)

そしてそれは動作します。しかし、明らかにこれは十分に一般的ではありません。また、今日、何人かのユーザーが私のところに来て、彼のアプリケーションにもいくつかの があると言いまし../../some_other_lib/common_things.cた。私たちのプロジェクトを調べたところ、さまざまなディレクトリが関係しているような多くのケースが見つかりました。私のアプローチでは、同じコンパイル行を使用して、そのようなディレクトリごとに個別のルールを作成する必要があります。これは私には良くないようです。

だから私の質問は、異なるディレクトリのソースを操作しながら、オブジェクトファイルを現在のディレクトリに置く(そしてチェックする)一般的なコンパイルルールを作成する方法ですか?

ありがとうございました。

4

3 に答える 3

9

CSRCディレクトリは変数から抽出$(dir ...)でき、このリストはvpathディレクティブで使用できます。

vpath %.c $(sort $(dir $(CSRC)))
vpath %.s $(sort $(dir $(SSRC)))
vpath %.cpp $(sort $(dir $(CPPSRC)))

(重複を削除する関数を投入しましたsortが、これは絶対に必要というわけではありません。)

これで、ルールを単純に保つことができmake、ディレクトリのリストでソース ファイルを検索します。

$(COBJ) := $(notdir $(CSRC))
$(SOBJ) := $(notdir $(SSRC))
$(CPPOBJ) := $(notdir $(CPPSRC))

.PHONY: all
all: $(EXECUTABLE)

$(EXECUTABLE): $(COBJ) $(SOBJ) $(CPPOBJ)
    ....

$(COBJ): %.o: %.c
    ...

$(SOBJ): %.o: %.s
    ...

$(CPPOBJ): %.o: %.cpp
    ...
于 2013-03-12T11:41:05.520 に答える
7

makefile関数notdirを次のように使用してみてください。

%.o:    %.c
    gcc -c $< -o $(notdir $@)

$@フルパスと同じである必要があります。例:../../lib2/startup.oadnotdirはそれを次の場所にトランクしますstartup.o

このルールを使用すると、現在のディレクトリにあるすべてのソースをコンパイルできます。

実際、あなたの例は次のようなものです。

.
└── common
    ├── lib1
    │   └── boot.c
    ├── lib2
    │   └── startup.c
    ├── test
    │   ├── Makefile
    │   └── test.c
    └── utils.c

私はそのように良くなると思います:

.
├── common
│   ├── lib1
│   │   ├── Makefile
│   │   ├── obj
│   │   └── src
│   │       └── boot.c
│   ├── lib2
│   │   ├── Makefile
│   │   ├── obj
│   │   └── src
│   │       └── startup.c
│   ├── Makefile
│   ├── obj
│   ├── src
│   │   └── utils.c
│   └── test
│       ├── Makefile
│       ├── obj
│       └── src
│           └── test.c
└── Makefile

そのためには、サブディレクトリMakefilesを呼び出すためにすべてのMakefileが必要です。src/ dirsは、objソースとオブジェクトを分離したものです。

SRC := utils.c

OBJ := $(SRC:%.c=%.o)

NAME := project

SRC_D := src
OBJ_D := obj

SUBDIRS := lib1/ \
           lib2/ \
           test/

all: $(NAME) $(SUBDIRS)
    @for dir in $(SUBDIRS); \
    do \
    $(MAKE) -C $$dir; \
    done

$(NAME):    $(OBJ:%.o=$(OBJ_D)/%.o)

$(OBJ_D)/%.o :  $(SRC_D)/%.c
    gcc -c $< -o $@
于 2013-03-11T15:08:10.743 に答える
2

OK、少し時間がかかりましたが、最終的に解決策を見つけました (ちなみに、このサイトのいくつかのスレッドを使用しています):

# Defining compilation rules in a way that object files will be produced in current directory, and not in the directory of source files:
all: <List of my targets>

define my_c_rule
$(subst .c,.o,$(notdir $(1))): $(1)
    $(CC) $(CFLAGS) $(CDEFINES) $$^ -o $$@
endef
$(foreach f, $(CSRC), $(eval $(call my_c_rule, $(f))))

$(CSRC)ソースファイルとそのパスのリストが含まれています。

以前に次のようなものがあった場合、それを考慮する必要があります。

.c.o:
    $(CC) $(CFLAGS) $(CDEFINES) $^ -o $@

all: <List of my targets>

...ここで、手順allで説明したルールの上に文を追加する必要があります。my_c_ruleこれを行わないと、make最初のソース ファイルをコンパイルした後で停止します。これは、古い「ワイルドカード」ルールがデフォルトのターゲットとして置き換えられない.c.oか(以前に作成された場合でも)、ワイルドカード以外のルール(上記のマクロの結果) が以前に作成された場合にデフォルトのターゲットを置き換えるためです。%.o: %.callboot.o: ../../lib1/boot.c

于 2013-03-11T17:43:48.410 に答える