Makefile: Wildcard for two programs with different source files - makefile

I'm working on a C project with two programs, a server and a client.
My projects structure:
.
+--/bin
| +--/client
| +--/server
|
+--/lib
| +--header1.h
| +--header2.h
| +--header3.h
|
+--/obj
| +--/client
| +--/server
|
+--/src
| +--/client
| | +--files.c
| +--/server
| +--otherfiles.c
|
+--Makefile
Now I'm stuck on the Makefile, both my programs need different and some overlapping headers. I tried looking into other projects/repositories, but that didn't help me.
This is what i currently got:
SOURCES_CLIENT = ${wildcard src/client/files.c}
SOURCES_SERVER = ${wildcard src/client/otherfiles.c}
HEADERS_CLIENT = ${wildcard lib/header1.h lib/header2.h}
HEADERS_SERVER = ${wildcard lib/header2.h lib/header3.h}
OBJ_CLIENT = ${SOURCES_CLIENT:.c=.o}
OBJ_SERVER = ${SOURCES_SERVER:.c=.o}
CC = gcc
CFLAGS = #not relevant
all: client server
client: ${OBJ_CLIENT}
${CC} -o $# $^
server: ${OBJ_SERVER}
${CC} -o $# $^
How would I create wildcard rules to convert my source files to object files (in the correct bin/ directory) using the corresponding header files? Also my Makefile seems to be optimizable, if so how?

