0

I have a project with sources in 2 locations. When the project links, it complains that a function is double-defined (it's not):

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

I think it is because the makefile has 2 different recipes to compile for each directory and they don't share the pre-compile definitions.

is there a better way of making a project with 2 source directories? Should I just add the few sources in the different directory to a mini-library and then add that?

Makefile:

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 $* = $($*)
clogwog
  • 343
  • 2
  • 13

1 Answers1

1

People build a projects from multiple directories all the time. Each case requires a different approach.

What you posted should work. A multiple definition is most likely not because of the Makefile. I would look at the error more closely. The toolchain is telling you where it found the two definitions.

Makefile:

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 $@

EDIT

Here is your problem.

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

You see that it is building both CheckSum.o and Config.o from the same source file CheckSum.c. Hence the multiple definitions at link time. This is the consequence of the bad pattern rule you had.

${OUT2_DIR}%.o:${SOURCES2}
Ziffusion
  • 8,779
  • 4
  • 29
  • 57
  • thanks ziffusion. i just updated the question with the actual output of the error. – clogwog Jan 27 '16 at 03:38
  • Can you post the entire build output? Also, is the Makefile correct? I see a couple of weird things. 1. `${OUT1_DIR}%.o:${SRC1_DIR}%.c ${SOURCES2}` seems odd. 2. `${OUT2_DIR}%.o:${SOURCES2}` does not seem properly indented. – Ziffusion Jan 27 '16 at 03:45
  • I unindented the `${OUT2_DIR}%.o:${SOURCES2}` line — it was otherwise a weird one. It looks to me as though every object file depends on every source file, so if a source file changes, all the object files in that directory will be recompiled. I doubt if that's what's wanted. – Jonathan Leffler Jan 27 '16 at 03:54
  • I've added a `Makefile` to the answer that you can try. Look at what `$(OBJECTS1)` and `$(OBJECTS2)` are. There are other changes as well. Make sure you replace reading spaces with tabs. – Ziffusion Jan 27 '16 at 03:56
  • i had simplified the makefile and output to illustrate the problem. i have updated the question to the full makefile and full error list. just ignore the libraries because before i made the change to add some extra source from the other directory , this was working, – clogwog Jan 27 '16 at 04:00
  • perhaps i just need to put those few extra files from the other directory in a library and link them together ? – clogwog Jan 27 '16 at 04:08
  • i finally tweaked to what you were saying.. change ${OUT2_DIR}%.o:${SOURCES2} to ${OUT2_DIR}%.o:${SRC2_DIR}/%.c and it works now.. I was thinking that it would compile everything in SRC2_DIR but it only gets called for the files i need. thank you !!!! – clogwog Jan 27 '16 at 04:11
  • I added an explanation for why you were seeing a multiple definition. – Ziffusion Jan 27 '16 at 04:30