Colourful makefile info command - linux

Usually I am using echo -e "\e[1:32mMessage\e[0m" to print colourful messages out of the makefile. But now I want to print message inside of the ifndef block, so I am using $(info Message) style. Is it possible to make this kind of message colourful ?

Yes. You can use a tool like tput to output the literal escape sequences needed instead of using echo -e (which isn't a good idea anyway) to do the same thing.
For example:
$(info $(shell tput setaf 1)Message$(shell tput sgr0))
Though that requires two shells to be spawned and two external commands to be run as opposed to the echo (or similar) methods in a recipe context so that's comparatively more expensive.
You could (and should if you plan on using the colors in more than one place) save the output from tput in a variable and then just re-use that.
red:=$(shell tput setaf 1)
reset:=$(shell tput sgr0)
$(info $(red)Message$(reset))
$(info $(red)Message$(reset))

Related

How do i use other command in the same line with echo

I want to use a command to be printed on the same line as the string.
for example, i want to print something like:
hostname: cpu1
but when i use the command like this it doesnt work
echo 'hostname:' hostname
You need to use $() to evaluate:
echo 'hostname:' $(hostname)
Two answers are already given saying that you "need to" and "should" use command substitution by doing:
echo "hostname: $(hostname)"
but I will disagree with both. Although that works, it is aesthetically unappealing. That command instructs the shell to run hostname and read its output, and then pass that output as part of the argument to echo. But all that work is unnecessary. For this simple use case, it is "simpler" to do:
printf "hostname: "; hostname
(Using printf to suppress the newline, and avoiding echo -n because echo really should be treated as deprecated). This way, the output of hostname goes directly to the shell's stdout without any additional work being done by the shell. I put "simpler" in quotes because an argument could be made that humans find printf "hostname: %s\n" "$(hostname)" or echo "hostname: $(hostname)" to be simpler, and perhaps looking at much code that does things that way warps your mind and even makes it look simpler, but a few moments reflection should reveal that indeed it is not.
OTOH, there are valid reasons for collecting the output and writing the message with echo/printf. In particular, by doing it that way, the message will (most likely) be written with one system call and not be subject to interleaving with messages from other processes. If you printf first and then execute hostname, other processes' data may get written between the output of printf and the output of hostname. As always, YMMV.
This is what you should do:
echo "hostname: `hostname`"
Words enclosed in backticks are read by the command line as commands even when they are inside a string, like in this case.
Have a great day! :)

What's the equivalent to ${var:-defaultvalue} in fish?

