How to get shell script output into Makefile.am at make time?

无人久伴 提交于 2019-12-23 18:09:22

问题


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:

  1. 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).
  2. AM_SUBST_NOTMAKE([MKFOO]) stops automake from generating a line of the form MKFOO = @MKFOO@ in Makefile.in. We need to do that assignment conditionally.
  3. We set up an automake conditional because we need to do different stuff for internal/external mkfoo inside Makefile.am
  4. 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:

  1. Conditionally recurse into mkfoo, and do it before src, which needs $MKFOO.
  2. Because there are times mkfoo is not even configured, it might not have a Makefile. That means we've broken make dist (and by extension, make distcheck). So we have to set DIST_SUBDIRS conditionally as well, and if we don't have mkfoo configured ensuring that it's distributed becomes our responsibility.
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!