Conditional AS_ARG_WITH in configure - autoconf

I have some custom autoconf macros that will be shared by several projects. I would like to have some of the AC_ARG_WITH macros depend on the project, so they don't show up when they do ./configure -h. For example:
if test $PKG_NAME = proj1; then
AC_ARG_WITH(foodir, AC_HELP_STRING([--with-foodir=DIR],
[where foo will come from]),
foodir=$withval,
foodir="")
fi
I've tried things like m4_if and AS_IF but it doesn't work. Is there any way to do this, or am I SOL?
Thanks!

So out of luck, I'd imagine. I was interested so tried coming up with a solution. I thought this might have been a possible configure.ac:
AC_INIT([Autohell], [0.0.1])
AC_PREREQ(2.13)
AC_ARG_ENABLE([extras],[AC_HELP_STRING([--enable-extras],[Enable extra options])],
[
AS_CASE([$enable_extras],
[yes],
[
AC_ARG_ENABLE([foo],[AC_HELP_STRING([--enable-foo],[Enable the Foo])],
[
enable_foo=$enableval
echo "Foo Enabled"
],
[
enable_foo="no"
echo "Foo Disabled"
])
],
[
echo "Extras Disabled"
])
],enable_extras="no")
AM_CONDITIONAL([FOO],[test "$enable_foo" = "yes"])
cat << EOF
Extras: ${enable_extras}
Foo: ${enable_foo}
EOF
Needless to say, it didn't work. Both --enable-extras and --enable-foo appear in ./configure --help and the variables set by the switches are independent, check out this sample output:
$ ./configure
Extras: no
Foo:
$ ./configure --enable-extras
Foo Disabled
Extras: yes
Foo: no
$ ./configure --enable-extras --enable-foo
Foo Enabled
Extras: yes
Foo: yes
$ ./configure --disable-extras --enable-foo
Extras Disabled...
Extras: no
Foo: yes
Output is quite interesting: although the switches and complementary variables are in place, the conditional blocks are respected so we can really only --enable-foo when we also --enable-extras.

Related

Creating variable from bash command output in makefile

Hello I would like to ask how I can create bash variable in makefile.
Below code does work but variable "targets" keeps being empty. How I can actually create "targets" and "current_target" variables in makefile?. Problem is that I have to create this variables from actual bash commands.
SHELL=/bin/bash
...
MAIN_APPS = 01_prep 02_prep 03_prep 04_prep 05_prep
foo : .check_targets .check_segment
#for f in $(MAIN_APPS) ; do \
targets=$(expr $(last_target) + 1); \
echo $(targets) + 1; \
curent_target=$(expr "$(echo $(f) | head -c 2) + 0"); \
if [ $(targets) = $(current_target)]; then \
break; \
else \
make $(f); \
fi \
done
output:
make foo last_target="02" segm=KI
+ 1
What I want to do is to make targets from my makefile which actually starts from 01 to 05 if I pass an argument last_target="05"
You mix up between make variables and shell variables. And you did not consider that make expands the recipes before passing them to the shell, reason why you frequently need to use $$ instead of $. Or, for command expansion, `...` instead of $(...). You are also using double quotes where you shouldn't (expr "..."). Finally, you use make in your recipe, which is not a good idea. You should use $(MAKE) (see the How the MAKE Variable Works section of the GNU make manual for the details).
Try the following (not tested) maybe:
SHELL=/bin/bash
...
MAIN_APPS = 01_prep 02_prep 03_prep 04_prep 05_prep
foo : .check_targets .check_segment
#for f in $(MAIN_APPS) ; do \
targets=`expr "$(last_target)" + 1`; \
echo "$$targets + 1"; \
tmp=`echo "$$f" | head -c 2`; \
curent_target=`expr "$$tmp" + 0`; \
if [ "$$targets" = "$$current_target" ]; then \
break; \
else \
$(MAKE) "$$f"; \
fi \
done
But I am almost 100% convinced that you are trying to use make as a kind of scripting language instead of as a sophisticated build system. If I understand well you are trying to rebuild only a subset of your MAIN_APPS by specifying a last target number. You could probably achieve the same with a much more make-ish style:
TARGETS := $(shell printf '%02d_prep\n' $$(seq $(last_target)))
.PHONY: foo
foo: $(TARGETS) .check_targets .check_segment
And that's all, no complex recipe for foo. Nothing at all (except, of course, the rules to build .check_targets, .check_segment and all xx_prep targets, that you do not show).
Explanation: I used the $(shell ...) make function and a small shell script to initialize make variable TARGETS with 01_prep 02_prep ... up to $(last_target)_prep. As noted in the comments this shell script does not even require bash and would work with the default make shell (sh). So, if you do not have other good reasons to use bash, get rid of the SHELL=/bin/bash line and your Makefile will be a bit more portable.
Then, I declared foo as phony because you probably don't have a file named foo and, in case you have one, you probably want make to build foo anyway.
Finally, I declared $(TARGETS), .check_targets, and .check_segment as prerequisites of foo. If you ask make to build foo and any of these prerequisites is out-of-date, make will build it using the rules you declared for it.
This is far more make-ish because it clearly tells make what depends on what instead of hiding it in a recipe. And make needs this to do its job correctly, which consist in comparing last modification dates of files to decide if something must be rebuilt or not. It also has extra benefits like, for instance, exploiting the parallelism of your computer to build several xx_prep in parallel if it is possible.