Hello I am trying to translate my .bashrc to fish format almost done, mostly is clear on the documentation but this part is giving me a headache.. is so my gnupg works with my yubikey ssh etc etc..
The fish version is latest 3.0 under Arch GNU/Linux
original on BASH:
# Set SSH to use gpg-agent
unset SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
export SSH_AUTH_SOCK="/run/user/$UID/gnupg/S.gpg-agent.ssh"
fi
echo "UPDATESTARTUPTTY" | gpg-connect-agent > /dev/null 2&>1
Mine half converted into fish:
set -e SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]
set -x SSH_AUTH_SOCK="/run/user/$UID/gnupg/S.gpg-agent.ssh"
end
echo "UPDATESTARTUPTTY" | gpg-connect-agent > /dev/null 2>&1
so as you see above I have so far converted the stdin and stderror pine and the unset variable with set -e the error I am having is a bit more obscure to me:
~/.config/fish/config.fish (line 33): ${ is not a valid variable in fish.
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]
^
from sourcing file ~/.config/fish/config.fish
called during startup
Any help will be much appreciated,
BTW will be nice a migrate too :) are there any out there?
[edit] ok got this working thanks to the response below, now all my bash environment, profile, bashrc etc is translated to fish and using it solely as my shell 100%
You should not change your login shell until you have a much better understanding of fish syntax and behavior. For example, in fish the equivalent of $$ is %self or $fish_pid depending on which fish version you are using. You should always specify the version of the program you are having problems with.
Assuming you're using fish 2.x that would be written as
if not set -q gnupg_SSH_AUTH_SOCK_by
or test $gnupg_SSH_AUTH_SOCK_by -ne %self
set -gx SSH_AUTH_SOCK "/run/user/$UID/gnupg/S.gpg-agent.ssh"
end
Also, notice that there is no equal-sign between the var name and value in the set -x.
Since ${var:-value} expands to value if $var is empty, you can always replace it by writing your code out the long way:
begin
if test -n "$gnupg_SSH_AUTH_SOCK_by"
set result "$gnupg_SSH_AUTH_SOCK_by"
else
set result 0
end
if [ "$result" -ne %self ]
set -x SSH_AUTH_SOCK "/run/user/$UID/gnupg/S.gpg-agent.ssh"
end
set -e result
end
Note that I don't use (a) endorse, (b) condone the use of, or (c) fail to hold unwarranted prejudices against users of, fish. Thus, my advice is very much suspect, and it's likely that there are considerably better ways to do this.
I had a similar question, related to XDG_* variables.
var1="${XDG_CACHE_HOME:-$HOME/.cache}"/foo
var2="${XDG_CONFIG_HOME:-$HOME/.config}"/foo
var3="${XDG_DATA_HOME:-$HOME/.local/share}"/foo
some-command "$var1" "$var2" ...
What I found as the best alternative is to simply set univeral variables once for the defaults--
set -U XDG_CACHE_HOME ~/.cache
set -U XDG_CONFIG_HOME ~/.config
set -U XDG_DATA_HOME ~/.local/share
Then in fish config file(s) or scripts, simply use "$XDG_CONFIG_HOME"/.... The value of an exported environment variable will override the universal variable if set, otherwise the universal variable is there as a default/fallback. If the universal variable is used, it is not exported to child processes, while an exported environment variable is, which provides the full equivalent to bash|zsh parameter expansion.

tput doesn't set color in the terminal

I wish to colorize my terminal while using interactive shell, namely the command prompt. I managed to do this using escape sequences:
PS1="\e[93m prompt> \e[0m"
I want to use tput instead of escape sequences. Like that:
PS1="$(tput setaf 1) prompt> "
However, this doesn't yeld any color.
I tried other tput subcommands in different ways. None of them gave any effect except of tput cols and tput lines which gave appropriate output.
How should I use tput properly in this case?

Bash - File local variables

I just wrote a small file to set my PS1 variable. This file is sourced from my .bashrc. Now I have a couple of questions regarding this approach.
But first the code:
setprompt:
# Normal variables
BOLD="$(tput bold)"
RESET="$(tput sgr0)"
RED="$(tput setaf 1)"
GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
BLUE="$(tput setaf 4)"
PINK="$(tput setaf 5)"
CYAN="$(tput setaf 6)"
GRAY="$(tput setaf 7)"
# Make non-printable variables
PROMPT_BOLD="\[$BOLD\]"
PROMPT_RESET="\[$RESET\]"
PROMPT_RED="\[$RED\]"
PROMPT_GREEN="\[$GREEN\]"
PROMPT_YELLOW="\[$YELLOW\]"
PROMPT_BLUE="\[$BLUE\]"
PROMPT_PINK="\[$PINK\]"
PROMPT_CYAN="\[$CYAN\]"
PROMPT_GRAY="\[$GRAY\]"
# Other variables
USERNAME="\u"
FULL_HOSTNAME="\H"
SHORT_HOSTNAME="\h"
FULL_WORKING_DIR="\w"
BASE_WORKING_DIR="\W"
# Throw it together
FINAL="${PROMPT_RESET}${PROMPT_BOLD}${PROMPT_GREEN}"
FINAL+="${USERNAME}#${SHORT_HOSTNAME} "
FINAL+="${PROMPT_RED}${FULL_WORKING_DIR}\$ "
FINAL+="${PROMPT_RESET}"
# Export variable
export PS1="${FINAL}"
.bashrc:
..
source ~/.dotfiles/other/setprompt
..
My questions:
Will this approach slow down my bash startup? Should I just write one ugly unreadable line of code instead of doing these variable definitions/sourcing?
I noticed, that the variables defined in setprompt are still defined in my .bashrc. I don't like this behaviour since it's not obvious to the editor of .bashrc that variables are defined when sourcing setprompt. Is this just the behaviour of source? What can I do about this?
Edit:
This is the approach I use now (recommended by tripleee):
getPrompt.sh:
#!/bin/bash
getPrompt () {
# Bold/Reset
local PROMPT_BOLD="\[$(tput bold)\]"
local PROMPT_RESET="\[$(tput sgr0)\]"
# Colors
local PROMPT_RED="\[$(tput setaf 1)\]"
local PROMPT_GREEN="\[$(tput setaf 2)\]"
# Miscellaneous
local USERNAME="\u" local SHORT_HOSTNAME="\h"
local FULL_WORKING_DIR="\w"
# Print for later use
printf "%s%s%s%s" "${PROMPT_RESET}${PROMPT_BOLD}${PROMPT_GREEN}" \
"${USERNAME}#${SHORT_HOSTNAME} " \
"${PROMPT_RED}${FULL_WORKING_DIR}\$ " \
"${PROMPT_RESET}"
}
.bashrc:
source ~/.dotfiles/bash/getPrompt.sh
PS1=$(getPrompt)
Keeping things human-readable is probably a good thing, and if performance is a problem, perhaps you can control whether this gets executed at all if your prompt is already set. As a first step, maybe move the call to .bash_profile instead of .bashrc.
You can either unset all the variables at the end of the script, or refactor the script so that it runs as a function, or as a separate script (i.e. call it instead of source it).
If you put it all in a function, the function will need to declare all the variables local.
If you run this as an external script, you will need to change it so that it prints the final value. Then you can call it like
PS1=$(setprompt)
without any side effects. (Perhaps you would want to do this with a function, too, just to keep it clean and modular.)

