I have the following makefile
# See gcc/clang manual to understand all flags
CFLAGS += -std=c99 # Define which version of the C standard to use
CFLAGS += -Wall # Enable the 'all' set of warnings
CFLAGS += -Werror # Treat all warnings as error
CFLAGS += -Wshadow # Warn when shadowing variables
CFLAGS += -Wextra # Enable additional warnings
CFLAGS += -O2 -D_FORTIFY_SOURCE=2 # Add canary code, i.e. detect buffer overflows
CFLAGS += -fstack-protector-all # Add canary code to detect stack smashing
# We have no libraries to link against except libc, but we want to keep
# the symbols for debugging
LDFLAGS = -rdynamic
# external libs
# par défaut les chemins classiques
LDFLAGS += -I$(HOME)/local/include
LDFLAGS += -L$(HOME)/local/lib
# Default compiler
CC=gcc
# folders
SOURCE_FOLDER=src
TESTS_FOLDER=tests
PAQUET_FOLDER=paquet
SEND_RECEIVE_DATA_FOLDER=sendAndReceiveData
CLIENT_FOLDER=client
SERVER_FOLDER=server
# folder of sources
PAQUET_FULL_PATH=$(SOURCE_FOLDER)/$(PAQUET_FOLDER)
SEND_RECEIVE_DATA_FULL_PATH=$(SOURCE_FOLDER)/$(SEND_RECEIVE_DATA_FOLDER)
CLIENT_FULL_PATH=$(SOURCE_FOLDER)/$(CLIENT_FOLDER)
SERVER_FULL_PATH=$(SOURCE_FOLDER)/$(SERVER_FOLDER)
# sources files
# On prend tout
PACKET_SOURCES = $(wildcard $(PAQUET_FULL_PATH)/*.c)
SEND_RECEIVE_DATA_SOURCES = $(wildcard $(SEND_RECEIVE_DATA_FULL_PATH)/*.c)
CLIENT_SOURCES = $(wildcard $(CLIENT_FULL_PATH)/*.c)
SERVER_SOURCES = $(wildcard $(SERVER_FULL_PATH)/*.c)
# objects
PACKET_OBJECTS=$(PACKET_SOURCES:.c=.o)
SEND_RECEIVE_DATA_OBJECTS=$(SEND_RECEIVE_DATA_SOURCES:.c=.o)
CLIENT_OBJECTS=$(CLIENT_SOURCES:.c=.o)
SERVER_OBJECTS=$(SERVER_SOURCES:.c=.o)
# another things
# Default target
all: clean server client
client: $(CLIENT_OBJECTS) $(PACKET_OBJECTS);
$(CC) $(CFLAGS) $(CLIENT_OBJECTS) $(LDFLAGS);
server: $(SERVER_OBJECTS) $(PACKET_OBJECTS);
$(CC) $(CFLAGS) $(SERVER_OBJECTS) $(LDFLAGS);
$(PACKET_OBJECTS): $(PACKET_OBJECTS);
$(CC) $(CFLAGS) -lz $(PACKET_OBJECT) $(LDFLAGS);
tests: $(PACKET_OBJECTS) $(TESTS_OBJECTS);
$(CC) $(CFLAGS) -lcunit $(LDFLAGS);
.PHONY: clean
clean:
@rm -f *.o
I got this message :
make: Circular src/paquet/packet_implem.o <- src/paquet/packet_implem.o dependency dropped. gcc -std=c99 -Wall -Werror -Wshadow -Wextra -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-all -lz -rdynamic -I/home/jy95/local/include -L/home/jy95/local/lib; /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function
_start': (.text+0x20): undefined reference to
main’ collect2: error: ld returned 1 exit status Makefile:71: recipe for target ‘src/paquet/packet_implem.o’ failed make: *** [src/paquet/packet_implem.o] Error 1
What I want :
1) Build the dependancies (PACKET_SOURCES) and (SEND_RECEIVE_DATA_SOURCES)
2) Build the client and the server with the dependancies from step 1
3) The executable “client” will be at the root of the folder.
How can I correct my errors ?
Advertisement
Answer
The problem occurs in this rule:
$(PACKET_OBJECTS): $(PACKET_OBJECTS);
$(CC) $(CFLAGS) -lz $(PACKET_OBJECT) $(LDFLAGS);
That says that every target in the expansion of $(PACKET_OBJECTS)
depends on every target in the expansion of $(PACKET_OBJECTS)
. That gives a great many dependency cycles, and in particular it gives you one-element cycles of object files depending on themselves.
In fact, this rule is problematic in several other ways:
- the recipe does not, in fact, create any of the rule’s designated targets
- instead, it attempts to link the object files (see next) together into an executable, assigning the default name to the result (perhaps
a.out
). - The recipe references an undefined variable
$(PACKET_OBJECT)
. I suppose that this is probably a misspelling of$(PACKET_OBJECTS)
. If instead you mean current target among those given in$(PACKET_OBJECTS)
, then that would be spelled$@
. - not only do the object files certainly not each have themselves as prerequisites, they also do not have each other as prerequisites. The dependencies for each object should be their corresponding sources.
- If you indeed mean for this rule to be used to build your object files then the recipe does not need to specify libraries to link in (e.g.
-lz
), and probably should not do so.
Chances are reasonably good that you could simply delete that rule altogether and thereby be better off. You might want to add -lz
to your LDFLAGS
; otherwise it would just be lost.
Additionally,
You probably want to move the
-I$(HOME)/local/include
option: it does not belong in LDFLAGS, and will not serve its purpose there. If you need it, then put it instead in yourCPPFLAGS
, or maybe inCFLAGS
or evenINCLUDES
.Your various rules that build executable targets should provide options that specify the name of the target to build. You can spell that as “
-o $@
“,It is unconventional to include your
clean
target as a prerequisite ofall
. It will always rebuild everything from scratch if you runmake
without specifying a target. Most people prefer to do that only on demand.Your
all
target does not build a target named “all”, so it, too, should be declared.PHONY
.
Very likely there’s more, but I’ll leave that for you to sort out.