I suppose your base variable definitions must actually look more like this:
SOURCES_CLIENT = ${wildcard src/client/*.c}
SOURCES_SERVER = ${wildcard src/server/*.c}
HEADERS_CLIENT = ${wildcard lib/client*.h}
HEADERS_SERVER = ${wildcard lib/server*.h}
One of the very first things you need to understand about make is that it knows just about nothing about build tools, directories, or files. It just manipulates strings, and chooses a subset of the strings it works with and forms to issue as shell commands, with timing and order governed by the ruleset expressed to it.
Among the implications is that if you want to build a given target then you have to write a rule for exactly that target. In particular, when you run make from the root directory of your project, the wanted binaries (in your scheme) are not client and server, they are bin/client and bin/server. Similarly, the wanted object file corresponding to src/client/files.c is not files.o or src/client/files.o but rather obj/client/files.o.
Having understood that, the next order of business is to define the object file lists correctly. You seem deeply committed to GNU make already, which makes things easier (at some cost in portability). Instead of your current definitions for OBJ_CLIENT and OBJ_SERVER, which provide for object files in a different location than you require, something using a (GNU-specific) substitution reference like this would work:
OBJ_CLIENT = $(SOURCES_CLIENT:src/client/%.c=obj/client/%.o)
OBJ_SERVER = $(SOURCES_SERVER:src/server/%.c=obj/server/%.o)
Having done that, however, you'll need to write explicit rules for building the object files; make's default rules do not handle the needed cross-directory correspondence. You can use GNU pattern rules effectively for this purpose. This is also where you would introduce the dependencies on the headers:
obj/client/%.o: src/client/%.c $(HEADERS_CLIENT)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Again taking into account the fact that you must provide build rules naming the targets you actually want to build, you might put this all together as:
SOURCES_CLIENT = $(wildcard src/client/*.c)
SOURCES_SERVER = $(wildcard src/server/*.c)
HEADERS_CLIENT = $(wildcard lib/client*.h)
HEADERS_SERVER = $(wildcard lib/server*.h)
OBJ_CLIENT = $(SOURCES_CLIENT:src/client/%.c=obj/client/%.o)
OBJ_SERVER = $(SOURCES_SERVER:src/server/%.c=obj/server/%.o)
CC = gcc
CFLAGS = #not relevant
all: bin/client bin/server
bin/client: $(OBJ_CLIENT)
$(CC) $(CFLAGS) -o $# $^
bin/server: $(OBJ_SERVER)
$(CC) $(CFLAGS) -o $# $^
obj/client/%.o: src/client/%.c $(HEADERS_CLIENT)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
obj/server/%.o: src/server/%.c $(HEADERS_SERVER)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#

These two rules should do what you're after
obj/client/%.o: src/client/%.c $(HEADERS_CLIENT)
$(CC) -c -o $# $<
obj/server/%.o: src/server/%.c $(HEADERS_SERVER)
$(CC) -c -o $# $<

Related

Use Makefile and sdcc to build a perfect automation for MCS-51 development

Since sdcc have some limitations, like compiling one file at a time, I've tried hard to write a Makefile to perfect the automation of MCS-51 development, which have some requirements:
Source file (.c) expect main.c are stored in ProjectFolder/Sources/, while main.c are stored at the root of project folder.
Headers are stored in ProjectFolder/Includes/.
Outputs through compiling, linking and locating should be stored at ProjectFolder/Builds/
Makefile should be smart enough to find all source files, instead of type their file name by hand.
Makefile should be smart enough to if there are some files in Sources/, or there's only main.c in the project.
The file structure can be depicted like:
Project Folder
|
|- Sources
| |
| |(some source files, but OPTIONAL)
|
|- Includes
| |
| |(some headers, but OPTIONAL)
|
|- Builds
| |
| |(some .rel .o .hex files. OUTPUT here)
|
|- main.c
|
|- Makefile
Here's my solution but still have a problem. It cannot be used for project only have one file main.c which means no source file in Sources/.
INCLUDES = Includes/
SOURCES = Sources/
BUILDS = Builds/
CC = sdcc
CFLAGS = -o $(BUILDS)
LOADER = stcgal
LOADER_FLAGS = -P stc89
$(BUILDS)main.ihx: main.c $(BUILDS)main.rel
# Link
#$(CC) main.c $(shell find $(BUILDS) -name "*.rel" -not -name "main.rel" -maxdepth 1) $(CFLAGS)
#echo Link & Locate Succeeded
$(BUILDS)main.rel: $(SOURCES) $(BUILDS)
# Compile
#for f in $(shell ls $(SOURCES)*.c) ; do \
$(CC) -c $${f} $(CFLAGS) ; \
done
#echo Compile Succeeded
$(SOURCES):
#mkdir $(SOURCES)
$(BUILDS):
#mkdir $(BUILDS)
clean:
# Remove all files in build folder
#rm $(BUILDS)*
#echo Build Folder Cleaned
load: $(BUILDS)main.ihx
# Load data to MCU via USB port
#$(LOADER) $(LOADER_FLAGS) -p $(shell ls /dev/tty.usbserial*) $(BUILDS)main.ihx
Let's try something. First note that I've not looked at the load target.
Let's start with the same definition as you:
INCLUDES = Includes/
SOURCES = Sources/
BUILDS = Builds/
CC = sdcc
We need a variable with the source files from Sources. GNU Make has a wildcard functions which does the same thing as your find. See that I'm using := to have an immediate expansion of the value, so the wildcard will not be executed several times.
SRCFILES := $(wildcard $(SOURCES)*.c)
Now a variable with the .rel files. It is build from main.rel and the SRCFILES value:
RELFILES := $(BUILDS)main.rel $(SRCFILES:$(SOURCES)%.c=$(BUILDS)%.rel)
Let's define another variable with the flag to pass so the Includes directory is searched:
CPPFLAGS = -I$(INCLUDES)
Now we can define pattern rules to describe how to build .rel files from .c files. I'm using an order-only prerequisite for the build directory:
$(BUILDS)%.rel: $(SOURCES)%.c | $(BUILDS)
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# -c $<
$(BUILDS)%.rel: %.c | $(BUILDS)
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
Let's define some usability targets:
.PHONY: all clean
all: $(BUILDS)main.ihx
clean:
rm $(BUILDS)*
And finally define how to build the targets which aren't handled by the pattern rules:
$(BUILDS)main.ihx: $(RELFILES) | $(BUILDS)
$(CC) $(LDFLAGS) -o $# $^ $(LOADLIBES) $(LDLIBS)
$(BUILDS):
mkdir $(BUILDS)
I've used a few variables (CC, CPPFLAGS, CFLAGS, LDFLAGS, LOADLIBES, LDLIBS) in the same way as they are used by the built-in rules of GNU Make.
I've kept your makefile behavior. There are good reasons to have Makefiles targeting to build in the current directory. Explaining them and modifying the Makefile for that is out of scope for this answer, you may look at MadScientist's GNU Make White Papers and the GNU Make Manual.

Attempt to link objects makes them recompile even if up-to-date

I have a recipe in my makefile that relies on several object files. I would like it to simply link the them, but they are always recompiling.
I've googled around and found information I did not know(marked with #) and changed it a bit, but the problem persisted.
I am led to believe make expects the name of the recipe be the name of the file, and I am failing to accomplish that. The problem is I do not what else to try and fix this. I would appreciate any help
CC = g++
#.PHONY: sfml-app
LIBS = -lsfml-graphics -lsfml-window -lsfml-system
APPLICATION = sfml-app
INCLUDE_DIR = -I include/
SOURCE_DIR = source
OUTPUT_DIR = bin
SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
OBJECTS = $(notdir $(patsubst %.cpp, %.o, $(SOURCES)))
#$(OUTPUT_DIR)/$(APPLICATION): $(OBJECTS)
#bin/sfml-app: $(OBJECTS)
#sfml-app: $(OBJECTS)
#$(APPLICATION): $(OBJECTS)
$(CC) $(OUTPUT_DIR)/*.o $(LIBS) -o $(OUTPUT_DIR)/$(APPLICATION)
%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $(OUTPUT_DIR)/$#
clean:
rm $(OUTPUT_DIR)/*
print-% : ; #echo $* = $($*)
This rule doesn't create the file it promises to:
%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $(OUTPUT_DIR)/$#
See that -o $(OUTPUT_DIR)/$#? That's instructing the compiler to create a file in $(OUTPUT_DIR) instead of in the working directory.
If you really want your object files to go in $(OUTPUT_DIR), you need to make sure that your rule indicates that:
$(OUTPUT_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $#
Or better, to act like the standard %.o: %.c rule (which will include CFLAGS etc):
$(OUTPUT_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(COMPILE.c) $(OUTPUT_OPTION) $<
I note your input files are named *.cpp - usually, that convention is for C++ files (i.e. to be compiled with $(COMPILE.cc), which will invoke $(CXX) rather than $(CC)). Check that you've not mixed up your C and C++ sources!

Make: How can I auto generate rules to build targets?

The question is a little vague, because I'm not entirely sure of the best way to ask what I'm trying to achieve in such a short summary.
To explain it best this is what I currently have....
common.mk
DESTDIR = ../../install/
tools.mk
CC = gcc
CFLAGS = -fPIC -Wall -Wextra -O2 -g -I.
LDFLAGS = -shared
RM = rm -f
MAKEDIR = mkdir -p
Makefile
include ../../builder/tools.mk
include ../../builder/common.mk
TEST_RUNNERS = test_foo test_bar
test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_bar_TESTS = tests/test_bar.c
test_bar_SOURCES = bar.c
# Gather lists of ALL sources and objects required to build test_foo
test_foo_ALL_SOURCES = $(test_foo_TESTS) $(test_foo_SOURCES)
test_foo_ALL_OBJECTS = $(test_foo_ALL_SOURCES:.c=.o)
# Compile All the sources required for test_foo
$(test_foo_ALL_SOURCES:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$#
include $(test_foo_ALL_SOURCES:.c=.d)
# Build test_foo and clean up temporary build files
test_foo: $(test_foo_ALL_OBJECTS)
$(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $#) $^
-${RM} ${test_foo_ALL_OBJECTS} ${test_foo_ALL_SOURCES:.c=.d}
# Gather lists of ALL sources and objects required to build test_bar
test_bar_ALL_SOURCES = $(test_bar_TESTS) $(test_bar_SOURCES)
test_bar_ALL_OBJECTS = $(test_bar_ALL_SOURCES:.c=.o)
# Compile All the sources required for test_bar
$(test_bar_ALL_SOURCES:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$#
include $(test_bar_ALL_SOURCES:.c=.d)
# Build test_bar and clean up temporary build files
test_bar: $(test_bar_ALL_OBJECTS)
$(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $#) $^
-${RM} ${test_bar_ALL_OBJECTS} ${test_bar_ALL_SOURCES:.c=.d}
What I want to do is remove all the complexity in having to manually add rules for each target, and instead "auto-generate" these rules. It's fairly clean and simple in my own mind...
TEST_RUNNERS = test_foo test_bar
So for each TEST_RUNNER that is specified in the list, a list of SOURCES (the code under test) and a list of TESTS (the unit test sources) must be provided...
test_foo_TESTS
test_foo_SOURCES
I've been playing around with foreach but it's not the right approach, and I'm not entirely sure what I need to do to achieve my goal, so after playing around for a few hours I thought I'd try and ask some of you guys because there's some pretty clever guys here that hopefully may be able to help me!
Another idea I was playing around with was to creating templates that I could call upon to generate these rules:
$(foreach runner,$(TEST_RUNNERS),$(eval $(call COMPILE_ALL_TEST_RUNNER_SOURCES, runner)))
$(foreach runner,$(TEST_RUNNERS),$(eval $(call MAKE_TEST_RUNNER_TEMPLATE, runner)))
define COMPILE_ALL_TEST_RUNNER_SOURCES
$($(1)_ALL_SOURCES:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$#
include $($(1)_ALL_SOURCES:.c=.d)
endef
define MAKE_TEST_RUNNER_TEMPLATE
$(1): $($(1)_ALL_OBJECTS)
$(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $#) $^
-${RM} ${$(1)_ALL_OBJECTS} ${$(1)_ALL_SOURCES:.c=.d}
endef
After spending a little more time reading the Make manual, I discovered this very useful page.
https://www.gnu.org/software/make/manual/html_node/Eval-Function.html
which has some really useful information on how I can construct my Makefile exactly how I want to. If anyone is interested, I'm using this as my basis for going forward...
TEST_RUNNERS = test_foo test_bar
test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_bar_TESTS = tests/test_bar.c
test_bar_SOURCES = bar.c
.PHONY: test
test: unittest
#
# Template to create rules for each TEST_RUNNER defined within TEST_RUNNERS
#
# $(1) is the name of the test runner
#
define test_TEST_RUNNER_template
THE_$(1)_SOURCES = $$($(1)_TESTS)
.PHONY: unittest unittest_$(1)
unittest: unittest_$(1)
unittest_$(1):
#echo "?(1)=" $(1) "?#=" $$# " THE_$(1)_SOURCES=" $$(THE_$(1)_SOURCES)
endef
# Create a rule for all TEST_RUNNERS when "make test" is invoked...
$(foreach runner,$(TEST_RUNNERS),$(eval $(call test_TEST_RUNNER_template,$(runner))))
If you're willing to add one more line per target:
test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_foo_ALL_OBJECTS := tests/test_foo.o foo.o
then a couple of pattern rules can handle all the rest:
%.o: %.c
$(CC) $(CFLAGS) -MMD -c $< -o $#
-include *.d tests/*.d
.PHONY: $(TEST_RUNNERS)
$(TEST_RUNNERS): test_% : $(DESTDIR)test_%
$(DESTDIR)test_%:
$(CC) -L$(DESTDIR) -o $# $^
(Trust me, this approach to dependency handling is much better than what you had. See here for a detailed explanation.)
If you don't like writing three lines per target, notice that the first two aren't actually used for anything and can be omitted.
If you are fond of the first two and really dislike the the third, yes, you can automate the process of constructing the object list, but it isn't worth the effort for this question.

Makefile not executing to the end

I have the following makefile but it just executes the 1st command where it builds me the .o files and not the .so files. What am I doing wrong?
Thanks,
SHELL = /bin/sh
CC = gcc
CFLAGS = -g -Wall
LDFLAGS = -shared
TARGET = Stepper.so
SOURCES = $(shell echo ./*.c)
HEADERS = $(shell echo ./*.h)
OBJECTS = $(SOURCES:.c=.o)
LIBS = liblua523.a
PREFIX = $(DESTDIR)/usr/local
BINDIR = $(PREFIX)/bin
$(OBJECTS): $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)
clean:
rm $(OBJECTS)
Unless you specify a different target on the command line, make always builds the first real target found in the makefile. In this case, the first real target is the first object file, so that's all that's built.
This is why you typically see makefiles with a first target of all or similar, which just depends on the various other targets you want built during a standard invocation of "make" with no arguments.
However, your makefile is really not right, in a number of ways. The fact that it's running it all means you actually only have one source file. As soon as you have >1 it will fail.
This:
SOURCES = $(shell echo ./*.c)
is not very efficient; you should use wildcard here:
SOURCES = $(wildcard ./*.c)
This rule:
$(OBJECTS): $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
Tells make, "for every object file, if any source file or any header file has changed, recompile it". Basically, it means that if you change ANYTHING in the directory, EVERYTHING will rebuild. If you want that you might as well write a shell script and not bother with make at all.
Further, the compiler will fail when you have >1 source file, as it will try to run:
gcc -g -Wall -c foo.c bar.c -o foo.o bar.o
which is not right.
You don't need to define this rule at all; make has a built-in rule which knows how to build an object file from a source file. Just replace it with this:
$(OBJECTS): $(HEADERS)
(no recipe) so make knows that the objects depend on the headers as well as the source. Note this is not ideal since all objects rebuild if any header changes but it's fine for a simple program.

Difference of two pattern rules and integration on makefile

I'm learning makefile and I'm little bit confused about the use of pattern rule and how to use it:
I have two questions:
difference form of pattern rules
In some examples I saw this form:
.c.o:
$(CC) $(CFLAGS) $< -o $#
Other times I saw this:
%.o: %.c
$(CC) $(CFLAGS) $< -o $#
Is this the same form or there are many differences?
How to integrate the pattern rule in my makefile
I have a makefile like this:
.PHONY: all brsserver brsclient clean
CC = gcc
CFLAGS = -Wall -pedantic -g -lpthread
# source files for server
SOURCES_SERV = brsserver.c func_client_serv.c comsock.c bris.c users.c aux_func.c Stack.c
# source files for client
SOURCES_CLI = brsclient.c func_client_serv.c comsock.c bris.c users.c aux_func.c Stack.c
# object file for server
OBJECTS_SERV = $(SOURCES_SERV:.c = .o)
# object file for client
OBJECTS_CLI = $(SOURCES_SERV:.c = .o)
# executable file server
SERV_EXE = brsserver
# executable file client
CLI_EXE = brsclient
I did this:
$(SERV_EXE): $(OBJECTS_SERV)
$(CC) $(CFLAGS) -o $# $^ newDeck.o
$(CLI_EXE): $(OBJECTS_CLI)
$(CC) $(CFLAGS) -o $# $^
But I want to use the pattern rule to do make brsserver and make brsclient from command.
it's enough do this?
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
As you can see, I have to complie only the brsserver including a module called newDeck.o.
The .c.o form is a suffix rule. This form is defined in the POSIX standard for the make program.
The %.o : %.c is a pattern rule. This is a GNU make feature, not part of the POSIX standard (I think there may be a few other make implementations that have something similar).
In this case, they are equivalent. However pattern rules in general are much more flexible than suffix rules; for example you can't represent a pattern rule like this:
foo%.o : bar%.c
as a suffix rule.

Resources