How to use `shell find` on Make for windows? - windows

I've got a Makefile that contains a statements like this:
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" -not -path modules/options/bindata.go -not -path modules/public/bindata.go -not -path modules/templates/bindata.go)
I'm trying to use it on windows and I know using this particular file wouldn't be a problem if I just used cygwin, msys2, vagrant, wsl or any other similar terminal. That said, I'd like to know how to use that Makefile with plain cmd.exe terminal (got my own reasons to do so, so please don't suggest using those ;)).
Right now my env var PATH has appended the Git for windows usr\bin path
that contains a nice toolset of ~437 unix commands and find
is amongst them.
So for instance, if I run find on my terminal... D:\software\PortableGit\usr\bin\find.exe will be used instead C:\Windows\System32\find.exe as expected, so far so good up to this point.
Problem is when I run the makefile for some reason I haven't understood yet C:\Windows\System32\find.exe is trying to be used instead on the statement $(shell find ...) so I'll get the error FIND: Parameter format not correct when doing make.
So basically my question would be, how can I instruct make to use the proper unix find that has higher priority on PATH? But if this wouldn't be possible to achieve easily... would it be possible to make that statement to become more cross-platform maybe using wildcards?
I've already checked the make docs:
https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html
https://www.gnu.org/software/make/manual/make.html#Choosing-the-Shell
but I didn't find anything that could help me out.
Also, the version of make I'm using can be downloaded from http://gnuwin32.sourceforge.net/packages/make.htm, at the moment of asking this question version I'm using is GNU Make 3.81

Related

MinGW Makefile is looking in c:\windows\system32 instead of /usr/bin

The following Makefile:
.PHONY: all
all: $(shell find example/data)
#echo $(shell which find)
When run with gnuwin32 Make in a MinGW bash shell, outputs the following:
$ make
FIND: Parameter format not correct
/usr/bin/find
This output is strange because the "FIND: Parameter format not correct" message comes from Windows' find.exe in C:\Windows\system32.
This means that:
$(shell find example/data) is using C:\Windows\system32\find.exe, even though
$(shell which find) identifies /usr/bin/find (the GNU find)
My question is: What is going on here? Why would $(shell find ...) be looking in C:\Windows\system32 instead of in /usr/bin? Why isn't the path consistent and what can I do to make $(shell find ...) behave the same way that find ... would behave from the MinGW bash shell?
I do not want to hard code the path to find; and I could probably get what I want by using which to find the path but I'm more concerned with the path being incorrect than I am about specifically getting find to work here.
When you say "MinGW bash shell" I assume you mean an MSYS/MSYS2 bash shell.
MSYS and MSYS2 provide a Unix/Linux-like shell, and some commands may exist in Unix/Linux with the same name as different commands in Windows.
The find is such a command.
There are several solutions to your problem:
Use the where command instead (your Makefile will be compatible with other platforms).
Specify the full path to the command you want to use. You could detect it with FINDCMD=$(shell which find) and then run it with $(shell $(FINDCMD) example/data)

Delete files from 00012 to 00441 using Terminal

