mingw32-make + mklink... just not getting along? - makefile

Not sure if anyone else has gotten this to work, but I'm having no end of trouble even with the following simple line in my Makefile running mingw32-make:
mklink Mk Makefile
The following created the link, but mingw32-make puked and threw error 255 thereafter:
$(shell cmd /c 'mklink Mk Makefile')
Nothing else is problematic, and I have a relatively complex makefile. Only mklink is doing this. (Apparently msys has it's own problems with ln so going down that path appears pointless.)

The following works for me, (on Win7 Home Premium, in VirtualBox),
provided I invoke it in a shell running with administrator privilege:
$ cat makefile.tst
all:
cmd /c "mklink mk makefile.tst"
#echo "Success!"
$ make -f makefile.tst
cmd /c "mklink mk makefile.tst"
symbolic link created for mk <<===>> makefile.tst
Success!
$ rm mk
$ mingw32-make -f makefile.tst
cmd /c "mklink mk makefile.tst"
symbolic link created for mk <<===>> makefile.tst
Success!
My shell, in this case is MSYS sh.exe, invoked via msys.bat from cmd.exe with UAC escalation to administrator privilege. This is so that I can show that the mklink command works both in MSYS' own make.exe, and in mingw32-make.exe; (of course, the mingw32-make.exe example also works directly from the elevated cmd.exe shell itself).
I suspect that attempting to use mklink directly within the makefile, without the cmd /c preamble, may not work because mklink is a cmd.exe built-in, which GNU make may not know to run this way ... it reports a CreateProcess failure, because the specified file cannot be found, when I try it.
Your use of make's $(shell ...) construct would not work, because that causes make to invoke the command in the wrong phase of operation ... when parsing the makefile itself, and constructing its dependency graph, rather than as a command to run when the containing rule is invoked, where it will now attempt to execute the output from the $(shell ...) command as a command in its own right; this is clearly not what you want!

Just to clarify the position with regard to MSYS' own ln command: it does work as well as can be expected, within the limitations of the versions of Windows on which it was originally implemented. In particular:
$ ln fileA fileB
creates a file-to-file hard link, on file systems such as NTFS, which support such links, and falls back to creating a copy on file systems such as FAT, which don't. Also:
$ ln dirA dirB
fails, as it should; hard linked directories are a recipe for disaster, and are not allowed, (just as they are forbidden on unix platforms). However:
$ ln -s fileA refB
will not create a symbolic link, (because no version of Windows supported them at the time when MSYS was developed, and no one has stepped forward to implement the capability, since they have become available ... although, their implementation still seems flaky, on Vista and Win7 anyway); rather, this command falls back to creating a hard link if possible, or a file copy otherwise. Similarly:
$ ln -s dirA refB
will not create a symbolic directory link, and in this case, there is no fall back; it simply and unconditionally fails! (It might be argued that a deep copy of the directory could be a suitable fall back action, but it isn't implemented so; instead, the lndir command is provided, to facilitate this).

Related

Cmd prompt vs other shells

I'm trying to learn how to create a makefile and I faced couple of issues related to commands which I should use.
ls is something i know to list directories.
rm is something I know to remove file or directory and some other.
Then I learnt that Unix-cmd is different from command prompt in windows and also from powershell.
I'm using Windows 11 to create a make file. and I found alternate commands for the above like
dir /a:b, instead of ls
erase instead of rm.
What is the difference btw these shells and where to find them?
Makefile:
print: $(wildcard *.c)
ls -la $?
Error I got:
ls
'ls' is not recognized as an internal or external command,
operable program or batch file
I want to know a little more info about them.
Also what makes are available something which gives some overview. Names are sufficient.

GNU make directory listing using $(shell dir ) command

I am trying to list all the subdirectories inside a certain folder. My operating system is Windows 10, I am using a GNU Make file and the version is : GNU Make 4.0 Built for x86_64-pc-cygwin, and this is the command I used :
ROOT_DIRECTORY := X:\
DIRS := $(shell dir $(ROOT_DIRECTORY) /s /b /ad)
$(info subdirs : $(DIRS))
when I execute the command dir /s /b /ad using the CMD it works just fine however when I try to execute it using the $(shell ) function the output is :
./tools/bin/sh: dir: command not found
subdirs :
make does not use cmd.exe to run shell commands, at least not by default. It uses a POSIX shell, which you can see is the component that issues your diagnostic message (.tools/bin/sh). The shell command for listing directory contents is ls, but it will not, by itself, give you what you want, because it has no equivalent to dir /ad.
That you are attempting to do this at all is suspicious. If make is an appropriate tool for your job at all then you should probably be approaching the problem in a different way. If you must use make, however, then one option would be to ensure that Cygwin's find program is installed, and use that:
DIRS := $(shell find * -type d)
(Be sure not to get Windows's find command, which does a different job. You may need to provide a path to the correct find.)
Another option might be to run cmd.exe explicitly.

Makefile error make (e=2): The system cannot find the file specified

I am using a makefile in windows to push some files on a Unix server (here a text file "blob.txt" in the same folder of my makefile).
My makefile script is:
setup:
pscp blob.txt username#hostname:/folder/
I start a command prompt, go in the folder where blob.txt and the makefile are present and type:
make setup
Which results in:
pscp blob.txt username#hostname:/folder/
process_begin: CreateProcess(NULL, pscp blob.txt username#hostname:/folder/, ...) failed.
make (e=2): The system cannot find the file specified.
make: *** [setup] Error 2
In a #fail ... whereas if I enter directly the command in the command prompt:
pscp blob.txt username#hostname:/folder/
It works ... I really wonder why.
The error
process_begin: CreateProcess(NULL, pscp blob.txt username#hostname:/folder/, ...) failed.
make (e=2): The system cannot find the file specified.
is almost certainly complaining that Windows cannot find pscp.
This is almost certainly because the value of %PATH% (or whatever) is different when make spawns a shell/console then when you have it open manually.
Compare the values to confirm that. Then either use the full path to pscp in the makefile recipe or ensure that the value of PATH is set correctly for make's usage.
I didn't want to remove GIT's bin folder from the PATH variable (I am using a Windows machine), as I use it quite often. So I looked for a workaround, and here it is:
Add the <git-installation-directory>/usr/bin directory to your PATH variable too. This basically adds the rest of the linux-like commands that come with the "GIT bash" to your environment. After applying this, my makefiles ran normally again. :)
If you are curious about what shell is being invoked by make, just add $(info $(SHELL)) at the beginning of your makefile. The path/name of the shell being invoked is printed to the console as soon as you run make.
I know this is an old question that has been answered, but thought I'd and my experiences for anyone still running into this. I was getting the same cryptic error Colonel Beauvel (though with the windows MOVE command, not pscp):
process_begin: CreateProcess(NULL, move /y foo\bar.c .\baz.c, ...) failed.
make (e=2): The system cannot find the file specified.
Our CI was running the same Makefile and working perfectly. Turns out CI was using mingw32-make and I was using GNU make. Uninstalling GNU make (which got installed as part of an unrelated bulk package) and aliasing mingw32-make to 'make' works perfectly.
#user3869623's solution works for me. I'd like to share some details of mine to complete the picture.
My makefile contains below target:
clean:
#echo '$(OS)'
ifeq ($(OS),Windows_NT)
del /s *.o *.d *.elf *.map *.log
endif
When I run make clean, I see this error:
Since it says something went wrong with echo, so I change my makefile target to below:
clean:
ifeq ($(OS),Windows_NT)
del /s *.o *.d *.elf *.map *.log
endif
This time, make clean gives me this error:
I am surprised to see bash here since I am working in Windows command line.
Then I checked my %PATH%, I see this entry:
C:\DevTools\Git\bin
There's a bash.exe and sh.exe in that path. So I removed this entry, and it works fine now.
BUT I STILL DON'T KNOW WHY BASH GET INTO THIS???
ADD 1
As to why the C:\DevTools\Git\bin shows up in my %PATH%, because I am using Sublime and it always asks me for the Git binaries:
In my case, I had git\bin in my %PATH% which contains bash.exe and sh.exe.
Removing %GIT_HOME%\bin from the PATH worked for me.
To build on user3869623's response.
In my case i had git\bin in my %PATH% which contains bash.exe and sh.exe.. Removing %GIT_HOME%\bin from the PATH worked for me
While this recommendation may allow make to run, it will likely cause issues for git, especially if the makefile is installing software from a git repository.
A better solution is to simply change %GIT_HOME%\bin to %GIT_HOME%\cmd
For those who tried removing the git bin folder from PATH and it didn't work for them, search your PATH variables for any paths containing bash.exe.
In my case I found a variable linking to cygwin bin folder C:\cygwin64\bin, removed it and it worked.
I had the same issue, and this thread really helped me solve it. In my case, it was a conflict between make and the sh.exe that was visible through my path, due to both git and mingw64. To fix my issue, without breaking Git, I added these lines to the top of my batch file that calls make:
set path=%path:git\bin=;%
set path=%path:mingw64\bin=;%
set path=%path:usr\bin=;%
This hides the extra sh.exe instances from make for that instance only.
I ran into this problem recently and this question was one of the top hits for my searches.
None of the other answers here helped me. The fix, for me, was to put the binary name in quotes:
setup:
"pscp" blob.txt username#hostname:/folder/
-"pscp" blob.txt username#hostname:/folder/ # Failure is OK, `-` in front
I'm on windows.
By explicitly setting my compiler to gcc (instead of cl?) it solved my problem.
CC = gcc
I hope some people more knowledgeable than me could explain why changing the compiler would impact the makefile parsing.

How do I get my Windows7 symlink to execute from command line?

I have a couple of batch files I want to use regularly, so I decided I would drop them as symlinks into a binaries folder in my path. The idea being that I would use them like I would any other command, without having to change directories. E.g.
> odbimport -u User -f filename
where odbimport is my symlink to the batch file odbimport.bat.
The process I used to make the symlinks is as follows:
C:\Users\user>mklink C:\utils\odbimport C:\util-files\odbimport.bat
symbolic link created for C:\utils\odbimport <<===>> C:\util-files\odbimport.bat
C:\Users\user>path
Path=C:\....;C:\utils\
C:\Users\user>where odbimport
C:\utils\odbimport
From what I've seen, it looks like I've made the symlink, and the path knows where to find it.
However, after I've made my symlink and attempt to execute, I get:
C:\Users\user> odbimport -u me -f somefile
'odbimport' is not recognized as an internal or external command,
operable program or batch file. "
I've been looking for an answer to this with no success. Everything I find seems to deal more with how to create working symlinks than addressing my issue. The closest thing I found was this. This is essentially my question, except kinda backwards because I don't really want to run the symlinks from Windows Explorer. I have also tried adding .LNK to my PATHEXT variable as in this question.
Add .bat extension to the symlink you create because on Windows .bat extension is necessary to tell the system it's actually an executable batch file. You will still be able to run the file by typing its name only.
mklink C:\utils\odbimport.bat C:\util-files\odbimport.bat
NTSF hardlinks can be used when source and target are on the same volume, the advantage is that such clones may be executed from Windows Explorer unlike symlinks:
mklink /h C:\utils\odbimport.bat C:\util-files\odbimport.bat
fsutil hardlink create C:\utils\odbimport.bat C:\util-files\odbimport.bat

"Permission Denied" using cygwin in Windows

Background:
I am trying to write a [.bat] file so I can double click it and a bash script will get invoked. The bash script will start up a few windows GUI apps to monitor GPU/CPU temperatures. I just did a fresh install of cygwin v1.7.7-1 (downloaded today) and windows 7.
Code:
monitor-temps.bat:
C:\cygwin\bin\bash.exe ~/bin/monitor-temps.bash
pause
Code:
monitor-temps.bash:
#!/usr/bin/bash
"/cygdrive/c/Users/michael/Desktop/apps_and_drivers/GPU-Z.0.4.8.exe" &
Output:
After I double click the [.bat] file, I get a:
C:\Users\michael\Desktop>C:\cygwin\bin\bash.exe ~/bin/monitor-temps.bash
C:\Users\michael\Desktop>pause
Press any key to continue . . . /home/michael/bin/monitor-temps.bash: line 2: /cygdrive/c/Users/michael/Desktop/apps_and_drivers/GPU-Z.0.4.8.exe: Permission denied
I still get the same permissions error when I cd to the directory and manually execute the application.
Permissions:
From my experience with permission problems in Linux, everything looks good because I am the user I think I am, and the file has the expected permissions:
$ whoami
michael
$ ls -l GPU*
-rwx------+ 1 michael None 890720 2010-12-01 19:23 GPU-Z.0.4.8.exe
Question:
Does anyone know how to fix this? Am I missing something?
As a Developer, I use a shortcut to provide a command-line interface (CLI) that behaves similar to Linux, in my Windows environment, and ran into the same issue trying to untar a file.
The fix was to set the shortcut to "Run as Administrator".
If you are using this method to access your Cygwin environment, go to the properties of the shortcut, select the Advanced button to get the options to "Run as Administrator", check the box, click Ok. And off you go!!
You can also set your batch file to do this, by making a shortcut to it and doing the above.
Hope that helps!
I think you have to change the directory or file permission. If you want to change permission of a file or directory then you have to add full path with the code.
As if you want to change permission on cocos2d-x folder on C:\yourDirectory (I'm on Windows; on Mac it would be / instead of \) write the code on cygwin console:
chmod -R 775 /cygwindrive/c/yourDirectory
Note: If it's in C: drive you have to run it as administrator.
Check the mount table with cat /proc/mounts or mount and make sure that every mount point out of /, /usr/bin, /usr/lib has a noacl flag. If it's missing, correct /etc/fstab and reboot. (Rebooting synced up the noacl flag of the root mount point for me, and I do not know if the same can be achieved without rebooting).
Check for a NULL SID record and other strange records in the output of icacls against the file. They appear added on writing by the POSIX ACL translation layer in Cygwin (using "noacl" in /etc/fstab allows disabling that, but the damage will have already been done).
Resetting the Windows ACL just on the file may not be enough if the containing parents had the NULL SID record. One has to run
icacls c:\cygwin64 /reset /t /l /c
from Command Prompt to remove the extraneous records from the Windows ACL in each file and directory.
Update
Other commands reset the ownership, remove default ACLs and show ACLs of a known binary before and after the changes:
set croot=c:\cygwin64
icacls %croot%\bin\ls.exe
%croot%\bin\getfacl /bin/ls
takeown /F %croot% /R /D Y > nul
icacls %croot% /reset /T /C /L /Q
icacls %croot%\bin\ls.exe
%croot%\bin\getfacl /bin/setfacl
%croot%\bin\getfacl /bin/find
%croot%\bin\setfacl -bk /bin/find
%croot%\bin\find -P / -xdev -exec /bin/setfacl -bk "{}" +
icacls %croot%\bin\ls.exe
%croot%\bin\getfacl /bin/ls
The easiest way to fix this is:
Download Sysinternals ProcMon, start it and let it run for a while.
Exclude all processes that generate noise.
When the log becomes less busy, start your file access attempt.
Search the ProcMon log for "Access Denied" messages.
Investigate. Should be easy to fix.
-rwx------+ might be the problem. Some hidden acl may forbid x for you.
Reset your acl with setfacl then.
$ cat >/tmp/faclx <<EOF
user::rwx
group::r--
mask:rwx
other:r--
EOF
$ setfacl -f /tmp/faclx /cygdrive/c/Users/michael/Desktop/apps_and_drivers/GPU-Z.0.4.8.exe
Or you need elevated permissions:
$ cygstart --action=runas /cygdrive/c/Users/michael/Desktop/apps_and_drivers/GPU-Z.0.4.8.exe
I had this problem, and fixed it by cd to the directory which contains the box I just made (packaged, or, repackaged). Then vagrant box add <file.box> --name <name>. I think the PATHs fvck things up, and cause it to fail. Then double check with vagrant box list. Then I mkdir coolbox; cd coolbox. Then I just vagrant init <name> and it all comes up like magic.
git bash, run command like this: cmd "/C postgresql-10.5-2-windows-x64.exe --unattendedmodeui minimal --mode unattended --servicename 'postgreSQL'"
I had a similar issue around tee redirection:
"%CYGWIN_ROOT%\bin\bash.exe" -c "{ cd ""%PWD:\=/%""; CHERE_INVOKING=. ""%CYGWIN_ROOT:\=/%/bin/bash.exe"" -l -i; } 2>&1 | ""%CYGWIN_ROOT:\=/%/bin/tee.exe"" -a ""%PROJECT_LOG_FILE:\=/%"""
This kind of code is required if you want to run a bash shell with login in a specific directory (cd before call to login shell).
But in mine case it won't work, because of the error: tee: 'standard output': Permission denied
Update:
Found a fix here: https://sourceware.org/pipermail/cygwin/2020-December/247185.html
In Win7,
1) Start command prompt.
2) Run chcp 65001
3) Change the font of command prompt to raster font.
4) Run c:\cygwin\bin\printf "\xce\b1\n"
This causes the error:
/usr/bin/printf: write error
What weird is that if the font is other than raster font,
this error does not occur.
A raster font triggers the console write error (a permission denied in case of piping) under 65001 code page specifically in the Windows 7.
You can follow the instruction found in this link: https://cygwin.readthedocs.io/en/latest/install/#install-and-maintain-cygwin
and when it comes to give permissions to the folder on windows use the command:
chmod ugo+x /usr/local/bin/cyg-get
From the Cygwin Terminal , as in this example:
Open Cygwin64 Terminal, and run:
chmod -R 775 /usr/local/bin/
just change the mode of the scripts using chmod command to make it executable.
see man chmod for more details.

Resources