How can I uninstall a version of a Cabal package?

Happstack Lite is breaking on me because it's getting blaze-html version 0.5 and it wants version 0.4. Cabal says that both versions 0.4.3.4 and 0.5.0.0 are installed. I want to remove the 0.5.0.0 and use just the older version. But cabal does not have an "uninstall" command, and when I try ghc-pkg unregister --force blaze-html, ghc-pkg says my command has been ignored.
What do I do?
UPDATE: Don't believe it. Although ghc-pkg claims to ignore the command, the command isn't ignored. And with Don Stewart's accepted answer you can remove exactly the version you wish to eliminate.
You can ghc-pkg unregister a specific version, like so:
$ ghc-pkg unregister --force regex-compat-0.95.1
That should be sufficient.
If you are outside a sandbox:
ghc-pkg unregister --force regex-compat-0.95.1
If you are inside a cabal sandbox:
cabal sandbox hc-pkg -- unregister attoparsec --force
The first -- is the argument separator for hc-pkg. This runs ghc-pkg in a sandbox aware manner.
There is also the cabal-uninstall package which provides a cabal-uninstall command. It unregisters the package and deletes the folder. It is worth mentioning though that it passes --force to ghc-pkg unregister so it can break other packages.
Here's a shell script I use to uninstall a package. It supports multiple installed versions of GHC and also wipes relevant files (but is provided without warranty, don't blame me if you hose your installation!)
#!/bin/bash -eu
# Usage: ./uninstall.sh [--force | --no-unregister] pkgname-version
# if you set VER in the environment to e.g. "-7.0.1" you can use
# the ghc-pkg associated with a different GHC version
: ${VER:=}
if [ "$#" -lt 1 ]
then
echo "Usage: $0 [--force | --no-unregister] pkgname-version"
exit 1
fi
if [ "$1" == "--force" ]
then force=--force; shift; # passed to ghc-pkg unregister
else force=
fi
if [ "$1" == "--no-unregister" ]
then shift # skip unregistering and just delete files
else
if [ "$(ghc-pkg$VER latest $1)" != "$1" ]
then
# full version not specified: list options and exit
ghc-pkg$VER list $1; exit 1
fi
ghc-pkg$VER unregister $force $1
fi
# wipe library files
rm -rfv -- ~/.cabal/lib/$1/ghc-$(ghc$VER --numeric-version)/
# if the directory is left empty, i.e. not on any other GHC version
if rmdir -- ~/.cabal/lib/$1
then rm -rfv -- ~/.cabal/share/{,doc/}$1 # then wipe the shared files as well
fi

make -j$TOTAL_PROCESSORS

