GNU make directory listing using $(shell dir ) command - windows

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.

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.

Is it possible to change the directory of a windows console from an app?

My goal is to write an app that lets you quickly assign aliases to long directory paths and change to them. I wrote an app that manages them in a file in the user's appdata directory, but I can't find a way to change the directory of the shell I run the program in from my app. My goal is to have it work from git bash, cmd.exe, and powershell. I want something like this:
cd /c/vsts/some-long-project-name-reports
g -a reports
Now I have an alias 'reports' for that directory. What I want to do get to that directory next time I open a console is:
g reports
I'm using dotnet core, though looking through questions it seems like there isn't a way to do this at all. With Directory.SetCurrentDirectory(path); or Environment.CurrentDirectory = path; it changes the working directory of the g.exe process, but when it exits the shell goes back to it's working directory when I ran the command.
I've come up with a solution for git bash, I changed my g app to output the path instead and have this as go in my path:
OUTPUT="$(g $1)"
cd $OUTPUT
Then I just need to use . or source to run the script in the current shell:
. go reports
And batch file go.bat doesn't need the . or source to work:
for /F "tokens=*" %%i in ('g %1') do set OUTPUT=%%i
cd %OUTPUT%
I guess I'll have to live with typing the extra characters, but is there a similar way to do this with powershell?
Define a wrapper function in PowerShell (assuming that g.exe outputs the target path):
function g { Set-Location (g.exe $args) }
Generally, as eryksun points out in a comment, an executable - which by definition runs in a child process - cannot change its parent process' working directory.
Therefore, the only solution is to output the target directory's path and let the parent process change to it.

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

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).

Listing folders and sub-folders in DOS and Unix?

I have to list folders and sub-folders from a given directory in DOS and Unix. I know i cand make this with DIR command, as follows: dir directory /ad /s, but the assignment tells me that I have to make it with find. It works with dir, but i have no idea how to make it with find. And I have to make it in UNIX too, so if you have some hints or something, please let me know.
Thanks.
Windows native find command is for finding strings in files or stdin, not for listing file names. download findutils for windows, then you can use find the same as what you used in Unix
WindowS:
C:\test> gnu_find.exe c:\path
Unix:
find /path

Calling Windows commands (e.g. del) from a GNU makefile

It does not appear to be possible to call Windows system commands (e.g. del, move, etc) using GNU Make. I'm trying to create a makefile that doesn't rely on the user having extra tools (e.g. rm.exe from Cygwin) installed.
When the following rule is run, an error is reported del: command not found:
clean:
del *.o
This is presumably because there is no such execuatable as "del". I've also tried running it as an option to cmd but with this only seems to open a new prompt:
clean:
cmd /C del *.o
I'm using Windows XP (5.1.2600) with GNU Make 3.79.1 that is bundled as part of MSys.
It seems the /C switch needs to be escaped because a / is interpreted as a path in GNU Make. The following works as expected:
clean:
cmd //C del *.o
Because DOS-based systems have two different commands for removing files and directories, I find that having two different defines works the best:
ifeq ($(OS),Windows_NT)
RM = cmd //C del //Q //F
RRM = cmd //C rmdir //Q //S
else
RM = rm -f
RRM = rm -f -r
endif
clean:
$(RM) $(TARGET).elf $(TARGET).map
$(RRM) $(BUILD_DIR)
Happened to me too. At the top of your makefile add:
SHELL=cmd
Since you are compiling on windows, select 'cmd' as the default shell. This
is important because GNU make will search the path for a linux/unix like shell and if it finds one it will use it instead. This is the case when cygwin is installed. The side effect of this behavior is that commands like 'del' and 'echo' are not found. If we tell GNU make to use 'cmd' as its shell, then 'del' and such will be available.
del is a builtin command of cmd.exe (as well as previously command.com). Your command cmd /C del *.o should work, if it starts a new command prompt I suspect that cmd maybe might be a wrapper. Have you tried to call cmd with its full path (e.g. c:/WINDOWS/system32/cmd.exe)?
Tom Longridge's answer was close to the truth for me, but the escaping needed to be done using a backslash before the forward slash on the Windows Vista Business machine I was needing this for:
RM=cmd \/C del
Another solution is to create a del.bat file containing:
#echo off
del %*
then the makefile can simply contain
clean:
del *.o
this cleans up the makefile, but may clutter your build directory slightly.
I just completed this. I am not sure if things have changed in DOS/Windows but this was how it had to be formatted with current versions.
OBJ=o
BIN=bin
clean:
cmd /C del $(OBJ)\\*.o
cmd /C del $(BIN)\\*.exe

Resources