Generate pkg-config out of Makefile - makefile

For a project, which historically uses make I would now like to generate a pkg-config file. However I cannot seem to prevent the substitution of the variables
mylib.pc:
echo 'prefix='$(PREFIX) > bzip2.pc
echo "exec_prefix=\${prefix}" >> mylib.pc
echo 'libdir=\${prefix}/lib' >> mylib.pc
install: mylib.pc
Afterwards I have a mylib.pc with expanded variables, which is not what I want.
So how does one generate a pkg-config out of a Makefile or how do I prevent variable substitution?

This will produce what I think you want:
mylib.pc:
echo 'prefix='$(PREFIX)
echo 'exec_prefix=$${prefix}' >> mylib.pc
echo 'libdir=$${prefix}/lib' >> mylib.pc

Related

Makefile: Reuse environment variables

In my Makefile deploy target I create environment variables and I want to reuse those in the following lines:
SHELL=/bin/sh
deploy:
export $(shell sh this-script-generate-key-values.sh | xargs)
echo ${VAR1} #there is no variable here
echo ${VAR2} #there is no variable here
Where:
this-script-generate-key-values.sh generates this output:
VAR1="somevalue"
VAR2="somevalue"
Why the variables are not set in subsequent lines? How can I make it work?
Notes:
This line works: sh this-script-generate-key-values.sh | xargs
The shell must be /bin/sh (no bash)
All lines in a Makefile recipe run in a separate shell. You need to run the lines in a single shell. Also you need to escape the dollar sign ($) so that variable substitution is not done by make but by the shell.
SHELL=/bin/sh
deploy:
export $$(this-script-generate-key-values.sh | xargs) ;\
echo $${VAR1} ;\
echo $${VAR2}
Just to expand on my comment -- you could output to a file, and use the file to generate your output as so:
vars.txt:
this-script-generate-key-values.sh > $#
deploy : vars.txt
echo VAR1=$$(sed -n 's|VAR1=\(.*\)|\1|p' vars.txt)
echo VAR2=$$(sed -n 's|VAR2=\(.*\)|\1|p' vars.txt)
note: you may have to generate dependencies for vars.txt or declare it .PHONY, otherwise, this will not run on every invocation of make.
If the .ONESHELL special target appears anywhere in the makefile then all recipe lines for each target will be provided to a single invocation of the shell. Newlines between recipe lines will be preserved.
.ONESHELL:
deploy:
export $$(this-script-generate-key-values.sh)
echo $${VAR1}
echo $${VAR2}

Setting env variable from Perl and using in Makefile

I'm trying to set env variable from Perl script and using it inside Makefile doesn't work. While dumping ENV hash tree shows variable successfully set.
Makefile code
list_gen: $(TESTBENCH_PATH)/blocks/soc_tb/global/default
perl list_gen.pl; \
$(MAKE) $(RECITAL_PATH)/catalog/catalog.xml
# touch $#
# Generates catalog.xml from .xmls of VIPs
$(RECITAL_PATH)/catalog/catalog.xml: $(VIP_XMLs)
#echo "# generating catalog.xml " ; \
echo "vip list is $(VIP_LIST)" ; \
rpfCatalog --add $(VIP_XMLs); \
for vip in $(VIP_LIST); \
do \
rpfCatalog --add $$TESTBENCH_PATH/common_blocks/$$vip/global/default.xml; \
done
Perl Script code
$ENV{"VIP_LIST"} = $vip_exists;
I don't think there is any elegant way to update environment of make by running any external command (like perl script) from it. Because even a direct way wouldn't work.
/home/user> cat makefile
NUM=100
first:
NUM=200
echo $(NUM)
second:
NUM=200; echo $(NUM)
third:
NUM=200; \
echo $(NUM);
/home/user> make first
NUM=200
echo 100
100
/home/user> make second
NUM=200; echo 100
100
/home/user> make third
NUM=200; \
echo 100;
100
If you are only looking for a perl script to modify it's parent's environment, something like this works (in a very limited way):
/home/user> cat change_env.pl
#!/usr/bin/perl -w
print "NUM=100\n";
/home/user> NUM=1
/home/user> echo $NUM
1
/home/user> eval $(./change_env.pl)
/home/user> echo $NUM
100
Coming to original your question, .. can't you call make after making the changes to your shell environment?
VIP_LIST=$(perl my.pl)
Would save the output of the script in the variable of the parent shell.
HTH
Georg
When you execute your Perl script, do it like $(./myperlscript.pl) on the prompt. What you need to do is
$ENV{VIP_LIST} = $vip_exists;
Drop the quotes

