build: replace ninjatool with ninja

Now that the build is done entirely by Meson, there is no need
to keep the Makefile conversion.  Instead, we can ask Ninja about
the targets it exposes and forward them.

The main advantages are, from smallest to largest:

- reducing the possible namespace pollution within the Makefile

- removal of a relatively large Python program

- faster build because parsing Makefile.ninja is slower than
parsing build.ninja; and faster build after Meson runs because
we do not have to generate Makefile.ninja.

- tracking of command lines, which provides more accurate rebuilds

In addition the change removes the requirement for GNU make 3.82, which
was annoying on Mac, and avoids bugs on Windows due to ninjatool not
knowing how to convert Windows escapes to POSIX escapes.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2020-08-13 09:28:11 -04:00
parent 2b8575bd5f
commit 09e93326e4
7 changed files with 59 additions and 1053 deletions

View File

@ -72,27 +72,8 @@ git-submodule-update:
endif
endif
export NINJA=./ninjatool
# 0. ensure the build tree is okay
# Running meson regenerates both build.ninja and ninjatool, and that is
# enough to prime the rest of the build.
ninjatool: build.ninja
Makefile.ninja: build.ninja ninjatool
./ninjatool -t ninja2make --omit clean dist uninstall cscope TAGS ctags < $< > $@
-include Makefile.ninja
${ninja-targets-c_COMPILER} ${ninja-targets-cpp_COMPILER}: .var.command += -MP
# If MESON is empty, the rule will be re-evaluated after Makefiles are
# reread (and MESON won't be empty anymore).
ifneq ($(MESON),)
Makefile.mtest: build.ninja scripts/mtest2make.py
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
-include Makefile.mtest
endif
# Ensure the build tree is okay.
# Check that we're not trying to do an out-of-tree build from
# a tree that's been used for an in-tree build.
ifneq ($(realpath $(SRC_PATH)),$(realpath .))
@ -117,6 +98,7 @@ ifeq ($(wildcard build.ninja),)
x := $(shell rm -rf meson-private meson-info meson-logs)
endif
# 1. ensure config-host.mak is up-to-date
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
@echo $@ is out-of-date, running configure
@if test -f meson-private/coredata.dat; then \
@ -125,6 +107,46 @@ config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
./config.status; \
fi
# 2. ensure generated build files are up-to-date
ifneq ($(NINJA),)
# A separate rule is needed for Makefile dependencies to avoid -n
export NINJA
Makefile.ninja: build.ninja
$(quiet-@){ echo 'ninja-targets = \'; $(NINJA) -t targets all | sed 's/:.*//; $$!s/$$/ \\/'; } > $@
-include Makefile.ninja
endif
ifneq ($(MESON),)
# The dependency on config-host.mak ensures that meson has run
Makefile.mtest: build.ninja scripts/mtest2make.py config-host.mak
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
-include Makefile.mtest
endif
# 3. Rules to bridge to other makefiles
ifneq ($(NINJA),)
NINJAFLAGS = $(if $V,-v,) \
$(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \
$(subst -k, -k0, $(filter -n -k,$(MAKEFLAGS)))
ninja-cmd-goals = $(or $(MAKECMDGOALS), all)
ninja-cmd-goals += $(foreach t, $(.tests), $(.test.deps.$t))
makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall
ninja-targets := $(filter-out $(makefile-targets), $(ninja-targets))
.PHONY: $(ninja-targets) run-ninja
$(ninja-targets): run-ninja
# Use "| cat" to give Ninja a more "make-y" output. Use "+" to bypass the
# --output-sync line.
run-ninja: config-host.mak
ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),)
+@$(NINJA) $(NINJAFLAGS) $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat
endif
endif
# Force configure to re-run if the API symbols are updated
ifeq ($(CONFIG_PLUGIN),y)
config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols
@ -144,13 +166,6 @@ ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fa
endif
endif # config-host.mak does not exist
# Only needed in case Makefile.ninja does not exist.
.PHONY: ninja-clean ninja-distclean clean-ctlist
clean-ctlist:
ninja-clean::
ninja-distclean::
build.ninja: config-host.mak
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet)
include $(SRC_PATH)/tests/Makefile.include
@ -170,8 +185,9 @@ recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
######################################################################
clean: recurse-clean ninja-clean clean-ctlist
if test -f ninjatool; then ./ninjatool $(if $(V),-v,) -t clean; fi
clean: recurse-clean
-@test -f build.ninja && $(quiet-@)$(NINJA) $(NINJAFLAGS) -t clean || :
-@test -f build.ninja && $(NINJA) $(NINJAFLAGS) clean-ctlist || :
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
find . \( -name '*.so' -o -name '*.dll' -o -name '*.[oda]' \) -type f \
@ -188,8 +204,8 @@ dist: qemu-$(VERSION).tar.bz2
qemu-%.tar.bz2:
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
distclean: clean ninja-distclean
-test -f ninjatool && ./ninjatool $(if $(V),-v,) -t clean -g
distclean: clean
-@test -f build.ninja && $(quiet-@)$(NINJA) $(NINJAFLAGS) -t clean -g || :
rm -f config-host.mak config-host.h*
rm -f tests/tcg/config-*.mak
rm -f config-all-disas.mak config.status
@ -198,7 +214,7 @@ distclean: clean ninja-distclean
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
rm -f *-config-target.h *-config-devices.mak *-config-devices.h
rm -rf meson-private meson-logs meson-info compile_commands.json
rm -f Makefile.ninja ninjatool ninjatool.stamp Makefile.mtest
rm -f Makefile.ninja Makefile.mtest
rm -f config.log
rm -f linux-headers/asm
rm -Rf .sdk

