mingw make fail by shell = cmd.exe - makefile

I compile phyx4.1 android build on win10 with mingw and failed.
After some hours research, I find this line SHELL = cmd.exe which make the behaviour stranger.
My makefile is like:
SHELL = cmd.exe
help:
echo hahaha
echo gagagaga
exit
I try to execute it by mingw command line
make help
but it enter cmd.exe and not return. anyone know why?
ps: finally, i found the solution, use mingw32-make.exe rather than make.exe ..thanks for your replays

GNU make passes -c to $(SHELL) to execute a command.
When you have a command like echo hahaha, make tries to run
cmd.exe -c echo hahaha
as cmd.exe does not recognize -c echo hahaha, it went into interactive session.
To make it work, you can do :
SHELL = cmd.exe
.SHELLFLAGS = /c
help:
echo hahaha
echo gagagaga
exit

The SHELL variable designates the command interpreter with which make should execute rules' recipes. For most make implementations it defaults to one or another variation on the Bourne shell, such as Bash. This is important, because it has a deep and pervasive impact on the effects of running recipes.
Different shells are not interchangeable. Different Bourne-family shells are often similar enough that they will not exhibit different behavior for the recipes in a given makefile, but cmd.exe is an another beast altogether. Trying to use cmd.exe as the shell for a makefile written with a Bourne shell in mind (as most are) is a recipe for disaster.
i try to execute it by mingw command line
make help
but it enter cmd.exe and not return anyone know why?
It seems likely that the issue revolves around the use of the exit command in the recipe, which appears completely pointless. It is possible, however, that cmd.exe just doesn't work at all with your particular make. The details don't really matter because overall, this is a knob that you generally should not twiddle. You especially should not turn it to the cmd.exe setting unless you are the makefile author and you know exactly what you are doing.

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.

GNU Make and using ; to execute multiple shell commands in the same command shell

I have a very basic problem using GNU Make 3.81 on Windows, I must be doing something very silly and I'm sure someone here will point it out in milliseconds. My problem is with using ";" to run multiple commands in the same shell.
As I understand it, make runs each line in its own command shell and so if you want to run two commands, one after the other, you must put them on the same line separated by a semicolon. In it's simplest form:
all:
echo hello; echo hello
...should produce the output:
hello
hello
But for me it produces the output:
hello; echo hello
In other words, the semicolon is being passed straight through to the shell, which doesn't make too much sense for cmd.exe.
I'm now ready to be embarrassed by everyone pointing out where I've gone wrong...
FYI, the reason I need this is that I'm using a $(foreach) loop which must execute two shell commands for each iteration.
You are be under the impression that ; is a GNU-make operator for executing multiple
commands in the same shell within a recipe. Not so. It is linux shell operator
for punctuating a sequence of commands on the same line. It is not an operator for
the Windows shell, cmd, so when the recipe:
echo hello; echo hello
is executed by make on Linux, it has the output you expect, but when executed by make
on Windows it just means echo this:
hello; echo hello
So, the answer is that your shell is the thing that has to understand that ; separates multiple commands on the same line, it's nothing to do with make. This is not the case for Windows cmd.exe but is presumably the case for the shells that normally arrive with environments that use make (Linux, msys etc.). In my case, a good workaround was this:
define useDef
echo hello
echo hello
endef
all:
$(call useDef)
With this form of "single-lined" definition I can invoke a multiline shell command inside $(foreach). Make still does each "hello" in its own shell but in my case that's OK because I'm appending outputs to a file. If you need two commands to be run in the same shell for some reason then, on Windows, you would need to write a separate batch file (which I suppose you could create from inside the makefile).
I know this question is relatively old, but I've stumbled across the same problem recently. The solution (for me) was quite simple. I replaced ; with &.
Basically
all:
echo hello & echo hello
will produce
hello
hello
in cmd.exe.
And it works with $(foreach) loops as well.
UPD: You also can use && instead of & if you don't want your commands to fail silently.

shellscripts in Makefiles do not work as expected