How can I test to see if a program is available in Make?

Here's what I have so far. I'm not looking for RVM-specific answers – I need to be able to replace rvm with, say, evm. Just wanted to pick something everyone would be familiar with :)
install_rvm:
ifeq ("`which rvm > /dev/null; echo $?`", "0")
#echo "rvm already installed!"
else
#echo "installing rvm..."
install_rvm_cmd
endif
Edit
Sorry for not saying this up-front, but I would like install_rvm_cmd to be run as it would normally – I don't want to hide the install process from the user.
I would do it like this:
.PHONY: install_rvm
install_rvm:
#if which rvm > /dev/null; then \
echo "rvm already installed!"; \
else \
echo "installing rvm..."; \
install_rvm_cmd; \
fi
It would be possible to use ifeq but it would entail performing the which rvm check even if install_rvm is not an actual target in a specific run of make. (I'm assuming the general case in which install_rvm is just one target among many.)
Although the string install_rmv_cmd itself wont' be output by make, its output will be output as usual. If you really want to have install_rmv_cmd out on stdout, you can always add echo install_rmv_cmd just before the command itself. To avoid repetition you could have the else branch be:
echo "installing rvm..."; \
cmd=install_rmv_cmd; \
echo $$cmd; \
$$cmd; \
In addition to Louis's answer, you can use ifdef. For example:
EVM_LOCATION := $(shell which evm)
CASK_LOCATION := $(shell which cask)
install_cask:
ifdef CASK_LOCATION
$(info cask is already installed!)
else
curl -fsSkL https://raw.github.com/cask/cask/master/go | python
endif
install_evm:
ifdef EVM_LOCATION
$(info evm is already installed!)
else
curl -fsSkL https://raw.github.com/rejeep/evm/master/go | bash
endif
You could use something like this (untested) which uses a stamp file to avoid doing any work once it has been done.
install_rvm_stamp:
__rvm=$$(command -v rvm);\
if [ -z "$$__rvm" ] || ! "$$__rvm" --version >/dev/null 2>&1; then \
echo "installing rvm..."; \
install_rvm_cmd; \
else \
echo 'rvm already installed!'
fi
touch '$#'
.PHONY: install_rvm
install_rvm: install_rvm_stamp
Alternatively, if you don't mind not "function testing" the binary you could do something like this instead.
rvm_bin := $(or $(realpath /usr/local/bin/rvm),$(realpath /bin/rvm),$(realpath /usr/bin/rvm),do_install_rvm)
install_rvm: $(rvm_bin)
do_install_rvm:
#echo "installing rvm..."
install_rvm_cmd
One final comment, as an augmentation to the make-level ifdef option presented in your answer; if the targets in question are only intended to be run manually (and are not used as prerequisites for any other targets) then the extraneous which calls can be avoided with some extra make-level checking.
ifneq (,$(findstring install_evm,$(MAKECMDGOALS)))
EVM_LOCATION := $(shell which evm)
endif
Wrap that in the following and you can avoid undefined variable warnings about MAKECMDGOALS if --warn-undefined-variables is used.
ifneq (undefined,$(origin MAKECMDGOALS))
....
endif

Simplest "configure" script ever that passes prefix argument to Makefile? (configure hello world)

My end goal is to produce a simple .deb package.
For that I've read it's better to provide 3 build phases in my build infrastructure of the project, rather than do it in the debian/ folder.
So first thing I need is a configure script, however I want the simplest configure script ever that just receives a "--prefix" argument and passes its value to the Makefile system (so the "install" target of the makefile can copy the files over to it).
Can I do this without using autoconf? I know autoconf is great but for the simplest configuration-phase ever I may not need it yet so badly.
Thanks
I wouldn't do it without autoconf. You're basically saying that you want to mimic one specific behavior of autoconf, without knowing all the ramifications and related behaviors that autoconf adds. This violates the principle of least surprise, as users (or even your deb tool) will expect the related behaviors (DESTDIR, --exec-prefix, etc.). Just use autoconf. You can make your configure.ac really simple:
AC_INIT([My App], [1.0], [my-email#me.com])
AM_INIT_AUTOMAKE([-Wall foreign])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
I ended up using this:
#!/usr/bin/env bash
prefix=NONE
test "$prefix" = NONE && prefix=/usr/local
usage ()
{
echo ""
echo "Usage : configure [--prefix=PREFIX]"
echo ""
}
while test x$1 != x; do
case $1 in
--prefix=*)
prefix=`echo $1 | sed 's/--prefix=//'`
;;
--prefix)
shift
prefix=$1
;;
--help)
usage
exit
;;
*)
echo Warning: unknown argument $1 >&2
usage
;;
esac
shift
done
echo -n "SUBDIRS = " > config.make
echo Configuration Summary
echo ---------------------
echo
echo "MyApp has been configured with "
echo " prefix = $prefix"
echo
echo >> config.make
echo
echo -n "prefix=$prefix" >> config.make
Then in the Makefile the first thing I need to do is:
top_srcdir=.
CONFIG_MAKE=$(top_srcdir)/config.make
-include $(top_srcdir)/config.make
I would be interested if there are better solutions than this.