what does "make -j$TOTAL_PROCESSORS" means?
Say if I have a two core processor, It will execute "make -j2". What exactly it does?
I am adding a small example below
For compiling my toolchain the script file uses -
pushd toolchaindir
export TARGET=powerpc-linux-gnu
export LINUX_ARCH=powerpc
TOTAL_PROCESSORS=$(grep processor /proc/cpuinfo | wc -l)
make -j$TOTAL_PROCESSORS
if [ "$?" = "0" ]; then
echo "built toolchain successfully"
else
echo "failed during build"
exit 1
fi
popd
exit 0
How it builds toolchain?
make -j2 tells make that it can run two shell commands at once. Make determines whether it can do this from your makefile, so you had better write your makefiles correctly!
Consider this noddy makefile:
1.o: 1.c
gcc -c 1.c -o 1.o
2.o: 2.c
gcc -c 2.c -o 2.o
prog: 1.o 2.o
gcc 1.o 2.o -o prog
If you say make -j2 prog, then make cleverly decides that the production of 1.o is entirely independent of 2.o. Thus it can run the two compiles at the same time without error. So it does. Make waits for both these compiles to finish before combining both object files into prog in the final link step.
Unspeakably clever, so long as you get your makefiles right (if they don't work under -jn then they are bad bad bad!).
In one word: yes
It authorizes make to start $TOTAL_PROCESSORS compilations in parallel.
It expands the environment variable TOTAL_PROCESSORS, presumably to a number which indicates how many CPUs/cores you have, and then runs make with this amount of parallel jobs.
You'll need to look at what sets TOTAL_PROCESSORS to a value.
It reads whatever you shell variable $TOTAL_PROCESSORS is and runs that many jobs. I'm guessing that variable is set to the number of processors or cores on your machine. You can echo it's value in a shell just to be sure.

How to use an older version of gcc in Linux

In Linux I am trying to compile something that uses the -fwritable-strings option. Apparently this is a gcc option that doesn't work in newer version of gcc. I installed gcc-3.4 on my system, but I think the newer version is still being used because I'm still get the error that says it can't recognize the command line option -fwritable-strings. How can I get make to use the older version of gcc?
You say nothing about the build system in use, but usually old versions of gcc can be invoked explicitly, by something like (this is for an autotools-based build):
./configure CXX=g++-3.4 CC=gcc-3.4
For a make-based build system, sometimes this will work:
make CXX=g++-3.4 CC=gcc-3.4
Most makefiles ought to recognise overriding CC and CXX in this way.
If editing the configuration/Makefile is not an option, Linux includes a utility called update-alternatives for such situations. However, it's a pain to use (links to various tutorials included below).
This is a little simpler - here's a script (from here) to easily switch your default gcc/g++ version:
#!/bin/bash
usage() {
echo
echo Sets the default version of gcc, g++, etc
echo Usage:
echo
echo " gcc-set-default-version <VERSION>"
echo
exit
}
cd /usr/bin
if [ -z $1 ] ; then
usage;
fi
set_default() {
if [ -e "$1-$2" ] ; then
echo $1-$2 is now the default
ln -sf $1-$2 $1
else
echo $1-$2 is not installed
fi
}
for i in gcc cpp g++ gcov gccbug ; do
set_default $i $1
done
If you 1) name this script switch-gcc, 2) put it in your path, and 3) make it executable (chmod +x switch-gcc), you can then switch compiler versions just by running
sudo switch-gcc 3.2
Further reading on update-alternatives:
https://lektiondestages.blogspot.com/2013/05/installing-and-switching-gccg-versions.html
https://codeyarns.com/2015/02/26/how-to-switch-gcc-version-using-update-alternatives/
https://askubuntu.com/questions/26498/choose-gcc-and-g-version
Maybe you could just give the whole path of the gcc-3.4 install while compiling your program:
/path_to_gcc_3.4/gcc your_program
If you can find where the writeable strings are actually being used, another possibility would be to use strdup and free on the subset of literal strings that the code is actually editing. This might be more complicated than downgrading versions of GCC, but will make the code much more portable.
Edit
In response to the clarification question / comment below, if you saw something like:
char* str = "XXX";
str[1] = 'Y';
str[2] = 'Z';
// ... use of str ...
You would replace the above with something like:
char* str = strdup("XXX");
str[1] = 'Y';
str[2] = 'Z';
// ... use of str ...
free(str);
And where you previously had:
char* str = "Some string that isn't modified";
You would replace the above with:
const char* str = "Some string that isn't modified";
Assuming you made these fixes, "-fwritable-strings" would no longer be necessary.

What does the gnuwin32 program: [.exe do?

Looking in the gnuwin32/bin directory, there is an odd-looking program file named [.exe
I couldn't find it in the documentation, gnuwin32.sourceforge.net or in a google search, so I ran it and got:
$ [
[: missing `]'
$
so I gave it ] as a parameter and got
$ [ ]
$
It didn't complain, so I assumed it was on the right track. I tried:
$ [ hello ]
again, no complaints. so I tried an arithmetic expression:
$ [ 1 + 1 ]
[: +: binary operator expected
$
I tried a bunch of different combinations, including prefix & postfix notation but nothing seemed to work. What does this thing do?
test a
==
[ a ]
It's just sugar
Edit: To clarify, that's the conditional syntax, e.g. [ "a" = "a" ]
It's used to evaluate conditional expressions.
It is equivalent to (possibly a symlink to?) the test executable.
The manpage is here.
You may see this in a lot of bash scripts:
if [ "$LOGNAME" = "scott" ]
then
echo "Logged in as Scott"
else
echo "incorrect user"
fi
The funny thing is, the [ is not part of the bash language, it's actually an executable whose return code is used by the 'IF'. This is the reason why the space after the [ and its first argument is mandatory - if it would be omitted, the script would try to execute ["$LOGNAME" and fail.
You can't do arithmetical operations with it - use expr for that (see here).
However, you can test for a wide range of file properties (does it exist? what type is it? etc) as well as use comparison operators on strings and numbers.
Another answer already mentioned it is the same as test. On bash, it is also a builtin, so you can get the help for it with the help builtin (help test).

Resources