I would like use automake to process/modify the binaries before they are installed. For example, I would like to extract the symbols from the binary into a separate file and location (like this). Another example is to collect the md5sums of critical assets for publishing a report.
This is a simplified (but representative) Makefile.am that I have:
abc_PROGRAMS = foo
foo_SOURCES = foo.cpp
pqr_PROGRAMS = bar
bar_SOURCES = bar.cpp
ALL_SYMS := $(PROGRAMS:%=%.sym)
sym_DATA = $(ALL_SYMS)
# A convenient target such as "make foo.sym" will trigger this rule:
$(ALL_SYMS): %.sym : %
...
objcopy --preserve-dates --only-keep-debug $< $@
objcopy --preserve-dates --strip-all --add-gnu-debuglink=$@ $<
...
I have tried a few ways to hook in my script in during install, but with limited success.
One potential way is using install-exec-local:
install-exec-local: $(ALL_SYMS)
The problem with install-exec-local is that when I use: "make install -j", the install-exec-local target runs in parallel with the install, so binaries foo and bar get installed into at their respective destination dirs, even while they are being were being modified by the %.sym rule, thereby potentiall messing up the installed files. However this solution works if -j is not used. I would like if I can leverage the advantages of using -j.
Another potential way is using install-exec-hook:
install-exec-hook: $(ALL_SYMS)
The problem with install-exec-hook is that the programs foo and bar are already installed before I get a chance to modify them using the %.sym rule. Besides foo and bar get installed at different locations, I don't have a generic way to get their destination locations while writing a suitable install-exec-hook rule.
Another potential way is to define STRIP_PROGRAM or something equivalent, but that does not work really well, because i think it won't work with the "make install" target, but only with "make install-strip -j". I have not gone this path, because our build scripts use "make install -j".
Another way is to do it is by creating build rules that run during build time rather than install time. But this one is really cumbersome, that it creates many files in the build directory and I would like to avoid it. Also new people in the project while adding new programs can easily bypass these finely tuned elaborate arrangements.
abc_PROGRAMS = foo
foo : foo.tmp
foo.sym : foo
noinst_PROGRAMS = foo.tmp
foo_tmp_SOURCES = foo.cpp
pqr_PROGRAMS = bar
bar : bar.tmp
bar.sym : bar
noinst_PROGRAMS += bar.tmp
bar_tmp_SOURCES = bar.cpp
sym_DATA = foo.sym bar.sym
foo bar: % : %.tmp
...
cp $@ $<
objcopy --only-keep-debug $@ [email protected]
objcopy --strip-all [email protected] $@
I would have loved if automake provided a hook which ran before a program is installed, or just after a program is built.
The stackoverflow.com community is really making a difference to the quality of solutions that are available on the internet. I am sure someone must have faced a problem similar to mine. I am awaiting good solutions or industry best practices on this issue. Lastly, I apologize for not being able to make the question much more brief or easier to understand.
Tell automake to run a few commands on a program just before installing or just after linking
The "just after linking" part can be accomplished using libtool
's postlink_cmds
step. postlink_cmds
is documented:
Variable: postlink_cmds
Commands necessary for finishing linking programs. postlink_cmds are executed immediately after the program is linked. Any occurrence of the string @OUTPUT@ in postlink_cmds is replaced by the name of the created executable (i.e. not the wrapper, if a wrapper is generated) prior to execution. Similarly, @TOOL_OUTPUT@ is replaced by the toolchain format of @OUTPUT@. Normally disabled (i.e. postlink_cmds empty).
Below is part of a configure.ac
that uses sed
to patch libtool
and postlink_cmds
after libtool
is created. We needed it to apply software capabilities on a Solaris shared object because our link options to set them through a mapfile -M <mapfile>
was being stripped (apparently libtool
reserves nearly all -M
options).
Though libtool
has a postlink_cmds
we don't know how to set it more traditionally. Maybe there is a AC_XXX
somewhere to do it.
#############################################################################
## Hack ahead. GNU's libtool does not honor our '-M cryptopp.mapfile' in AM_LDFLAGS
## for the libcryptopp.so recipe. Many thanks to John Martin of Oracle for help wielding
## elfedit. The hw_cap = 0x1800 is SSE2 SSE and its needed for old hardware when new
## instructions are present, like SSE4.1, SSE4.2, CLMUL, AES, RDRAND, RDSEED and SHA.
## TODO: determine if we are allowed to hijack libtool's postlink_cmds function. It
## works well but we may be violating a policy somewhere along the line.
if test "$IS_SUN_OS" -ne "0" && test "$IS_SUN_COMPILER" -ne "0"; then
if test "$IS_IA32" -ne "0"; then
echo "Adding postlink script"
rm -f postlink.sh 2>/dev/null
echo "echo \"Fixing shared object capabilities\"" >> postlink.sh
echo "elfedit -e 'cap:hw1 0x1800' .libs/cryptest" >> postlink.sh
echo "elfedit -e 'cap:hw1 0x1800' .libs/cryptestcwd" >> postlink.sh
echo "elfedit -e 'cap:hw1 0x1800' .libs/libcryptopp.so.6.0.0" >> postlink.sh
echo "" >> postlink.sh
chmod +x postlink.sh
echo "Adding postlink script to libtool postlink_cmds"
sed 's|postlink_cmds=""|postlink_cmds="./postlink.sh"|g' libtool > libtool.fixed
mv libtool.fixed libtool
chmod +x libtool
fi
fi
Before hacking with sed
, I tried setting postlink_cmds
more traditionally in configure.ac
. Unfortunately, it did not work and it resulted in postlink_cmds=""
in the generated libtool
. Here is something that does not work:
if test x"$postlink_cmds" = "x"; then
postlink_cmds="./postlink.sh"
else
postlink_cmds="~ ./postlink.sh"
fi
The ~
is due to the libtool
manual stating:
... The convention used for naming variables that hold shell commands for delayed evaluation, is to use the suffix _cmd where a single line of valid shell script is needed, and the suffix _cmds where multiple lines of shell script may be delayed for later evaluation. By convention, _cmds variables delimit the evaluation units with the ~ character where necessary.
Along the lines of option #3, you might in this case consider setting up one of the INSTALL
variables (INSTALL, INSTALL_DATA, INSTALL_PROGRAM, INSTALL_SCRIPT) and point it at a script that does what you want, and calls the real install
as the last step.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With