Makefile to compile all src and generate static library - c

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.

Related

makefile: build .o files in another directory

Edit: This is the final Makefile, it build all .o files in build dir and produce one executable.
CXX = g++
CXXFLAGS = -g -Wall
SRC_DIR = ./src
BUILD_DIR = ./build
SRC = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(SRC:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
LIBS = -lusb-1.0 -lpulse-simple -lpulse
EXEC = AndroidMicLinux
all: $(EXEC)
$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -o $# -c $<
$(EXEC) : $(OBJS)
$(CXX) -o $(EXEC) $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(EXEC)
There are many issues with this makefile. Most of them have to do with expansion of variables. If you simply visualize the expansion of variables you'll likely see the problems. Remember that make is just doing text substitution to expand variables. There's no "magic" happening here.
So for example:
SRC = $(wildcard $(SRC_DIR)/*.cpp)
Let's suppose that you have the files ./src/foo.cpp and ./src/bar.cpp. That means that $(SRC) will expand to those two files. Fine. Then you have:
OBJS = $(BUILD_DIR)/$(notdir $(SRC:.cpp=.o))
How does this work? First we expand BUILD_DIR:
OBJS = ./build/$(notdir $(SRC:.cpp=.o))
Then we expand $(SRC:.cpp=.o) which gives ./src/foo.o ./src/bar.o. Then the notdir is applied which gives foo.o bar.o. That's substituted for the function, so the result is:
OBJS = ./build/foo.o bar.o
You can see this is wrong. You can't just stick a string before a function and expect that string to be appended to every word of the function! You need to explicitly tell make that you want to do that. Probably you want something like this instead:
OBJS = $(SRCS:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
Next this rule:
%.o : %.c
$(CC) -o $(OBJS) -c $(SRC)
First the recipe is wrong. What does this expand to?
g++ -o ./build/foo.o ./build/bar.o -c ./src/foo.cpp ./src/bar.cpp
Clearly that's a totally invalid compile line. You want just the one object file and source file not all of them. This is what automatic variables are for:
%.o : %.c
$(CC) -o $# -c $<
However this is still wrong: this pattern rule will never match. Why? Because when make tries to build ./build/foo.o the % pattern matches the string ./build/foo. So when make looks to see if the prerequisite %.c exists it will check for ./build/foo.c. First, your filenames end in .cpp not .c so this should be %.cpp. But beyond that, the source files are in a different directory than the destination files so you can't just use %. You have to write it like this:
$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
$(CC) -o $# -c $<
I'll also point out that convention uses CC for the C compiler; if you're compiling C++ you should be using the CXX variable. Also you set a FLAGS variable but your compile rule doesn't actually use it; you can't just put it in the link rule. And, for C++ compiler flags the convention is to use CXXFLAGS as the variable.

How to stop Make from recompiling the whole project if one include file changes? [duplicate]

I have the following makefile that I use to build a program (a kernel, actually) that I'm working on. Its from scratch and I'm learning about the process, so its not perfect, but I think its powerful enough at this point for my level of experience writing makefiles.
AS = nasm
CC = gcc
LD = ld
TARGET = core
BUILD = build
SOURCES = source
INCLUDE = include
ASM = assembly
VPATH = $(SOURCES)
CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
-nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS = -f elf
#CFILES = core.c consoleio.c system.c
CFILES = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES = assembly/start.asm
SOBJS = $(SFILES:.asm=.o)
COBJS = $(CFILES:.c=.o)
OBJS = $(SOBJS) $(COBJS)
build : $(TARGET).img
$(TARGET).img : $(TARGET).elf
c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img
$(TARGET).elf : $(OBJS)
$(LD) -T link.ld -o $# $^
$(SOBJS) : $(SFILES)
$(AS) $(ASFLAGS) $< -o $#
%.o: %.c
#echo Compiling $<...
$(CC) $(CFLAGS) -c -o $# $<
#Clean Script - Should clear out all .o files everywhere and all that.
clean:
-del *.img
-del *.o
-del assembly\*.o
-del core.elf
My main issue with this makefile is that when I modify a header file that one or more C files include, the C files aren't rebuilt. I can fix this quite easily by having all of my header files be dependencies for all of my C files, but that would effectively cause a complete rebuild of the project any time I changed/added a header file, which would not be very graceful.
What I want is for only the C files that include the header file I change to be rebuilt, and for the entire project to be linked again. I can do the linking by causing all header files to be dependencies of the target, but I cannot figure out how to make the C files be invalidated when their included header files are newer.
I've heard that GCC has some commands to make this possible (so the makefile can somehow figure out which files need to be rebuilt) but I can't for the life of me find an actual implementation example to look at. Can someone post a solution that will enable this behavior in a makefile?
EDIT: I should clarify, I'm familiar with the concept of putting the individual targets in and having each target.o require the header files. That requires me to be editing the makefile every time I include a header file somewhere, which is a bit of a pain. I'm looking for a solution that can derive the header file dependencies on its own, which I'm fairly certain I've seen in other projects.
As already pointed out elsewhere on this site, see this page:
Auto-Dependency Generation
In short, gcc can automatically create .d dependency files for you, which are mini makefile fragments containing the dependencies of the .c file you compiled.
Every time you change the .c file and compile it, the .d file will be updated.
Besides adding the -M flag to gcc, you'll need to include the .d files in the makefile (like Chris wrote above).
There are some more complicated issues in the page which are solved using sed, but you can ignore them and do a "make clean" to clear away the .d files whenever make complains about not being able to build a header file that no longer exists.
You could add a 'make depend' command as others have stated but why not get gcc to create dependencies and compile at the same time:
DEPS := $(COBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$#) -o $# $<
The '-MF' parameter specifies a file to store the dependencies in.
The dash at the start of '-include' tells Make to continue when the .d file doesn't exist (e.g. on first compilation).
Note there seems to be a bug in gcc regarding the -o option. If you set the object filename to say obj/_file__c.o then the generated _file_.d will still contain _file_.o, not obj/_file_c.o.
This is equivalent to Chris Dodd's answer, but uses a different naming convention (and coincidentally doesn't require the sed magic. Copied from a later duplicate.
If you are using a GNU compiler, the compiler can assemble a list of dependencies for you. Makefile fragment:
depend: .depend
.depend: $(SOURCES)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^>>./.depend;
include .depend
There is also the tool makedepend, but I never liked it as much as gcc -MM
You'll have to make individual targets for each C file, and then list the header file as a dependency. You can still use your generic targets, and just place the .h dependencies afterwards, like so:
%.o: %.c
#echo Compiling $<...
$(CC) $(CFLAGS) -c -o $# $<
foo.c: bar.h
# And so on...
Basically, you need to dynamically create the makefile rules to rebuild the object files when the header files change. If you use gcc and gnumake, this is fairly easy; just put something like:
$(OBJDIR)/%.d: %.c
$(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(#D)/\1.o $(#D)/\1.d:,' >$#
ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif
in your makefile.
Over and above what #mipadi said, you can also explore the use of the '-M' option to generate a record of the dependencies. You might even generate those into a separate file (perhaps 'depend.mk') which you then include in the makefile. Or you can find a 'make depend' rule which edits the makefile with the correct dependencies (Google terms: "do not remove this line" and depend).
Simpler solution: Just use the Makefile to have the .c to .o compilation rule be dependent on the header file(s) and whatever else is relevant in your project as a dependency.
E.g., in the Makefile somewhere:
DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv
::: (your other Makefile statements like rules
::: for constructing executables or libraries)
# Compile any .c to the corresponding .o file:
%.o: %.c $(DEPENDENCIES)
$(CC) $(CFLAGS) -c -o $# $<
None of the answers worked for me. E.g. Martin Fido's answer suggests gcc can create dependency file, but when I tried that it was generating empty (zero bytes) object files for me without any warnings or errors. It might be a gcc bug. I am on
$ gcc --version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
So here's my complete Makefile that works for me; it's a combination of solutions + something that wasn't mentioned by anyone else (e.g. "suffix replacement rule" specified as .cc.o:):
CC = g++
CFLAGS = -Wall -g -std=c++0x
INCLUDES = -I./includes/
# LFLAGS = -L../lib
# LIBS = -lmylib -lm
# List of all source files
SRCS = main.cc cache.cc
# Object files defined from source files
OBJS = $(SRCS:.cc=.o)
# # define the executable file
MAIN = cache_test
#List of non-file based targets:
.PHONY: depend clean all
## .DEFAULT_GOAL := all
# List of dependencies defined from list of object files
DEPS := $(OBJS:.o=.d)
all: $(MAIN)
-include $(DEPS)
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
#suffix replacement rule for building .o's from .cc's
#build dependency files first, second line actually compiles into .o
.cc.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$#) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $# $<
clean:
$(RM) *.o *~ $(MAIN) *.d
Notice I used .cc .. The above Makefile is easy to adjust for .c files.
Also notice importance of these two lines :
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$#) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $# $<
so gcc is called once to build a dependency file first, and then actually compiles a .cc file. And so on for each source file.
I believe the mkdep command is what you want. It actually scans .c files for #include lines and creates a dependency tree for them. I believe Automake/Autoconf projects use this by default.

Makefile does not iterate over all the source files?

I want to compile many source file and build a library from them.
My makefile looks approximately like this:
SOURCES := /home/test/src/\*.c
OBJECTS := $(SOURCES:.c=.o)
.PHONY: compileLibrary
compileLibrary:
$(CC) -fPIC -c $(SOURCES) -o $(OBJECTS)
$(CC) -shared -o libshared.so $(OBJECTS)
How ever the process does not iterate over each source file, it seems that makefile does not replace the * in SOURCES by its value.
*.c, on its own, is not expanded, you have to use the wildcard function (like $(wildcard *.c))
It is *.c, not \*.c. \ is escape and removes the special meaning of *.
Obviously your makefile shouldn't contain absolute path. Normally the current directory has to be the one where the makefile is in, so take advantage of it.
You should be actually using the features of make:
libshared.so: $(OBJECTS)
$(CC) -shared -o $# $<
compileLibrary: libshared.so
(note: you can probably do without the compilation rule, because the default is likely good enough)

Rule not recognized in makefile?

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 $<

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.

Resources