makefileが作成された後でアイデアを作成するという、トップレベルの再帰的なmakefileを1つ作成しようとしています。プロジェクト。GNU同じ名前の他のファイルを見たときにソースファイルを再利用するようにする
同じ名前のファイルがありますが、別のディレクトリにある場合、GNU makeは最初のディレクトリの.cppファイルを使用し、残りのビルド全体でリンカが実行される生成される.oファイルはすべて同じソースファイルに基づいているため、関数の複数の定義について不平を言います。
私が参照しているコードは私の実際のプロジェクトのコードではありませんが、私の主なプロジェクトをビルドしようとしているのと同じ問題があります。ソースコードがサブディレクトリにあるトップレベルディレクトリのレイアウトを次に示します。 "こんにちは" ハロー/ HELLO.CPPプリントと世界/ HELLO.CPP版画 "世界!!" -
[email protected]:~/work/temp/maketest$ tree
.
├── exec
│ └── main.cpp
├── hello
│ ├── hello.cpp
│ └── hello.h
├── makefile
└── world
├── hello.cpp
└── hello.h
この例は非常に簡単です。 main.cppは "HelloWorld !!"を印刷するために各関数を呼び出します。
ここに各ファイルがあります。
のexec/main.cppに
#include <iostream>
#include "../hello/hello.h"
#include "../world/hello.h"
int main()
{
print_hello();
print_world();
return 0;
}
ハロー/ HELLO.CPP
#include "hello.h"
void print_hello()
{
std::cout << "Hello";
}
世界/ HELLO.CPPここ
#include "hello.h"
void print_world()
{
std::cout << "World!!\n";
}
は私のメイクです
#Specify modules to include in the build - corresponds to source code locations.
MODULES := exec \
world \
hello
CXX := g++
RM := rm -rf
#Create a list of the source directories
SRC_DIR := $(addprefix ./,$(MODULES))
#Create a variable for the build output directory
BUILD_DIR := $(addprefix ./build/,$(MODULES))
#C++ Compiler flags
CPPFLAGS := -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c
#Flags for generating dependency files.
DEPFLAGS := -MMD -MP -MT "[email protected]" -MF "$$(@:%.o=%.d)"
#Creates a list of all the source files that we wish to include in the build
CPP_SRCS := $(foreach sdir, $(SRC_DIR), $(wildcard $(sdir)/*.cpp))
#Creates a list of all the object files that we need to build based off source files
OBJ_TARGET := $(foreach sdir, $(MODULES), $(wildcard $(sdir)/*.cpp))
OBJS := $(patsubst %.cpp, ./build/%.o, $(OBJ_TARGET))
#Specify directories to search
vpath %.cpp $(SRC_DIR) $(BUILD_DIR)
#"function" that contains the rule to make the .o files that exist within a source director and sub-directory
define make-goal
$1/%.o: %.cpp
@echo 'Building file: $$<'
@echo 'Invoking: Linux G++ Compiler'
$(CXX) $(CPPFLAGS) "$$<" -o "[email protected]" $(DEPFLAGS)
@echo 'Finished building: $$<'
@echo ' '
endef
.PHONY: all checkdirs clean build/HelloWorld
all: checkdirs build/HelloWorld
build/HelloWorld: $(OBJS)
@echo 'Building Target: [email protected]'
@echo 'Invoking: G++ Linker'
$(CXX) -L/usr/local/lib $^ -o [email protected]
@echo 'Finished building target: [email protected]'
@echo ' '
clean:
-$(RM) $(BUILD_DIR)
#Makes sure that the output directory exists
checkdirs: $(BUILD_DIR)
#Creates the output directory, build, if it doesn't exist
$(BUILD_DIR):
@mkdir -p [email protected]
#This is the important "recursive" part - this will loop through all source directories and call 'make-goal', which contains the rule to make the associated .o file.
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))
この小さなプロジェクトを作成しようとすると、次のようになります。注意./world/hello.cppは.oファイルをビルドするときに2回使用されます。最初にbuild/world/hello.oに出力され、2回目に/build/hello/hello.oに出力され、リンカは失敗します。 .oファイルは同じです。 .oファイルを構築するとき./world/hello.cppが2回使用されている理由
Building file: ./exec/main.cpp
Invoking: Linux G++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./exec/main.cpp" -o "build/exec/main.o" -MMD -MP -MT "build/exec/main.o" -MF "build/exec/main.d"
Finished building: ./exec/main.cpp
Building file: ./world/hello.cpp
Invoking: Linux G++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./world/hello.cpp" -o "build/world/hello.o" -MMD -MP -MT "build/world/hello.o" -MF "build/world/hello.d"
Finished building: ./world/hello.cpp
Building file: ./world/hello.cpp
Invoking: Linux G++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./world/hello.cpp" -o "build/hello/hello.o" -MMD -MP -MT "build/hello/hello.o" -MF "build/hello/hello.d"
Finished building: ./world/hello.cpp
Building Target: build/HelloWorld
Invoking: G++ Linker
CPP_SRCS: ./exec/main.cpp ./world/hello.cpp ./hello/hello.cpp
g++ -L/usr/local/lib build/exec/main.o build/world/hello.o build/hello/hello.o -o build/HelloWorld
build/hello/hello.o: In function `print_world()':
/home/otter/work/temp/maketest/./world/hello.cpp:4: multiple definition of `print_world()'
build/world/hello.o:/home/otter/work/temp/maketest/./world/hello.cpp:4: first defined here
build/exec/main.o: In function `main':
/home/otter/work/temp/maketest/./exec/main.cpp:7: undefined reference to `print_hello()'
collect2: error: ld returned 1 exit status
makefile:46: recipe for target 'build/HelloWorld' failed
make: *** [build/HelloWorld] Error 1
だから誰もが知っているのですか? .cppファイルは同じ名前を持っていても、別のディレクトリにあり、makeは同じ名前のファイルが見つかるたびに、最初のファイルを別のファイルとして扱い、最初のファイルを再利用しないほどスマートになると思います。私は時間があればそれ以降の解決しようとするでしょう - -
'$ 1 /%。o:%.cpp' - " $ 1 "部分が間違っています。 –
あなたの 'vpath'ディレクトリは' SRC_DIR'と 'BUILD_DIR'で検索するようにmakeに指示します。ビルドディレクトリをソース 'vpath'ディレクトリにすることは意味がありませんが、問題の根本原因は' vpath'があなたが提供するディレクトリを順番に検索することです。 'world'は' hello'の前に 'モジュール。 – user657267