$(TARGET): build $(OBJECTS)
ar rcs $# $(OBJECTS)
ranlib $#
What are "ar rcs" and "ranlib"?
ar is used to create libraries (that are archives containing compiled code)
man ar:
ar -- create and maintain library archives
...
-r Replace or add the specified files to the archive
-c Whenever an archive is created, an informational message to that effect is written to standard error. If the -c option is speci-
fied, ar creates the archive silently.
-s Write an object-file index into the archive, or update an existing one, even if no other change is made to the archive. You may
use this modifier flag either with any operation, or alone. Running `ar s' on an archive is equivalent to running `ranlib' on
it.
The first argument is the name of the resulting libraries, the others are the object files to insert in it.
ranlib generates an index to the contents of an archive and stores it in the archive.
Related
This question already has answers here:
Makefile issue: smart way to scan directory tree for .c files
(4 answers)
Closed last year.
I need to create a static library using source files in different directories. I am able to create static library by specifying each and every source file in the Makefile. It increased more content in the Makefile.
Let me explain what I did with an example:
#Specifying the each and every source files to FILES is more complex to me. Trying to find out alternative to this problem
Files = Source1\A.c Source\B.c Source2\C.c Source3\D.c ........... Sorce3/Z.c
$(OUT_FILE_NAME): $(patsubst %.c,%.o,$(wildcard $(FILES)))
ar -r -o $# $^
#Compiling every *.c to *.o
%.o: %.c dirmake
arm-none-eabi-gcc -c -o $# $<
I'm trying to explore alternative way to specifying all source files in the Makefile. This will help us to not modify this Makefile again if any new source file added. Is it possible to do that?
I tried to search for this problem and many sources explain how to create static library but I don't see any alternative solution for this problem.
Without knowing the details of your development environment I would try these minimal changes first. Using the wildcard-function for the source directories will enable you to add more sources without having to edit the Makefile every time. Just keep the directories clean of any unused c-files to avoid including stuff in your library that you don't want.
I have also made the Files variable simply expanded (evaluated once) by using := for assignment. I also simplified the prerequisite of the first rule and fixed the case of the variable-name.
Files := $(wildcard Source1/*.c) $(Source2/*.c) $(Source3/*.c)
$(OUT_FILE_NAME): $(patsubst %.c,%.o,$(Files))
ar -r -o $# $^
#Compiling every *.c to *.o
%.o: %.c dirmake
arm-none-eabi-gcc -c -o $# $<
So here is a Makefile I have been given, with comment I have added.
MF= Makefile_c #name of the makefile
CC= cc #compiler to use
CFLAGS= -g #flags to use
LFLAGS= -lm #flags to use after the thingy
EXE= hello #name to give the executable
INC= \ # ??? What's this for ???
# No user-defined include files at present - list here if required.
# name of the source file
SRC= \
hello.c
#delete default suffix
.SUFFIXES:
#define the suffixes we are interested in
.SUFFIXES: .c .o
OBJ= $(SRC:.c=.o) # names to give the object files
#The .o files depend on the .c files. Compile the object files.
.c.o:
$(CC) $(CFLAGS) -c $<
all: $(EXE) #The output is the executable
$(OBJ): $(INC) #The objects depend on whatever INC is
# The executable depends on the object files. build it from the object files.
$(EXE): $(OBJ)
$(CC) $(CFLAGS) -o $# $(OBJ) $(LFLAGS)
# ??? the object files depend on the makefile???
$(OBJ): $(MF)
# remove any old executables or object files.
clean:
rm -f $(OBJ) $(EXE) core
I am still learning about makefiles so please correct me if I have misidentified anything. The makefile works fine But I want to adapt it to work with my program that has multiple files and header files. I suspect that the variable $INC will somehow make this possible, but so far my attempts to use it have not worked.
For now I would like to understand what this makefile is trying to do, cn you tell me what $INC is for?
The makefile works fine But I want to adapt it to work with my program that has multiple files and header files. I suspect that the variable $INC will somehow make this possible
Unfortunately, no. The \ is just a line continuation, so you can write content for the variable in the next line. It's empty here. This is just a very simple (and ancient!) approach for dependencies: List them yourself. The intention is to list all files your C source file #includes there, so make will rebuild when any of these included files change.
There are much advanced patterns, gcc (and other compilers) allow to do automatic dependency information for make, but this is out of scope for this question. (*)
As for building with multiple source files, this Makefile already supports it, again using an "ancient" way, a suffix rule. It automatically considers all .c files in your directory part of your final program.
(*) As mentioned by Tormund Giantsbane in the comments, this document has nice information on the topic auf automatic dependencies
I am working on project, where i use couple of .c and .h files.
I created Makefile where i actualize executable program based on changes in all of these files.
Problem is, when i use make, program is compiled, but when i execute program, it runs without any change. I need to save ( working in vim so :w ) all included files, even when i changed only one.
If i don't save all these files, program is compiled, but executes the same thing as it did before change.
Could someone explain me why is that ?
Makefile code :
CC=gcc
CFLAGS=-WALL
execFile: execFile.o functions.h newDataTypes.h
Thank you.
The reason you are not getting execFile updated is because you're NOT updating it. Or at least you don't seem to be in this particular case.
There are many ways to get about doing this. However since you are using gcc and I assume you're using gnu make the following is probably the best solution you can execute1.
Given the files:
-rw-r--r-- 1 user sudo 73 Nov 4 22:54 exeFile.c
-rw-r--r-- 1 user sudo 74 Nov 4 22:54 exeFile.h
-rw-r--r-- 1 user sudo 90 Nov 4 22:55 hello_world.c
-rw-r--r-- 1 user sudo 888 Nov 4 23:03 Makefile
cat exeFile.c
#include <stdio.h>
#include "exeFile.h"
int main()
{
hello_world();
}
exeFile.h
#ifndef _EXEFILE_H
#define _EXEFILE_H
extern void hello_world();
#endif
hello_world.c
#include <stdio.h>
#include "exeFile.h"
void hello_world()
{
printf("Hello World\n");
}
you can set up a make file that generates dependencies and ensures that the program will always be compiled correctly:
CC=gcc
CFLAGS=-Wall
SOURCES=exeFile.c hello_world.c
EXE=exeFile
OBJ=$(SOURCES:%.c=%.o)
DEPDIR := .deps
$(shell mkdir -p $(DEPDIR) >/dev/null)
DEPFLAGS = -MT $# -MMD -MP -MF $(DEPDIR)/$*.Td
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
COMPILE.cc = $(CXX) $(DEPFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
POSTCOMPILE = #mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $#
%.o: %.c
%.o: %.c $(DEPDIR)/%.d
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(POSTCOMPILE)
%.o : %.cc
%.o : %.cc $(DEPDIR)/%.d
$(COMPILE.cc) $(OUTPUT_OPTION) $<
$(POSTCOMPILE)
%.o : %.cxx
%.o : %.cxx $(DEPDIR)/%.d
$(COMPILE.cc) $(OUTPUT_OPTION) $<
$(POSTCOMPILE)
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
$(EXE): $(OBJ)
$(CC) -o $# $(OBJ) $(LDFLAGS)
clean:
$(RM) $(OBJ) $(EXE)
dev-clean: clean
$(RM) -r $(DEPDIR)
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SOURCES))))
Let's go over the relevant parts about dependencies
DEPDIR =
This implementation places dependency files into a subdirectory named .deps .
$(shell mkdir -p $(DEPDIR) 2>/dev/null)
GCC does not create subdirectories for output, this line ensures that the DEPDIR directory always exists.
DEPFLAGS = ...
These are GCC-specific flags which tell the compiler to generate dependency info.
-MT $#
Set the name of the target in the generated dependency file.
-MMD
Generate dependency information in addition to compiling. -MMD omits system headers from the generated dependencies: if you prefer to preserve system headers as prerequisites, use -MD instead.
-MP
Adds a make target for each prerequisite in the list, this avoids errors when deleting files.
-MF $(DEPDIR)/$*.Td
Write the generated dependency file to a temporary file $(DEPDIR)/$*.Td e.g. hello_world.c will generate hello_world.Td as temp dependency content for use in Makefile.
POSTCOMPILE = ...
First rename the generated temporary dependency file to the real dependency file. We do this in a separate step to side-step compile errors. Next we explicitly touch the files to avoid a gcc bug.
%.o : %.c
Delete the built-in rules for building object files from .c files, so that our rule is used instead. Do the same for the other built-in rules.
... $(DEPDIR)/%.d
Declare the generated dependency file as a prerequisite of the target, so that if it’s missing the target will be rebuilt.
$(DEPDIR)/%.d: ;
Create a pattern rule with an empty recipe, so that make won’t fail if the dependency file doesn’t exist.
.PRECIOUS: $(DEPDIR)/%.d
Mark the dependency files precious to make, so they won’t be automatically deleted as intermediate files.
include ...
Include the dependency files that exist: translate each file listed in SOURCES into its dependency file. Use wildcard to avoid failing on non-existent files.
1 See Auto-Dependencies Generation for details.
Fix:
Tell make that the executable depends only on the object file and the object file depends on the header files:
execFile: execFile.o
execFile.o: functions.h newDataTypes.h
Explanation:
In order to build your executable two steps are needed:
compilation of C source files (that include header files) to produce object files,
linking of the object files to produce the executable.
So, when changing your header files you must re-compile, that is re-built the object files, not just re-link that would produce the same executable from the same object files.
In your Makefile the dependencies are not properly defined. You did not tell make that the object file (execFile.o) shall be rebuilt when your header files change. Instead, you told it that the executable (execFile) shall be rebuilt.
First of all, your dependencies are mistaken. Your executable does not depend on the .h header files, as they are using only at compilation time. The dependencies are normally between .o files and .h files, as when you modify one .h file, the including .c file must be compiled to generate the .o file. so in case you have execFile.o (which, on lack of complete information, I'll suppose it depends on execFile.c, which #includes functions.h and newDataTypes.h, the rule should be:
execFile.o: execFile.c functions.h newDataTypes.h
As it has been pointed out in other responses, there's no need to write the command to build the .o file, as there is a default rule like this:
.c.o:
$(CC) $(CFLAGS) -o $# -c $<
(observe there's a -c option to the compiler indicating to compile only and don't link, we'll return here below) which means that once you detect the .o is outdated (as the dependencies on .c and .hs mark) it will be compiled with the above command, which result in:
gcc -Wall -o execFile.o -c execFile.c
making the appropiate compilation.
Other thing is the dependencies of the executable file. These have to be included, as make(1) doesn't know which object files form your final executable. In this case, assuming you have your program execFile depend on execFile.o and a.o, b.o and c.o, I normally use to write:
execFile_objs = execFile.o a.o b.o c.o
execFile: $(execFile_objs)
$(CC) $(LDFLAGS) -o $# $(execFile_objs)
so any of the .os is changed (because an indirect change in a source file) the whole program is linked again (but only the touched files are compiled)
NOTE
In the case (not normal) that you have a Makefile to create a program that has only one source file and several include files you can compile each time the whole thing each time you modify one source file, in this way:
execFile: execFile.c functions.h newDataTypes.h
$(CC) $(CFLAGS) $(LDFLAGS) -o $# execFile.c
This will execute
gcc -Wall -o execFile execFile.c
Observe that there is no -c (compile only, don't link) option in this command.
There's no mention of the include files (they are included because of the #include directives in the code... and you only state here that the executable depends also (and have to be built) in case any of the .h files are modified.
Automatic dependency rules are a little confusing at first, as they induce you to think there are such rules to make any kind of file from any other kind of file (well, there are for .c -> .o files, and .c -> <nothing> to compile directly to an executable) normally you have to include dependencies in such cases when your target depends on more files than the automatic rule states. In such cases, it is very important not to include any command, so the compiler selects the automatic rule (when you don't include a command to generate the target, the make(1) program tries to use a default rule for it, or nothing at all if you have not included commands, it only assumes your dependencies are indirect through this fake target --- and, as this fake target is not built in the process, it will fail always and be followed)
I am trying to add more then one file created in different directories to a static library but apparently it does not work as expected.
My makefile structure is something like this:
./src/drv/platform/AVR/
- hal
- hw
--- spi
--- uart
In hal I define a library name in $(LIB_TARGET) named libHal and all the *.o files should be archived in that library.
In hw I define another library name in $(LIB_TARGET) named libHw and all *.o files in hw/spi and hw/uart should go in that library: first the library libHw is created with the object files in hw/spi and they are never missed, then the objects in hw/uart are created and should be added to libHw.
In each subdirectory a generic makefile with suffix rules is ran that creates the object files and then should add each *.o to the library. At the end of the run I should have in another library directory(as in another location) 2 libs, libHal and libHw, libHal contains everything in hal, libHw everything in hw.
In this case the directory hw does not have any source files and looks like this:
SUBDIRS:= spi uart
LIB_TARGET = libHw.a
.PHONY: $(SUBDIRS) clean all
default: all
$(SUBDIRS)::
$(MAKE) -C $# $(MAKECMDGOALS)
all clean : $(SUBDIRS)
Each of the uart and spi subdirs hold something like this:
include $(TGT_BASE)/make/generic.mk
SRCS := uart.c
include $(TGT_BASE)/make/rules.mk
The file generic.mk only holds generic platform definitions.
The code for the generic makefile rules.mk with all the suffix rules.
.PHONY : all clean
OBJS = $(SRCS:.c=.o)
DEPS = $(OBJS:.o=.d)
LIB_TARGETT = $(LIB_DIR)/$(LIB_TARGET)
### Archive into a library file (.a)
$(LIB_DIR)/%.a: $(OBJS)
#echo $(MSG_L)
#echo 'Adding $^ to library $#'
$(AR) $(ARFLAGS) $# $^
#echo $(MSG_L)
### rule for c files
%.o: %.c
#echo $(MSG_C)
$(CC) -c $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $< -o $#
#echo $(MSG_C)
### make dependencies
%.d: %.c
#echo $(MSG_D)
$(CC) -E -MM $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $(CURDIR)/$< > $#
#echo $(MSG_D)
all: $(DEPS) $(OBJS) $(LIB_TARGETT)
clean:
$(RM) -rf *.o *.d .depend
The makefile that exists in most
Now the problem is that sometimes some of the *.o files in hw/uart are not added to the library defined in hw. Running make in debug reveals that make itself considers the prerequisites for the library to be older then the last access to the library so they are missed.
Found an implicit rule for 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
Pruning file 'uart.o'.
Finished prerequisites of target file 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
Prerequisite 'uart.o' is older than target 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
To explain better how this goes when it works here is an example
make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror -Os -mmcu=atmega328p -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
------- make Lib -------
Adding uart.o to library F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/li
bHw.a
avr-ar rcs F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a uart.o
------- make Lib -------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'
And here is an example if it when it is not working
make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror -Os -mmcu=atmega328p -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'
I am using make 3.82.90 and Windows 7.
So any idea how I can force make to not miss those objects? Or to see their real time of creation and properly add them to the library? Remember, sometimes they are added, but sometimes they are not.
Thank you.
When you say it always works when you run it with make all --debug=a it always works: which part of that matters? If you run make all does it always work? Or if you run make --debug=a does it always work? Or do you have to use both to make it always work?
Since you're not showing all the makefile, we can't say much. For example, how are you setting the value of OBJS? Where and how do you define the rules that build object files (or are you using make's built-in rules for that)? That information is critical. It looks like what's happening is that make is asking you to build one file but your rules build a different file, so make sees that the file it expects was not actually updated and doesn't do anything.
Also, it's very confusing that in your overview you talk about things like dir1, dir2, dir2.1, etc. but then in the error output you provide completely different paths. We can't determine how the "real" pathnames in your example match up with the pseudo-paths in your overview.
Please either use real paths everywhere, or edit your example output to use the pseudo-paths, so we can see which paths are doing what.
I am trying to write a makefile which should pick the sources from src/ and headers from inc/
~/Linuz/src: 1.c, 2.c, 3.c ...
~/Linuz/inc: abc.h, dyz.h
Please help me to create a makefile which should be available at
~/Linuz/some_other_dir/Makefile
PS: Trying to compile it for my linux machine.
Thank you for your suggestions.
all: my_program
%.o: ../src/%.c
$(CC) $(CFLAGS) -I../inc/ -c -o $# $^
my_program: 1.o 2.o 3.o
$(CC) $(LDFLAGS) -o $# $^
clean:
rm -f *.o my_program
If you put your Makefile in the ~/Linuz/some_other_dir/, the following rule
%.o: ../src/%.c
will get the c files from the ../src/ folder (~/Linuz/src/) and create the object (*.o) files in the same folder of the Makefile.
The -I../inc/ option means that the makefile canl get a header files from the ../inc/ folder (~/Linuz/inc/).
The my_program: 1.o 2.o 3.o rule means that the makefile will create the binary in the same directory of Makefile from the object files 1.o and 2.o and 3.o
From the make manual:
$^ The names of all the prerequisites, with spaces between them.
For prerequisites which are archive members, only the member named is
used (see Archives). A target has only one prerequisite on each other
file it depends on, no matter how many times each file is listed as a
prerequisite. So if you list a prerequisite more than once for a
target, the value of $^ contains just one copy of the name. This list
does not contain any of the order-only prerequisites; for those see
the `$|' variable, below.
$# The file name of the target of the rule. If the target is an
archive member, then ‘$#’ is the name of the archive file. In a
pattern rule that has multiple targets (see Introduction to Pattern
Rules), ‘$#’ is the name of whichever target caused the rule's recipe
to be run.