Makefile 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. PYTHON?=python
  2. PYTHON3?=python3
  3. TESTFLAGS=-p -v
  4. TESTOPTS=
  5. SETUPFLAGS=
  6. LXMLVERSION:=$(shell $(PYTHON3) -c 'import re; print(re.findall(r"__version__\s*=\s*\"([^\"]+)\"", open("src/lxml/__init__.py").read())[0])' )
  7. PARALLEL?=$(shell $(PYTHON) -c 'import sys; print("-j7" if sys.version_info >= (3, 5) else "")' )
  8. PARALLEL3?=$(shell $(PYTHON3) -c 'import sys; print("-j7" if sys.version_info >= (3, 5) else "")' )
  9. PYTHON_WITH_CYTHON?=$(shell $(PYTHON) -c 'import Cython.Build.Dependencies' >/dev/null 2>/dev/null && echo " --with-cython" || true)
  10. PY3_WITH_CYTHON?=$(shell $(PYTHON3) -c 'import Cython.Build.Dependencies' >/dev/null 2>/dev/null && echo " --with-cython" || true)
  11. CYTHON_WITH_COVERAGE?=$(shell $(PYTHON) -c 'import Cython.Coverage; import sys; assert not hasattr(sys, "pypy_version_info")' >/dev/null 2>/dev/null && echo " --coverage" || true)
  12. CYTHON3_WITH_COVERAGE?=$(shell $(PYTHON3) -c 'import Cython.Coverage; import sys; assert not hasattr(sys, "pypy_version_info")' >/dev/null 2>/dev/null && echo " --coverage" || true)
  13. PYTHON_BUILD_VERSION ?= *
  14. MANYLINUX_LIBXML2_VERSION=2.9.14
  15. MANYLINUX_LIBXSLT_VERSION=1.1.35
  16. MANYLINUX_CFLAGS=-O3 -g1 -pipe -fPIC -flto
  17. MANYLINUX_LDFLAGS=-flto
  18. MANYLINUX_IMAGES= \
  19. manylinux1_x86_64 \
  20. manylinux1_i686 \
  21. manylinux_2_24_x86_64 \
  22. manylinux_2_24_i686 \
  23. manylinux2014_aarch64 \
  24. manylinux_2_24_aarch64 \
  25. manylinux_2_24_ppc64le \
  26. manylinux_2_24_s390x \
  27. musllinux_1_1_x86_64 \
  28. musllinux_1_1_aarch64
  29. .PHONY: all inplace inplace3 rebuild-sdist sdist build require-cython wheel_manylinux wheel
  30. all: inplace
  31. # Build in-place
  32. inplace:
  33. $(PYTHON) setup.py $(SETUPFLAGS) build_ext -i $(PYTHON_WITH_CYTHON) --warnings $(subst --,--with-,$(CYTHON_WITH_COVERAGE)) $(PARALLEL)
  34. inplace3:
  35. $(PYTHON3) setup.py $(SETUPFLAGS) build_ext -i $(PY3_WITH_CYTHON) --warnings $(subst --,--with-,$(CYTHON3_WITH_COVERAGE)) $(PARALLEL3)
  36. rebuild-sdist: require-cython
  37. rm -f dist/lxml-$(LXMLVERSION).tar.gz
  38. find src -name '*.c' -exec rm -f {} \;
  39. $(MAKE) dist/lxml-$(LXMLVERSION).tar.gz
  40. dist/lxml-$(LXMLVERSION).tar.gz:
  41. $(PYTHON) setup.py $(SETUPFLAGS) sdist $(PYTHON_WITH_CYTHON)
  42. sdist: dist/lxml-$(LXMLVERSION).tar.gz
  43. build:
  44. $(PYTHON) setup.py $(SETUPFLAGS) build $(PYTHON_WITH_CYTHON)
  45. require-cython:
  46. @[ -n "$(PYTHON_WITH_CYTHON)" ] || { \
  47. echo "NOTE: missing Cython - please use this command to install it: $(PYTHON) -m pip install Cython"; false; }
  48. qemu-user-static:
  49. docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
  50. wheel_manylinux: $(addprefix wheel_,$(MANYLINUX_IMAGES))
  51. $(addprefix wheel_,$(filter-out %_x86_64, $(filter-out %_i686, $(MANYLINUX_IMAGES)))): qemu-user-static
  52. wheel_%: dist/lxml-$(LXMLVERSION).tar.gz
  53. time docker run --rm -t \
  54. -v $(shell pwd):/io \
  55. -e AR=gcc-ar \
  56. -e NM=gcc-nm \
  57. -e RANLIB=gcc-ranlib \
  58. -e CFLAGS="$(MANYLINUX_CFLAGS) $(if $(patsubst %aarch64,,$@),-march=core2,-march=armv8-a -mtune=cortex-a72)" \
  59. -e LDFLAGS="$(MANYLINUX_LDFLAGS)" \
  60. -e LIBXML2_VERSION="$(MANYLINUX_LIBXML2_VERSION)" \
  61. -e LIBXSLT_VERSION="$(MANYLINUX_LIBXSLT_VERSION)" \
  62. -e PYTHON_BUILD_VERSION="$(PYTHON_BUILD_VERSION)" \
  63. -e WHEELHOUSE=$(subst wheel_,wheelhouse/,$@) \
  64. quay.io/pypa/$(subst wheel_,,$@) \
  65. bash /io/tools/manylinux/build-wheels.sh /io/$<
  66. wheel:
  67. $(PYTHON) setup.py $(SETUPFLAGS) bdist_wheel $(PYTHON_WITH_CYTHON)
  68. wheel_static:
  69. $(PYTHON) setup.py $(SETUPFLAGS) bdist_wheel $(PYTHON_WITH_CYTHON) --static-deps
  70. test_build: build
  71. $(PYTHON) test.py $(TESTFLAGS) $(TESTOPTS)
  72. test_inplace: inplace
  73. $(PYTHON) test.py $(TESTFLAGS) $(TESTOPTS) $(CYTHON_WITH_COVERAGE)
  74. test_inplace3: inplace3
  75. $(PYTHON3) test.py $(TESTFLAGS) $(TESTOPTS) $(CYTHON3_WITH_COVERAGE)
  76. valgrind_test_inplace: inplace
  77. valgrind --tool=memcheck --leak-check=full --num-callers=30 --suppressions=valgrind-python.supp \
  78. $(PYTHON) test.py
  79. fuzz: clean
  80. $(MAKE) \
  81. CC="/usr/bin/clang" \
  82. CFLAGS="$$CFLAGS -fsanitize=fuzzer-no-link -g2" \
  83. CXX="/usr/bin/clang++" \
  84. CXXFLAGS="-fsanitize=fuzzer-no-link" \
  85. inplace3
  86. $(PYTHON3) src/lxml/tests/fuzz_xml_parse.py
  87. gdb_test_inplace: inplace
  88. @echo "file $(PYTHON)\nrun test.py" > .gdb.command
  89. gdb -x .gdb.command -d src -d src/lxml
  90. bench_inplace: inplace
  91. $(PYTHON) benchmark/bench_etree.py -i
  92. $(PYTHON) benchmark/bench_xpath.py -i
  93. $(PYTHON) benchmark/bench_xslt.py -i
  94. $(PYTHON) benchmark/bench_objectify.py -i
  95. ftest_build: build
  96. $(PYTHON) test.py -f $(TESTFLAGS) $(TESTOPTS)
  97. ftest_inplace: inplace
  98. $(PYTHON) test.py -f $(TESTFLAGS) $(TESTOPTS)
  99. apidoc: apidocclean inplace3
  100. @[ -x "`which sphinx-apidoc`" ] \
  101. && (echo "Generating API docs ..." && \
  102. PYTHONPATH=src:$(PYTHONPATH) sphinx-apidoc -e -P -T -o doc/api src/lxml \
  103. "*includes" "*tests" "*pyclasslookup.py" "*usedoctest.py" "*html/_html5builder.py" \
  104. "*.so" "*.pyd") \
  105. || (echo "not generating Sphinx autodoc API rst files")
  106. apihtml: apidoc inplace3
  107. @[ -x "`which sphinx-build`" ] \
  108. && (echo "Generating API docs ..." && \
  109. make -C doc/api html) \
  110. || (echo "not generating Sphinx autodoc API documentation")
  111. website: inplace3 docclean
  112. PYTHONPATH=src:$(PYTHONPATH) $(PYTHON3) doc/mkhtml.py doc/html . ${LXMLVERSION}
  113. html: apihtml website s5
  114. s5:
  115. $(MAKE) -C doc/s5 slides
  116. apipdf: apidoc inplace3
  117. rm -fr doc/api/_build
  118. @[ -x "`which sphinx-build`" ] \
  119. && (echo "Generating API PDF docs ..." && \
  120. make -C doc/api latexpdf) \
  121. || (echo "not generating Sphinx autodoc API PDF documentation")
  122. pdf: apipdf pdfclean
  123. $(PYTHON) doc/mklatex.py doc/pdf . ${LXMLVERSION}
  124. (cd doc/pdf && pdflatex lxmldoc.tex \
  125. && pdflatex lxmldoc.tex \
  126. && pdflatex lxmldoc.tex)
  127. @cp doc/pdf/lxmldoc.pdf doc/pdf/lxmldoc-${LXMLVERSION}.pdf
  128. @echo "PDF available as doc/pdf/lxmldoc-${LXMLVERSION}.pdf"
  129. # Two pdflatex runs are needed to build the correct Table of contents.
  130. test: test_inplace
  131. test3: test_inplace3
  132. valtest: valgrind_test_inplace
  133. gdbtest: gdb_test_inplace
  134. bench: bench_inplace
  135. ftest: ftest_inplace
  136. clean:
  137. find . \( -name '*.o' -o -name '*.so' -o -name '*.py[cod]' -o -name '*.dll' \) -exec rm -f {} \;
  138. rm -rf build
  139. docclean:
  140. $(MAKE) -C doc/s5 clean
  141. rm -f doc/html/*.html
  142. pdfclean:
  143. rm -fr doc/pdf
  144. apidocclean:
  145. rm -fr doc/html/api
  146. rm -f doc/api/lxml*.rst
  147. rm -fr doc/api/_build
  148. realclean: clean docclean apidocclean
  149. find src -name '*.c' -exec rm -f {} \;
  150. rm -f TAGS
  151. $(PYTHON) setup.py clean -a --without-cython