简体   繁体   中英

A generated C file and autotools

In an autoools-based build, I'd like to replace a version-controlled C file with a generated C file.

This dummy, hello world example sort-of works:

#!/bin/sh -ex
cat > configure.ac <<EOF
AC_INIT([hello], [0.01])
AC_PREREQ([2.68]) 
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([1.11])
AC_CONFIG_FILES([Makefile])
AC_PROG_CC
AC_OUTPUT
EOF

cat > autogen.sh <<EOF
touch NEWS README AUTHORS ChangeLog COPYING
autoreconf -i
EOF
chmod +x autogen.sh

printf "
bin_PROGRAMS = hello
hello_SOURCES = hello.c 

hello.c: generate
\t./generate
" > Makefile.am

cat > hello.c <<EOF
#include <stdio.h>
int main()
{
    puts("hello world");
    return 0;
}
EOF

cat > generate <<EOF0
#!/bin/sh
cat > hello.c <<EOF
#include <stdio.h>
int main()
{
    puts("HELLO WORLD");
    return 0;
}
EOF
EOF0
chmod +x generate


./autogen.sh
./configure 
make -j$(nproc)

except it prevents me from doing an out-of-tree build such as:

mkdir B
cd B
../configure
make

which I can normally do in an autotools-based package. How can I generated the C file so that out-of-tree builds continue to work?

It is important to remember that make doesn't really know much about directories; for the most part, everything is a string to it. That's not always so obvious, but it tends to really bite you when you are trying to write a build system that can handle out-of-source builds.

You provide a build rule wherein hello.c depends on your generate script, which is fine in principle. Make will even handle the dependency processing correctly in an out-of-source build, finding the generate script in the source directory. But the recipe in the build rule explicitly runs ./generate , which does not exist when you're performing an out-of-source build. Furthermore, you have a disconnect between the dependency and the build rule: 'generate' is not the same thing as './generate'.

There are two main alternatives:

  1. In your build rules, rely only on automatic make variables (eg $< ) to refer to dependencies. When make is performing an out-of-source build, it initializes automatic variables with viable paths.

  2. Refer to files in the source directory via explicit paths.

To use option (1) by itself, you would need to work around the problem of how to run the generate script when it is (presumably) not in the path. You can do that by running it indirectly, via the shell. The make rule you would want in that case would be

hello.c: generate
    $(SHELL) $<

That should work for either in-source or out-of-source building. The $(SHELL) make variable should be provided by the Autotools.

To use option (2), on the other hand, you would probably rely on $(srcdir) or $(top_srcdir) :

# Note that the dependency name will always contain a '/':
hello.c: $(srcdir)/generate
    $<

(You can also name the generate script, with path, in the build recipe, but it's usually best to avoid repeating yourself.) The $(srcdir) and $(top_srcdir) variables are also provided by the Autotools. The former refers to the directory in the source tree that corresponds to the build-tree directory we are currently building; the latter refers to the source-tree directory containing the configure script.

Of those two, I'd rate (1) a bit more in the spirit of out-of-source building, but there isn't really that much difference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM