Skip to content
Advertisement

Makefile – wildcard and recipe build

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 tomain’ 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 your CPPFLAGS, or maybe in CFLAGS or even INCLUDES.

  • 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 of all. It will always rebuild everything from scratch if you run make 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.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement