Use help2man in parallel automake - automake

I'm working on a project built using GNU autotools (autoconf, automake). It does work well, but I've a problem with help2man: When building parallel (MAKEFLAGS=-j3), the project is built twice - once using "normal" target, once using the foo.1 make call.
The following is the relevant part from Makefile.am:
foo.1 : $(top_srcdir)/man/foo.x $(top_srcdir)/src/main.c $(top_srcdir)/configure.ac
$(MAKE) $(AM_MAKEFLAGS) foo$(EXEEXT)
-$(HELP2MAN) -o $# --include $< $(top_builddir)/foo
So, my question is how to write Makefile.am to support the following:
Distribute foo.1 to support systems without help2man
Do not throw errors
Rebuild manpage if necessary
I'm looking forward to your answer

foo.1 needs correct prerequisites. AIUI, help2man just needs the executable binary to be built:
foo.1 : $(top_srcdir)/man/foo.x $(top_srcdir)/configure.ac $(top_builddir)/foo
-$(HELP2MAN) -o $# --include $< $(top_builddir)/foo
so that's 3)
don't understand what you want out of 2), which is not possible in general.
dist_man_MANS = foo.1
which is 1)

There seems to be no easy solution to this question; the following works for me.
In configure.ac, you have to check for help2man. If cross-compiling, you must not run help2man, as the executable will be run. The following snippet is therefore contained:
# Man pages
AS_IF([test "$cross_compiling" = "no"], [
AM_MISSING_PROG([HELP2MAN], [help2man])
], [
HELP2MAN=:
])
For building, there is a two-level concept. First, you check if the manpage is newer than the executable; if so, to prohibit unnecessary manpage rebuilds, you check against the source using a temporary file being last altered when the manpage itself was. So, Makefile.am contains:
dist_man_MANS = foo.1
EXTRA_DIST += $(dist_man_MANS:.1=.x) common.x
MOSTLYCLEANFILES += $(dist_man_MANS:=-t)
MAINTAINERCLEANFILES += $(dist_man_MANS)
common_dep = $(top_srcdir)/common.x $(top_srcdir)/configure.ac $(top_srcdir)/.version
common_indirect_dep = $(top_srcdir)/common.x $(top_srcdir)/configure $(top_srcdir)/.version
foo.1 : $(common_indirect_dep) $(top_builddir)/foo$(EXEEXT)
foo.1-t : $(common_dep) $(top_srcdir)/main-helpversion.c
SUFFIXES += .x .1 .1-t
.x.1:
test -f $# || if test -f $(top_srcdir)/`echo $# | $(SED) -e 's,.*/,,'`; then \
touch -r $(top_srcdir)/`echo $# | $(SED) -e 's,.*/,,'` $#; \
else \
touch -d #0 $#; \
fi
touch -r $# $#-t
$(MAKE) $(AM_MAKEFLAGS) $#-t
if test -s $#-t; then \
mv -f $#-t $#; \
else \
rm -f $#-t; \
if test -s $#; then touch $#; else rm -f $#; fi; \
fi
.x.1-t:
$(HELP2MAN) -o $# -I $< -I $(top_srcdir)/common.x -s 1 foo$(EXEEXT)

Related

GNU RISCV GCC Makefile.in all target recipe

RISCV-GCC Makefile.in
# The target built for a native non-bootstrap build.
all:
#if gcc-bootstrap
[ -f stage_final ] || echo stage3 > stage_final
#r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(MAKE) $(RECURSE_FLAGS_TO_PASS) `cat stage_final`-bubble
#endif gcc-bootstrap
#: $(MAKE); $(unstage)
#r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
#if gcc-bootstrap
if [ -f stage_last ]; then \
TFLAGS="$(STAGE$(shell test ! -f stage_last || sed s,^stage,, stage_last)_TFLAGS)"; \
$(MAKE) $(TARGET_FLAGS_TO_PASS) all-host all-target; \
else \
#endif gcc-bootstrap
$(MAKE) $(RECURSE_FLAGS_TO_PASS) all-host all-target \
#if gcc-bootstrap
; \
fi \
#endif gcc-bootstrap
&& :
What does this statement, #: $(MAKE); $(unstage), do in this recipe for target all?
I have tried to remove other statements but this one, and make this Makefile, it does nothing. However, according to the mechanism of make, it should invoke the recipe for first target if without dependencies, therefore it will spawn a new shell process to call make in current directory, which may lead to a indefinitively recursive call. But it just does nothing and terminate.
I am confused about what that statement, #: $(MAKE); $(unstage) do, and why need it there in recipe.

