web-dev-qa-db-ja.com

オブジェクトファイルを個別のサブディレクトリに配置する方法

Makeを使用してオブジェクトファイルを別のサブディレクトリに配置しようとすると、おそらく非常に基本的な手法で問題が発生します。このページの情報を使用しようとしました: http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types

Makeから次の出力を取得します。

make: *** No rule to make target `ku.h', needed by `obj/kumain.o'.  Stop.

ただし、ku.hはターゲットではなく依存関係です(ただし、cソースファイル内には明らかに#includeされています)。オブジェクトファイルにサブディレクトリを使用しようとしない場合(つまり、OBJDIRの部分を見逃す場合)、正常に動作します。 makeがku.hをターゲットと考えるのはなぜですか?

私のメイクファイルはこれです:(スタイルはさまざまな情報源を読んだ後です)

.SUFFIXES:
.SUFFIXES: .c .o

CC=gcc 
CPPFLAGS=-Wall
LDLIBS=-lhpdf
VPATH=%.c src
VPATH=%.h src
VPATH=%.o obj
OBJDIR=obj

objects= $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
  kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
  kushapes.o )

ku : $(objects)
  $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)

$(objects) : ku.h kudefines.h kuglobals.h kufns.h | $(OBJDIR)

$(OBJDIR):
  mkdir $(OBJDIR)

.PHONY: clean
clean :
  rm $(objects)

編集:vpathディレクティブを使用するように変更を適用しました。私のバージョンは、VPATH = xxxとvpath%.c xxxがうまく混合されていませんでした。ただし、別の問題が発生します(間違ったvpathを追加する前の問題でした)。これが出力になりました。

    gcc  -o ku -lhpdf obj/kumain.o obj/kudlx.o obj/kusolvesk.o ..etc
    gcc: obj/kumain.o: No such file or directory
    gcc: obj/kudlx.o: No such file or directory
    gcc: obj/kusolvesk.o: No such file or directory
    gcc: obj/kugetpuz.o: No such file or directory
    gcc: obj/kuutils.o: No such file or directory
    gcc: obj/kurand.o: No such file or directory
    gcc: obj/kuASCboard.o: No such file or directory
    gcc: obj/kuPDFs.o: No such file or directory
    gcc: obj/kupuzstrings.o: No such file or directory
    gcc: obj/kugensud.o: No such file or directory
    gcc: obj/kushapes.o: No such file or directory
    make: *** [ku] Error 1

マニュアルでは「暗黙のルールはmakeに慣習的なテクニックの使用方法を指示しているため、使用時に詳細なルールを指定する必要はありません。たとえば、は、Cコンパイルの暗黙のルールです。ファイル名は、実行される暗黙のルールを決定します。たとえば、Cコンパイルは、通常、.cファイルを取り、.oファイルを作成します。ファイル名の末尾。」また、「VPATHで指定されたディレクトリまたはvpathで指定されたディレクトリの検索も、暗黙のルールの考慮中に行われます(「暗黙のルールの使用」を参照)。

ここでも「たとえば、ファイルfoo.oに明示的な規則がない場合、makeは、そのファイルが存在する場合にfoo.cをコンパイルする組み込み規則などの暗黙の規則を考慮します。そのようなファイルが現在のディレクトリにない場合、適切なディレクトリが検索されます。foo.cがディレクトリのいずれかに存在する(またはmakefileで言及されている)場合、Cコンパイルの暗黙のルールが適用されます。

暗黙のルールをメイクファイルで機能させるための支援は大歓迎です。

編集番号2:Jack Kellyのおかげで、.cファイルをコンパイルするための明示的なルールを作成しました。暗黙のルールを使用しようとするところがどこにもなかったからです。また、vpath情報についてal_miroに感謝します。

動作するmakfileは次のとおりです。

.SUFFIXES:
.SUFFIXES: .c .o

CC=gcc 
CPPFLAGS=-Wall
LDLIBS=-lhpdf
OBJDIR=obj
vpath %.c src
vpath %.h src

objects = $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
  kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
  kushapes.o )

ku : $(objects)
  $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)

$(OBJDIR) obj/%.o : %.c ku.h kudefines.h kuglobals.h kufns.h 
  $(CC) -c $(CPPFLAGS) $< -o $@

.PHONY : clean
clean :
  rm $(objects)
54
RussellG

GNUmakeを使用しているため、オブジェクトファイルのコンパイルにはパターンルールを使用します。

$(OBJDIR)/%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
62
Jack Kelly

これは、ほとんどのプロジェクトで使用するメイクファイルです。

ソースファイル、ヘッダー、インラインファイルをサブフォルダー、およびサブフォルダーのサブフォルダーなどに入れることができ、各オブジェクトの依存関係ファイルを自動的に生成しますこれは、ヘッダーおよびインラインファイルを変更すると、依存しているファイルの再コンパイルがトリガーされることを意味します。

ソースファイルはシェルのfindコマンドで検出されるため、明示的に指定する必要はなく、心のコンテンツにコーディングし続けるだけです。

また、プロジェクトのコンパイル時に、すべてのファイルを「リソース」フォルダーからbinフォルダーにコピーします。これはほとんどの場合便利です。

