问题
I am working on an autotools project, and am a newbie to the autotools world. For various reasons, detailed at the bottom for completeness, I have a shell script from which I want to get the output for use in my makefile.
I have a situation similar to the following. Autoconf generates a script from an AC_CONFIG_FILES
command. e.g.
AC_CONFIG_FILES([thescript], [chmod +x thescript])
thescript.in
#!/bin/sh
# -*- sh -*-
# @configure_input@
echo @abs_top_builddir@/bar/foo
What I really want to do is use whatever is returned by @abs_top_builddir@/bar/foo
for use in my Makefile. I want to have this value available in a variable at make time and be able to access it in my Makefile.am as, say $(FOOPLACE)
. How can I achieve this?
Reason I require This / Extra Information
This question is related to a previous question of mine located here:
How to get absolute path to top build directory in autoconf configure.ac?
The project requires a subproject which has its own makefile and configure.ac. The subproject is a program which is used to generate source files for the main project. There is an option to disable the building of this project and attempt to use an installed version instead. In this case, the location of the installed version is provided in the variable FOOPLACE
(uisng AC_PATH_PROG
). When I am using the locally built verision I want to put the location of it in FOOPLACE
instead. The variable is then used in Makefile.am as $(FOOPLACE)
.
It seems there is a bug in autoconf which means the only place that abs_top_builddir can be accessed is in configure files generated by AC_CONFIG_FILES
at configure time. There are details of why I want to do this in the linked question.
回答1:
The question as written
In your Makefile.am, you could do something like this:
foo.c: foo.in
FOOPLACE=`./thescript`; $(FOOPLACE) -c -o $@ $<
That has the benefit of not requiring a GNU-ism in what is meant to be portable Makefile code.
The right and hard way
I have prepared a dummy package that uses a tool called mkfoo
. It can use the internal copy or the copy on the host's system.
Let's look first at configure.ac
:
AC_PREREQ([2.67])
AC_INIT([parent], [0], [jack@jackkelly.name])
AM_INIT_AUTOMAKE([foreign])
AC_ARG_WITH([mkfoo],
[AS_HELP_STRING([--with-mkfoo],
[Path to mkfoo, "external", "internal", or "check" @<:@check@:>@])],
[MKFOO=$withval],
[with_mkfoo=check])
AS_IF([test "$with_mkfoo" = check -o "$with_mkfoo" = external],
[AC_PATH_PROG([MKFOO], [mkfoo], [no])])
AS_IF([test "$with_mkfoo" = external -a "$MKFOO" = no],
[AC_MSG_ERROR([External mkfoo demanded, but not found.])])
dnl We conditionally set MKFOO in Makefile.am
AM_SUBST_NOTMAKE([MKFOO])
AM_CONDITIONAL([USE_INTERNAL_MKFOO],
[test "$with_mkfoo" = internal -o "$MKFOO" = no])
AM_COND_IF([USE_INTERNAL_MKFOO], [AC_CONFIG_SUBDIRS([mkfoo])])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT
There are a few things going on here:
- The default behaviour is "check for mkfoo, if it's not there, build and use the bundled copy". Note also that it supports
--with-mkfoo=PATH
(user may have a copy installed in an odd place),--with-mkfoo=internal
(needed for distcheck, where we want to test everything) and--with-mkfoo=external
(a kindness to package maintainers, who don't like bundled subprojects). AM_SUBST_NOTMAKE([MKFOO])
stopsautomake
from generating a line of the formMKFOO = @MKFOO@
inMakefile.in
. We need to do that assignment conditionally.- We set up an automake conditional because we need to do different stuff for internal/external
mkfoo
insideMakefile.am
- We configure the
mkfoo
directory conditionally.
Now, the toplevel Makefile.am
:
if USE_INTERNAL_MKFOO
SUBDIRS = mkfoo
DIST_SUBDIRS = mkfoo
else
SUBDIRS =
DIST_SUBDIRS =
endif
SUBDIRS += src
DIST_SUBDIRS += src
## Need to make sure the internal tools work during distcheck.
DISTCHECK_CONFIGURE_FLAGS = --with-mkfoo=internal
dist-hook:
if ! USE_INTERNAL_MKFOO
cp -fpR $(srcdir)/mkfoo $(distdir)
endif
What's going on here:
- Conditionally recurse into
mkfoo
, and do it beforesrc
, which needs$MKFOO
. - Because there are times
mkfoo
is not even configured, it might not have aMakefile
. That means we've brokenmake dist
(and by extension,make distcheck
). So we have to setDIST_SUBDIRS
conditionally as well, and if we don't havemkfoo
configured ensuring that it's distributed becomes our responsibility. - When we
make distcheck
we want to use the internal copy because it's better to exercise everything in the source tarball.
Now, src/Makefile.am
:
if USE_INTERNAL_MKFOO
MKFOO = $(abs_top_builddir)/mkfoo/mkfoo
else
MKFOO = @MKFOO@
endif
bin_SCRIPTS = foo
CLEANFILES = foo
EXTRA_DIST = foo.in
foo: foo.in
$(MKFOO) < $< > $@
There is nothing shocking here except the conditional assignment of MKFOO
.
src/foo.in
:
I am foo.in!
Now for the subpackage. mkfoo/configure.ac
:
AC_PREREQ([2.67])
AC_INIT([mkfoo], [0], [jack@jackkelly.name])
AM_INIT_AUTOMAKE([foreign])
AC_PROG_CC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
As you can see, nothing special. What about mkfoo/Makefile.am
?
bin_PROGRAMS = mkfoo
mkfoo/mkfoo.c
:
#include <stdio.h>
int main(int argc, char *argv[]) {
puts("Internal mkfoo.");
return 0;
}
Just a dummy test program.
回答2:
what does not work with the following line in your Makefile.am?
FOOPLACE=$(shell @abs_top_builddir@/thescript)
回答3:
FOOPLACE
seems to be created by its presence in configure.ac in a conditional, even if the condition is not true (see the linked question for details). It is therefore present but empty at make time. It also seems variables cannot be redefined in the Makefile.am, however, they can be appended to. Since FOOPLACE
is empty, the output from the script can be added to it with the following.
FOOPLACE+=$(shell $(abs_top_builddir)/thescript)
来源:https://stackoverflow.com/questions/15136267/how-to-get-shell-script-output-into-makefile-am-at-make-time