Rule not recognized in makefile? - c

I have a basic makefile to compile C files necessary for compiling a shared library, I have an error because the makefile is not recognized:
SOURCES=/home/test/project/sources
OBJECTS=/home/test/project/objects
$(OBJECTS)/%.o:$(SOURCES)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJECTS)/%.o
$(CC) -shared -o libsharedlib.so $<
When I run make I get that there is no rule for target: $(OBJECTS)/%.o needed by sharedlib. While the rule is written right before sharedlib.

The main problem is that nowhere you are explicitly telling make what your source files are. Start by doing that:
SOURCEDIR=/home/test/project/sources
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
Then, derive the object file names from the source file names by substituting .c for .o:
OBJECTDIR=/home/test/project/objects
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(OBJECTDIR)/%.o,$(SOURCES))
You can still keep your generic rule to build object files:
$(OBJECTDIR)/%.o: $(SOURCEDIR)/%.c
$(CC) -fPIC -c $^ -o $#
But you give the explicit list of object files to the rule to make sharedlib:
libsharedlib.so: $(OBJECTS)
$(CC) -shared -o $# $<
Note that I made the name of the rule the same as the file that is being generated. That's important, because calling make twice in a row will then skip building the library a second time. You can always add an alias if you want:
sharedlib: libsharedlib.so
In that case, it's also good to tell make that sharedlib is not a real file:
.PHONY sharedlib
This prevents weird things from happening if you ever did have a file called sharedlib in the directory.

The library rule
sharedlib: $(OBJECTS)/%.o
is not enough to tell Make which objs are needed for the library.
This should work, and gives explicit control on which are the sources/objs pairs you want in the library:
SOURCESDIR=/home/test/project/sources
OBJECTDIR=/home/test/project/objects
OBJLIST = \
$(OBJECTS)/file1.o \
$(OBJECTS)/file2.o
$(OBJECTDIR)/%.o: $(SOURCESDIR)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJLIST)
$(CC) -shared -o libsharedlib.so $<

Related

No rule to make target 'main.o', needed by 'out'. Stop