This is my Bash version:
3.2.57(1)-release
I found that this MIGHT possible using terminal rm code, but it doesn't work for me
Here is a picture of the first files:
Picture of a bunch of Files
Typing rm _{00012..00441} I get this error:
Terminal Error
Seems like the code us unable to use the leading zeros since is trying to find the files like 12,13,14,15, instead of 00012,00013,00014,00015
To make things more difficult, the last file in the range has a different amount of leading zeros, so using rm _000{ wont work
In trying to use AppleScript to run this as
do shell script ("rm _{" & STARTrange & ".." & ENDrange & "}.psd")
Try this command.
find ./ -name "_0*.psd" -type f -delete;
Thanks to Cyrus I made this work. The answer in OSX is to install the latest version of Bash using homebrew.
Using this guide I was able to change the default Bash from terminal to the one Homebre installs: https://apple.stackexchange.com/questions/193411/update-bash-to-version-4-0-on-osx
Thanks
For versions of bash older than v4.0 either of these should work:
rm _000{12..99} _00{100..441}
rm $(printf '_%.5i ' {12..441})

How do I generate recursive ctags without Exuberant Ctags?

I recently took a new job as a software developer for a company with a large and complicated primary software package, with many different hooks depending on how your new code wants to integrate with the old code. This is all well and good, except as a new employee I'm not yet familiar with the overall structure of the source code and often cannot find the project code that I'm looking for.
The whole svn repository is stored on my local computer under ~/Documents/trunk. I want to be able to generate a ctags file so that I can quickly jump to symbol definitions from within vim so I can learn what different pieces of code do. Unfortunately, I do not have admin access to this computer so I cannot install Exuberant Ctags to make my life easy; I have to remain with the version of ctags that ships on OS X.
How can I generate tags such that vim can find symbols even if they are defined in another subfolder of trunk? I wrote a simple bash script to hopefully generate the tags, but that does not seem to work. The script is simply:
#!/bin/bash
for i in $(find . -name '*.cpp' -or -name '*.h')
do
ctags -w -d $i
done
Like I said though, this doesn't work, so any ideas for how to solve this are much-appreciated.

GNU Make Under Windows: Check for cygwin in PATH

I have been putting together a makefile in a Windows environment for my team to use. I decided to use MinGW's version of make for Windows. I put that executable with its dependencies into a repository location that should be in everyone's PATH variable. The executable was renamed "make.exe" for simplicity.
Then I realized that I have to account for the case when someone has cygwin's bin folder in their path. Commands like echo, rmdir, and mkdir will call echo.exe, rmdir.exe, and mkdir.exe from cygwin's bin folder. This means that I need to appropriately catch this scenario and use different flags for each command.
I see three cases here:
Cygwin's bin path comes before the path where make.exe is located in the repository. When a team member executes make.exe, they will be executing cygwin's make. Unix-style commands must be used.
Cygwin's bin path comes after the path where make.exe is located in the repository. The correct make.exe will be executed, but I still have to use Unix-style commands.
Cygwin is not installed or not in the PATH. I can use all Windows commands in this case.
I am fine with treating cases 1 and 2 the same. Since MinGW's make and cygwin's make are both based on GNU Make, then I don't see this being much of an issue other than incompatibility issues between versions of GNU Make. Let's just assume that isn't a problem for now.
I have come up with the following check in my makefile.
ifneq (,$(findstring cygdrive,$(PATH))$(findstring cygwin,$(PATH))$(findstring Cygwin,$(PATH)))
#Use Unix style command variables
else
#Use Windows style command variables
endif
Finding "cygdrive" in the path variable means that we are most likely in case 1. Finding "cygwin" or "Cygwin" in the path variable most likely means that we are in case 2. Not finding either string in the path most likely means that we are in case 3.
I am not completely fond of this solution because the cygwin's folder can be renamed or the string "cygwin" or "cygdrive" can be put in the PATH variable without having cygwin installed. One team member is still having issues as he has cygwin's bin path in the PATH variable, but the above does not catch that. I am assuming that he renamed the folder to something else, but I haven't been able to check on that.
So is there a better way to figure out what syntax that I should be using?
Here is another solution that I thought up.
ifeq (a,$(shell echo "a"))
#Use Unix style command variables
else
#Use Windows style command variables
endif
This is based on the fact that 'echo "a"' in Unix will print a (without quotes) but windows will print "a" (with the quotes). If I am using the Unix style echo then I can assume that I am using all Unix commands.
I don't find this solution very elegant though, so I am not marking it as the solution for this question. I think this is better than what I originally had though.
Cygwin make v. MinGW make: Does mingw make support the jobserver, as in can you do make -j5? If not, ${.FEATURES} has jobserver for cygwin make. Maybe load is a good test too.
Cygwin before non-cygwin on path: cygpath.exe is unique to cygwin. You could just look for this in ${PATH}. Unfortunately, Windows users like using spaces in folder names, and there's no way of dealing with this in pure make. $(shell which make) will return /usr/bin/make for cygwin, though a shell invocation on every make run is very smelly.
You don't install a compiler from a repository, is not make a similar case? Just get your users to install cygwin and be done with it.

How can I make the "find" Command on OS X default to the current directory?

I am a heavy command line user and use the find command extensively in my build system scripts. However on Mac OS X when I am not concentrating I often get output like this:
$ find -name \*.plist
find: illegal option -- n
find: illegal option -- a
find: illegal option -- m
find: illegal option -- e
find: *.plist: No such file or directory
Basically, I forgot to add the little dot:
$ find . -name \*.plist
Because BSD find requires the path and GNU find doesn't (it assumes the current directory if you don't specify one). I use Linux, Mac OS X and Cygwin often all at the same time, so it's of great benefit to me to have all my tools behave the same. I tried writing a bash find function that added "./" if I forgot, but I failed. Thanks for your help. :)
Install GNU find instead.
$ brew install findutils
$ alias find=gfind
Yay, it works!
If you can't discipline yourself to use find 'correctly', then why not install GNU find (from findutils) in a directory on your PATH ahead of the system find command.
I used to have my own private variant of cp that would copy files to the current directory if the last item in the list was not a directory. I kept that in my personal bin directory for many years - but eventually removed it because I no longer used the functionality. (My 'cp.sh' was written in 1987 and edited twice, in 1990 and 1997, as part of changes to version control system notations. I think I removed it around 1998. The primary problem with the script is that cp file1 file2 is ambiguous between copying a file over another and copying two files to the current directory.)
Consider writing your own wrapper to find:
#!/bin/sh
[ ! -d "$1" ] && set -- . "$#"
exec /usr/bin/find "$#"
The second line says "if argument 1 is not a directory, then adjust the command line arguments to include dot ahead of the rest of the command. That will be confusing if you ever type:
~/bin/find /non-existent/directory -name '*.plist' -print
because the non-existent directory isn't a directory and the script will add dot to the command line -- the sort of reason that I stopped using my private cp command.
If you must call it 'find', then you want:
alias find=/usr/bin/find\ .
in your .profile or .bash_profile or …. Substitute the real path (if not /usr/bin/find) on your Mac OSX. Enter the full path to avoid cycles (bash normally would interpret alias find=find without issues, but better be sure).
But you better not name the alias find (findl, myfind etc), because it will become a habit and trouble for you if you try it on another system.
find ./ -name "*.plist"
edit: hmm, i may have misunderstood the question! if you were crazy, how about emulating it via a shell script? i routinely keep random utility scripts in ~/.bin, and that's the first thing in my PATH. if you had a similar setup perhaps you could do something like: (untested!)
#!/bin/sh
# remapping find!
CMD=`echo $1 | cut -c 1`
if [ $CMD = '-' ]
then
# pwd search
/usr/bin/find ./ $*
else
# regular find
/usr/bin/find $*
fi
I would suggest that if you're writing scripts (which are more likely to be migrated from one system to another sometime in the future) that you should try to use the more specific form of the command, that is specifying the "." instead of relying on a default. For the same reason, I might even suggest writing sh scripts instead of relying on bash which might not be installed everywhere.
This is probably not what you want but how about: alias find="find ."
or choose a new name (findl for find local?)
You may want to run the commands found in this link: https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/
It is a bit outdated, for example I found I did not have to add many commands to my path at all.
This covers your problem by having your system use the Non-BSD find utility from the findutils package, while also installing other tools you may want as well.

Resources