make fclean && make all works, make re doesn't

I'm working on an advanced makefile that I found in a book. I've got some simple rules inside:
clean to delete binaries
fclean to delete some extra files too (links to binaries generated by ln)
all to make all
re to make fclean then make all
when I do make fclean then make all, it works perfectly. When i do make re, an error occurs:
error: unable to open output file '/Users/malberte/work/libft/bin/libft/common/ft_atoi.o':
'No such file or directory'
1 error generated.
So here is my code:
$(_MODULE_NAME)_OBJS := $(addsuffix $(_OBJEXT),$(addprefix $($(_MODULE_NAME)_OUTPUT)/,$(basename $(SRCS)))) $(DEPS)
$(_MODULE_NAME)_BINARY := $($(_MODULE_NAME)_OUTPUT)/$(BINARY)$(BINARY_EXT)
$(_MODULE_NAME)_EXPOSE_BINARY := $(_ROOT)/$(BINARY)$(BINARY_EXT)
ifneq ($(_NO_RULES),T)
ifneq ($($(_MODULE_NAME)_DEFINED), T)
_CLEAN := clean-$(_MODULE_NAME)
_FCLEAN := fclean-$(_MODULE_NAME)
_ALL := all-$(_MODULE_NAME)
_RE := re-$(_MODULE_NAME)
_IGNORE := $(shell mkdir -p $($(_MODULE_NAME)_OUTPUT))
.PHONY: all re $(_ALL) $(_RE)
re: fclean all
# re: $(_RE)
# $(_RE): $(_FCLEAN) $(_ALL)
all: $(_ALL)
$(_ALL): $($(_MODULE_NAME)_BINARY)
.PHONY: $(_MODULE_NAME)
$(_MODULE_NAME): $($(_MODULE_NAME)_BINARY)
.PHONY: fclean clean $(_CLEAN)
fclean: $(_FCLEAN)
$(_FCLEAN): $(_CLEAN)
rm -rf $($(patsubst fclean-%,%,$#)_EXPOSE_BINARY)
clean: $(_CLEAN)
$(_CLEAN):
rm -rf $($(patsubst clean-%,%,$#)_OUTPUT)
$($(_MODULE_NAME)_OUTPUT)/%.o: $(_MODULE_PATH)/%.c
#$(COMPILE.c) -o '$#' '$<'
$($(_MODULE_NAME)_OUTPUT)/$(BINARY)$(_LIBEXT): $($(_MODULE_NAME)_OBJS)
#if [ "$(LIBMERGE)" = "F" ]; \
then \
$(AR) r '$#' $^; \
ranlib '$#'; \
else \
libtool -static -o '$#' $^; \
fi
$($(_MODULE_NAME)_OUTPUT)/$(BINARY)$(_EXEEXT): $($(_MODULE_NAME)_OBJS)
$(LINK.c) $^ -o '$#'
$(_MODULE_NAME)_DEFINED := T
endif
endif
I've tried lot of things, I really don't understand what is happening when I use make re and it throws the error above.
Someone has an idea please ?
You have this line in your makefile:
_IGNORE := $(shell mkdir -p $($(_MODULE_NAME)_OUTPUT))
which creates the output directory, as the makefile is being parsed. Then you run your clean target which invokes this recipe:
rm -rf $($(patsubst clean-%,%,$#)_OUTPUT)
which causes the output directory to be deleted. Then you run your all target which invokes the compiler and asks it to write the output file to $($(_MODULE_NAME)_OUTPUT)/%.o but that directory no longer exists.
So the compiler gives you the error:
error: unable to open output file '...': No such file or directory
If you run make twice, then the first time you clean and delete the directory, then when you run make all it will run the _IGNORE shell command and create the directory again so it will exist.
If you run make re one time, then the makefile is only parsed one time and the output directory is only created one time (before it's deleted).
Okay thank you so much. It drove me to think about how a makefile really works, so here is my basic solution, thanks to you:
$(_MODULE_NAME)_OBJS := $(addsuffix $(_OBJEXT),$(addprefix $($(_MODULE_NAME)_OUTPUT)/,$(basename $(SRCS)))) $(DEPS)
$(_MODULE_NAME)_BINARY := $($(_MODULE_NAME)_OUTPUT)/$(BINARY)$(BINARY_EXT)
$(_MODULE_NAME)_EXPOSE_BINARY := $(_ROOT)/$(BINARY)$(BINARY_EXT)
ifneq ($(_NO_RULES),T)
ifneq ($($(_MODULE_NAME)_DEFINED), T)
_OUTPUT_TREE := output-tree-$(_MODULE_NAME)
_CLEAN := clean-$(_MODULE_NAME)
_FCLEAN := fclean-$(_MODULE_NAME)
_ALL := all-$(_MODULE_NAME)
_RE := re-$(_MODULE_NAME)
# _IGNORE := $(shell mkdir -p $($(_MODULE_NAME)_OUTPUT))
.PHONY: all re $(_ALL) $(_RE)
re: fclean all
# re: $(_RE)
# $(_RE): $(_FCLEAN) $(_ALL)
all: $(_ALL)
$(_ALL): $($(_MODULE_NAME)_BINARY)
.PHONY: $(_MODULE_NAME)
$(_MODULE_NAME): $($(_MODULE_NAME)_BINARY)
.PHONY: fclean clean $(_CLEAN)
fclean: $(_FCLEAN)
$(_FCLEAN): $(_CLEAN)
rm -rf $($(patsubst fclean-%,%,$#)_EXPOSE_BINARY)
clean: $(_CLEAN)
$(_CLEAN):
rm -rf $($(patsubst clean-%,%,$#)_OUTPUT)
$($(_MODULE_NAME)_OUTPUT)/%.o: $(_MODULE_PATH)/%.c | $(_OUTPUT_TREE)
#$(COMPILE.c) -o '$#' '$<'
$($(_MODULE_NAME)_OUTPUT)/$(BINARY)$(_LIBEXT): $($(_MODULE_NAME)_OBJS)
#if [ "$(LIBMERGE)" = "F" ]; \
then \
$(AR) r '$#' $^; \
ranlib '$#'; \
else \
libtool -static -o '$#' $^; \
fi
$($(_MODULE_NAME)_OUTPUT)/$(BINARY)$(_EXEEXT): $($(_MODULE_NAME)_OBJS)
$(LINK.c) $^ -o '$#'
.PHONY: output-tree $(_OUTPUT_TREE)
output-tree: $(_OUTPUT_TREE)
$(_OUTPUT_TREE):
mkdir -p $($(_MODULE_NAME)_OUTPUT)
$(_MODULE_NAME)_DEFINED := T
endif
endif
I added a prerequisite order to the atomic target
$($(_MODULE_NAME)_OUTPUT)/%.o: $(_MODULE_PATH)/%.c | $(_OUTPUT_TREE)
Here is the rule:
.PHONY: output-tree $(_OUTPUT_TREE)
output-tree: $(_OUTPUT_TREE)
$(_OUTPUT_TREE):
mkdir -p $($(_MODULE_NAME)_OUTPUT)
I'll see if I need more adjustments but it seems to be the right way !

Makefile improvement when intermediate files do not really change

I have a Makefile like this
all: *.foo
./finalstep *.foo > $#
%.foo: %.bar
./secondstep < $< > $#
%.bar: %.baz
./firststep < $< > $#
The thing is that often changes in a .baz file are minor in the sense that the .bar file produced after the change is the same (content-wise, or as would be detected by diff) as before the change.
Since secondstep and finalstep (and possible some more intermediate steps) are expensive it would be preferable if the lack of change in the .bar files could be detected and thus the invocation of secondstep (and maybe even finalstep) spared. Is there any way to achieve this?
My attempt to do something like this is as follows:
%.bar: %.baz
touch $#; cp $# $#.backup; ./firststep < $< > $#
%.foo: %.bar
diff -q $< $<.backup || ./secondstep < $< > $#
But this has a lot of drawbacks (and does not work correctly if one invokes make with arguments).
Is there any better method? Basically, make should consider two different filetimes for .bar files: One that gets updated each time firststep is run and that is used to determine whether .bar itself needs to be remade. Another that is only updated when a run of firststep results in a net change of content of the file and that is used to determine whethr .foo needs to be remade ...
I think you should experiment with something like this (not tested):
all: %.foo
./finalstep %.foo > $#
%.foo: %.bar
#if [[ -f $< && -f $<.backup ]]; then \
if diff -q $< $<.backup; then \
echo "IDENTICAL => do nothing"; \
else \
echo "DIFFERENT => proceed"; \
./secondstep < $< > $#; \
fi; \
else \
echo "NOT FOUND => proceed"; \
./secondstep < $< > $#; \
fi; \
cp $< $<.backup
%.bar: %.baz
./firststep < $< > $#;
Basically, the intention of the big recipe is to handle all the relevant combinations of $< and $<.backup (in the same subshell!):
both files present and equal (diff returns 0) => do nothing
both files present and differ (diff returns 1) => execute
one of the files not present => execute
Whatever is the above choice, make a backup at the end.

How To test the exit status, and do something in Makefile

I'm trying to do this ..... and this is how my Makefile look like
.PHONY: run
SHELL := /bin/tcsh
run:
md5sum -c md; \
if ($$?==0) then \
echo "PASS" \
else \
echo "FAIL" \
endif
But i got this error.
if: Badly formed number.
make: *** [run] Error 1
Is what I'm doing correct? Or is there a better way of doing that in a Makefile?
Basically, you should simply not, ever, use csh (or tcsh) for writing makefile rules. Write the rule using POSIX shell:
.PHONY: run
run:
md5sum -c md; \
if [ $$? -eq 0 ]; then \
echo "PASS"; \
else \
echo "FAIL"; \
fi

Eliminating duplication in a Makefile

This is the same Makefile as in Makefile command substitution problem, but a different question.
REBAR=./rebar
REBAR_DEBUG=$(REBAR) -C rebar.debug.config
REBAR_COMPILE=$(REBAR) get-deps compile
LAST_CONFIG:=$(shell cat config.tmp)
PLT=dialyzer/sqlite3.plt
all: config_normal compile
compile:
$(REBAR_COMPILE)
test:
$(REBAR_COMPILE) eunit
clean:
-rm -rf deps ebin priv doc/* .eunit c_src/*.o
docs:
$(REBAR_COMPILE) doc
static: config_debug
$(REBAR_DEBUG) get-deps compile
ifeq ($(wildcard $(PLT)),)
dialyzer --build_plt --apps kernel stdlib erts --output_plt $(PLT)
else
dialyzer --plt $(PLT) -r ebin
endif
cross_compile: config_cross
$(REBAR_COMPILE) -C rebar.cross_compile.config
valgrind: clean
$(REBAR_DEBUG) get-deps compile
valgrind --tool=memcheck --leak-check=yes --num-callers=20 ./test.sh
ifeq ($(LAST_CONFIG),normal)
config_normal:
echo "$(LAST_CONFIG) == normal"
else
config_normal: clean
echo "$(LAST_CONFIG) != normal"
rm -f config.tmp
echo "normal" > config.tmp
endif
ifeq ($(LAST_CONFIG),debug)
config_debug: ;
else
config_debug: clean
rm -f config.tmp
echo "debug" > config.tmp
endif
ifeq ($(LAST_CONFIG),cross)
config_cross: ;
else
config_cross: clean
rm -f config.tmp
echo "cross" > config.tmp
endif
.PHONY: all compile test clean docs static valgrind config_normal config_debug config_cross
How can I eliminate (or significantly decrease) the duplication between config_normal, config_debug, and config_cross?
If you are using at least version 3.80 of GNU make, you can use $(eval) to create the rules from a template, like this:
define templ
ifeq ($$(LAST_CONFIG),$(config))
config_$(config):
echo "$$(LAST_CONFIG) == $(config)"
else
config_$(config):
echo "$$(LAST_CONFIG) != $(config)"
rm -f config.tmp
echo "$(config)" > config.tmp
endif
endef
$(foreach config,normal debug cross,$(eval $(templ)))

Resources