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.)
Related
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.
Say in ~/prj/abc/abcsim/abctsim/abcxyz/Makefile there is a line below.
TOOLCHAIN_DIR := $(PWD)/../../../prj1/tools/gcc_tools
If I'm in directory ~/test, and if I run make -C ~/prj/abc/abcsim/abctsim/abcxyz, this doesn't work because the $(PWD) variable is set to ~/test, not ~/prj/abc/abcsim/abctsim/abcxyz. How can I get the directory path where the Makefile exists?
In bash there's something for this : How can I get the source directory of a Bash script from within the script itself?
If you really use make -C (not make -f) and your Makefile is not included in another, you can simply use the CURDIR variable. GNU make sets it to the absolute path of the current directory when it starts, "after it has processed any -C options". So, in your case it should do exactly what you want.
Else, if you sometimes use make -f or if you have included Makefiles, you can put this as the first line of any of your Makefiles (or, at least, before any include statement):
HERE := $(dir $(lastword $(MAKEFILE_LIST)))
and then use $(HERE) to refer to this Makefile's directory. See the GNU make manual for the details.
Note: I was almost sure this question would be a duplicate. Surprisingly I searched SO for a clear answer and found only old answers that first suggest shell calls before using make built-ins or wrong answers (using firstword instead of lastword, for instance).
How can I correctly set environment variables in a makefile on Windows?
I get an error about CreateProcess.
C:\>make.exe -f build.makefile start
export MALLOC_PERTURB_=110
process_begin: CreateProcess(NULL, export MALLOC_PERTURB_=110, ...) failed.
make (e=2): The system cannot find the file specified.
c:\testmake.makefile:4: recipe for target 'start' failed
make: *** [start] Error 2
START:
export NODE_ENV=110
echo $(NODE_ENV)
Your question isn't entirely clear but there are a number of obvious things wrong there.
First off you are running make under Windows but writing recipes as if they were shell scripts. That's not the case on Windows (by default at least).
So export is being attempted to be run as an external command which is failing (hence the error message about CreateProcess failing).
You also don't show us the target that is actually throwing that error.
Additionally you are expecting the export and assignment on the first line of the recipe to be in effect for the second line in the recipe body (for the start target).
But that isn't the case. Each line in a makefile target's recipe runs in an independent environment. So the export and assignment on the first line of the START target's recipe doesn't affect the second line.
To do that you need to use one long line or use the .ONESHELL feature of recent versions of make.
Additionally, you are using $(NODE_ENV) in your recipe expecting that to be the shell variable you previously set. And even ignoring the previously stated problem that isn't correct.
make is going to expand $(NODE_ENV) as a make variable before it even runs the recipe at all. You meant ${NODE_ENV} or $NODE_ENV for a shell variable. That said for a make recipe you actually need to escape the $ because ${NODE_ENV} is also a valid make variable expansion. So you need $${NODE_ENV} or $$NODE_ENV there.
Put together you end up with this (assuming you have a shell somewhere to use).
SHELL := /path/to/your/shell
START:
export NODE_ENV=110; \
echo "$${NODE_ENV}"
(though you don't actually need export at that point but that's a different issue entirely).
But if you don't have a shell to use then you get to use cmd.exe and I'm not sure what the equivalent of export there is (though as I just said you don't need it for this) and you end up with something like this (entirely untested):
START:
NODE_ENV=110; \
echo %NODE_ENV%
I am writing my own unix scripts so I want to add a new directory for Bash. I add sth in .bash_profile like this.
PATH="~/Documents:${PATH}"
export PATH
and in my ~/Documents, there is a file named test of which the content is
#!/usr/bin/env python3.5
print("hahahhah")
I also used
chmod 755 test
to make it executable.
But I cannot call it in terminal directly. ./test works as usual.
What went wrong?
After I change to
PATH="$HOME/Documents:${PATH}"
export PATH
nothing happens.
FDSM_lhn#9-53:~/Documents$ test
FDSM_lhn#9-53:~/Documents$ ./test
hahahhah
Solution:
The fundamental reason is that I have a command of the same name as default one, So it won't work any way! Changing name will be sufficient!
Tilde doesn't get expanded inside strings. So by quoting the right-hand side of the assignment you prevent it from being expanded and get a literal ~ in your PATH variable which doesn't help you any.
You have two ways to fix this:
Drop the quotes on the assignment (yes this is safe, even for $PATH values with spaces, etc.).
Use $HOME instead of ~.
I prefer the second solution but the first is entirely valid for this case.
Beware though that in places where you aren't doing a straight assignment you often cannot just drop the quotes and trying to use ~ will cause problems.
In which case you will end up finding a question like this with an answer like this and something ugly like this.
Yes, I know that I can run
. my_cd_script.sh
to change my directory directly. However, once I do that, my $PATH is messed up. For instance, when I type ls, the shell will return Command not found.
Anyone encountered this?
I named a variable "path" without a second thought, although I would've expected shell to be case sensitive. – user1836155
If you're running into variable names not seeming to be case-sensitive, then I suspect you're not actually using bash. Maybe csh instead, or some other variant in the csh family... – twalberg
I used the "#!/bin/bash" header though – user1836155
The header means nothing when you source a file with . myscript - it's just a comment in that case. – twalberg