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.