I keep getting this error and I can't figure out what I am doing wrong. I am using an template so I can get in the dir bin the executable. The dir include the header files. The dir obj for the object files created and the src for the .c files.
My makefile
OBJ_dir = obj
INC_DIR = include
OBJECTS = main.o client.o private.o memory.o process.o proxy.o server.o
main.o = main.h memory-private.h stdio.h stdlib.h string.h syscall.h unistd.h wait.h sysexits.h memory.h
client.o = client.h
private.o = private.h
memory.o = memory.h memory_private.h
process.o = process.h
proxy.o = proxy.h
server.o = server.h
CC = gcc
CFLAGS = -Wall –I $(INC_DIR)
LIBS = -lm
out: $(OBJECTS)
$(CC) $(addprefix $(OBJ_dir)/,$(OBJECTS)) -o bin/out $(LIBS)
%.o: src/%.c $($#)
$(CC) $(CFLAGS) -o $(OBJ_dir)/$# -c $<
clean:
rm –f *.o out
rm –f out
There are many issues here. It's probably a good idea to read at least the first few chapters of the GNU make manual to understand how make and makefiles work.
Take this rule:
out: $(OBJECTS)
$(CC) $(addprefix $(OBJ_dir)/,$(OBJECTS)) -o bin/out $(LIBS)
First, it's not right to list a different target than the file you actually build. Here you told make you'd build a target named out, but your recipe actually builds a target named bin/out. That's wrong.
Second, but similarly, it's not right to have your target depend on one set of prerequisites (the files defined by $(OBJECTS)) but then have the recipe of your rule use a completely different set of prerequisites (by adding a $(OBJ_dir)/ prefix to all the files).
This tells make "please build files main.o, client.o, etc., but what my command will actually use is files obj/main.o, obj/client.o, etc.". It doesn't make sense to tell make to build targets that you aren't going to actually use.
This should be:
bin/out: $(addprefix $(OBJ_dir)/,$(OBJECTS))
$(CC) $^ -o $# $(LIBS)
In general if you ever find yourself writing a recipe where you are modifying the automatic variables like $# or $^ instead of using them as-is, you're almost certainly doing something wrong.
Next your pattern rule has other issues:
%.o: src/%.c $($#)
$(CC) $(CFLAGS) -o $(OBJ_dir)/$# -c $<
First, you cannot use automatic variables like $# in a prerequisite list. Those values are only set when expanding the recipe of a rule. They are not set (empty) when evaluating the prerequisite list. So $($#) expands to the empty string here and does nothing.
Second you have the same problem as above where you are not creating $# you are creating $(OBJ_dir)/$# which is wrong. You should write your rule like this:
$(OBJ_dir)/%.o: src/%.c
$(CC) $(CFLAGS) -o $# -c $<
so that the target lists the file you want to build, and the recipe uses $# without modification.
As for your prerequisites, you should just create them directly rather than trying to use fancy variables (which can't work). As the comment above suggests, just change:
proxy.o = proxy.h
to:
proxy.o : proxy.h
(and all the rest) and it will work. Note, though, that make always builds the first explicit target it sees by default so you may have to re-arrange your makefile a little bit if you want bin/out to be the default target.

Makefile to compile all src and generate static library

I've got a large-ish C project, and I want to generate a static library from all of my sources in the src/ file using the includes from my include/ path, and some other includes for my RTOS.
I have a working set of steps in the line commands that work:
gcc src/drivers/* src/packets/* (...more files) -c -I ./include -I ../SatelliteSim/Source/include/ -I ../SatelliteSim/Project/ -I ../SatelliteSim/Source/portable/GCC/POSIX/ -m32 -DDEBUG=1 -g -UUSE_STDIO -D__GCC_POSIX__=1 -pthread
then, ar -rsc telecommands.a *.o
My current attempt at the Makefile looks like this:
CXXFLAGS := -I./include -I../SatelliteSim/Source/include/ -I../SatelliteSim/Project/ -I../SatelliteSim/Source/portable/GCC/POSIX/ -m32 -DDEBUG=1 -g -UUSE_STDIO -D__GCC_POSIX__=1 -pthread
MODULES := commands/commands \
driver_toolkit/driver_toolkit \
(... more 'modules')
SOURCES := src/$(MODULES).c
OBJS := bin/$(MODULES).o
all: telecommands.a
telecommands.a: $(OBJS)
ar -rsc $# $^
$(OBJS): $(SOURCES)
$(CXX) $(CXXFLAGS) -c $^ -o $#
But i'm getting an issue with my include files in the compilation step.
Hopefully someone can point out what I'm doing wrong :)
Thanks in advance!
You have at least two major problems.
The first is your SOURCES and OBJS variable assignments are wrong. Make does straightforward textual replacement when it expands variables. So:
MODULES := foo bar biz
SOURCES := src/$(MODULES).c
OBJS := bin/$(MODULES).o
expands to simply:
SOURCES := src/foo bar biz.c
OBJS := bin/foo bar biz.o
which is clearly not right. If you are willing to use GNU make-specific functions, which operate individually on each word in the variable, you can get what you want:
SOURCES := $(patsubst %,src/%.c,$(MODULES))
OBJS := $(patubst %,bin/%.o,$(MODULES))
The next problem you have is this:
$(OBJS): $(SOURCES)
$(CXX) $(CXXFLAGS) -c $^ -o $#
which expands to something like this:
bin/foo.o bin/bar.o bin/biz.o : src/foo.c src/bar.c src/biz.c
$(CXX) $(CXXFLAGS) -c $^ -o $#
Again, make is not going to somehow infer that you want each object file on the left to somehow be matched with some source file on the right, using some string matching heuristic. That's not how make works. If there are multiple targets on the left side, make creates a separate rule for each one where each one contains all the prerequisites on the right side. So the above is the same as if you'd written:
bin/foo.o : src/foo.c src/bar.c src/biz.c
$(CXX) $(CXXFLAGS) -c $^ -o $#
bin/bar.o : src/foo.c src/bar.c src/biz.c
$(CXX) $(CXXFLAGS) -c $^ -o $#
bin/biz.o : src/foo.c src/bar.c src/biz.c
$(CXX) $(CXXFLAGS) -c $^ -o $#
which means that it will compile all the source files to create each object file.
In makefiles you have to write a rule that builds one target at a time, from the prerequisites of that target. So for example you can use a pattern rule:
bin/%.o : src/%.c
$(CXX) $(CXXFLAGS) -c $< -o $#
Note I used $< instead of $^ because you only want to compile the source file. Note that this invokes the compiler one time for each source file, to generate that output file. Make is not well-suited to environments where a single invocation of the build tool generates many different outputs (although if you're willing to restrict yourself to GNU make version 4.3 or higher you can do it if you want).
This will not rebuild any object files if headers change because you've not listed any headers as prerequisites.
You mention getting an issue with my include files in the compilation step but that's not helpful information to us. If you still have compilation problems after fixing your makefile, you can open a new question but please include exactly (cut and paste) the kinds of errors you see and also the compile line that make prints that generates these errors.

Compiling multiple .c and .h files

My program is divided into 6 files:
list.h (Containing basic list struct info and function prototypes)
list.c (Containg the implementation of the above)
search_tree.h (Containing basic tree struct info and function prototypes)
search_tree.c (Containing the implementation of the above, and includes list.h)
search.h ( again, prototypes of functions )
search.c (implementation of the aobve functions)
main.c ( Requires all of the above in order to run )
I cant seem to figure out what the makefile should be, i've tried the one below but it doesnt work and i get errors of structs and functions not implemented.
myprog: list.o search_tree.o search.o main.o
gcc -o myprog list.o search_tree.o search.o main.o
list.o: list.c list.h
gcc -c list.c
search_tree.o: search_tree.c search_tree.h
gcc -c search_tree.c
search.o: search.c search.h
gcc -c search.c
main.o: search.h search_tree.h list.h hash_table.h
gcc -c main.c
You do not need to explicitly create a rule for each file - make has a number of implicit rules that already do 90% of what you need. Your makefile can be as simple as
CC=gcc
CFLAGS=-std=c11 -pedantic -Wall -Werror # my usual compiler flags
LDFLAGS= # specify additional libraries and library search paths here
myprog: main.o search.o search_table.o list.o
$(CC) -o $# $(LDFLAGS) $?
clean:
rm -rf myprog *.o
There's already an implicit rule to build .o files from .c files, so you don't need to create your own unless you want to override the default, which is
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
You do need the explicit myprog rule to link the object files into the executable since the executable name doesn't match any of the source or object file names. $# expands to the target name, myprog, and $? expands to the list of prerequisites for the target (i.e., the object files). $< expands to the first name in the list of prerequisites.
This doesn't cover header file dependencies, but your project is small enough for that to not be too much of an issue. However, give this article a read for one way to handle that.
Similar to John's proposal with a small bug fixed ($^ automatic variable instead of $?), a bit more automation (wildcard to search for the C source files) and with dependencies added for the header files ($(OBJS): %.o: %.h static pattern rule):
EXEC := myprog
OBJS := $(patsubst %.c,%.o,$(wildcard *.c))
$(EXEC): $(OBJS)
$(CC) -o $# $(LDFLAGS) $^
$(OBJS): %.o: %.h
clean:
rm -f $(EXEC) $(OBJS)

Make file that compiles gcc and puts the objects in a separate folder

I am trying to create a make file that will work accordingly
OBJECT_DIRECTORY := out/obj
C_SOURCE_FILES = (Path and files fetched from different make files)
CFLAGS += -mcpu=$(CPU) -mthumb -mabi=aapcs -mfloat-abi=soft
CFLAGS += -Wall -Werror
CFLAGS += -D$(DEVICE) -std=gnu99
$(OBJECT_DIRECTORY)/%.o: %.c
$(CC) $(C_SOURCE_FILES) $(CFLAGS) -c -o $# $<
I verified that the C_SOURCE_FILES variable actually contains the c source files. This since I am able to compile using this:
$(OBJECT_DIRECTORY)/%.o:
$(CC) $(C_SOURCE_FILES) $(CFLAGS) -c
Problem with that is that the object files are not placed in the folder where I need them for the linking.
By the way, I am executing the make file from the Eclipse C/C++ IDE
I would be extremely happy if someone could help me solve this problem.
Try this:
$(OBJECT_DIRECTORY)/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
You don't need the C_SOURCE_FILES variable here. This recipe will create out/obj/{file}.o for every file called {file}.c.
You don't show it, but the dependency list for the executable being created from the object files must explicitly call out each object file.
I solved the problem, I think... By creating a list of target files to be used in the compilation.
# Create the object file names needed for the target. Make needs these file names as target for the compilation
TEMP := $(notdir $(C_SOURCE_FILES:.c=.o))
C_OBJECT_FILES := $(addprefix $(OBJECT_DIRECTORY)/, $(TEMP:.c=.o) )
TEMP_1 := $(notdir $(ASSEMBLER_SOURCE_FILES:.s=.o))
ASSEMBLER_OBJECT_FILES := $(addprefix $(OBJECT_DIRECTORY)/,$(TEMP_1:.s=.o) )
# Tells make to compile all the files in the C_OBJECTS_VARIABLE
all: $(C_OBJECT_FILES)
# Do the compilation of the c files and place the object files in the out/obj folder
$(C_OBJECT_FILES): $(C_SOURCE_FILES)
$(CC) $(CFLAGS) -M $< -MF "$(#:.o=.d)" -MT $#
$(CC) $(CFLAGS) -c -o $# $<
# Tells make to compile all the files in the ASSEMBLER_OBJECTS_VARIABLE
all: $(ASSEMBLER_OBJECT_FILES)
# Do the compilation of the assembler files and place the object files in the out/obj folder
$(ASSEMBLER_OBJECT_FILES): $(ASSEMBLER_SOURCE_FILES)
$(CC) $(ASMFLAGS) -c -o $# $<
This works well and consistently. Issue I have now is that the rule for linking is not executed at all...
## Link C and assembler objects to an .out file
$(BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out: $(C_OBJECT_FILES) $(ASSEMBLER_OBJECT_FILES) $(LIBRARIES)
$(CC) $(LDFLAGS) -o $(BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out
I am wondering if it has anything to do with "all:"
Found the solution to that problem as well. I created a couple of new rules to make sure that the linking is getting executed. Now the make file works well.

Resulting file names as a input of a variable

I have many functions in different files.
eg: OBJ_SRC=sum.c sub.c mul.c div.c remainder.c
When I am creating a library I do like this:
libarithmatic.a: $(OBJ_SRC)
gcc -c $(OBJ_SRC) # creates sum.o sub.o..
ar rcs libarithmatic.a $(OBJS) #<--- problem #OBJS
How to store the output of gcc -c $(OBJ_SRC): add.o sub.o mul.o.. (newly created/updated file names) into OBJS variable?
The usual way is with patsubst
OBJS=$(patsubst %.c,%.o,$(OBJ-SRC))
Now calling gcc as part of the target to build the library is a bad idea. It misses the main point of using make at all as you are asking gcc to blindly recompile all the objects instead of having make find which have changed. The usual rule is:
libarithmatic.a: $(OBJS)
ar rcs libarithmatic.a $(OBJS)
You can put in the pattern rule for compiling the .c files, but if you'd just put in
%.o: %.c
gcc -c $<
you don't have to bother as that is implicit. Well, the default implicit rule is really
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
where CC defaults to suitable compiler and you can override it and CPPFLAGS and CFLAGS default to empty and you can set them to whatever flags you want to use for compilation. CPPFLAGS is for both C and C++, CFLAGS is for C only, CXXFLAGS is for C++ only (C++ compiler is CXX).
On a side-note, I'd suggest looking at CMake, which supports generating build files for various platforms, IDEs and the new ultra-fast ninja. The corresponding CMakeLists.txt would be as trivial as
project(arithmatic)
add_library(arithmatic sum.c sub.c mul.c div.c remainder.c)
and making it a shared library as trivial as adding SHARED keyword when you want to.
Note, that the % placeholder does not have to be at the beginning. If you want to put the objects in different directory from the sources, you can write things like
OBJS=$(patsubst src/%.c,obj/%.o,$(SOURCES))
(the sources have to be listed with the directory prefix in this case) or perhaps
OBJS=$(patsubst %.c,.objs/%.o,$(SOURCES))
And you can similarly use the pattern in the rules, so
obj/%.o: src/%.c
mkdir -p obj
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
or
.objs/%.o: %.c
mkdir -p .objs
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
You have to make sure the output directory exists as the compiler won't create it (so I include the mkdir in the rules) and you have to explicitly specify compiler output, because it would create it in current directory otherwise.

Resources