クレジットを提供するために、自動依存機能は主にScott McPeakのページに基づいていました。このページは [〜#〜] here [〜#〜] であり、いくつかの追加の修正/調整があります私のニーズ。

Makefileの例

#Compiler and Linker
CC          := g++-mp-4.7

#The Target Binary Program
TARGET      := program

#The Directories, Source, Includes, Objects, Binary and Resources
SRCDIR      := src
INCDIR      := inc
BUILDDIR    := obj
TARGETDIR   := bin
RESDIR      := res
SRCEXT      := cpp
DEPEXT      := d
OBJEXT      := o

#Flags, Libraries and Includes
CFLAGS      := -fopenmp -Wall -O3 -g
LIB         := -fopenmp -lm -larmadillo
INC         := -I$(INCDIR) -I/usr/local/include
INCDEP      := -I$(INCDIR)

#---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
SOURCES     := $(Shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS     := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))

#Defauilt Make
all: resources $(TARGET)

#Remake
remake: cleaner all

#Copy Resources from Resources Directory to Target Directory
resources: directories
    @cp $(RESDIR)/* $(TARGETDIR)/

#Make the Directories
directories:
    @mkdir -p $(TARGETDIR)
    @mkdir -p $(BUILDDIR)

#Clean only Objecst
clean:
    @$(RM) -rf $(BUILDDIR)

#Full Clean, Objects and Binaries
cleaner: clean
    @$(RM) -rf $(TARGETDIR)

#Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))

#Link
$(TARGET): $(OBJECTS)
    $(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIB)

#Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
    @mkdir -p $(dir $@)
    $(CC) $(CFLAGS) $(INC) -c -o $@ $<
    @$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
    @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
    @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
    @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
    @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp

#Non-File Targets
.PHONY: all remake clean cleaner resources
47

VPATH行が間違っています。

vpath %.c  src
vpath %.h  src

つまり、資本ではなく、=がありません。現在のところ、.hファイルは見つからず、作成するターゲットであると考えています。

23
al_miro

一般に、$(OBJDIR)にファイルを配置するすべてのルールの左側で$(OBJDIR)を指定するか、$(OBJDIR)からmakeを実行する必要があります。 VPATHはソース用であり、オブジェクト用ではありません。

詳細については、これらの2つのリンクと、「賢い」回避策をご覧ください。

5
Theo Belaire

私は組み込みのルールが大好きなので、私の意見では次の解決策はナイスではありません。ただし、GNU makeは出力ディレクトリに対してvpathのようなものをサポートしていません。また、組み込みルールは、_%_の_%.o_のように一致できません_obj/foo_の_obj/foo.o_に一致し、makeを_vpath %.c src/_で検索し、_src/obj/foo.c_を検索しますが、_src/foo.c_は検索しません。

しかし、これはあなたが得ることができる組み込みのルールに近いため、私の知る限りでは利用可能な最も素晴らしいソリューションです。

_$(OBJDIR)/%.o: %.c
        $(COMPILE.c) $(OUTPUT_OPTION) $<
_

説明:$(COMPILE.c) $(OUTPUT_OPTION) $<は実際に_.c.o_の実装方法です。 http://git.savannah.gnu.org/cgit/make.git/tree/defaultを参照してください。 c (およびマニュアルにも記載されています)

さらに、$(OBJDIR)に自動生成されたファイルのみが含まれる場合は、順序のみの前提条件でオンザフライで作成し、クリーンルールをわずかに単純化できます。

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

$(OBJDIR)/%.o: %.c | $(OBJDIR)
        $(COMPILE.c) $(OUTPUT_OPTION) $<

.PHONY: clean
clean:
        $(RM) -r $(OBJDIR)
_

これには、機能order-onlyが利用可能である必要があり、$(filter order-only, $(.FETAURES))を使用して確認できます。 Kubuntu 14.04 GNU make 3.81およびOpenSUSE 13.1 GNU make 3.82。両方ともorder- onlyが有効になっているため、Kubuntu 14.04に古いバージョンのGNU OpenSUSE 13.1。よりもmakeが付属しているのはなぜか、make 4.1を今すぐダウンロードします:)

2
Christian Hujer

暗黙のルール(およびGNU MAKE)で作業するすべての人のために、異なるディレクトリをサポートする簡単なmakefileを以下に示します。

#Start of the makefile

VPATH = ./src:./header:./objects

OUTPUT_OPTION = -o objects/$@

CXXFLAGS += -Wall -g -I./header

Target = $(notdir $(CURDIR)).exe

Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))



all: $(Target)

$(Target): $(Objects)
     $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))


#Beware of -f. It skips any confirmation/errors (e.g. file does not exist)

.PHONY: clean
clean:
     rm -f $(addprefix objects/,$(Objects)) $(Target)

よく見てみましょう(curdirで現在のディレクトリを参照します):

この行は、curdir/srcにある使用済み.oファイルのリストを取得するために使用されます。

Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))
#expands to "foo.o myfoo.o otherfoo.o"

変数を介して、出力は別のディレクトリ(curdir/objects)に設定されます。

OUTPUT_OPTION = -o objects/$@
#OUTPUT_OPTION will insert the -o flag into the implicit rules

コンパイラーが新しいオブジェクトフォルダー内のオブジェクトを確実に見つけるために、パスがファイル名に追加されます。

$(Target): $(Objects)
     $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))
#                                    ^^^^^^^^^^^^^^^^^^^^    

これは一例であり、間違いなく改善の余地があります。

追加情報については、以下を参照してください。 文書化。10.2章を参照

または: Oracle:プログラミングユーティリティガイド

1
A. Frank