具有 2 个源目录的 makefile 使包含保护失败

Posted

技术标签:

【中文标题】具有 2 个源目录的 makefile 使包含保护失败【英文标题】:makefile with 2 source directories make include guard fail 【发布时间】:2016-01-27 03:16:11 【问题描述】:

我有一个项目,其来源位于 2 个位置。 当项目链接时,它抱怨一个函数是双重定义的(它不是):

cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src src/Meter.c -o build/x86_64-linux-gnu/obj/Meter.o
cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src src/PaymentHandler.c -o build/x86_64-linux-gnu/obj/PaymentHandler.o
cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src src/PaymentHandlerDaemon.c -o build/x86_64-linux-gnu/obj/PaymentHandlerDaemon.o
cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src src/PrintSocketReceiver.c -o build/x86_64-linux-gnu/obj/PrintSocketReceiver.o
cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src src/SerialPrinter.c -o build/x86_64-linux-gnu/obj/SerialPrinter.o
cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src ../../Bla/trunk/src/CheckSum.c -o build/x86_64-linux-gnu/obj/Bla/CheckSum.o
cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src ../../Bla/trunk/src/CheckSum.c -o build/x86_64-linux-gnu/obj/Bla/Config.o
cc build/x86_64-linux-gnu/obj/Meter.o build/x86_64-linux-gnu/obj/PaymentHandler.o build/x86_64-linux-gnu/obj/PaymentHandlerDaemon.o build/x86_64-linux-gnu/obj/PrintSocketReceiver.o build/x86_64-linux-gnu/obj/SerialPrinter.o build/x86_64-linux-gnu/obj/Bla/CheckSum.o build/x86_64-linux-gnu/obj/Bla/Config.o -o build/x86_64-linux-gnu/obj/../PaymentHandlerDaemon -lrt -lpthread -lconfig -lm -L../../libSOS/trunk/build/x86_64-linux-gnu -lSOS  -L../lib/ABCUtilLib/build/x86_64-linux-gnu -lABCUtil -L../lib/ABCUtilSO/build/x86_64-linux-gnu   -lABCMain
build/x86_64-linux-gnu/obj/Bla/Config.o: In function `CheckSum_Buffer':
/home/builder/projects/Applications/PaymentHandlerDaemon/trunk/../../Bla/trunk/src/CheckSum.c:34: multiple definition of `CheckSum_Buffer'
build/x86_64-linux-gnu/obj/Bla/CheckSum.o:/home/builder/projects/Applications/PaymentHandlerDaemon/trunk/../../Bla/trunk/src/CheckSum.c:34: first defined here
build/x86_64-linux-gnu/obj/Bla/Config.o: In function `CheckSum_Stream':
/home/builder/projects/Applications/PaymentHandlerDaemon/trunk/../../Bla/trunk/src/CheckSum.c:54: multiple definition of `CheckSum_Stream'
build/x86_64-linux-gnu/obj/Bla/CheckSum.o:/home/builder/projects/Applications/PaymentHandlerDaemon/trunk/../../Bla/trunk/src/CheckSum.c:54: first defined here
build/x86_64-linux-gnu/obj/Bla/Config.o: In function `pppfcs16':
/home/builder/projects/Applications/PaymentHandlerDaemon/trunk/../../Bla/trunk/src/CheckSum.c:125: multiple definition of `pppfcs16'
build/x86_64-linux-gnu/obj/Bla/CheckSum.o:/home/builder/projects/Applications/PaymentHandlerDaemon/trunk/../../Bla/trunk/src/CheckSum.c:125: first defined here
build/x86_64-linux-gnu/obj/Meter.o: In function `Meter_MessagePumpProc':
/home/builder/projects/Applications/PaymentHandlerDaemon/trunk/src/Meter.c:365: undefined reference to `Config_GetHardwareInfo'
collect2: error: ld returned 1 exit status
make: *** [build/x86_64-linux-gnu/obj/../PaymentHandlerDaemon] Error 1

我认为这是因为 makefile 为每个目录编译了 2 个不同的配方,并且它们不共享预编译定义。

