web-dev-qa-db-ja.com

パスインクルードとsrcディレクトリのメイクファイル

このチュートリアルに従う:

http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/

3つのファイルがあり、そのうち2つは.cファイル、1つは.hファイルです。チュートリアルはメイクファイルの設定に関するもので、最初のいくつかの手順が機能しています。最後のステップでは、.hファイルと.cファイルのディレクトリパスを設定します。 .cファイルをsrcファイルに入れ、.hファイルをインクルードファイルに入れました。

この/home/bob/testcode/src <-.cファイルが含まれているように見えます。

そして、/home/bob/testcode/include <-.hファイルを含みます。

コード:

IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)

ODIR=obj
LDIR =../lib

_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))

_OBJ = hellomake.o hellofunc.o 
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))


$(ODIR)/%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

hellomake: $(OBJ)
    gcc -o $@ $^ $(CFLAGS)

.PHONY: clean

clean:
    rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ 

それがどのように機能するかを理解し、それを私が使用しているライブラリで使用したいと思います。誰かがこのコードを設定する方法を教えてもらえますか? "/home/bob/testcode/include/" w /およびw/o "および/として多くのオプションを試しましたが、まだ機能しません。

目標は、60を超えるヘッダーファイルと30のソースファイルを含むライブラリを操作することです。これらのファイルから1つのメインを実行する必要があるため、この基本的なmakefileを機能させて、拡張できるようにする必要があります。

一般的な問題は、これらの行が開いたままになっていることです。

IDIR =../include
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))

そして

OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))

さまざまなパスの代替を試しましたが、生成されるエラーは次のようになります。

gcc -o hellomake  -I../include
gcc: fatal error: no input files
compilation terminated.
make: *** [hellomake] Error 4

よろしくお願いします。

10
iBeyondPower

あなたのチュートリアルは悪い習慣を助長します、あなたはそれを私見で避けるべきです。

ここであなたのルールで:

_$(ODIR)/%.o: %.c $(DEPS)
_

ソースファイルがsrcディレクトリにある間、makeに現在のディレクトリを調べるように指示しているため、このパターンは使用されず、適切なパターンがありません。


プロジェクトディレクトリを次のように整理してください。

_+ include/
|-- all .h files here
+ lib/
|-- all thirdparty library files (.a files) here
+ obj/
|-- all .o files will be placed here
+ src/
|-- all .c files here
+ Makefile
_

次に、グッドプラクティスを使用して、プロセスを段階的に実行していきましょう。

