# Main Makefile for Sage.
# The default target ("all") builds Sage and the whole (HTML) documentation.
#
# Target "build" just builds Sage.
#
# See below for targets to build the documentation in other formats,
# to run various types of test suites, and to remove parts of the build etc.
default: all
all: base-toolchain
$(MAKE) all-start
build: base-toolchain
$(MAKE) all-build
build-local: base-toolchain
$(MAKE) all-build-local
build-venv: base-toolchain
$(MAKE) all-build-venv
start: base-toolchain
$(MAKE) build-start
sageruntime: base-toolchain
$(MAKE) all-sageruntime
SAGE_ROOT_LOGS = logs
# The --stop flag below is just a random flag to induce graceful
# breakage with non-GNU versions of make.
# See https://github.com/sagemath/sage/issues/24617
# Defer unknown targets to build/make/Makefile
%::
@if [ -x relocate-once.py ]; then ./relocate-once.py; fi
$(MAKE) build/make/Makefile --stop
+build/bin/sage-logger \
"cd build/make && ./install '$@'" logs/install.log
# CONFIG_FILES lists all files that appear in AC_CONFIG_FILES in configure.ac;
# except for build/make/Makefile-auto, which is unused by the build system
CONFIG_FILES = build/make/Makefile src/bin/sage-env-config build/bin/sage-build-env-config
# SPKG_COLLECT_FILES contains the files that influence the *runtime* of the
# portions of the 'configure' script generated by the SAGE_SPKG_COLLECT macro
SPKG_COLLECT_FILES = build/pkgs/*/package-version.txt build/pkgs/*/dependencies*
# If configure was not run before, complain.
# If configure is newer than the files it generated (we test build/make/Makefile),
# we regenerate config.status by running the "config.status --recheck".
# Either way we regenerate the generated files by calling "config.status".
build/make/Makefile: configure $(SPKG_COLLECT_FILES) $(CONFIG_FILES:%=%.in)
@if [ -x config.status ]; then \
case '$?' in \
*configure*|*package-version*|*dependencies*) \
$(MAKE) reconfigure;; \
*) \
./config.status;; \
esac; \
else \
$(MAKE) reconfigure; \
fi
reconfigure:
rm -f config.log
mkdir -p logs/pkgs
ln -s logs/pkgs/config.log config.log
@if [ -x config.status ]; then \
./config.status --recheck && ./config.status; \
else \
echo >&2 '****************************************************************************'; \
echo >&2 'error: Sage source tree is unconfigured. Please run "./configure" first.'; \
echo >&2 'note: Type "./configure --help" to see the available configuration options.'; \
echo >&2 '****************************************************************************'; \
exit 1; \
fi
# Preemptively download all source tarballs of normal packages.
DOWNLOAD_PACKAGES=:all:
download:
export SAGE_ROOT=$$(pwd) && \
export PATH=$$SAGE_ROOT/build/bin:$$PATH && \
sage-package download $(DOWNLOAD_PACKAGES)
dist: build/make/Makefile
./sage --sdist
ci-build-with-fallback:
$(MAKE) build && $(MAKE) SAGE_CHECK=no pypi-wheels; \
if [ $$? != 0 ]; then \
echo "Incremental build failed, falling back"; \
$(MAKE) doc-clean doc-uninstall sagelib-clean; \
$(MAKE) build && $(MAKE) SAGE_CHECK=no pypi-wheels; \
fi
###############################################################################
# Cleaning up
###############################################################################
SAGE_ROOT = $(CURDIR)
SAGE_SRC = $(SAGE_ROOT)/src
clean:
@echo "Deleting package build directories..."
if [ -f "$(SAGE_SRC)"/bin/sage-env-config ]; then \
. "$(SAGE_SRC)"/bin/sage-env-config; \
if [ -n "$$SAGE_LOCAL" ]; then \
rm -rf "$$SAGE_LOCAL/var/tmp/sage/build"; \
fi; \
fi
# "c_lib", ".cython_version", "build" in $(SAGE_SRC) are from old sage versions
# Cleaning .so files (and .c and .cpp files associated with .pyx files), cython_debug and "sagelib/src/build" is for old editable installs.
sagelib-clean:
@echo "Deleting Sage library build artifacts..."
if [ -d "$(SAGE_SRC)" ]; then \
(cd "$(SAGE_SRC)" && \
rm -rf c_lib .cython_version cython_debug; \
rm -rf build; find . -name '*.pyc' -o -name "*.so" | xargs rm -f; \
rm -f $$(find . -name "*.pyx" | sed 's/\(.*\)[.]pyx$$/\1.c \1.cpp/'); \
cd sage/ext/interpreters/ && rm -f *.so *.c *.h *.py* *.pxd) \
&& rm -rf "$(SAGE_ROOT)"/build/pkgs/sagelib/src/build; \
fi
# Don't use "meson setup --wipe "$$d";" due to https://github.com/sagemath/sage/pull/39030#issuecomment-3021583924
@echo "Wiping meson build directories..."
rm -rf "$(SAGE_ROOT)/build/sage-distro"
sage_docbuild-clean:
(cd "$(SAGE_ROOT)/build/pkgs/sage_docbuild/src" && rm -rf build)
sage_setup-clean:
(cd "$(SAGE_ROOT)/build/pkgs/sage_setup/src" && rm -rf build)
build-clean: clean doc-clean sagelib-clean sage_docbuild-clean
doc-clean:
if [ -f "$(SAGE_SRC)"/bin/sage-env-config ]; then \
. "$(SAGE_SRC)"/bin/sage-env-config; \
if [ -n "$$SAGE_LOCAL" ]; then \
rm -rf "$$SAGE_LOCAL/share/doc/sage/inventory"; \
rm -rf "$$SAGE_LOCAL/share/doc/sage/doctrees"; \
fi; \
fi; \
cd "$(SAGE_SRC)/doc" && $(MAKE) clean
# Deleting src/lib is to get rid of src/lib/pkgconfig
# that was forgotten to clean in #29082.
misc-clean:
@echo "Deleting build artifacts generated by autoconf, automake, make ..."
rm -rf logs
rm -rf dist
rm -rf tmp
rm -f aclocal.m4 config.log confcache
rm -rf autom4te.cache
rm -f build/make/Makefile build/make/Makefile-auto
rm -f build/platform/meson/sage-configure-native-file.ini
rm -rf src/lib
bdist-clean: clean
$(MAKE) misc-clean
@echo "Deleting build artifacts generated by configure ..."
rm -f config.status
distclean: build-clean
$(MAKE) misc-clean
@echo "Deleting all remaining output from build system ..."
rm -rf local
rm -f src/bin/sage-env-config
rm -f prefix venv
# Delete all auto-generated files which are distributed as part of the
# source tarball
bootstrap-clean:
rm -rf config/install-sh config/compile config/config.guess config/config.sub config/missing configure build/make/Makefile-auto.in
rm -f src/doc/en/installation/*.txt
find src/doc/en/reference/spkg -maxdepth 1 -name index.rst -prune -o -name "*.rst" -exec rm -f {} \+
for a in environment environment-optional src/environment src/environment-optional; do rm -f $$a.yml $$a-3.[89].yml $$a-3.1[0-9].yml; done
rm -f build/pkgs/cypari/version_requirements.txt
rm -f build/pkgs/cysignals/version_requirements.txt
rm -f build/pkgs/cython/version_requirements.txt
rm -f build/pkgs/gmpy2/version_requirements.txt
rm -f build/pkgs/jupyter_core/version_requirements.txt
rm -f build/pkgs/memory_allocator/version_requirements.txt
rm -f build/pkgs/numpy/version_requirements.txt
rm -f build/pkgs/pkgconfig/version_requirements.txt
rm -f build/pkgs/pplpy/version_requirements.txt
rm -f build/pkgs/setuptools/version_requirements.txt
rm -f build/pkgs/wheel/version_requirements.txt
# Remove absolutely everything which isn't part of the git repo
maintainer-clean: distclean bootstrap-clean
rm -rf upstream
# Remove everything that is not necessary to run Sage and pass all its
# doctests.
micro_release:
$(MAKE) sagelib-clean
$(MAKE) misc-clean
@echo "Stripping binaries ..."
LC_ALL=C find local/lib local/bin local/var/lib/sage/venv-python* -type f -exec strip '{}' ';' 2>&1 | grep -v "File format not recognized" | grep -v "File truncated" || true
@echo "Removing sphinx artifacts..."
rm -rf local/share/doc/sage/doctrees local/share/doc/sage/inventory
@echo "Removing documentation. Inspection in IPython still works."
rm -rf local/share/doc local/share/*/doc local/share/*/examples local/share/singular/html
@echo "Removing unnecessary files & directories - make will not be functional afterwards anymore"
@# We keep src/sage for some doctests that it expect it to be there and
@# also because it does not add any weight with rdfind below.
@# We need src/bin/ for the scripts that invoke Sage
@# We need sage, the script to start Sage
@# We need local/, the dependencies and the built Sage library itself.
@# We keep VERSION.txt.
@# We keep COPYING.txt so we ship a license with this distribution.
find . -name . -o -prune ! -name config.status ! -name src ! -name sage ! -name local ! -name VERSION.txt ! -name COPYING.txt ! -name build -exec rm -rf \{\} \;
cd src && find . -name . -o -prune ! -name sage ! -name bin -exec rm -rf \{\} \;
if command -v rdfind > /dev/null; then \
echo "Hardlinking identical files."; \
rdfind -makeresultsfile false -makehardlinks true .; \
else \
echo "rdfind not installed. Not hardlinking identical files."; \
fi
# Leaves everything that is needed to make the next "make" fast but removes
# all the cheap build artifacts that can be quickly regenerated.
# Issue #30960: We no longer uninstall sagelib.
fast-rebuild-clean: misc-clean
rm -rf upstream/
rm -rf build/pkgs/sagelib/src/build/temp.*
# The .py files in src/build are restored from src/sage without their
# mtimes changed.
-find build/pkgs/sagelib/src/build -name '*.py' -exec rm \{\} \;
# Remove leftovers from ancient branches
rm -rf src/build
###############################################################################
# Testing
###############################################################################
TEST_LOG = $(SAGE_ROOT_LOGS)/test.log
TEST_FILES = --all
TEST_FLAGS =
# When the documentation is installed, "optional" also includes all tests marked 'sagemath_doc_html',
# see https://github.com/sagemath/sage/issues/25345, https://github.com/sagemath/sage/issues/26110, and
# https://github.com/sagemath/sage/issues/32759
TEST_OPTIONAL = sage,optional
# Keep track of the top-level *test* Makefile target for logging.
TEST_TARGET = $@
TEST = ./sage -t --logfile=$(TEST_LOG) $(TEST_FLAGS) --optional=$(TEST_OPTIONAL) $(TEST_FILES)
test-git-no-uncommitted-changes:
./tools/test-git-no-uncommitted-changes
test: all
@echo '### make $(TEST_TARGET): Running $(TEST)' >> $(TEST_LOG)
$(TEST); \
$(MAKE) test-git-no-uncommitted-changes
check:
@$(MAKE) test
testall:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_OPTIONAL="$(TEST_OPTIONAL),external" test
testlong:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" test
testalllong:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" testall
ptest:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) -p" test
ptestall:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_OPTIONAL="$(TEST_OPTIONAL),external" ptest
ptestlong:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" ptest
ptestalllong:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" ptestall
testoptional:
@echo "'make $@' is deprecated; use 'make test'"
@$(MAKE) test
testoptionallong:
@echo "'make $@' is deprecated; use 'make testlong'"
@$(MAKE) testlong
ptestoptional:
@echo "'make $@' is deprecated; use 'make ptest'"
@$(MAKE) ptest
ptestoptionallong:
@echo "'make $@' is deprecated; use 'make ptestlong'"
@$(MAKE) ptestlong
# *test*-nodoc targets skip the docbuild and skip all tests that depend on the documentation
test-nodoc: TEST_OPTIONAL := $(TEST_OPTIONAL),!sagemath_doc_html,!sagemath_doc_pdf
test-nodoc: build
@echo '### make $(TEST_TARGET): Running $(TEST)' >> $(TEST_LOG)
$(TEST); \
$(MAKE) test-git-no-uncommitted-changes
check-nodoc:
@$(MAKE) test-nodoc
testall-nodoc:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_OPTIONAL="$(TEST_OPTIONAL),external" test-nodoc
testlong-nodoc:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" test-nodoc
testalllong-nodoc:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" testall-nodoc
ptest-nodoc:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) -p" test-nodoc
ptestall-nodoc:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_OPTIONAL="$(TEST_OPTIONAL),external" ptest-nodoc
ptestlong-nodoc:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" ptest-nodoc
ptestalllong-nodoc:
@$(MAKE) TEST_TARGET="$(TEST_TARGET)" TEST_FLAGS="$(TEST_FLAGS) --long" ptestall-nodoc
testoptional-nodoc:
@echo "'make $@' is deprecated; use 'make test-nodoc'"
@$(MAKE) test-nodoc
testoptionallong-nodoc:
@echo "'make $@' is deprecated; use 'make testlong-nodoc'"
@$(MAKE) testlong-nodoc
ptestoptional-nodoc:
@echo "'make $@' is deprecated; use 'make ptest-nodoc'"
@$(MAKE) ptest-nodoc
ptestoptionallong-nodoc:
@echo "'make $@' is deprecated; use 'make ptestlong-nodoc'"
@$(MAKE) ptestlong-nodoc
###############################################################################
# The 'configure' script is just one of the files generated by 'bootstrap'.
# CONFIGURE_DEPENDENCIES is the list of files that influence the generation of 'configure'.
CONFIGURE_DEPENDENCIES = \
configure.ac src/bin/sage-version.sh m4/*.m4 \
pyproject.toml \
build/pkgs/*/spkg-configure.m4 \
build/pkgs/*/type build/pkgs/*/SPKG.rst \
build/pkgs/*/checksums.ini build/pkgs/*/requirements.txt \
build/pkgs/*/version_requirements.txt build/pkgs/*/package-version.txt \
build/pkgs/*/spkg-install build/pkgs/*/spkg-install.in
# SPKG_INFO_DEPENDENCIES is the list of files that influence the run of 'sage-spkg-info' and hence
# the generation of the files generated in 'src/doc' by 'src/doc/bootstrap'.
SPKG_INFO_DEPENDENCIES = \
build/pkgs/*/type build/pkgs/*/SPKG.rst \
build/pkgs/*/requirements.txt \
build/pkgs/*/version_requirements.txt build/pkgs/*/package-version.txt \
build/pkgs/*/distros/*.txt
configure: bootstrap src/doc/bootstrap $(CONFIGURE_DEPENDENCIES) $(SPKG_INFO_DEPENDENCIES)
./bootstrap -d
install: all
@echo "******************************************************************"
@echo "The '$@' target is a no-op; 'make' already does 'make install'"
@echo "You can change the install prefix from its default"
@echo "(the subdirectory 'local') by using ./configure --prefix=PREFIX"
@echo "You can also consider using the binary packaging scripts"
@echo "from https://github.com/sagemath/binary-pkg"
@echo "******************************************************************"
# Setting SAGE_PKGCONFIG is only so that make does not exit with
# "This Makefile needs to be invoked by build/make/install".
list:
@$(MAKE) --silent build/make/Makefile >&2
@$(MAKE) --silent -f build/make/Makefile SAGE_PKGCONFIG=dummy $@
.PHONY: default build dist install micro_release reconfigure \
misc-clean bdist-clean distclean bootstrap-clean maintainer-clean \
test check testoptional testall testlong testoptionallong testallong \
ptest ptestoptional ptestall ptestlong ptestoptionallong ptestallong \
test-git-no-uncommitted-changes \
list \
doc-clean clean sagelib-clean build-clean