I found many answers here and elsewhere on the topic, but none that worked. Please help me out here.
I need to set some environment variables, which is partly done in some scripts, called from a master script, partly directly. Here is a minimal Makefile that shows the unwanted behaviour:
FC := ifort
SHELL := /bin/bash
some_target: load_ifort
$(FC) file.f
load_ifort:
source /usr/local2/bin/ifort-compilervars.sh ia32
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic
if I call make, I get an "ifort: command not found" error. If I execute the two comamnds by hand on the command line before calling make, ifort is found and everything is good.
What am I missing???
Each line in a recipe gets executed in a separate subshell. So you create one shell which sources the .sh file, then exits and forgets everything, then another shell which starts with a clean slate.
The straightforward solution in your case would be to collect all these commands in a single variable. I have factored out the LM_LICENSE_FILE assignment because that can be done in Make directly, but you could include that in the FC variable as well.
LM_LICENSE_FILE := /usr/local2/misc/intel2013/flexlm/server.lic
export LM_LICENSE_FILE
FC := source /usr/local2/bin/ifort-compilervars.sh ia32; \
ifort
some_target:
$(FC) file.f
If the shell commands can be straightforwardly run by Make as well, you could include them, or perhaps translate the sh file into Make commands by a simple script.
Another option would be to create a simple wrapper in your PATH; maybe call it fc:
#!/bin/sh
. /usr/local2/bin/ifort-compilervars.sh ia32
ifort "$#"
then just use fc where you currently have $(FC). (If the ifort-compilervars.sh file contains Bash constructs, in spite of the name, you should change the shebang to #!/bin/bash.)
As a rule, only one-liner shell commands "work". From the comment about "bash", it seems likely you are using GNU make. In your example, the word "source" is not found in the GNU make manual's index. (If you found this in a working example, it would be helpful to start from that). There are two types of variables of interest:
makefile variables, which live in the make program
environment variables, which are "exported"
The latter would include $PATH, which is used to find programs. For updating that, you do need shell commands. But (lacking some special provision in the make program), exported variables from a shell script are not passed up into the make program and made available for the next line of the makefile.
You could reorganize the makefile to provide a rule which combines the source command and other initialization into a shell command which then recurs (carrying those variables along) into a subprocess which would then do the compiles. Something like
build:
sh -c "source /usr/local2/bin/ifort-compilervars.sh ia32; \
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic; \
$(MAKE) some_target"
some_target: load_ifort
$(FC) file.f

Calling vcvars from bash script

I need to call vcvars32.bat and vcvars64.bat from within the same bash script (msys) which builds different version of my application.
The problem is that, even if I am able to call the batch files with the cmd.exe command, once it returns the Visual Studio variables are obviously not set.
I cannot call vcvars from an external batch file (like msys.bat) which call the bash script, as I need in the same script to call both of them sequentially.
So, is there any way to call vcvars in order to properly set the variables in the bash script while running?
One way to solve this is to run your commands from within the vcvars environment, rather than trying to export it back to the bash side. That's the approach we've chosen for our project.
The main problem is that vcvars*.bat doesn't accept commands to execute in the environment, so a little bit of trickery with cmd is required. So I came up with a simple Bash script called vcvars_env_run.sh that accepts arbitrary arguments and forwards them to a cmd.exe on which vcvars64.bat has been called. The bulk of the work is figuring out how to properly forward quoted arguments, and things like &&, ||, return codes, etc.
I've uploaded the script and some examples at https://github.com/kromain/wsl-utils
You might need to tweak it a little to switch between vcvars32.bat and vcvars64.bat, but hopefully it helps for what you're trying to do.
The POSIX shell export -p prints the values of all environment variables such that an eval of the output recreates those values. The idea is to invoke this from a subshell after vcvars*.bat has run and to eval the captured output in the top-level script.
A Cygwin environment variable setup script can obtain the results of vcvars*.bat as follows:
eval "$($(cygpath "$COMSPEC") /c vcvars_export "$vcvars_bat" "$(
cygpath -w "$SHELL")")"
where vcvars_bat contains the path of the relevant vcvars*.bat file. You will find this value e.g. in the target of the x64 Native Tools Command Prompt for VS 2019.lnk file, which can be read with readlink -t. (Note also that the vcvarsall.bat script allows specification of the compiler and SDK version to use, useful when precise control is needed).
The local vcvars_export.bat file contains
#echo off
call %1 > nul
"%2" -c "export -p"
Limitations of the Cygwin native process invocation subsystem (argument quoting is done heuristically) make this auxiliary file necessary.
What you need to do is to use the command: "call" in your batch script. So it could look something like:
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\vcvars32.bat"
echo DevEnvDir set to: %DevEnvDir%
If you don't use the "call" then the script will exit after the vcvars32.bat exits and won't run any other command.

Bash: What is the effect of "#!/bin/sh" in a bash script with curl

I make a complex and long line command to successful login in a site. If I execute it in Console it work. But if I copy and paste the same line in a bash script it not work.
I tried a lot of thing, but accidentally discovery that if I NOT use the line
#!/bin/sh
it work! Why this happens in my mac OSX Lion? What this config line do in a bash script?
A bash script that is run via /bin/sh runs in sh compatibility mode, which means that many bash-specific features (herestrings, process substitution, etc.) will not work.
sh-4.2$ cat < <(echo 123)
sh: syntax error near unexpected token `<'
If you want to be able to use full bash syntax, use #!/bin/bash as your shebang line.
"#!/bin/sh" is a common idiom to insure that the correct interpreter is used to run the script. Here, "sh" is the "Bourne Shell". A good, standard "least common denominator" for shell scripts.
In your case, however, "#!/bin/sh" seems to be the wrong interpreter.
Here's a bit more info:
http://www.unix.com/answers-frequently-asked-questions/7077-what-does-usr-bin-ksh-mean.html
Originally, we only had one shell on unix. When you asked to run a
command, the shell would attempt to invoke one of the exec() system
calls on it. It the command was an executable, the exec would succeed
and the command would run. If the exec() failed, the shell would not
give up, instead it would try to interpet the command file as if it
were a shell script.
Then unix got more shells and the situation became confused. Most
folks would write scripts in one shell and type commands in another.
And each shell had differing rules for feeding scripts to an
interpreter.
This is when the "#! /" trick was invented. The idea was to let the
kernel's exec() system calls succeed with shell scripts. When the
kernel tries to exec() a file, it looks at the first 4 bytes which
represent an integer called a magic number. This tells the kernel if
it should try to run the file or not. So "#! /" was added to magic
numbers that the kernel knows and it was extended to actually be able
to run shell scripts by itself. But some people could not type "#! /",
they kept leaving the space out. So the kernel was exended a bit again
to allow "#!/" to work as a special 3 byte magic number.
So #! /usr/bin/ksh and
#!/usr/bin/ksh now mean the same thing. I always use the former since at least some kernels might still exist that don't understand the
latter.
And note that the first line is a signal to the kernel, and not to the
shell. What happens now is that when shells try to run scripts via
exec() they just succeed. And we never stumble on their various
fallback schemes.
The very first line of the script can be used to select which script interpreter to use.
With
#!/bin/bash
You are telling the shell to invoke /bin/bash interpreter to execute your script.
Assure that there are not spaces or empty lines before #!/bin/bash or it will not work.

Resources