まず、必要がない場合は何も定義しないでください。 Makeには、手動で実行する前に使用する必要のある事前定義された変数と関数が多数あります。実際、彼には非常に多くの機能があるため、ディレクトリにMakefileがまったくなくても、単純なプロジェクトをコンパイルできます。

  1. 最終的なターゲット、つまり実行可能ファイルに名前を付けます。

    _EXE = hellomake
    _
  2. ソースとビルドの出力ディレクトリを一覧表示します。

    _SRC_DIR = src
    OBJ_DIR = obj
    _
  3. ソースファイルを一覧表示します。

    _SRC = $(wildcard $(SRC_DIR)/*.c)
    _
  4. ソースファイルから、オブジェクトファイルを一覧表示します。

    _OBJ = $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) # patsubst is far less readable
    # You can also do it like that
    OBJ = $(addprefix $(OBJ_DIR)/, $(notdir $(SRC)))
    _
  5. 渡すプリプロセッサフ​​ラグをいくつか取得しましたか?続ける。

    _CPPFLAGS += -Iinclude # -I is a preprocessor flag, not a compiler flag
    _
  6. 追加するコンパイラフラグがありますか?どうぞ。

    _CFLAGS += -Wall # some warnings about bad code
    _
  7. いくつかのリンカーフラグを取得しましたか?

    _LDFLAGS += -Llib # -L is a linker flag
    _
  8. リンクするサードパーティのライブラリを入手しましたか?

    _LDLIBS += -lm # Left empty if no libs are needed
    _

さて、変数が正しく入力されたので、いくつかのレシピをロールバックします。

デフォルトのターゲットはallと呼ばれるべきであることが広く知られています。簡単にするために、これはMakefileの最初のターゲットであり、その前提条件は、コマンドラインでmakeを書き込むときに作成するターゲットです。

_all: $(EXE)
_

次に、実行可能ファイルをビルドするための前提条件をリストし、そのレシピを入力して、これらをどのように処理するかを指示します。

_$(EXE): $(OBJ)
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
_

いくつかの簡単なメモ:

  • $(CC)は、Cでコンパイルおよびリンクするときに必要なものがすでに含まれている組み込み変数です。
  • リンカエラーを回避するには、shouldput $(LDFLAGS)beforeオブジェクトファイルと$(LDLIBS)
  • $(CPPFLAGS)$(CFLAGS)役に立たないここで、コンパイルフェーズはすでに終了しています。ここではリンクフェーズです。

次のステップでは、ソースファイルとオブジェクトファイルが同じプレフィックスを共有していないため、組み込みのルールが特定のケースをカバーしていないため、makeに正確に何をするかを指示する必要があります。

_$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
_

さて、実行可能ファイルはうまくビルドされるはずです。必要に応じてビルドディレクトリをクリーンアップできます。

_clean:
    $(RM) $(OBJ)
_

最後のもの。ルールが_.PHONY_特別ルールを使用してターゲット出力を生成しない場合は常に指定する必要があります。

_.PHONY: all clean
_

最終結果:

_EXE = hellomake

SRC_DIR = src
OBJ_DIR = obj

SRC = $(wildcard $(SRC_DIR)/*.c)
OBJ = $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

CPPFLAGS += -Iinclude
CFLAGS += -Wall
LDFLAGS += -Llib
LDLIBS += -lm

.PHONY: all clean

all: $(EXE)

$(EXE): $(OBJ)
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

clean:
    $(RM) $(OBJ)
_
35
Chnossos

特定の「ターゲット」がないmakeユーティリティは、ファイルの最初のターゲットを作成します。

最初のターゲットは通常「all」という名前です

投稿されたファイルの場合、オブジェクトファイルを作成し、コマンドラインでターゲットが指定されていない場合は実行可能ファイルを作成し続けません

次のことを提案します。

Shell := /bin/sh

# following so could define executable name on command line
# using the '-D' parameter
#ifndef $(NAME)
    NAME := hellomake
#endif

# use ':=' so macros only evaluated once


MAKE    :=  /usr/bin/make
CC      :=  /usr/bin/gcc

CFLAGS  := -g -Wall -Wextra -pedantic
LFLAGS  :=

ODIR    := obj
IDIR    := ../include
LIBS    :=
LIBPATH := ../lib

DEPS    := $(wildcard $(IDIR)/*.h)
SRCS    := $(wildcard *.c)
OBJS    := $(SRCS:.c=.o)

.PHONY: all
all: $(NAME) $(OBJS)

$(ODIR)/%.o: %.c $(DEPS)
    $(CC) $(CFLAGS) -c -o $@ $< -I$(DEPS)

$(NAME): $(OBJS)
    $(CC) $(LFLAGS) -o $@ $^ -L$(LIBPATH) -l$(LIBS)

.PHONY: clean
clean:
    rm -f $(ODIR)/*.o
    rm -f $(NAME)


however, in your proposed project,
not every source file needs every header file
so should use either gcc or sed to generate the dependency files
then use makefile rules similar to the following,
which may need a little 'tweaking' for your project
because the include files are not in the same directory
as the source files:

DEP := $(SRCS:.c=.d)

#
#create dependency files
#
%.d: %.c 
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========

# 
# compile the .c files into .o files using the compiler flags
#
%.o: %.c %.d 
     # 
     # ========= START $< TO $@ =========
     $(CC) $(CCFLAGS) -c $< -o $@ -I$(IDIR) 
     # ========= END $< TO $@ =========
     # 

# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependencies for that .c file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
0
user3629249

単純なMakefile定義は、あなたの質問にあるように私には問題ないようです。ファイル名の前にコンパイラオプションを指定してみてください。

$(ODIR)/%.o: %.c $(DEPS)
    $(CC) $(CFLAGS) -c -o $@ $<

hellomake: $(OBJ)
    gcc $(CFLAGS) -o $@ $^

ソースディレクトリからmakeを実行する必要があります。

0
chqrlie