src/p1.c src/p1.s
STRIPPED_FILE= $(src:%.c=%.o)
all:
#echo $(STRIPPED_FILE)
output is src/p1.o src/p1.s
Question:
Why has $(src:%.c=%.o) listed src/p1.s though I have given src:%.c
How can i get only src/p1.o?
Related
I have a project that includes many source files in different folder locations. For some reason my Makefile can either do one of the following but not both at the same time (which is what I really want):-
1) Compile all files into a separate directory
2) Perform the compilation ONCE, gcc needs to be called once only as this significantly reduces the compilation time.
This is a code snippet that works to achieve option 1:-
INCLDDIRS := "The needed include directories"
CFLAGS = "some c flags"
C_SOURCE = "Many many source files in different directories"
C_SOURCE_NAMES = $(notdir $(C_SOURCE))
OBJECT_DIRECTORY = ObjDir
C_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_NAMES:.c=.o) )
all: $(OBJECT_DIRECTORY) $(C_OBJECTS)
$(OBJECT_DIRECTORY):
mkdir ObjDir
$(OBJECT_DIRECTORY)/%.o:%.c
$(CC) $(CFLAGS) $(INCLDDIRS) -c -o $# $<
For some reason the above compiles each c source file individually and generates an object file (i.e. gcc is called for all source files). Which is not what I want. However, at least all generated files are located in ObjDir
and this is the code snippet that works to achieve option 2:-
INCLDDIRS := "The needed iclude directories"
CFLAGS = "some c flags"
C_SOURCE = "Many many source files in different directories"
C_SOURCE_NAMES = $(notdir $(C_SOURCE))
OBJECT_DIRECTORY = ObjDir
C_OBJECTS = $(OBJECT_DIRECTORY)/*.o
all: $(OBJECT_DIRECTORY) $(C_OBJECTS)
$(OBJECT_DIRECTORY):
mkdir ObjDir
$(C_OBJECTS): (C_SOURCE)
$(CC) $(CFLAGS) $(INCLDDIRS) -c $(C_SOURCE)
For the above snippet, all files are compiled once (i.e. gcc is called only once) but the object files are generated at the same location as the Makefile and not into a separate directory. I do not want to mv the files after they are generated as this is not the cleaner solution.
My Question is:
What do I have to do to my Makefile so that compilation is performed once and that the object files are generated into a separate directory?
The makefile you want will look something like this.
INCLDDIRS := "The needed include directories"
CFLAGS = "some c flags"
C_SOURCE = "Many many source files in different directories"
C_SOURCE_NAMES = $(notdir $(C_SOURCE))
OBJECT_DIRECTORY = ObjDir
BINARY := your_binary
all: $(BINARY)
$(OBJECT_DIRECTORY):
mkdir $#
$(OBJECT_DIRECTORY/$(BINARY): $(C_SOURCE) | $(OBJECT_DIRECTORY)
$(CC) $(CFLAGS) $(INCLDDIRS) -o $# $^
It uses an order-only prerequisite for the output directory (so make knows to create it first but not count it as causing a rebuild).
It lists the source files as the prerequisites of the output binary and uses them all on the compilation line.
The main problem with this makefile, and with your goal, is that a change to any source file will cause every source file to be recompiled from scratch. That's fairly inefficient as far as incremental work goes. (That's why the default idea is to use intermediate object files. You trade some from-clean speed off against incremental speed.)
The reason your second makefile didn't work correctly is that, in a clean directory, the C_OBJECTS variable has no value. Your wildcard $(OBJECT_DIRECTORY)/*.o matches nothing.
That said it was also incorrect in that it listed every source file as a prerequisite for every object file which isn't at all correct.
In my current project, more than 200MB C files are present. While making targets I can able to see only < 100MB is used to create a binary. How, to identify what are the files are not touched while creating targets. So, that we can strip it off and make the codebase more sleek.
How, to identify the list of files created for target while compiling?
I think the best approach is to use one of the methods Linux offers for monitoring file system access:
inotifywait
kfsmd
loggerfs
auditd / auditctl / ausearch
You could also run the make command with strace (strace -f make) and parse the output for open() calls.
That is what I used to do in the past.
Take your pick.
I would probably:
make clean
make 2>out to capture the full log of the build to a file
grepthe out file for gcc invocations
Filter out the filenames from the gcc invocations
Build a sorted list of those filenames
Build a sorted list of filenames in the project.
Compare the two.
Or something like that. Shouldn't be too hard.
Another method is to open the (autogenerated) dependency files for you executables and shared libraries. They are going to contain .o as prerequisites, which normally correspond to .c.
This works best for non-recursive make build systems with complete dependency trees.
If your make is GNU make, as seems likely, you could consider
variations on the following approach. (For simplicity I'll assume that the only
source files of interest are .c files.)
Say we have Makefile in directory dir that makes some default
target and possibly others, including intermediate targets.
You can use another makefile, say, unused_srcs.mk that you include in
Makefile, such that in dir you can run:
make unused_srcs
which will display a list of all the source files in dir that don't
contribute to the default target. Or run:
make unused_srcs target=TARG
for some target TARG, and get a list of all the source files in dir that
don't contribute to TARG.
This assumes that Makefile has a clean target, or maybe several
variants of clean[-???], that can suitably clean the default target or
any target you might be interested in, and that you don't mind
a suitable clean[-???] being invoked for the unused_srcs target.
For example, in dir we have:
main.c
extern void boo(void);
int main(void)
{
boo();
return 0;
}
boo.c
#include <stdio.h>
void boo(void)
{
puts("Boo!");
}
noop.c
void noop(void){}
Makefile
.phony: all clean
all: boo
objs = main.o boo.o
boo: $(objs)
gcc -o $# $^
clean-obj:
rm -f *.o
clean: clean-obj
rm -f boo
# include /some/standard/place/unused_srcs.mk
include unused_srcs.mk
And in some standard place which, for simplicity, we'll assume is again dir,
we have:
unused_srcs.mk
.phony: unused_srcs
ifndef $(target)
target = all
endif
ifndef $(cleaner)
cleaner = clean
endif
all_srcs = $(wildcard *.c)
used_srcs = $(filter %.c,$(shell ($(MAKE) $(cleaner) && $(MAKE) -n -d $(target)) \
| grep -e 'Considering target file' | sed -e "s/[\`\']//g" -e "s/\.$$//g" -))
unused_srcs = $(filter-out $(used_srcs),$(all_srcs))
unused_srcs:
#echo $(unused_srcs)
In this project:-
noop.c is unused by boo (it is completely superfluous)
noop.c and main.c are unused by boo.o
noop.c and boo.c are unused by main.o
And we can discover such facts with make unused_srcs commands:
$ make unused_srcs
noop.c
$ make unused_srcs target=boo
noop.c
$ make unused_srcs target=boo.o
main.c noop.c
$ make unused_srcs cleaner=clean-obj target=boo.o
main.c noop.c
$ make unused_srcs target=main.o
boo.c noop.c
$ make unused_srcs target=clean
boo.c main.c noop.c
Clearly all the heavy-lifting is done in the evaluation of $(used_srcs)
and $(unused_srcs) in unused_srcs.mk, and mostly the former.
The evaluation of $(used_srcs) exploits GNU make's -d option, which
generates fulsome debugging info, together with the fact that any source
file that does contribute to the chosen TARG must itself be considered
a potential target when TARG is made.
Together, these things mean that if we clean TARG and then run make -n -d TARG
the output will be the debugging info of a dry-run (-n) of make TARG,
and in this output a line like:
Considering target file `FILE.c'.
will appear for each .c file FILE.c that contributes to TARG, and
for no other .c files that may be present.
The evaluation of $(used_srcs) generates that debugging info and filters
it to extract the names of the .c files.
The evaluating of $(unused_srcs) then just weeds out the $(used_srcs)
from the list of all the .c files there are.
I have source code in one directory and have a makefile in a different directory. I am able to compile the code using the make system's vpath mechanism. The .o files are being created in the same folder where the makefile is. But I want to move those .o files to a different directory called obj. I tried the following:
vpath %.o obj
However, they are still being created in the same folder as the makefile. Can anyone help me to solve this issue?
Here are some highlighted lines of the makefile:
PATH_TO_OBJ:- ../obj
SRC :- .c files
OBJS :- $(SRC:.c = .o)
.c.o = $(CC) $(CFLAGS) -c
exe: cc $(LFLAGS) -o $(PATH_TO_OBJ) $(SRC).
After this also, .o file is creating in same folder of Makefile. Not moving to obj
-o option defines where to save the output file, produced by a gcc compiler.
gcc main.c -c -o path/to/object/files/main.o
Make's VPATH is only for finding source files. The placement of object files is up to the thing that is building them. There's a nice description at http://mad-scientist.net/make/vpath.html (I see someone beat me to posting this in a comment).
The *BSD build systems use variants of make that can place object files (and other generated files, including C sources from lex and yacc variants) in /usr/obj automatically. If you have access to that version of make, that will likely be a good way to deal with whatever underlying problem you are trying to solve.
I have implemented a binary tree program which includes the tree.c with the functions, the tree.h with the declarations of them and a main.c for testing.
Also, I have a makefile which is:
CC=gcc
CFLAGS=-g -Wall
DEPS = tree.h
OBJ = main.o tree.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
tree: $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -f *.o tree
Now I want to make it generate a library not only an object file for the binary trees functions and afterwards to generate the documentation of doxygen inside the makefile. Any help would be helpful.
I know that my answer comes in a bit late, but i hope someone will benefit from this.
I have a makefile that generates Doxygen doc.
You have to twist Doxygen a tiny bit
Create the Doxygen setup file that fits Your need, then open that in an editor and remove the lines containg the following two settings (they will be added by the make file later)
INPUT
FILE_PATTERNS
add this line
#INCLUDE = doxyfile.inc
Save this file under a different name I use Doxyfile.mk
in You makefile You need a list of sources and the directories where they are located
example
SRCS = $(OBJS:.o=.c)
SRCDIRS = ./src
SRCDIRS += ./other_src
Now You can put this rule in the Makefile, it will create the file doxyfile.inc that contains the settings You removed from Doxyfile.mk.
.PHONY: all clean distclean doxy
# If makefile changes, maybe the list of sources has changed, so update doxygens list
doxyfile.inc: Makefile.mk
echo INPUT = $(SRCDIRS) > doxyfile.inc
echo FILE_PATTERNS = *.h $(SRCS) >> doxyfile.inc
doxy: doxyfile.inc $(SRCS)
doxygen.exe doxyfile.mk
Bonus: If run from inside an IDE like Eclipse the errors that Doxygen spits out becomes clickable and will jump to the bad comment.
Well, I don't really know the syntax for the doxygen command, so I'll make a generic answer:
in your Makefile, each
term: [dep]
action
is a target.
So if you add something like:
doc: $(OBJ)
doxygen with-correct-options
You will be able to generate the documentation using:
make doc
(doc being here the name of the target)
Now, if you add:
all: tree doc
#echo "Generating program and doc."
you will have the program and the documentation generated with simply invoking
make
In the end, there is an additional statment your Makefile could have use of: .PHONY. It's "A way to mark one of many targets as not directly producing files, and ensure their execution even if a file having the same name as the target exists". In other terms, it's to make sure doc, clean or all will always be executed even if files named doc, clean or all exist.
Its syntax is the following:
.PHONY: all clean doc
And is usually put at the end of the Makefile.
I have 3 questions about compiling and linking my project in fewer steps...
First, my project looks like: ( I use Watcom C to compile//link my project )
Directory 'MyProject' contains 3 sub directories for different modules and some files:
directory 'A' ( a.h and a.c included )
directory 'B' ( b.h and b.c included )
directory 'C' ( c.h and c.c included )
my.c and my.h
my.lnk
makefile
And within each sub directory there is one corresponding makefile...
[Q1] Assume I update a.h in directory A and a.h is referenced by b.c in directory B, then my original steps will be:
compile in directory A ( obj and lib generated...)
compile in directory B ( obj and lib generated...)
back to directory MyProject then compile and link
Can I just take one step to cover above ?
[Q2] If I want to ignore all existing obj/lib and rebuild all, how to do it ?
I know this takes time but sometimes "kill and rebuild" will be better...
[Q3] If my.h is updated and it is referenced by a.c,b.c, and c.c...
Can I just take one step to cover above ?
[My makefile in sub directory looks like]
INCLUDE1 = -ic:\watcom\h
OBJECTS1 = a.obj
CFLAGS = -zq -mf -oxsbl $(INCLUDE1)
DEST = a.exe
COMPILER = wpp386
.erase # special cmd, tell wmake to "erase" target if make is not successful
.cpp.obj: .AUTODEPEND
$(COMPILER) $(CFLAGS) $<
$(DEST) : $(OBJECTS1) makefile
[My makefile in main directory looks like]
INCLUDE1 = -i=c:\myproj\my -i=c:\watcom\h
OBJECTS1 = my.obj
CFLAGS = -zq -fp6 -mf -6r -s -oxsbl $(INCLUDE1)
DEST = my.exe
COMPILER = wpp386
LINKER = wlink
LNK_FILE = my.lnk
.erase # special cmd, tell wmake to "erase" target if make is not successful
.cpp.obj: .AUTODEPEND
$(COMPILER) $(CFLAGS) $<
$(DEST) : $(OBJECTS1) makefile my.lnk
$(LINKER) #$(LNK_FILE)
[Update 1]
I use wpp386 as compiler and it is watcom c++ tool.
To build the target I use one batch file to compile cpp file:
#echo off
del a1.lib
del *.err
wmake -h
wlib -q a1.lib + a.obj
del *.obj
I can successfully compile cpp file and everything is fine.
In directory B, I use the same way(batch file+makefile) to compile b.cpp
To sum up my project works and the reason why I ask is to find "faster compiling/linking sequence" if I just update some header file...
I tried add the command ehco hello to the rule $(DEST) and found it was ok. Then use echo $(MAKE) and got:
...
echo C:\WATCOM\BINW\WMAKE.EXE
C:\WATCOM\BINW\WMAKE.EXE
...
Thanks !
I'm not familiar with your compiler, so I can't see how these makefiles work, so we'll have to take this one step at a time.
1) when you go into a subdirectory A, what command do you use to build the targets? Does it work? How about in subdirectory B?
2) In the main makefile, can you add a command, like echo hello to the $(DEST) rule? If that works, try echo $(MAKE).
EDIT:
Non-GNU versions of Make are troublesome, but we'll see what we can do.
Try editing the makefile in subdir A:
INCLUDE1 = -ic:\watcom\h
OBJECTS1 = a.obj
CFLAGS = -zq -mf -oxsbl $(INCLUDE1)
DEST = a1.lib # NOTE THIS CHANGE
COMPILER = wpp386
.erase # special cmd, tell wmake to "erase" target if make is not successful
.cpp.obj: .AUTODEPEND
$(COMPILER) $(CFLAGS) $<
$(DEST) : $(OBJECTS1) makefile
wlib -q $# + $(OBJECTS1)
del $(OBJECTS1)
Instead of the batch file, just run make -h. This should rebuild the library (if the library needs rebuilding). If it works, try moving up into MyProject and running make -h -C A. This should execute the makefile in A and rebuild the library there (unless WMAKE has some other syntax).
If that works, try making the same changes in B, then editing the $(DEST) rule in the main makefile:
$(DEST) : $(OBJECTS1) makefile my.lnk
$(MAKE) -h -C A
$(MAKE) -h -C B
$(LINKER) #$(LNK_FILE)
Cross your fingers and run make -h. This should rebuild both libraries, compile, link, and solve Q1...