Bash script: only echo line to ~/.bash_profile once if the line doesn't yet exist

I wrote a bash git-install script. Toward the end, I do:
echo "Edit ~/.bash_profile to load ~/.git-completioin.bash on Terminal launch"
echo "source ~/.git-completion.bash" >> ~/.bash_profile
The problem is, if you run the script more than once, you end up appending this line multiple times to ~/.bash_profile. How do I use bash scripting with grep or sed (or another option you may recommend) to only add the line if it doesn't yet exist in the file. Also, I want to add the line to ~/.profile if that file exists and ~/.bash_profile doesn't exist, otherwise just add it to ~/.bash_profile.
Something like this should do it:
LINE_TO_ADD=". ~/.git-completion.bash"
check_if_line_exists()
{
# grep wont care if one or both files dont exist.
grep -qsFx "$LINE_TO_ADD" ~/.profile ~/.bash_profile
}
add_line_to_profile()
{
profile=~/.profile
[ -w "$profile" ] || profile=~/.bash_profile
printf "%s\n" "$LINE_TO_ADD" >> "$profile"
}
check_if_line_exists || add_line_to_profile
A couple of notes:
I've used the . command instead of source as source is a bashism, but .profile may be used by non-bash shells. The command source ... is an error in .profile
I've used printf instead of echo because it's more portable and wont screw up backslash-escaped characters as bash's echo would.
Try to be a little more robust to non-obvious failures. In this case make sure .profile exists and is writable before trying to write to it.
I use grep -Fx to search for the string. -F means fixed strings, so no special characters in the search string needs to be escaped, and -x means match the whole line only. The -qs is common grep syntax for just checking the existence of a string and not to show it.
This is proof of concept. I didn't actually run this. My bad, but it's Sunday morning and I want to go out and play.
if [[ ! -s "$HOME/.bash_profile" && -s "$HOME/.profile" ]] ; then
profile_file="$HOME/.profile"
else
profile_file="$HOME/.bash_profile"
fi
if ! grep -q 'git-completion.bash' "${profile_file}" ; then
echo "Editing ${profile_file} to load ~/.git-completioin.bash on Terminal launch"
echo "source \"$HOME/.git-completion.bash\"" >> "${profile_file}"
fi
How about:
grep -q '^source ~/\.git-completion\.bash$' ~/.bash_profile || echo "source ~/.git-completion.bash" >> ~/.bash_profile
or in a more explicit (and readable) form:
if ! grep -q '^source ~/\.git-completion\.bash$' ~/.bash_profile; then
echo "Updating" ~/.bash_profile
echo "source ~/.git-completion.bash" >> ~/.bash_profile
fi
EDIT:
You should probably add an additional newline before your one-liner, just in case ~/.bash_profile does not end in one:
if ! grep -q '^source ~/\.git-completion\.bash$' ~/.bash_profile; then
echo "Updating" ~/.bash_profile
echo >> ~/.bash_profile
echo "source ~/.git-completion.bash" >> ~/.bash_profile
fi
EDIT 2:
This is a bit easier to modify and slightly more portable:
LINE='source ~/.git-completion.bash'
if ! grep -Fx "$LINE" ~/.bash_profile >/dev/null 2>/dev/null; then
echo "Updating" ~/.bash_profile
echo >> ~/.bash_profile
echo "$LINE" >> ~/.bash_profile
fi
The -F and -x options are specified by POSIX and were suggested in several other answers and comments.
# Decide which profile to add to
PROFILE=~/.bash_profile
if ! [ -e "$PROFILE" ] && [ -e ~/.profile ]; then
PROFILE=~/.profile
fi
# Add to profile if it doesn't appear to be there already. Err on the side of
# not adding it, in case user has made edits to their profile.
if ! grep -s 'git-completion\.bash' "$PROFILE"; then
echo "Editing $PROFILE to load ~/.git-completion.bash on Terminal launch"
echo "source ~/.git-completion.bash" >> "$PROFILE"
fi

Resources