make sees different PATH than account's .bashrc-configured PATH - unix

I want to call ShellCheck, a Haskell program for linting shell scripts, from a Makefile.
When I install ShellCheck via cabal install, it is installed as ~/.cabal/bin/shellcheck. So, I have configured Bash accordingly:
$ cat ~/.bashrc
export PATH="$PATH:~/.cabal/bin"
$ source ~/.bashrc
$ shellcheck -V
ShellCheck - shell script analysis tool
version: 0.3.4
license: GNU Affero General Public License, version 3
website: http://www.shellcheck.net
This enables me to run shellcheck from any directory in Bash. However, when I try to call it from a Makefile, make cannot find shellcheck.
$ cat Makefile
shlint:
-shlint lib/
shellcheck:
-shellcheck lib/**
lint: shlint shellcheck
$ make shellcheck
shellcheck lib/**
/bin/sh: 1: shellcheck: not found
make: [shellcheck] Error 127 (ignored)
I think that make is not receiving the same PATH as my normal Bash shell. How can I fix this?

Try using $HOME, not ~:
export PATH="$PATH:$HOME/.cabal/bin"
The ~-means-home-directory feature is not supported in pathnames everywhere in all shells. When make runs a recipe it doesn't use the user's shell (that would be a disaster!) it uses /bin/sh always.
On some systems (particularly Debian/Ubuntu-based GNU/Linux distributions) the default /bin/sh is not bash, but rather dash. Dash doesn't support ~ being expanded in the PATH variable.
In general, you should reserve ~ for use on the command line as a shorthand. But in scripting, etc. you should always prefer to write out $HOME.
ETA:
Also, the double-star syntax lib/** is a non-standard feature of shells like bash and zsh and will not do anything special in make recipes. It is identical to writing lib/*.
You can force make to use a different shell than /bin/sh by adding:
SHELL := /bin/bash
to your makefile, for example, but this makes it less portable (if that's an issue).

Related

WSL PATH environment variable is incorrect / zsh config not loaded [duplicate]

I am using Ubuntu via WSL 2.0 on Windows 10 and would like to run Texlive from the Windows command line. To do so I prepended the Texlive folder to the path in /etc/environment (I also tried a number of other locations eg. $HOME/.bashrc):
C:\Users\scott\Documents>wsl echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/Windows/system32:...
C:\Users\scott\Documents>wsl
scott#SCOTT-PC:/mnt/c/Users/scott/Documents$ echo $PATH
/usr/local/texlive/2020/bin/x86_64-linux:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/Windows/system32:...
Why is there a difference between these two paths? Is it possible to change the first PATH variable?
To be honest, when I first looked at this question, I thought it would be an easy answer. Oh how wrong I was. There are a lot of nuances to how this works.
Let's start with the fairly "easy" part, though. The main difference between the first method and the second:
wsl by itself launches into a login (and interactive) shell
the shell launched with wsl echo $PATH is neither a login shell nor an interactive shell
So the first will source both login scripts (e.g. ~/.profile) and interactive startup scripts (e.g. ~/.bashrc). The second form does not get to source either of these.
You can see this a different way (and get to the solution) with the following commands:
wsl -e bash -c 'echo $PATH'
wsl -e bash -li -c 'echo $PATH'
The -li forces bash to run as a login and interactive shell, thus sourcing all of the applicable startup scripts. And, as #bovquier points out in the comments, a single quote is needed here to prevent PowerShell from interpolating the $ before it gets to Bash. That, or escape it.
You should be able to run TeX Live the same way, just replacing the "echo $PATH" with the startup command you need for TeX Live.
A second option would be to create a script that both adds the path and runs the command, and just launch that script through wsl /path/to/script.sh
That said, I honestly don't think that your current login/interactive PATH is coming from /etc/environment. In my testing, at least, /etc/environment has no use in WSL, and that's to be expected. /etc/environment is only sourced by PAM modules, and with no login check performed by WSL, there's no reason to invoke PAM in either the wsl nor the wsl echo $PATH commands.
I'd expect that you still have the PATH setting in ~/.bashrc or somewhere similar), and that's where the shell is picking it up from at the moment.
While this isn't necessarily critical to understanding the answer, you might also wonder, if /etc/environment isn't used for setting the default (non-login, non-interactive) path in WSL, what is? The answer seems to be that it is hard-coded into the init that starts up WSL. That init is also what appends the Windows path (assuming you don't have that feature disabled in /etc/wsl.conf).

does gmake automatically define $(INSTALL)?

gmake doesn't seem to have a value for $(INSTALL). is this supposed to be defined by the user?
$(CC) works fine. most sample Makefiles i went over didn't have an explicit definition of $(INSTALL)...
if it has to be defined by user, what are best practices (other than aliasing _PROGRAM and _DATA)? why prefer install over cp?
Makefile
helloworld:
echo 'hello, world' >helloworld
install:
$(INSTALL) ${HOME}/ helloworld
log
$ make helloworld
$ make install
/home/<username>/ helloworld
make: /home/kevins/: Permission denied
make: *** [Makefile:5: install] Error 127
version info
GNU Make 4.3
Built for x86_64-pc-linux-gnu
There is no default value defined for INSTALL. You can see all the default rules and variables by running:
make -p -f/dev/null
Whether install or cp is a better fit depends entirely on your use-case. install does a lot more than cp. But, you can run other commands in addition to cp to take care of those things, and install is not available on every system. So, it's what's best for you.

How to install SQLite with Archives extension?

I want to explore the use of SQLite Archive files. I downloaded the amalgamation source code from the downloads page (https://sqlite.org/download.html) and compiled it (gcc shell.c sqlite3.c -lpthread -ldl).
I managed to compile the executable but the Archives option is not there.
Running ./sqlite3 -A shows the error:
./sqlite3: Error: unknown option: -A
Trying to run the .ar command in commandline shows:
Error: unknown command or invalid arguments: "ar". Enter ".help" for help
Running .help also does not show the option for .archive.
How do I install SQLite with the Archives extension?
Compile from source…
$ curl -LO https://www.sqlite.org/src/tarball/sqlite.tar.gz
$ tar xzf sqlite.tar.gz
$ mkdir build
$ cd build
$ ../sqlite/configure
$ make
You will find the executable command line program (sqlite3) in the build directory.
Add compile options by changing the ../sqlite/configure line to something like…
$ ../sqlite/configure CFLAGS='-DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FOREIGN_KEYS=1'
View configure help for more flags like linking additional libraries…
$ ../sqlite/configure --help
Optionally install the headers (sqlite3.h) and libraries (libsqlite3.a, libsqlite3.so, libsqlite3.dylib, etc) by running…
$ make install
Ensure archive support exists…
$ ./sqlite3 -help
...
OPTIONS include:
-A ARGS... run ".archive ARGS" and exit
...
You have to compile it with SQLITE_HAVE_ZLIB defined (And link with -lz).
It's easiest using the autoconf or src source distribution, since the configure script tests for a bunch of things including zlib, and compiles the library and shell with a bunch of useful options that you're not using in your manual compilation of the shell.

Do Curly Brace Wildcards work in GNU Make 4 (or even POSIX Make)?

I found a difference of behaviour between GNU Make 4.1 and 3.81 and wonder whether my code is not POSIX compliant which 4 is enforcing more strictly, or whether something else is going on.
I distilled the failure case to this Makefile
.POSIX:
all: test-b
test-a:
cat a.txt b.txt c.txt >results.txt
test-b:
cat {a,b,c}.txt >results.txt
Assuming those files have been created with cat {a,b,c}.txt, target test-a always works, yet test-b works on Make 3.81 but fails on 4.1.
The output for 3.81:
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
$ make
cat {a,b,c}.txt >results.txt
$ echo $?
0
The output for 4.1:
$ make --version
GNU Make 4.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ make
cat {a,b,c}.txt >results.txt
cat: {a,b,c}.txt: No such file or directory
Makefile:9: recipe for target 'test-b' failed
make: *** [test-b] Error 1
$ echo $?
2
It's possible the cat command is actually failing in 3.81 and it just isn't pointing it out, as later versions of GNU Make mention passing the -e flag to the shell when invoking target commands to make it more POSIX compliant, but I can't see how that command could be failing.
I assume the wildcards are handled solely by the shell, so I can't see how invoking the shell via a make target command should be any different.
Which is these behaviours are correct? If wildcards like that don't work in Makefiles, which other wildcards can I assume to work?
test-b still fails in 4.1 even if .POSIX: is removed from the file.
Recipes are sent to the shell. They are not interpreted by make. So your question is really, are curly-brace expansions supported by the shell?
That depends on which shell make uses. They are not supported by POSIX standard sh. They are supported by bash (and many other shells).
Make always invokes /bin/sh, regardless of what shell you personally use, unless you specifically set the make SHELL variable to something else. On some systems, /bin/sh is a symlink to /bin/bash so they are the same thing (bash runs in a "POSIX emulation" mode when invoked as /bin/sh but most bash features are still available). Other systems use different shells, such as dash, as /bin/sh which do not have extra bash features.
So, you can either (a) not have a portable makefile and assume /bin/sh is the same as /bin/bash, (b) set SHELL := /bin/bash in your makefile to force it to use bash always (but fail on systems that don't have bash installed), or (c) write your makefile recipes to use only POSIX sh features so it works regardless of which shell is used for /bin/sh.

Cannot source autojump script with zsh on archlinux

autojump on ArchLinux for some reason is not working in zsh.
Although If I switch to bash it works fine.
$ sudo pacman -S autojump
autojump: does not work on zsh
$ source /usr/etc/profile.d/autojump.sh
$ j
zsh: command not found: j
$ source /usr/etc/profile.d/autojump.bash
$ j
zsh: command not found: j
autojump: works on bash
$ bash
(bash) $ source /usr/etc/profile.d/autojump.bash
(bash) $ j
autojump: ...
My environment:
$ echo $SHELL
/bin/zsh
$ zsh --version
zsh 5.0.2 (x86_64-unknown-linux-gnu)
I use autojump on OS X with zsh, so it also doesn't look like a zsh specific issue to me.
Aren’t you supposed to use autojump.zsh instead?
Though from what I see the only thing autojump.sh is doing is sourcing autojump.zsh or autojump.bash from some place so it should work with .sh. Work if maintainers of arch have patched autojump.sh: it does not expect to find autojump in /usr/etc.
If it does not work with autojump.zsh, post the output of doing (set -x ; source /usr/etc/profile.d/autojump.zsh).
There is no /usr/etc/profile.d/autojump.zsh pushed when autojump is installed via pacman. I don't know why this is the case.
However, I performed, manual user installation and added autojump plugin in my zsh configuration that takes care of sourcing the file.
I have tried above the ways,but I solved this problem by add the
source ~/.autojump/etc/profile.d/autojump.zsh
because the I have not find the /usr/etc/profile.d/autojump.zsh
I had repeated trouble with Autojump in ZSH regardless of sourcing the .zsh version. I never found a decent fix and eventually chose to stick with ZSH and stop using Autojump.
My personal solution was to switch from Autojump to FASD. It has the same functionality of Autojump via the 'z' alias. It also allows for specifically jumping to either a file or directory.
FASD has been a reliable part of my ZSH setup and surpasses the functionality of Autojump. I wrote up my experiences with FASD at greater length on my blog at Civet.ws

Resources