Read environment variable in make file

I have a environment variable set with name $MY_ENV_VARIABLE.
How do I use this variable inside my makefile to (for example) include some source files?
LOCAL_SRC_FILES = $(MY_ENV_VARIABLE)/libDEMO.so
Something like above doesn't seem to work.
Note: in my case this is needed for building with the Android NDK but I guess this applies to make in general.
Just to add some information...
The syntax to access the environment variable in make is like other variables in make...
#export the variable. e.g. in the terminal,
export MY_ENV_VARIABLE="hello world"
...
#in the makefile (replace before call)
echo $(MY_ENV_VARIABLE)
This performs the substitution before executing the commmand. If you instead, want the substitution to happen during the command execution, you need to escape the $ (For example, echo $MY_ENV_VARIABLE is incorrect and will attempt to substitute the variable M in make, and append it to Y_ENV_VARIABLE)...
#in the makefile (replace during call)
echo $$MY_ENV_VARIABLE
Make sure you exported the variable from your shell. Running:
echo $MY_ENV_VARIABLE
shows you whether it's set in your shell. But to know whether you've exported it so that subshells and other sub-commands (like make) can see it try running:
env | grep MY_ENV_VARIABLE
If it's not there, be sure to run export MY_ENV_VARIABLE before running make.
That's all you need to do: make automatically imports all environment variables as make variables when it starts up.
I just had a similar issue (under Cygwin):
Running echo $OSTYPE on the shell prints the value, but
running env | grep OSTYPE doesn't give any output.
As I can't guarantee that this variable is exported on all machines I want to run that makefile on, I used the following to get the variable from within the makefile:
OSTYPE = $(shell echo $$OSTYPE)
Which of course can also be used within a condition like the following:
ifeq ($(shell echo $$OSTYPE),cygwin)
# ...do something...
else
# ...do something else...
endif
EDIT:
Some things I found after experimenting with the info from jozxyqk's answer, all from within the makefile:
If I run #echo $$OSTYPE or #echo "$$OSTYPE" in a recipe, the variable is successfully expanded into cygwin.
However, using that in a condition like ifeq ($$OSTYPE,cygwin) or ifeq ("$$OSTYPE","cygwin") doesn't expand it.
Thus it is logical that first setting a variable like TEST = "$$OSTYPE" will lead to echo $(TEST) printing cygwin (the expansion is done by the echo call) but that doesn't work in a condition - ifeq ($(TEST),cygwin) is false.

Resources