How to make backtick commands fail in Makefiles? - makefile

The following Makefile target doesn't fail:
test:
echo `blah`
How can I can make it fail besides running the backticked command on its own on the previous line.
$ make --version
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

This isn't a make problem, not really. Make simply waits for the shell it invoked to finish, then checks the exit code. If it's 0 (success) then make assumes the job succeeded. If it's any other value, make believes the job failed.
If you run this command at the shell, you'll see that the exit code is not preserved:
$ echo `bah`
...errors...
$ echo $?
0
There's nothing make can do about this. You'll have to find a way to ensure that your command exits with a failure. You haven't given us enough information about what actual command you want to run to help you solve this problem.
ETA
There are lots of possibilities. But since you've still not provided any real specifics, I'll just suggest one possibility: you can test the resulting value to see if it was empty or not:
test:
var=`blah`; [ -n "$$var" ] || exit 1; ...do stuff with $$var...

Related

How to ignore failure of command called through command builtin?

I have a shell script (running on macOS with GNU bash, version 3.2.57(1)-release) where I set -e at the beginning, but I also want to ignore some of the potential failures, so that they don't end the execution of the script. I'm doing that by appending || ... to the relevant commands:
#!/bin/sh
set -e
false || echo ignore failure
The above works and outputs ignore failure, as expected.
However, if I call the false command through the command builtin, this strategy doesn't work -- the following version of the script exits as soon as false fails, without printing anything:
#!/bin/sh
set -e
command false || echo ignore failure
Why is that? How can I get the desired behavior of ignoring the failure even in the second case?
(In this simplified example, I could of course just delete the command builtin, but in my actual use case, it's part of a function that I don't control.)
Why does command false || echo fail?
Seems like this is a bug in bash versions below 4.0.
I downloaded the old versions 3.2.57 and 4.0, compiled them on Linux, and ran your script. I could reproduce your problem in 3.2.57. In 4.0 everything worked as expected.
Strangely, I couldn't find an according note in bash's lists list of changes, but if you search for set -e you find multiple other bugfixes regarding the behavior of set -ein other versions, for instance:
This document details the changes between this version, bash-4.4-rc1, and
the previous version, bash-4.4-beta.
[...]
o. Fixed a bug that caused set -e to be honored in cases of builtins invoking other builtins when it should be ignored.
How to fix the problem?
The best way would be to use more recent version of bash. Even on macOS this shouldn't be a problem. You can compile it yourself or install it from something like brew.
Other than that, you can use workarounds like leaving out command or adding a subshell ( command false; ) || echo ignore failure (courtesy of Nate Eldredge). In either case, things get quite cumbersome. As you don't know when exactly the bug happens you cannot be sure that you correctly worked around it every time.

Testing if Matlab license is in use from the command line / bash

I'm running CentOS 6.9. I want to test if a Matlab license is currently in use from the command line. Currently, the best way I can think of is
/opt/matlab/R2018b/bin/matlab -nodesktop -nosplash -r "exit;"
export RETURN_VALUE=$?
Is there a better way of doing this? Perhaps catching the actual licensing error from Matlab itself? I don't want to go the grep approach in this instance.
I'm looking for something where I could use the Matlab executable (or some other Mathwork's executable) to just test if the license is available.
EDIT :
Matlab emits different licensing errors depending on if the the license is unavailable vs. if you are an unauthorized user. It is important to be able to distinguish between the two because I'd ultimately like to write a prolog script for Slurm to handle the differences between the two. Some users are permitted to use the license, others are not. This is why my above example is inadequate.
You should be able to utilize the lmutil command-line utility that is distributed with MATLAB, specifically with the lmstat command. The location of this command-line program depends on your system, but it's typically in $MATLAB_ROOT/etc/$arch
Specifically to get the status of licenses, you can use the lmstat option:
./lmutil lmstat -a -c /path/to/license
This will parse the license file and communicate with the license server specified in the file to get the status of its licenses.
If you check out the documentation for lmutil (./lmutil --help) and lmstat (./lmutil lmstat --help) you'll see a number of different options that may be useful for what you are trying to accomplish.

GNU Make - terminal rules and keyword "null"

