How to dynamically rename an object file in a makefile - makefile

I am very very new to makefiles. The most complex task I had done before was to include new .h and and .cpp or .c in already designed makefiles.
I have to port the compilation process of a project from Visual Studio to gcc and there is an already made solution for this written by a colleague but he used 4 bash scripts and a makefile to compile the solution.
Instead of doing that I was looking for solutions to make it easier to maintain. My question may be very dumb I admit, but I could not find it anywhere nor I could understand it all properly.
In the target below:
$(OBJECTS): %.o: %.cpp
$(CC) $(CPPFLAGS) -c $< -o $#
I would like to test if the .o being created already exists and rename it to something else. This is necessary because in the project there are several source files that have the same name yet they are different in content.
For example, if the current .cpp being compiled is called file.cpp and the object that will be generated is file.o, the rule should test whether file.o already exists and rename the current file.o to something else.
If you know any good tutorial that explains this, please let me know. I found lots of examples that show how to make tests for the current file being compiled by that rule, but none that would rename the object .o.
Thanks in advance and sorry for any "dumbness" written here. :-)

First of all, you have our deep sympathy.
Make is not really designed to handle such ambiguity, so we'll have to use a kludge. You haven't said what you want to rename the file to, so for now lets say we move file.o to file_save.o.
# This tells Make that these are not real targets, so that it will
# proceed even if file.o already exists.
.PHONY: $(OBJECTS)
$(OBJECTS): %.o: %.cpp
# If file.o exists, move it to file_save.o
#if [ -f $# ]; then mv $# $*_save.o; fi
$(CC) $(CPPFLAGS) -c $< -o $#

Expansion of my comment on the question:
Perhaps you should consider placing object files in the same directory hieryarchy as the source files, to prevent naming conflicts.
So that src/network/client.cpp is compiled to build/obj/network/client.o.
I'm extremely rusty when it comes to makefiles but I believe I solved that by doing something like:
$SRC= src/network/client.cpp src/main.cpp .....
$OBJ= makefile_replace_function($SRC, .o)
$(OBJ) : $(SRC)
compile_instructions
Where you will have to replace makefile_replace_function and compile_instructions to their real equivalents since I have forgotten then...
I realize this might not be very helpful but atleast its an idea to consider.

Related

makefile: dependency not build

