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
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 # 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. # a tree that's been used for an in-tree build.
ifneq ($(realpath $(SRC_PATH)),$(realpath .)) ifneq ($(realpath $(SRC_PATH)),$(realpath .))
@ -117,6 +98,7 @@ ifeq ($(wildcard build.ninja),)
x := $(shell rm -rf meson-private meson-info meson-logs) x := $(shell rm -rf meson-private meson-info meson-logs)
endif endif
# 1. ensure config-host.mak is up-to-date
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
@echo $@ is out-of-date, running configure @echo $@ is out-of-date, running configure
@if test -f meson-private/coredata.dat; then \ @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; \ ./config.status; \
fi 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 # Force configure to re-run if the API symbols are updated
ifeq ($(CONFIG_PLUGIN),y) ifeq ($(CONFIG_PLUGIN),y)
config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols
@ -144,13 +166,6 @@ ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fa
endif endif
endif # config-host.mak does not exist 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) SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet)
include $(SRC_PATH)/tests/Makefile.include include $(SRC_PATH)/tests/Makefile.include
@ -170,8 +185,9 @@ recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
###################################################################### ######################################################################
clean: recurse-clean ninja-clean clean-ctlist clean: recurse-clean
if test -f ninjatool; then ./ninjatool $(if $(V),-v,) -t clean; fi -@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 # 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 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 \ find . \( -name '*.so' -o -name '*.dll' -o -name '*.[oda]' \) -type f \
@ -188,8 +204,8 @@ dist: qemu-$(VERSION).tar.bz2
qemu-%.tar.bz2: qemu-%.tar.bz2:
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)" $(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
distclean: clean ninja-distclean distclean: clean
-test -f ninjatool && ./ninjatool $(if $(V),-v,) -t clean -g -@test -f build.ninja && $(quiet-@)$(NINJA) $(NINJAFLAGS) -t clean -g || :
rm -f config-host.mak config-host.h* rm -f config-host.mak config-host.h*
rm -f tests/tcg/config-*.mak rm -f tests/tcg/config-*.mak
rm -f config-all-disas.mak config.status 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 qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
rm -f *-config-target.h *-config-devices.mak *-config-devices.h rm -f *-config-target.h *-config-devices.mak *-config-devices.h
rm -rf meson-private meson-logs meson-info compile_commands.json 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 config.log
rm -f linux-headers/asm rm -f linux-headers/asm
rm -Rf .sdk rm -Rf .sdk

9
configure vendored
View File

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

View File

@ -404,10 +404,8 @@ Built by Meson:
Built by Makefile: Built by Makefile:
`Makefile.ninja` `Makefile.ninja`
A Makefile conversion of the build rules in build.ninja. The conversion A Makefile include that bridges to ninja for the actual build. The
is straightforward and, were it necessary to debug the rules produced Makefile is mostly a list of targets that Meson included in build.ninja.
by Meson, it should be enough to look at build.ninja. The conversion
is performed by scripts/ninjatool.py.
`Makefile.mtest` `Makefile.mtest`
The Makefile definitions that let "make check" run tests defined in 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() cpu = host_machine.cpu_family()
targetos = host_machine.system() targetos = host_machine.system()
configure_file(input: files('scripts/ninjatool.py'),
output: 'ninjatool',
configuration: config_host)
if cpu in ['x86', 'x86_64'] if cpu in ['x86', 'x86_64']
kvm_targets = ['i386-softmmu', 'x86_64-softmmu'] kvm_targets = ['i386-softmmu', 'x86_64-softmmu']
elif cpu == 'aarch64' elif cpu == 'aarch64'

View File

@ -70,8 +70,9 @@ def process_tests(test, targets, suites):
print('.test.driver.%d := %s' % (i, driver)) print('.test.driver.%d := %s' % (i, driver))
print('.test.env.%d := $(.test.env) %s' % (i, env)) print('.test.env.%d := $(.test.env) %s' % (i, env))
print('.test.cmd.%d := %s' % (i, cmd)) print('.test.cmd.%d := %s' % (i, cmd))
print('.test.deps.%d := %s' % (i, ' '.join(deps)))
print('.PHONY: run-test-%d' % (i,)) 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,)) print('\t@$(call .test.run,%d,$(.test.output-format))' % (i,))
test_suites = test['suite'] or ['default'] 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: check-block
check-block: $(SRC_PATH)/tests/check-block.sh qemu-img$(EXESUF) \ check-block: $(SRC_PATH)/tests/check-block.sh qemu-img$(EXESUF) \
qemu-io$(EXESUF) qemu-nbd$(EXESUF) $(QEMU_IOTESTS_HELPERS-y) \ 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 endif