i'm having trouble understanding why Make will run the "lib"-recipe even if the file already exists.
Shouldn't it be ignored as long "$(LIBBIN)" is not in .PHONY ?
Here is an extract from the Makefile in question (ts=2, see "TODO").
.PHONY: all clean default apps lib examples
default: lib
all: apps lib examples
apps: $(APPBINS)
lib: $(LIBBIN)
examples: $(EXBINS)
$(LIBBIN): % : %.$(VERSION)
# TODO -f should really not be necessary. why is the recipe run, when the file exists?
ln -sf $^ $#
$(LIBBIN).$(VERSION): $(LIBOBJECTS) | $(LIBOUTDIR)
$(CC) $^ -o $# $(LIBLDFLAGS)
chmod 755 $#
i was hoping one of you gurus knows the answer ;-)
kind regards,
yogo1212
EDIT: maybe i should say, that i've already tried to make the prereqs. of lib and all order-only. There was no visible effect.
EDIT2: turns out that this works indeed. the link file seemed to have had a timestamp that was off by a minute and make was confused.
the phenomenon went away after re-creating the folder structure and restarting.
The makefile part you've given is correct and works for me, after I simplified it due to missing details in your example. So, your example is not accurately reflecting your situation. Please try to provide a SSCCE
$ cat Makefile
LIBBIN = /tmp/foo
VERSION = 1.0
lib: $(LIBBIN)
$(LIBBIN): % : %.$(VERSION)
ln -s $^ $#
$(LIBBIN).$(VERSION): $(LIBOBJECTS) | $(LIBOUTDIR)
touch $#
$ make
touch /tmp/foo.1.0
ln -s /tmp/foo.1.0 /tmp/foo
$ make -f /tmp/x3.mk
make: Nothing to be done for `lib'.
Related
What does this part mean in Makefile?
1 CC=gcc
2 CXX=g++
3 RM=rm
4 PROTOC=protoc
5 ODB=odb
Sorry, I'm a beginner
They're setting up substitutions so that you can later have a command like:
$(RM) x.o
and it will magically become, when executing:
rm x.o
It allows you to (for example) change it later to be rm -rf and you only change it in one place.
Typically you'll see things like:
$(CC) $(CFLAGS) -c -o object_file.o source_file.c
If you compile a compile of hundred C source files, and you suddenly discover they all needed a new -I directive, you probably want that in one single place :-)
See the "variables" section of the GNU Make manual for (much) more detail, if you wish.
We also use it in our shop for making our builds somewhat more "readable", things like:
PERM_FOR_EXE=chmod 700
PERM_FOR_CFG=chmod 400
PERM_FOR_DATA=chmod 500
RM=rm
FORCE_RM=rm -f
RM_DIR_AND_BELOW=rm -rf
PROTO_FOR_PY=protoc --output=betterproto
PROTO_FOR_CPP=protoc --output=cpp
PROTO_FOR_BCPL=echo FAT CHANCE
I'm really struggling in understanding why the following makefile won't work:
all: buildFolders main.out
mv main.out build/
-echo "File compiled"
buildFolders:
mkdir -p build src
cp *.c src/
%.s: %.c
gcc -S $< -o $#
%.out: src/%.s
gcc $< -o $#
It is executed in a folder containing only the makefile and a main.c file. It should build the src and build folder, copy the main.c in the src folder and then start compiling the main.out. Unfortunately it throws the error "no rule to make target 'main.out'". Since I have the %.out that matches 'main.out' I don't see why it gives me that error. Instead it should look for the src/main.s file, create it and then use it to generate the main.out.
What am I doing wrong? Thanks
You have a number of problems.
First, listing prerequisites in order doesn't create a dependency relationship. If, for example, you ever wanted to enable parallel builds then this:
all: buildFolders main.out
doesn't force the buildFolders target to be built before main.out. These two targets both must be built before all but this doesn't tell make that there's any relationship between buildFolders and main.out. If buildFolders must be completed before main.out can be built then main.out must list buildFolders as a prerequisite.
Second, you haven't told make how to build a file src/main.c. It's built as a side-effect of the buildFolders target, but make can't know that. You need to explain to make that this file can exist. I recommend adding a rule:
src/%.c: %.c
mkdir -p src
cp $< $#
and removing the buildFolders target altogether.
However, I really question why you want to do this anyway. What's the point of copying the source files in the current directory to some sub-directory to build them? It's dangerous and confusing to have multiple copies of source files lying around because they can get out of sync with each other, then you're building older versions and you spend hours trying to understand why something doesn't work. It's a really bad idea.
I would like to change the working directory of a makefile.
(Extraneous info: I have a legacy makefile that I mostly want to reuse, though many targets and generated deps files make assume that the working directory will not be different. My idea is to create a makefile for my newer project, which is in a different directory, and include the old one, and set the working directory to the old directory.)
I easily can do this from the command line with
make -f /path/to/new/makefile -C /path/to/old/makefile
The users of this makefile would like not to type that out every time.
Attempt 1
Use MAKEFLAGS in the makefile itself. But neither of these seem to have any effect. (I understand why -f couldn't have an effect; I'm really wondering about -C.)
I've looked at http://www.gnu.org/software/make/manual/html_node/Options-Summary.html, but I can't find anything about what is allowed in MAKEFLAGS and what isn't.
Attempt 2
Create a makefile2 with the new targets
include path/to/old/makefile
foo: bar
and then makefile passes everything through
%:
$(MAKE) -f $(abspath makefile2) -C path/to/old/makfele /$*
I don't get nice autocompletion, parallel jobs don't work, and debug options (dry run) doesn't work.
So
(1) Why doesn't -C work MAKEFLAGS (it does work, but I made a mistake; it doesn't work, and it is documented; it doesn't work, and it is not documented but it is intentional; it doesn't work, and it is a bug)?
(2) Is there a better way of change a makefile's working directory?
Some things are wrong here :
make -f /path/to/new/makefile -C /path/to/old/makefile
The -f options specifies the name of the Makefile to be found when searched in the directory specified with -C (or the current directory if not provided). So it is more :
make -C /path/to/old/Makefile -f name_of_old_makefile
If the name is simply Makefile or makefile, there is no need to provide the -foption.
The MAKEFLAGS variable does not contains -f or -C in the called sub-Makefile.
To be able to pass multiple targets to another makefile, you need the MAKECMDGOALS variable.
Ultimately, all you have to do in your new Makefile is to have someting like this :
all:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $#
%:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $(MAKECMDGOALS)
I have created a makefile for the generation of a simple web page. The idea behind the makefile is this:
We're compiling one web page, index.html
index.html requires a stylus css main.sty that must be compiled
There are a number of examples used in the page
The code for example one lives in lib/examples/one
Each example contains three parts
The markup (a .jade template file)
Some code (a .coffee script file)
A description (a .md markdown file)
The build script must render each example into a single html file
Jade, Pygments, and Markdown are used to generate three html files
An example.jade template is used to combine these into one example file
example.jade must be copied to the correct build example directory, because the template language can only do relative imports. So in order to import example/one/code.html, we must copy the template to example/one and have it include code.html.
When finished, each example x will have compiled to tbuild/examples/x.html
The lib/index.jade template is moved to build (so that it can include the example files)
Jade is then used to compile the index.jade template into html
This is a wee bit of a simplification, but it's easier to understand this way. The simplification is that there are actually two markup files (left.html and right.html) in each example, and that the code file is both run through pygments and used as a script, so both code.html and code.coffee need to make it into build.
Right now, the makefile looks like this:
LIB = lib
BUILD = build
LIBEX = $(LIB)/examples
BUILDEX = $(BUILD)/examples
EXAMPLES = $(addsuffix .html,$(addprefix $(BUILDEX)/,$(shell ls $(LIBEX) | grep -v '.jade')))
all: $(BUILD)/main.css index.html
index.html: $(BUILD)/index.jade $(EXAMPLES)
jade < $< --path $< > $#
$(BUILD)/index.jade: $(LIB)/index.jade
mkdir -p $(#D)
cp $< $#
$(BUILD)/main.css: $(LIB)/main.sty
mkdir -p $(#D)
stylus -u nib < $< > $#
$(BUILDEX)/%.html: $(BUILDEX)/%/template.jade $(BUILDEX)/%/left.html $(BUILDEX)/%/right.html $(BUILDEX)/%/code.html $(BUILDEX)/%/code.coffee $(BUILDEX)/%/text.html
jade < $< --path $< > $#
$(BUILDEX)/%/template.jade: $(LIBEX)/template.jade
mkdir -p $(#D)
cp $< $#
$(BUILDEX)/%/left.html: $(LIBEX)/%/left.jade
jade < $< --path $< > $#
$(BUILDEX)/%/right.html: $(LIBEX)/%/right.jade
jade < $< --path $< > $#
$(BUILDEX)/%/code.html: $(LIBEX)/%/code.coffee
pygmentize -f html -o $# $<
$(BUILDEX)/%/code.coffee: $(LIBEX)/%/code.coffee
mkdir -p $(#D)
cp $< $#
$(BUILDEX)/%/text.html: $(LIBEX)/%/text.md
markdown < $< > $#
clean:
rm index.html -f
rm $(BUILD) -rf
This works, but the problem is that when I touch "lib/examples/intro/code.coffee" and re-run make, I get the following:
mkdir -p build/examples/intro
cp lib/examples/template.jade build/examples/intro/template.jade
jade < lib/examples/intro/left.jade --path lib/examples/intro/left.jade > build/examples/intro/left.html
jade < lib/examples/intro/right.jade --path lib/examples/intro/right.jade > build/examples/intro/right.html
pygmentize -f html -o build/examples/intro/code.html lib/examples/intro/code.coffee
mkdir -p build/examples/intro
cp lib/examples/intro/code.coffee build/examples/intro/code.coffee
markdown < lib/examples/intro/text.md > build/examples/intro/text.html
jade < build/examples/intro/template.jade --path build/examples/intro/template.jade > build/examples/intro.html
jade < build/index.jade --path build/index.jade > index.html
rm build/examples/intro/right.html build/examples/intro/code.coffee build/examples/intro/code.html build/examples/intro/left.html build/examples/intro/text.html build/examples/intro/template.jade
Which, as you'll notice, is way more than needs to be done to regenerate the example. What I was hoping for was something more like this:
mkdir -p build/examples/intro
pygmentize -f html -o build/examples/intro/code.html lib/examples/intro/code.coffee
cp lib/examples/intro/code.coffee build/examples/intro/code.coffee
jade < build/examples/intro/template.jade --path build/examples/intro/template.jade > build/examples/intro.html
jade < build/index.jade --path build/index.jade > index.html
In other words, what I'm asking is:
What do I need to do to make the makefile not rebuild too much when I change something small?
In the above example, left.html, right.html, and text.html are all rebuilt when I touch code.coffee. How can I prevent this?
Why does make put the rm command at the end of the output? This seems like it might be causing some re-building where unnecessary.
Thanks for reading all the way through this beast of a question! I know that my make-fu is lacking, so any tips as to how to clean up the makefile and reduce redundancy are more than welcome!
This build system is too large and complex to reproduce easily -- and I hate to post solutions I haven't tested -- but try adding this line:
.SECONDARY:
EDIT:
I haven't been able to reproduce the behavior you describe, but I can offer some pointers.
The .SECONDARY: is a rule; it can go anywhere in the makefile. Basically, if Make detects a chain of chain of implicit rules, A->B->C, where A is a file that exists and C is the target, it considers B an intermediate file and will delete it once the job is done. The .SECONDARY: rule blocks the deletion.
You can combine rules that have the same commands. This:
foo: bar
do something $< $#
baz: quartz
do something $< $#
quince: geef
do something $< $#
can be rewritten as this:
foo: bar
baz: quartz
quince: geef
foo baz quince:
do something $< $#
That will remove a lot of redundancy in your makefile, and perhaps make things clearer.
Like #Beta mentioned, you are running into troubles with intermediate files here.
Each file that is not mentioned explicitely in the Makefile, but rather inferred via a pattern rule (a rule with %), is intermediate and is deleted right after make ran. And then remade on the next run.
That's the core of your "problem": The left.html and right.html files are deleted right away. Beta already mentioned that declaring them as .SECONDARY fixes this problem, like the make manual tells you.
By declaring a target .SECONDARY without any prerequisites anywhere in the Makefile (really: anywhere), you declare all targets as secondary - so, no auto-deletes.
You could also use PHONY for targets that are not files to improve the performance. Like all and clean. See here for more information: What is the purpose of .PHONY in a makefile?
How I stop make from saying make: Nothing to be done for 'all'. or make: 'file' is up to date? I'd like my build to be silent when it's not doing anything - there are other places where echo is called to track build progress, so this message is just cluttering things up. I am currently silencing it like this:
all: dependency1 dependency2
#:
Something tells me there must be a better way. Any ideas?
Edit:
I would like to keep command echo working when it does need to build something, however. A good example of what I'm hoping for is along the lines of --no-print-directory, but I can't find any other flags to shut up selected messages.
Maybe make -s?
So after a couple days of reading around the web, it looks like there isn't any better way than what I'm doing. Some people recommended something along the lines of:
all: dependency1 dependency2 | silent
silent:
#:
That is, just depending on the silent target would be enough to quiet things down. Since I didn't come up with any other workable solutions, I'm going with what I have.
You might try...
$ make -q || make
The advantage of doing it this way is that nothing is printed when there is nothing to do but make produces the normal output when it does need to proceed...
To quote (from memory) from the old make(1) man page, BUGS section: There are some things you can't get make to shut up about. Meanwhile, the -s or --silent option may help.
You can set the -s commandline argument to make in the makefile itself, by setting MAKEFLAGS. Nothing is printed unless you explicitely print it, so I use the following makefile to echo invoked commands.
MAKEFLAGS += -s
PROJECT = progname
CC = g++
SDIR = src
ODIR = obj
BDIR = bin
IDIR = include
OBJS = $(patsubst $(SDIR)/%.cc,$(ODIR)/%.o,$(wildcard $(SDIR)/*.cc))
.PHONY: all debug clean
all: $(BDIR)/$(PROJECT)
debug: CFLAGS += -g -Wall -Wextra
debug: all
$(BDIR)/$(PROJECT): $(OBJS)
#mkdir -p $(BDIR)
#echo LINKING $<
#$(CC) -o $# $(OBJS) -I$(IDIR)
$(ODIR)/%.o: $(SDIR)/%.cc
#mkdir -p $(ODIR)
#echo "COMPILING $<"
#$(CC) -o $# -c $< $(CFLAGS)
clean:
#echo "CLEAN"
#rm -rf $(BDIR) $(ODIR)
Removing the MAKEFLAGS variable will print all invoked commands. The Makefile compiles any c++ project where source files (with .cc extension) are put into the src directory and header files are put into the include directory.
make 2>&1 | egrep -v 'Nothing to be done|up to date'