The question was edited after MadScientist's answer. See history for the original makefile, but the problem stays the same.
I have a small makefile:
DEPFLAGS=-MD -Mo $(OUTDIR)/$*.Td
POSTCOMPILE=#mv -f $(OUTDIR)/$*.Td $(OUTDIR)/$*.d && touch $#
VPATH=../src
OUTDIR=../out
SOURCES:=$(notdir $(wildcard ../src/*.c))
OBJECTS:=$(SOURCES:%.c=$(OUTDIR)/%.o)
all: $(OBJECTS) $(OBJECTS:%.o=%.d)
$(OUTDIR)/%.o : %.c
$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
#$(CC) $(DEPFLAGS) -c $< -o $#
#$(POSTCOMPILE)
$(OUTDIR)/%.d : ;
.PRECIOUS: $(OUTDIR)/%.d
Directory structure looks like:
src
contains file.c
out
empty, after make: contains file.o and file.d
make
contains the makefile
When I call the makefile everything works fine and two files are generated: file.o and file.d
However, when I delete file.d nothing happens. I would expect that make finds a missing dependency for file.c and starts a rebuild. Why doesn't it happen?
Make version is 3.81 built for i386-pc-mingw32 under Windows 7.
Marking a file as .PRECIOUS does not remove all aspects of it's "intermediateness". All it does is prevent it from being deleted, but this feature of intermediate files is still in effect:
If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file, then make can leave well enough alone. It won’t bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target.
This is why your .d file is not recreated. In order for it to be recreated you need to ensure it's not an intermediate file. Fortunately this is trivial to do: you just need to mention the files explicitly somewhere as a target or prerequisite. You can do it like this:
all: $(OBJECTS) $(SOURCES:%.c=$(OUTDIR)/%.d)
Or if you prefer like this:
depends: $(SOURCES:%.c=$(OUTDIR)/%.d)
which would allow you to run make depends to update the dependency files, if you wanted to.
I'll just point out in passing that this method of managing dependencies is considered outdated. There's a better, more advanced way it can be done described here among other places.
(I'll be a horrific necromancer here, but I've ran into same problem, and found that actual issue isn't one mentioned in answer or comments here)
Dependency rule generated by compiler by default sports file name with ALL suffixes replaced by single suffix .o and path removed. Which doesn't match the pattern of rule in makefile.
For gcc 4.x and later correct options would be
$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d
#$(CC) -MF $(OUTDIR)/$*.Td -MT $# -c $< -o $#
Mo flag no longer exist, you have to use only MF flag to specify dependency file name.MT flag allows to provide a literal line for target name.

Makefile's 'vpath' doesn't work when searching prerequisites with wildcards

My project includes .c and .s (asm) files. I compile both types with 'gcc' and put output .o files to separate directory './bin'. To do that I'm using single makefile rule like this
bin/%.o: %.[cs]
$(CC) $(CFLAGS) -o $# -c $<
(As far as I understand, using square brackets wildcard in such context is a little bit unconventional, but it's working and it looks neat, so...)
The other day I decided to move some of my .c files to dedicated directory './common', so I added
vpath %.c common
at the beginning of the makefile. And now each time I try to 'make', it stops and throws an error on a file I had moved. For example, for 'common/foo.c' I get
"*** No rule to make target bin/foo.o, needed by..."
as if I haven't specified 'vpath'. But when I modify the rule to compile only .c files
bin/%.o: %.c
... ...
magically it starts to operate properly again and checks './common' for sources.
Looks like 'vpath' mechanism and wildcards can not work together, but I'm still new to 'make' and eager to learn what's the exact reason of such behavior. Any ideas anyone? Thanks in advance.
(Tested with make–3.81 and make–4.1.)
UPD: Having all the files and 'bin' directory reside on the same level like so
|-bin/
|-foo.c
|-bar.s
|-baz.c
|-Makefile
here's MWE
ROOTS = foo.o bar.o
OBJS = baz.o
SS = $(addprefix bin/,$(ROOTS) $(OBJS))
all: ff.out
ff.out: $(SS)
ld -o $# $^
bin/%.o: %.[cs]
gcc -o $# -c $<
Now if I move, say, 'foo.c' to separate directory and specify 'vpath', build stops with "No rule to make target bin/foo.o, needed by ff.out".
I suggest careful reading of How Not to Use VPATH as you seem to be at Step Three of that by having the OBJDIR in some places but not others.
To be explict, using a static pattern rule doesn't get you away from needing either at least one rule per source directory, or at least one make invocation per source directory. So, the simple answer is add a new rule for the new common/ directory that's the same as the other one:
bin/%.o: common/%.[cs]
gcc -o $# -c $<
There are lots of more comprehensive, but complex, answers, see the followon article for some of them.
For simple projects, there is no reason not to just track what directories you have in your main Makefile by adding extra rules. Also, there's a reasonable case for not having that bin/ dir and splitting .o and .out locations. Distributors and others expect to be able to control where files are created running from a seperate directory anyway.
I've thrown up a git repo with branches based on your cut down example that may clarify things.

Makefile doesn't rebuild the obj's when the CFLAGS are modified?

As we know that the binary depends on the obj's, and the obj's depends on the .c files ( assuming a C Project). Let's say, I have a env.mk file. This file has a flag like 'export NO_DISPLAY=YES'. In the main Makefile, I have the following.
ifeq ($(NO_DISPLAY),YES)
CFLAGS += -D__DISPLAY_DISABLE
endif
Obviously, env.mk is included in the main make file. whenever, I change the flag value 'NO_DISPLAY'. The makefile never rebuilts the executable again. However, the same works fine when the .o files are deleted. I understand that the reason behind it as it depends on the .c,.h files. The .c .h files are not modified, therefore makefile ignores to rebuild it. But, I would like makefile to rebuild the code if the CFLAGS value is changed. How can I do it? Please note, I don't want to delete the objs and rebuild it.
target_dbg: $(patsubst ./src/%.c,./obj_dbg/%.o,$(wildcard ./src/*.c))
#echo "Target main rule__dbg $(NPROCS)"
$(CC) $(patsubst ./src/%.c,./obj_dbg/%.o,$(wildcard ./src/*.c)) $(LIBS) -o gif_dbg
./obj_dbg/%.o: ./src/%.c ./include/*.h
#echo "I am called first..dbg"
#mkdir -p ./obj_dbg
#$(CC) $(CFLAGS) -E $<
$(CC) $(CFLAGS) $(LDFLAGS) -DDEBUG -c $< -o $#
Any help will be appreciated.
Make simply works by examining timestamps on files. You hardly want every build artefact to depend on your Makefile (at least not while actively developing it) but if you seriously want Make to handle this dependency, you could put the CFLAGS definition in a secondary file buildflags.mk, include it from the main Makefile, and make all object files depend on buildflags.mk.
I hardly think anybody would actually do this in practice, though. There will always be situations where the only way to be sure you get a clean build is to flush everything and start over. Make sure you have good and up-to-date realclean and/or distclean targets, and make sure you remember to use them when you make fundamental changes to your build infrastructure. Having a nightly build job (or similar) which starts the build from a completely clean slate -- e.g. by checking out a new copy into a temporary directory -- is also obviously a good idea.
Alternatively, or additionally, include a copy of the build flags as a static string in each object file, so you can verify them later, perhaps using a --help option or similar.
You could use make's -B option to force a rebuild each time you change your CFLAGS. See this answer.

Canonical 'simple project' makefile

Your small C/C++ project has reached a point where it's no longer practical to have all your code in one file. You want to split out a few components. So you make a src/ directory, and then... you have to write a real Makefile. Something more than hello: hello.o. Uh-oh... was it $# or $< or $^? Crap. You don't remember (I never do).
Do you have a 'one-size fits all' simple Makefile that can deal with straightforward source trees? If so, what's in it and why? I'm looking for the smallest, simplest Makefile that can compile a directory full of C files nicely without me having to edit the Makefile every time I add a file. Here's what I have so far:
CXX = clang++
CXXFLAGS = ...
LDFLAGS = ...
EXENAME = main
SRCS = $(wildcard src/*.cc)
OBJS = $(patsubst src%.cc,build%.o, $(SRCS))
all: $(EXENAME)
build/%.o: src/%.cc
#mkdir -p $(dir $#)
$(CXX) -c -o $# $^ $(CXXFLAGS)
$(EXENAME): $(OBJS)
$(CXX) -o $# $^ $(LDFLAGS)
clean:
rm -rf $(EXENAME) build/
This Makefile builds all the .cc files in the src/ directory into .o files in the build/ directory, then links them up into the parent directory.
What would you do differently?
I would reconsider you decision not to have an explicit list of sources-- I think it may cause you trouble in the long run. But if that's your decision, this makefile is pretty good.
In the %.o rule I would use $< instead of $^, so that later you can add dependencies like
build/foo.o: bar.h
And when you're ready, you can take a look at Advanced Auto-Dependency Generation.
I've never used CMake, so I really can't say anything about that. The best that I can offer is a program that we have at school called 'makemake', which automatically makes Makefiles - http://www.cs.rit.edu/~swm/makemake/ It's not a very advanced program, but it gets the job done. On the plus side, it's incredibly easy to use - simply do 'makemake > Makefile' in the directory and you have a Makefile which will build and link all the source files in that directory(C and C++). On the bright side, if you ever add more files, you just run makemake again and you have a new makefile. On the downside, there's no way to keep any custom targets that you've done from one generated makefile to the next.
As for 'one size fits all' makefiles, while you could definitely do that, it takes away from the purpose of the 'make' command in the first place - which is to keep track of the files last modified time, and thus only re-compile the files that have recently changed, or depend on header files that have just changed(although to generate the correct you can use 'makedepend' - http://www.x.org/archive/X11R7.5/doc/man/man1/makedepend.1.html ). You could use what you currently have plus makedepend in order to make a self-updating makefile.
Use automake tools. Its easy to make changes and less burden to the developer. Its as simple as specifying the SOURCES, LDLIBS, LDFLAGS as variables. At first it may seem like a bit weird. But it becomes your favorite as you do more on it.

Makefile trickery using VPATH and include

I'm playing around with make files and the VPATH variable. Basically, I'm grabbing source files from a few different places (specified by the VPATH), and compile them into the current directory using simply a list of .o-files that I want.
So far so good, now I'm generating dependency information into a file called '.depend' and including that. Gnumake will attempt to use the rules defined so far to create the included file if it doesn't exist, so that's ok. Basically, my makefile looks like this.
VPATH=A/source:B/source:C/source
objects=first.o second.o third.o
executable: $(objects)
.depend: $(objects:.o=.c)
$(CC) -MM $^ > $#
include .depend
Now for the real question, can I suppress the generation of the .depend file in any way? I'm currently working in a clearcase environment -> sloooow, so I'd prefer to have it a bit more under control when to update the dependency information.
It's more or less an academic exercise as I could just wrap the thing in a script which is touching the .depend file before executing make (thus making it more recent than any source file), but it'd interesting to know if I can somehow suppress it using 'pure' make.
I cannot remove the dependency to the source files (i.e. using simply .depend:), as I'm depending on the $^ variable to do the VPATH resolution for me.
If there'd be any way to only update dependencies as a result of updated #include directives, that'd be even better of course.. But I'm not holding my breath for that one.. :)
If you don't want to remake .depend every time, you mustn't have a rule for it. Note that whenever you really need to remake the dependencies file, you must also remake an object file (this is not my insight, it comes from Advanced Auto-Dependency Generation, and it took me some time to grasp it). So construct .depend in the linking rule, using a PHONY target:
DEPEND_FILE = .depend
# put this command in the executable rule
$(MAKE) DEPENDENCIES
.PHONY: DEPENDENCIES
DEPENDENCIES: $(objects:.o=.c)
$(CC) -MM $^ > $(DEPEND_FILE)
-include $(DEPEND_FILE)
You can make things more efficient by having seperate depend files, one for each object, so that when one changes you don't have to recalculate the dependencies of all the objects:
# put this command in the %.o rule
$(CC) -MM $< > $*.d
-include *.d
(EDIT: just corrected a dumb mistake.)

Resources