What does *$ mean when expanding macros in a Watcom makefile? - makefile

I have a peculiar set of makefiles in a legacy project. They are processed by the Watcom make, but they seem to have the NMAKE file format. I frequently encounter the following construct:
*$(_cmd_run)
$(_cmd_run) is simply a macro expansion, but in this case there is also an asterisk before the dollar sign. I can't seem to find any documentation as to what its purpose is. NMAKE documentation doesn't have anything with regard to this syntax. I've even tried to look up Open Watcom source files, but to no avail.
What does this asterisk signify?

This is a workaround for handling "long" command lines under DOS, so it can be dropped off safely. From WMAKE's help:
Under DOS, an asterisk prefix (*) will cause Make to examine the length of the command argument. If it is too long (> 126 characters), it will take the command argument and stuff it into a temporary environment variable and then execute the command with "#env_var" as its argument.

Related

How to run csh script in bash shell

My default shell is bash in Ubuntu 14.04. I have a csh script file named clean.sh with the following make command:
#! /bin/csh -f
make -f commande.make del
And commande.make has
CKHOME=../CHEMKIN/DATA_BASES
LIN_DATA=${CKHOME}/LIN_FILES/
LINK_CKTP=${CKHOME}/LINK_CKTP_FILES/
#-----------------------------------------------------
include schema_cinetique.make
LINKFILE=${NAME}_LINK
LINKTPFILE=${NAME}_LINKTP
LINKFILE_OLD=${NAME_OLD}_LINK
LINKFILE_NEW=${NAME_NEW}_LINK
#-----------------------------------------------------
cplink :
${COPY} ${LINK_CKTP}${LINKFILE} LINK
cplink2 :
${COPY} ${LINK_CKTP}${LINKFILE} LINKZ1
tplink :
${COPY} ${LINK_CKTP}${LINKTPFILE} LINKTPZ1
calcul :
${COPY} jobtimp1 LJOBNZ1
${COPY} unsteadyf.dat1 DATZ1
del :
${DELETE} LINKZ1 LINKTPZ1 LJOBNZ1 DATZ1 SOLASUZ1
I opened the terminal and moved to the location and tried
./clean.sh
or
csh clean.sh &
or
csh -f clean.sh
Nothing worked.
I got the following line in the terminal,
LINKZ1 LINKTPZ1 LJOBNZ1 DATZ1 SOLASUZ1
make: LINKZ1: Command not found
make: *** [del] Error 127
So, how to run clean.sh file ?
You are confused. The Csh script contains a single command which actually runs identically in Bash.
#!/bin/bash
make -f commande.make del
Or, for that matter, the same with #!/bin/sh. Or, in this individual case, even sh clean.sh, since the shebang is then just a comment, and the commands in the file are available in sh just as well as in csh.
Once make runs, that is what parses and executes the commands in commande.make. make is not a "Fortran command", it is a utility for building projects (but the makefile named commande.make probably contains some instructions for how to compile Fortran code).
In the general case, Csh and Bash are incompatible, but the differences are in the shell's syntax itself (so, the syntax of loops and conditionals, etc, as well as variable assignments and various other shell builtins).
As an aside, Csh command files should probably not have a .sh extension, as that vaguely implies Bourne shell (sh) syntax. File extensions on Unix are just a hint to human readers, so not technically important; but please don't confuse them/us.
(As a further aside, nobody should be using Csh in 2022. There was a time when the C shell was attractive compared to its competition, but that was on the order of 40 years ago.)
The subsequent errors you are reporting seem to indicate that the makefile depends on some utilities which you have not installed. Figuring that out is a significant enough and separate enough question that you should probably ask a new question about that, probably with more debugging details. But in brief, it seems that make needs to be run with parameters to indicate what NAME and COPY (and probably some other variables) should be. Try with make -f commande.make COPY=cp DELETE=rm NAME=foobar for a start, but it's probably not yet anywhere near sufficient.
(I would actually assume that there will be a README file or similar to actually instruct you how to use commande.make since it seems to have some local conventions of its own.)
It seems the script is written having portability in mind, i.e. the name of the cp and rm binaries is kept in variables rather than hard-coding it. My best guess is that this has been done to make it possible to run the script on non UNIX systems, like Windows.
To make it work, export the respective variables before running the script. For the del action you are calling, only the DELETE variable is needed. It should be set to rm which is the command used to remove files on Linux:
export DELETE=rm
./clean.sh
Note: exporting the variable can also be done in one line when invoking the script, by prepending it to the command line:
DELETE=rm ./clean.sh
This behaviour is described in the bash manual:
The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described in Shell Parameters. These assignment statements affect only the environment seen by that command.

Bad subsitution when trying to do string replacement with parameter expansion

Maybe this is a dumb question, but I'm writing a very small Gedit external tool for compiling .qrc (Qt resource files) on a key press. This is my code:
echo $GEDIT_CURRENT_DOCUMENT_PATH
pyrcc $GEDIT_CURRENT_DOCUMENT_PATH -o ${GEDIT_CURRENT_DOCUMENT_PATH/.qrc/.py}
Running the above, I get
/home/user/.local/lib/python3/qrecartivi/resources.qrc
/home/user/.config/gedit/tools/new-tool: 12: /home/user/.config/gedit/tools/new-tool: Bad substitution
where line 12 actually is the 2n line of my sh code (This offset is due to gedit adding some comments in).
I just cannot figure out why this substition should be wrong. Thanks in advance.
As stated in comment by #chepner, the syntax ${var/str1/str2} is not supported by your shell interpreter (Dash) which is strictly POSIX-compliant.
You have two solutions:
Use Bash which supports this kind of variable substitution
Use a POSIX-compliant way to substitute an extension with another. Like this for example:
pyrcc "$GEDIT_CURRENT_DOCUMENT_PATH" -o "$(basename "$GEDIT_CURRENT_DOCUMENT_PATH" .qrc).py"