有没有更好的方法来制作具有 2 个源目录的项目?我应该只是将不同目录中的几个源添加到迷你库中然后添加吗?

生成文件:

CC ?= gcc
ARCH = $(shell $(CC) -dumpmachine)

# compile and link flags
CC_FLAGS ?= -c -w -fPIC -g3 -Og -D__EMULATE_SOS__

CC_INCLUDE = -I../../libSOS/trunk/include
CC_INCLUDE += -I. -I../../include
CC_INCLUDE += -I../lib/ABCUtilSO/src
CC_INCLUDE += -I../../Bla/trunk/src

# Libraries
LIBS := -lrt -lpthread -lconfig -lm
LIBS += -L../../libSOS/trunk/build/$(ARCH) -lSOS 
LIBS += -L../lib/ABCUtilLib/build/$(ARCH) -lABCUtil
LIBS += -L../lib/ABCUtilSO/build/$(ARCH)    -lABCMain


OUT1_DIR = build/$(ARCH)/obj
OUT2_DIR = build/$(ARCH)/obj/Bla

# result
EXEC = $OUT1_DIR/../PaymentHandlerDaemon

#-------------------------------------------------------------
# main sources (1)
SRC1_DIR = src
#all the sources in the srec directory will be included
SOURCES1 = $(wildcard $SRC1_DIR/*.c)
# deduce the object list from the source list
_OBJECTS1 = $(patsubst %.c,%.o,$(SOURCES1) )
# the replace the source directory wioth the output directory
OBJECTS1 = $(patsubst $SRC1_DIR%,$OUT1_DIR%,$(_OBJECTS1) )

#-------------------------------------------------------------
# extra sources (2)
SRC2_DIR = ../../Bla/trunk/src
#SRC2_LIST = Meter.c
SRC2_LIST = CheckSum.c Config.c
#all the sources in the srec directory will be included
#SOURCES2 = $(pathsubs %,$(SRC2_DIR)/%,$(SRC2_LIST))
SOURCES2 =  $(patsubst %.c,$SRC2_DIR/%.c,$(SRC2_LIST))
# deduce the object list from the source list
_OBJECTS2 = $(patsubst %.c,%.o,$(SOURCES2) )
# the replace the source directory wioth the output directory
OBJECTS2 = $(patsubst $SRC2_DIR%,$OUT2_DIR%,$(_OBJECTS2) )

#-------------------------------------------------------------
# build receipes

all: $(EXEC)
# Main target
$(EXEC): $(OBJECTS1) $(OBJECTS2)
    $(CC) $(OBJECTS1) $(OBJECTS2) -o $@ $(LIBS)


# To obtain object files
$OUT1_DIR%.o:$SRC1_DIR%.c 
    @mkdir -p $(OUT1_DIR)
    $(CC) -c $(CC_FLAGS) $(CC_INCLUDE) $< -o $@

# # To obtain object files
 $OUT2_DIR%.o:$SOURCES2
    @mkdir -p $(OUT2_DIR)
    $(CC) -c $(CC_FLAGS) $(CC_INCLUDE) $< -o $@


# To remove generated files
clean:
    rm -fr build/$(ARCH)


# debug.. for example use as    make -print-SRC_DIR
print-%  : ; @echo $* = $($*)

【问题讨论】:

【参考方案1】:

人们总是从多个目录构建项目。每种情况都需要不同的方法。

您发布的内容应该有效。由于Makefile,多重定义很可能不是。我会更仔细地查看错误。 toolchain 告诉你它在哪里找到了这两个定义。

生成文件:

CC ?= gcc
# compile and link flags
CC_FLAGS ?= -c -w -fPIC -g3 -Og 

CC_INCLUDE += -I../../AnotherProject/src

# Libraries
LIBS := -lrt -lpthread -lconfig -lm

OUT1_DIR = build/obj
OUT2_DIR = build/obj/extra2

# result
EXEC = build/MyProgram

#-------------------------------------------------------------
# main sources (1) (everything in src directory)
SRC1_DIR = src
SOURCES1 = $(wildcard $SRC1_DIR/*.c)
# deduce the object list from the source list
_OBJECTS1 = $(patsubst %.c,%.o,$(SOURCES1) )
# the replace the source directory wioth the output directory
OBJECTS1 = $(patsubst $SRC1_DIR%,$OUT1_DIR%,$(_OBJECTS1) )

#-------------------------------------------------------------
# extra sources (just cherry pick what i need to reuse)
SRC2_DIR = ../../AnotherProject/src
SRC2_LIST = CheckSum.c Config.c
#all the sources in the srec directory will be included
SOURCES2 =  $(patsubst %.c,$SRC2_DIR/%.c,$(SRC2_LIST))
# deduce the object list from the source list
_OBJECTS2 = $(patsubst %.c,%.o,$(SOURCES2) )
# the replace the source directory wioth the output directory
OBJECTS2 = $(patsubst $SRC2_DIR%,$OUT2_DIR%,$(_OBJECTS2) )

#-------------------------------------------------------------
# build receipes

all: debug $(EXEC)

debug: FORCE
    echo "1====" $(OBJECTS1)
    echo "2====" $(OBJECTS2)

FORCE:

# Main target
$(EXEC): $(OBJECTS1) $(OBJECTS2)
    $(CC) $(OBJECTS1) $(OBJECTS2) -o $@ $(LIBS)


# To obtain object files
$OUT1_DIR/%.o:$SRC1_DIR/%.c
    @mkdir -p $(OUT1_DIR)
    $(CC) -c $(CC_FLAGS) $(CC_INCLUDE) $< -o $@

# To obtain the extra object files
$OUT2_DIR/%.o:$SRC2_DIR/%.c
    @mkdir -p $(OUT2_DIR)
    $(CC) -c $(CC_FLAGS) $(CC_INCLUDE) $< -o $@

编辑

这是你的问题。

cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src ../../Bla/trunk/src/CheckSum.c -o build/x86_64-linux-gnu/obj/Bla/CheckSum.o
cc -c -c -w -fPIC -g3 -Og -D__EMULATE_SOS__ -I../../libSOS/trunk/include -I. -I../../include -I../lib/ABCUtilSO/src -I../../Bla/trunk/src ../../Bla/trunk/src/CheckSum.c -o build/x86_64-linux-gnu/obj/Bla/Config.o

您会看到它正在从同一个源文件CheckSum.c 构建CheckSum.oConfig.o。因此在链接时有多个定义。这是您使用的错误模式规则的结果。

$OUT2_DIR%.o:$SOURCES2

【讨论】:

感谢 ziffusion。我刚刚用错误的实际输出更新了问题。 你能发布整个构建输出吗?另外,Makefile 是否正确?我看到了一些奇怪的事情。 1.$OUT1_DIR%.o:$SRC1_DIR%.c $SOURCES2 看起来很奇怪。 2. $OUT2_DIR%.o:$SOURCES2 似乎没有正确缩进。 我取消了$OUT2_DIR%.o:$SOURCES2 行的缩进——否则它很奇怪。在我看来,每个目标文件都依赖于每个源文件,因此如果源文件发生更改,该目录中的所有目标文件都将被重新编译。我怀疑这是否是我们想要的。 我在答案中添加了Makefile,您可以尝试。看看$(OBJECTS1)$(OBJECTS2) 是什么。还有其他变化。确保用制表符替换阅读空间。 我已经简化了 makefile 和输出来说明问题。我已将问题更新为完整的 makefile 和完整的错误列表。只是忽略这些库,因为在我进行更改以从另一个目录添加一些额外的源之前,这是有效的,

以上是关于具有 2 个源目录的 makefile 使包含保护失败的主要内容,如果未能解决你的问题,请参考以下文章

2个Dirs,3个头文件的makefile错误

具有到父级的相对包含路径的 C++ makefile

Makefile 包含来自其他目录的头文件

使 rsync 排除所有包含具有特定名称的文件的目录

Linux 内核 makefile cscope 目标

[Make]Makefile 模版