9
configure vendored
View File

@ -1905,7 +1905,7 @@ case "$meson" in
*) meson=$(command -v "$meson") ;;
esac
# Probe for ninja (used for compdb)
# Probe for ninja
if test -z "$ninja"; then
for c in ninja ninja-build samu; do
@ -1914,6 +1914,9 @@ if test -z "$ninja"; then
break
fi
done
if test -z "$ninja"; then
error_exit "Cannot find Ninja"
fi
fi
# Check that the C compiler works. Doing this here before testing
@ -6779,6 +6782,7 @@ echo "PYTHON=$python" >> $config_host_mak
echo "SPHINX_BUILD=$sphinx_build" >> $config_host_mak
echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
echo "MESON=$meson" >> $config_host_mak
echo "NINJA=$ninja" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
if $iasl -h > /dev/null 2>&1; then
echo "CONFIG_IASL=$iasl" >> $config_host_mak
@ -7030,7 +7034,7 @@ fi
mv $cross config-meson.cross
rm -rf meson-private meson-info meson-logs
NINJA=${ninja:-$PWD/ninjatool} $meson setup \
NINJA=$ninja $meson setup \
--prefix "$prefix" \
--libdir "$libdir" \
--libexecdir "$libexecdir" \
@ -7063,7 +7067,6 @@ NINJA=${ninja:-$PWD/ninjatool} $meson setup \
if test "$?" -ne 0 ; then
error_exit "meson setup failed"
fi
touch ninjatool.stamp
fi
if test -n "${deprecated_features}"; then

View File

@ -404,10 +404,8 @@ Built by Meson:
Built by Makefile:
`Makefile.ninja`
A Makefile conversion of the build rules in build.ninja. The conversion
is straightforward and, were it necessary to debug the rules produced
by Meson, it should be enough to look at build.ninja. The conversion
is performed by scripts/ninjatool.py.
A Makefile include that bridges to ninja for the actual build. The
Makefile is mostly a list of targets that Meson included in build.ninja.
`Makefile.mtest`
The Makefile definitions that let "make check" run tests defined in

View File

@ -47,10 +47,6 @@ supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64'
cpu = host_machine.cpu_family()
targetos = host_machine.system()
configure_file(input: files('scripts/ninjatool.py'),
output: 'ninjatool',
configuration: config_host)
if cpu in ['x86', 'x86_64']
kvm_targets = ['i386-softmmu', 'x86_64-softmmu']
elif cpu == 'aarch64'

View File

@ -70,8 +70,9 @@ def process_tests(test, targets, suites):
print('.test.driver.%d := %s' % (i, driver))
print('.test.env.%d := $(.test.env) %s' % (i, env))
print('.test.cmd.%d := %s' % (i, cmd))
print('.test.deps.%d := %s' % (i, ' '.join(deps)))
print('.PHONY: run-test-%d' % (i,))
print('run-test-%d: %s' % (i, ' '.join(deps)))
print('run-test-%d: $(.test.deps.%d)' % (i,i))
print('\t@$(call .test.run,%d,$(.test.output-format))' % (i,))
test_suites = test['suite'] or ['default']

File diff suppressed because it is too large Load Diff

View File

@ -140,7 +140,7 @@ QEMU_IOTESTS_HELPERS-$(CONFIG_LINUX) = tests/qemu-iotests/socket_scm_helper$(EXE
check: check-block
check-block: $(SRC_PATH)/tests/check-block.sh qemu-img$(EXESUF) \
qemu-io$(EXESUF) qemu-nbd$(EXESUF) $(QEMU_IOTESTS_HELPERS-y) \
$(filter qemu-system-%, $(ninja-targets-c_LINKER) $(ninja-targets-cpp_LINKER))
$(filter qemu-system-%, $(ninja-targets))
@$<
endif