Bash missing $(HOME) variable

I have been compiling an application using Makefile for quite a while without any problems. Today, I realized that my Makefile wasn't working any longer. A bit of debugging and I soon found out that $(HOME) was not defined
$echo $(HOME)
-bash: HOME: command not found
I always thought that $HOME and $(HOME) could be used interchangeably. Is there a reason why a system could be configured to avoid the use of $(HOME)?
It's ${HOME}, not $(HOME).
$(HOME) would expand to the output of a HOME command. Since there (probably) is no such command, you'll get an error message.
However, $(HOME) is the correct syntax in a Makefile. If you need help debugging your Makefile, you'll need to show us what's in it -- or, better, a small Makefile that exhibits the same problem. A make rule like:
target:
echo $(HOME)
should print the path of your home directory when you run make target.
In the shell, you can refer to the HOME variable as $HOME or as ${HOME}; the latter can avoid problems with adjacent tokens.
In a Makefile, you can use either $(HOME) or ${HOME}, but the $(HOME) form is more common. You can omit the parentheses only when the variable name is one character long (but even then you should use them for clarity). (Nobody has claimed that make is a model of clear and intuitive syntax.)

Blacklist program from bash completion

Fedora comes with "gstack" and a bunch of "gst-" programs which keep appearing in my bash completions when I'm trying to quickly type my git aliases. They're of course installed under /usr/bin along with a thousand other programs, so I can't just remove their directory from my PATH. Is there any way in Linux to blacklist these specific programs from appearing for completion?
I've tried the FIGNORE and GLOBIGNORE environment variables but they don't work, it looks like they're only for file completion after you've entered a command.
In 2016 Bash introduced an option for that. I'm reproducing the text from this newer answer by zuazo:
This is rather new, but in Bash 4.4 you can set the EXECIGNORE variable:
aa. New variable: EXECIGNORE; a colon-separate list of patterns that
will cause matching filenames to be ignored when searching for commands.
From the official documentation:
EXECIGNORE
A colon-separated list of shell patterns (see Pattern Matching) defining the list of filenames to be ignored by command search using
PATH. Files whose full pathnames match one of these patterns are not
considered executable files for the purposes of completion and command
execution via PATH lookup. This does not affect the behavior of the [,
test, and [[ commands. Full pathnames in the command hash table are
not subject to EXECIGNORE. Use this variable to ignore shared library
files that have the executable bit set, but are not executable files.
The pattern matching honors the setting of the extglob shell option.
For Example:
$ EXECIGNORE=$(which pytest)
Or using Pattern Matching:
$ EXECIGNORE=*/pytest
I don't know if you can blacklist specific files, but it is possible to complete from your command history instead of the path. To do that add the following line to ~/.inputrc:
TAB dynamic-complete-history
FIGNORE is for SUFFIXES only. It presumes for whatever reason that you want to blacklist an entire class of files. So you need to knock off the first letter.
E.g. To eliminate gstack from autocompletion:
FIGNORE=stack
Will rid gstack but also rid anything else ending in stack.

What does the bash command "rm *~" do?

Does the bash command rm *~ just remove files ending in tilde or is there a more advanced bash or gnu make pattern here? Google does not seem able to search for this two symbol combination. I found this in a Makefile clean: target.
Would gnu make ever create files with trailing ~'s using only the implicit rules?
The ~ (tilde) character has a special meaning in a path in two cases:
~user # the home directory of user
~/folder # folder inside your home directory
For the most part, that's it. The command you refer to does exactly what it looks like it does: removes files whose names end in a tilde. Text editors such as emacs save backup copies of files under filenames ending in tildes.
So, this command is probably used to remove these backup copies from the current directory (but not subdirectories). One reason why one would want to do so is if the directory will be copied to a web server, as server-side code (e.g. PHP files) can contain sensitive information such as passwords.
As you guessed, rm *~ just removes file with names ending with a tilde (~). Filenames ending with a tilde are usually backup files created by editors (in particular, emacs was one of the earlier editors to use this convention). After editing source code, it is common to have a number of these files left behind. This is why the clean target in the Makefile removes these.
Whether *~ is some special bash pattern is not relevant for most makefiles, as /bin/sh is used by default to execute make recipes. Only if SHELL is set in the makefile will a different shell be used.
An easy way to see make's implicit rules is to run make -p in a directory without a makefile. You will get an error saying no targets specified, but make will also print out the implicit rules it is using. If you grep this output for a tilde, you'll see there are no implicit rules that name files with it.
Nope, just what you said. Removes files ending with ~.
Edit -> the only special meaning the ~ character may have, is as short-hand for the the current user's home directory (as $HOME), but only in the beginning of a path.
I have used that command to erase files ending in "~". I think that there is no special escape character associated with the tilde symbol.
Yes to both
Actually, both of your possibilities are somewhat true.
There is no wildcard or special filename syntax associated with ~, unless it occurs at the beginning of a word.
But the filename pattern ending in tilde is produced automatically by the mv(1) and cp(1) programs on most linux distros1 if the -b (backup) option is specified and the target file exists. A make rule on such a system might contain a mv -b ... or cp -b ... command.
1. But not on the Mac or BSD.

Resources