Considering the following:
all:
mv info.h info.h.back
generate_info.sh
compile
mv info.h.back info.h
How do I force make to run the last line even if compilation failed?
I am aware of .DELETE_ON_ERROR but this deals only with removing targets on failure.
I am also aware of the option to add - before the compile command. Unfortunately this will make the whole make to return with a good error code, which is unacceptable.
You can't force make to do this. You'll have to arrange for it to be done in your shell script, yourself. Make will send every "logical line" of the shell script to the same shell command. Turn multiple physical lines into one logical line by appending backslashes to the end of the physical lines.
So, for example:
all:
mv info.h info.h.back
generate_info.sh && compile; \
r=$$?; mv info.h.back info.h; \
exit $$r
This saves the return code of the two commands in the shell variable r, then runs the mv command, then exits the shell with the result code that was saved.
The generate_info.sh && compile means that the second command (compile) will only run if the first command (generate_info.sh) succeeds.
Related
From the docs:
Usually when a recipe line fails, if it has changed the target file
at all, the file is corrupted and cannot be used--or at least it is not
completely updated. Yet the file's time stamp says that it is now up to
date, so the next time 'make' runs, it will not try to update that file.
The situation is just the same as when the shell is killed by a signal;
*note Interrupts::. So generally the right thing to do is to delete the
target file if the recipe fails after beginning to change the file.
'make' will do this if '.DELETE_ON_ERROR' appears as a target. This is
almost always what you want 'make' to do, but it is not historical
practice; so for compatibility, you must explicitly request it.
So, here I have a makefile:
# The idea here is to auto-generate the file ('make.include')
# and to use it as a makefile.
# For simplicity, I replaced the "auto-generate" part, with "touch".
# I also simplified the dependency-tree with 'phony'.
# In practice, we re-generate, only when "need" to.
make.include : phony
+touch '$#'
make -f '$#'
.PHONY: phony
Running:
$ make -q
I get:
touch 'make.include'
make: *** Deleting file 'make.include'
Now, i don't see how to prevent make from deleting this newly auto-generated 'make.include' (which may well be quite a costly process to re-run), unless i resort to the .PRECIOUS special target.
But, demanding the user to explicitly define their "precious" targets, is not in-line with that quote from the docs above. Right?
This arises because of your use of + in +touch '$#' and executing make with the -q option. From the GNU Make Manual the -q option is
“Question mode”. Do not run any recipes, or print
anything; just return an exit status that is zero if the specified
targets are already up to date, one if any remaking is required, or
two if an error is encountered. See Instead of Executing Recipes.
The + symbol is only relevant when make is executed with the -t, -n or -q options and it tells make to execute any commands it precedes make is executed with any of the options -t, -n or -q. So, when you execute your current makefile with make -q you are asking make to check if everything is up to date without running any commands but because you've specified + before touch '$#' make must execute this command. To then leave everything the way it was before you executed make -q make must delete the file it created with +touch '$#'.
To answer your question specifically. If you don't want make to delete make.include then you can run make without the -q option on the makefile specified in your question.
However, the recipe for a target, i.e. make.include should not call its self with make -f make.include. It would probably be better to rewrite the makefile so that the recipe for make.include only creates make.include and it is then called with make -f make.include in another recipe.
make.include:
+touch $#
all: make.include
make -f $<
I have a Makefile that call a bunch of makers such as compilers and small scripts. Sometime (often a ClearCase issue), the executable flag is missing or worse the script is missing.
What is the best way to check the executable flag and the existence of a list of programs in a Makefile.
My first implementation was to foreach on each executable and call them, then catch the exit flag. Because that check takes some time, I had to ifdef it in order to bypass the check for all makes rules that does not need to use these scripts. For example the case of make clean only call rm which has to be installed on all platforms. I don't need to check the other programs.
The second implementation was just to check the execution flag with a $(shell) and a [ -x foo ] combined in a ifdef directive. I feed this solution is a bit ugly.
The third solution is to call a shell script that do the job. However, this shell script must remain executable in any case. I can do FOO != chmod u+x checker but this is also quite ugly.
What would be the best solution?
Will an approach like the following help?
target: source ./script_1
test -x ./script_1 || chmod +x ./script_1
./script_1 < source > target
I know nothing about shell scripting but something has come up and I need to be able to understand what two lines of code do so that I can modify a project I am working on
SDKROOT= make -C $TEMP_DIR -f $PROJECT_DIR/greg/Makefile VPATH=$PROJECT_DIR/greg || exit $?
$TEMP_DIR/greg -o $DERIVED_FILES_DIR/${INPUT_FILE_BASE}.m $INPUT_FILE_PATH
will you please explain what these two lines of code do... I know what the variables are and the path names but the rest of the syntax is confusing and foreign. Please help.
The first line:
SDKROOT= make -C $TEMP_DIR -f $PROJECT_DIR/greg/Makefile VPATH=$PROJECT_DIR/greg || exit $?
SDKROOT= sets the environment variable SDKROOT to nothing for the execution of the make command.
make is the build tool, and it's being run with the following options:
-C $TEMP_DIR: means run make in the directory $TEMP_DIR
-f $PROJECT_DIR/greg/Makefile specifies to make to use the Makefile in $PROJECT_DIR/greg
VPATH=$PROJECT_DIR/greg sets another variable, VPATH to $PROJECT_DIR/greg. VPATH specifies to make a search path for prerequisits.
|| exit $? means that if the make command fails the script should exit with the same error code as make, as $? means the return code of the last run program/command.
The second line:
$TEMP_DIR/greg -o $DERIVED_FILES_DIR/${INPUT_FILE_BASE}.m $INPUT_FILE_PATH
appears to be running the command $TEMP_DIR/greg with the option -o $DERIVED_FILES_DIR/${INPUT_FILE_BASE}.m and with some input from $INPUT_FILE_PATH. This looks like the program which may have been built from the previous line's make command, so it's hard to know exactly what it does.
EDIT
The SDKROOT is an environment variable used by XCode to say where the SDK it's using is installed. It will be a path like /Developer/SDKs/MacOSX"${HOST_VERSION}".sdk/ for instance. The value should be setup somewhere in XCode I imagine (I don't used xcode so can't be more helpful than that.). By doing SDKROOT= at the beginning of the command the value of SDKROOT will be nothing/blank. The reason for this is that the code being compiled will use resources which exist in the SDKROOT, rather than local ones; such resources may be classes, config or libraries for example.
I have this in my Makefile:
run:
for x in *.bin ; do ./$$x ; done
such that it launches all executables one by one. I want to do this:
run:
for x in *.bin ; do ./$$x &; done
so that it starts each executable and puts it in the background. I get a syntax error for the above statement when I put the ampersand.
I dont want to invoke the make as make & since this will run processes in the background but still one by one, whereas I want individual executables to run in the background, so that at any instant I have more than one executable running.
Thank you in advance.
Try to execute via a subshell:
run:
for x in *.bin ; do (./$$x &); done
Maybe make -j is a better option. Try a Makefile that looks something like this:
BINS = $(shell echo *.bin)
.PHONY: $(BINS)
run: $(BINS)
*.bin:
./$#
And then execute with make -j <jobs> where <jobs> is number of simultaneous jobs to run.
The syntax error you're getting is a shell syntax error, rather than a problem with make syntax. The ampersand is in fact a command terminator/separator, just as semicolon is; so the way to express the for loop you want is:
run:
for x in *.bin ; do ./$$x & done
However, as others have noted, where it's practical it's usually more flexible to express things directly as make dependencies rather than complicated shell snippets and shell loops.
Try:
run:
for x in *.bin ; do (./$$x &) ; done
The ()'s run the command in a subshell.
I ran into this useful tip that if you're working on files a lot and you want them to build automatically you run:
watch make
And it re-runs make every couple seconds and things get built.
However ... it seems to swallow all the output all the time. I think it could be smarter - perhaps show a stream of output but suppress Nothing to be done for 'all' so that if nothing is built the output doesn't scroll.
A few shell script approaches come to mind using a loop and grep ... but perhaps something more elegant is out there? Has anyone seen something?
Using classic gnu make and inotifywait, without interval-based polling:
watch:
while true; do \
$(MAKE) $(WATCHMAKE); \
inotifywait -qre close_write .; \
done
This way make is triggered on every file write in the current directory tree. You can specify the target by running
make watch WATCHMAKE=foo
This one-liner should do it:
while true; do make --silent; sleep 1; done
It'll run make once every second, and it will only print output when it actually does something.
Here is a one-liner:
while true; do make -q || make; sleep 0.5; done
Using make -q || make instead of just make will only run the build if there is something to be done and will not output any messages otherwise.
You can add this as a rule to your project's Makefile:
watch:
while true; do $(MAKE) -q || $(MAKE); sleep 0.5; done
And then use make watch to invoke it.
This technique will prevent Make from filling a terminal with "make: Nothing to be done for TARGET" messages.
It also does not retain a bunch of open file descriptors like some file-watcher solutions, which can lead to ulimit errors.
How about
# In the makefile:
.PHONY: continuously
continuously:
while true; do make 1>/dev/null; sleep 3; done
?
This way you can run
make continuously
and only get output if something is wrong.
Twitter Bootstrap uses the watchr ruby gem for this.
https://github.com/twbs/bootstrap/blob/v2.3.2/Makefile
https://github.com/mynyml/watchr
Edit:
After two years the watchr project seems not to be maintained anymore. Please look for another solution among the answers. Personally, if the goal is only to have a better output, i would recommend the answer from wch here
I do it this way in my Makefile:
watch:
(while true; do make build.log; sleep 1; done) | grep -v 'make\[1\]'
build.log: ./src/*
thecompiler | tee build.log
So, it will only build when my source code is newer than my build.log, and the "grep -v" stuff removes some unnecessary make output.
This shell script uses make itself to detect changes with the -q flag, and then does a full rebuild if and only if there are changes.
#!/bin/sh
while true;
do
if ! make -q "$#";
then
echo "#-> Starting build: `date`"
make "$#";
echo "#-> Build complete."
fi
sleep 0.5;
done
It does not have any dependencies apart from make.
You can pass normal make arguments (such as -C mydir) to it as they are passed on to the make command.
As requested in the question it is silent if there is nothing to build but does not swallow output when there is.
You can keep this script handy as e.g. ~/bin/watch-make to use across multiple projects.
There are several automatic build systems that do this and more - basically when you check a change into version control they will make/build - look for Continuous Integration
Simple ones are TeamCity and Hudson
#Dobes Vandermeer -- I have a script named "mkall" that runs make in every subdirectory. I could assign that script as a cron job to run every five minutes, or one minute, or thirty seconds. Then, to see the output, I'd redirect gcc results (in each individual makefile) to a log in each subdirectory.
Could something like that work for you?
It could be pretty elaborate so as to avoid makes that do nothing. For example, the script could save the modify time of each source file and do the make when that guy changes.
You could try using something like inotify-tools. It will let you watch a directory and run a command when a file is changed or saved or any of the other events that inotify can watch for. A simple script that does a watch for save and kicks off a make when a file is saved would probably be useful.
You could change your make file to output a growl (OS X) or notify-send (Linux) notification. For me in Ubuntu, that would show a notification bubble in the upper-right corner of my screen.
Then you'd only notice the build when it fails.
You'd probably want to set watch to only cycle as fast as those notifications can display (so they don't pile up).
Bit of archaeology, but I still find this question useful. Here is a modified version of #otto's answer, using fswatch (for the mac):
TARGET ?= foo
all:
#fswatch -1 . | read i && make $(TARGET)
#make -ski TARGET=$(TARGET)
%: %.go
#go build $<
#./$#