BACKGROUND
This is related to my question GNU make - transform every prerequisite into target (implicitly)
I've posted this question because it's interesting and may be useful by itself - to understand make - and I don't want it to get lost in the "original" question.
INFO
I have a file Dummy.mk:
%:: null
#:
null:
#:
which I pass to my make as make all MAKEFILES=Dummy.mk.
When I replace null with saflkjsaflkjdsa,
%:: saflkjsaflkjdsa
#:
saflkjsaflkjdsa:
#:
the behavior of the build was different: the rule was never executed.
The reason is because this is a "terminal rule":
One choice is to mark the match-anything rule as terminal by defining
it with a double colon. When a rule is terminal, it does not apply
unless its prerequisites actually exist. Prerequisites that could be
made with other implicit rules are not good enough. In other words, no
further chaining is allowed beyond a terminal rule.
Since saflkjsaflkjdsa did not exist, the rule was not executed. Ok fine I understand that.
But when I set Dummy.mk using the keyword null
%:: null
#:
null:
#:
the %:: rule does execute i.e. it captures ALL targets, filenames, etc giving me outputs of the form :2: update target <item> due to: null where <item> is any filename or target that make reads in.
Since the rule is executing using null but not with using saflkjsaflkjdsa, make is definitely detecting null as "existing".
QUESTION
But then why do I still get the output :5: target 'null' does not exist?
Is that because of the OS- or shell-level peculiarities of null existing but not existing at the same time?
Environment
* Windows 8, 64-bit
* Make 4.2.1 (here's output of make
# GNU Make 4.2.1
# Built for Windows32
# Copyright (C) 1988-2016 Free Software Foundation, Inc.
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software: you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.
find_and_set_shell() path search set default_shell = C:/Users/User1/Desktop/A/QNX_SDK/host/win32/x86/usr/bin/sh.exe
...
* Shell that make is using internally is:
C:\Users\User1\Desktop\A\Project\bld\armle-v7\release\subProj>where sh
C:/Users/User1/Desktop/A/QNX_SDK/host/win32/x86/usr/bin/sh.exe
C:\Users\User1\Desktop\A\Project\bld\armle-v7\release\subProj>sh --help
GNU bash, version 3.1.17(1)-release-(i686-pc-msys)
Usage: sh [GNU long option] [option] ...
sh [GNU long option] [option] script-file ...
GNU long options:
--debug
--debugger
--dump-po-strings
--dump-strings
--help
--init-file
--login
--noediting
--noprofile
--norc
--posix
--protected
--rcfile
--restricted
--verbose
--version
--wordexp
Shell options:
-irsD or -c command or -O shopt_option (invocation only)
-abefhkmnptuvxBCHP or -o option
Type `sh -c "help set"' for more information about shell options.
Type `sh -c help' for more information about shell builtin commands.
Use the `bashbug' command to report bugs.
Is that because of the OS- or shell-level peculiarities of null existing but not existing at the same time?
Since you didn't specify which OS or shell you're using, it's impossible for us to say. All I can say is that I tried to replicate your problem on my GNU/Linux system and couldn't: on my system no targets were built in either case (using null or saflkjsaflkjdsa made no difference)
My suspicion is you're using Windows; I have a vague recollection that null is special somehow on Windows. But, I don't do Windows so I can't say for sure.

How to exit from cygwin/bash environment called from a perl script?

On windows XP, I have a bat file which calls a perl script, which itself shall contain a "make" command in a cygwin context. (I can't change this BAT -> PERL -> CYGWIN structure). This works a little bit but I don't find how to exit from the cygwin environment.
For example, in my perl script, this line seems to work :
print STDOUT "START PERL SCRIPT\n" ;
system ("$ENV{CYGWIN_HOME}\\bin\\bash | $ENV{CYGWIN_HOME}\\bin\\make -version");
print STDOUT "END OF PERL SCRIPT\n" ;
However, in my cmd.exe, this is my output:
START PERL SCRIPT
GNU Make 3.80 Copyright (C) 2002 Free Software
Foundation, Inc.
This is free software; see the source for copying
conditions. There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
bash-3.2$
My problem is that I stay in bash environment : the line "bash-3.2$" still waits for a command, and I cant' find a solution to exit automatically from it (the only way is to manually print "exit" in cmd.exe).
My perl script is thus stopped instead of automatically continuing its jobs.
I've not succeeded with solutions such as
"Using perl to run more than one system command in a row"
Do you know how to write the perl script and commands in order to get out of the bash environment and continue the perl script ?
Thanks a lot,
Calim
Update
So finally I have moved to another solution. It seems to work (i.e. I go back to my perl script after the shell command is executed) ; I just hope there will be no unexpected effect. Do you have any opinion about it ?
print STDOUT "START PERL SCRIPT\n";
open ( CYGWIN , "|-" , "$ENV{CYGWIN_HOME}\\bin\\bash" ) ;
print CYGWIN "$ENV{CYGWIN_HOME}\\bin\\make -w -C /cygdrive/c/tmp/Generation makefile" ;
close CYGWIN ;
print STDOUT "END OF PERL SCRIPT\n";
Why are you piping the ouptut of bash to make?!?!?!
system("$ENV{CYGWIN_HOME}\\bin\\make -version");
Or maybe you need some environment variables set up by bash.
system("$ENV{CYGWIN_HOME}\\bin\\bash -c 'make -version'");
So finally I have moved to another solution. It seems to work (i.e. I go back to my perl script after the shell command is executed) ; I just hope there will be no unexpected effect. Do you have any opinion about it ?
print STDOUT "START PERL SCRIPT\n";
open ( CYGWIN , "|-" , "$ENV{CYGWIN_HOME}\\bin\\bash" ) ;
print CYGWIN "$ENV{CYGWIN_HOME}\\bin\\make -w -C /cygdrive/c/tmp/Generation makefile" ;
close CYGWIN ;
print STDOUT "END OF PERL SCRIPT\n";

Making make print commands before executing when NOT using CMake

I see that this is the same question as
Making cmake print commands before executing
But that answer doesn't work for me. I'm guessing that answer only works with cmake. What options work without cmake?
Note tried these
make VERBOSE=1 target
make target VERBOSE=1
VERBOSE=1 make target
make V=1 target
make target V=1
V=1 make target
make -V target
make -v target
none of them worked.
make -v returns
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
By default, make does print every command before executing it. This printing can be suppressed by one of the following mechanisms:
on a case-by-case basis, by adding # at the beginning of the command
globally, by adding the .SILENT built-in target.
somewhere along the make process, by invoking sub-make(s) with one of the flags -s, --silent or --quiet, as in $(MAKE) --silent -C someDir, for example. From that moment on, command echoing is suppressed in the sub-make.
If your makefile does not print the commands, then it is probably using one of these three mechanisms, and you have to actually inspect the makefile(s) to figure out which.
As a workaround to avoid these echo-suppressing mechanisms, you could re-define the shell to be used to use a debug mode, for example like make SHELL="/bin/bash -x" target. Other shells have similar options. With that approach, it is not make printing the commands, but the shell itself.
If you use the flag -n or --just-print, the echo-suppressing mechanisms will be ignored and you will always see all commands that make thinks should be executed -- but they are not actually executed, just printed. That might be a good way to figure out what you can actually expect to see.
The VERBOSE variable has no standard meaning for make, but only if your makefile interprets it.
For my version of make, I found BOTH paramters -n and -d helped.
GNU Make 3.80 Copyright (C) 2002 Free Software Foundation, Inc
-d Print lots of debugging information.
-n, --just-print, --dry-run, --recon
Don't actually run any commands; just print them.
When a bunch of makefile fragments are included, the line numbers don't make sense without this key debug flag.
CreateProcess(....exe,...)
Reading makefile `../../../../build/Makefile.options' (search path) (don't care) (no ~ expansion)...
Makefile:361: Extraneous text after `else' directive
Makefile:368: Extraneous text after `else' directive
Makefile:368: *** only one `else' per conditional. Stop.
in my case i was able to suppress commands in output by setting up below variable in top my make file
# Use `make V=1` to print commands.
$(V).SILENT:
add the above line in top of you make file and when you call any target it wont print
Before :
muhasan#admins-MacBook-Pro fx.identitymanagement % make dockerstatus
cd identity.API/ && docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------
identityapi_backend_1 dotnet Identity.API.dll Up 0.0.0.0:5000->80/tcp
identityapi_db_1 docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
muhasan#admins-MacBook-Pro fx.identitymanagement %
After :
muhasan#admins-MacBook-Pro fx.identitymanagement % make dockerstatus
Name Command State Ports
--------------------------------------------------------------------------------------
identityapi_backend_1 dotnet Identity.API.dll Up 0.0.0.0:5000->80/tcp
identityapi_db_1 docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
muhasan#admins-MacBook-Pro fx.identitymanagement %
My Makefile
# Use `make V=1` to print commands.
$(V).SILENT:
Path = identity.API
builddocker:
cd devops && cp -rv Dockerfile docker-compose.yml ../${Path}/ && cd ..
installdocker:
cd ${Path}/ && docker-compose up -d
dockerstatus:
cd ${Path}/ && docker-compose ps
I think this is what you want:
make MAKE_VERBOSE=1 target

Resources