Commit b9eb4482 authored by Michael Droettboom's avatar Michael Droettboom Committed by GitHub

Merge pull request #56 from iodide-project/packaging

MVP of a proper packaging system
parents 5285facd c68233c7
......@@ -17,13 +17,13 @@ jobs:
# Set up the Debian testing repo, and then install g++ from there...
sudo bash -c "echo \"deb http://ftp.us.debian.org/debian testing main contrib non-free\" >> /etc/apt/sources.list"
sudo apt-get update
sudo apt-get install node-less cmake build-essential clang-format-6.0 flake8 uglifyjs
sudo apt-get install node-less cmake build-essential clang-format-6.0 flake8 uglifyjs python3-yaml
sudo apt-get install -t testing g++-8
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-6
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 80 --slave /usr/bin/g++ g++ /usr/bin/g++-8
sudo update-alternatives --set gcc /usr/bin/gcc-8
sudo pip install pytest-xdist selenium
sudo pip install pytest-xdist selenium PyYAML
# Get recent version of Firefox and geckodriver
wget -O firefox.tar.bz2 https://download.mozilla.org/\?product\=firefox-nightly-latest-ssl\&os\=linux64\&lang\=en-US
......
......@@ -7,7 +7,10 @@ charset = utf-8
indent_size = 2
indent_style = space
[*.py]
[**.py]
indent_size = 4
[tools/*]
indent_size = 4
[Makefile]
......
*.bc
*.a
*.o
*.pyc
.patched
.built
.packaged
.pytest_cache/
__pycache__
geckodriver.log
......@@ -15,8 +19,4 @@ installs
/emsdk/emsdk
/dateutil/python-dateutil-2.7.2
/pytz/pytz-2018.4
/six/six-1.11.0
/cycler/cycler-0.10.0
/pyparsing/pyparsing-2.2.0
......@@ -33,41 +33,9 @@ LDFLAGS=\
-lstdc++ \
--memory-init-file 0
NUMPY_ROOT=numpy/build/numpy
NUMPY_LIBS=\
$(NUMPY_ROOT)/core/multiarray.so \
$(NUMPY_ROOT)/core/umath.so \
$(NUMPY_ROOT)/linalg/lapack_lite.so \
$(NUMPY_ROOT)/linalg/_umath_linalg.so \
$(NUMPY_ROOT)/random/mtrand.so \
$(NUMPY_ROOT)/fft/fftpack_lite.so
PANDAS_ROOT=pandas/build/pandas
PANDAS_LIBS=\
$(PANDAS_ROOT)/_libs/lib.so
MATPLOTLIB_ROOT=matplotlib/build/matplotlib
MATPLOTLIB_LIBS=\
$(MATPLOTLIB_ROOT)/_path.so
DATEUTIL_ROOT=dateutil/python-dateutil-2.7.2/build/lib/dateutil
DATEUTIL_LIBS=$(DATEUTIL_ROOT)/__init__.py
PYTZ_ROOT=pytz/pytz-2018.4/build/lib/pytz
PYTZ_LIBS=$(PYTZ_ROOT)/__init__.py
SIX_ROOT=six/six-1.11.0/build/lib
SIX_LIBS=$(SIX_ROOT)/six.py
PYPARSING_ROOT=pyparsing/pyparsing-2.2.0/build/lib
PYPARSING_LIBS=$(PYPARSING_ROOT)/pyparsing.py
CYCLER_ROOT=cycler/cycler-0.10.0/build/lib
CYCLER_LIBS=$(CYCLER_ROOT)/cycler.py
KIWISOLVER_ROOT=kiwisolver/build
KIWISOLVER_LIBS=$(KIWISOLVER_ROOT)/kiwisolver.so
SITEPACKAGES=root/lib/python$(PYMINOR)/site-packages
all: build/pyodide.asm.js \
......@@ -79,14 +47,7 @@ all: build/pyodide.asm.js \
build/matplotlib-sideload.html \
build/renderedhtml.css \
build/test.data \
build/numpy.data \
build/dateutil.data \
build/pytz.data \
build/pandas.data \
build/matplotlib.data \
build/kiwisolver.data \
build/pyparsing.data \
build/cycler.data
build/packages.json
build/pyodide.asm.js: src/main.bc src/jsimport.bc src/jsproxy.bc src/js2python.bc \
......@@ -142,8 +103,10 @@ test: all build/test.html
lint:
flake8 src
flake8 test
flake8 tools/*
clang-format -output-replacements-xml src/*.c src/*.h src/*.js | (! grep '<replacement ')
benchmark: all build/test.html
python benchmark/benchmark.py $(HOSTPYTHON) build/benchmarks.json
python benchmark/plot_benchmark.py build/benchmarks.json build/benchmarks.png
......@@ -153,52 +116,18 @@ clean:
rm -fr root
rm build/*
rm src/*.bc
echo "CPython and Numpy builds are not cleaned. cd into those directories to do so."
%.bc: %.cpp $(CPYTHONLIB)
$(CXX) --bind -o $@ $< $(CXXFLAGS)
make -C packages clean
make -C six clean
echo "The Emsdk and CPython are not cleaned. cd into those directories to do so."
%.bc: %.c $(CPYTHONLIB)
$(CC) -o $@ $< $(CFLAGS)
# TODO: It would be nice to generalize this
build/numpy.data: $(NUMPY_LIBS)
./packager.sh numpy $(NUMPY_ROOT)@/lib/python3.6/site-packages/numpy
build/dateutil.data: $(DATEUTIL_LIBS)
./packager.sh dateutil $(DATEUTIL_ROOT)@/lib/python3.6/site-packages/dateutil
build/pytz.data: $(PYTZ_LIBS)
./packager.sh pytz $(PYTZ_ROOT)@/lib/python3.6/site-packages/pytz
build/pandas.data: $(PANDAS_LIBS)
./packager.sh pandas $(PANDAS_ROOT)@/lib/python3.6/site-packages/pandas
build/matplotlib.data: $(MATPLOTLIB_LIBS)
./packager.sh matplotlib $(MATPLOTLIB_ROOT)@/lib/python3.6/site-packages/matplotlib
build/kiwisolver.data: $(KIWISOLVER_LIBS)
./packager.sh kiwisolver kiwisolver/build@/lib/python3.6/site-packages
build/cycler.data: $(CYCLER_LIBS)
./packager.sh cycler $(CYCLER_ROOT)@/lib/python3.6/site-packages
build/pyparsing.data: $(PYPARSING_LIBS)
./packager.sh pyparsing $(PYPARSING_ROOT)@/lib/python3.6/site-packages
build/test.data: $(CPYTHONLIB)
./packager.sh test $(CPYTHONLIB)/test@/lib/python3.6/test
python2 $(FILEPACKAGER) build/test.data --preload $(CPYTHONLIB)/test@/lib/python3.6/test --js-output=build/test.js --export-name=pyodide --exclude \*.wasm.pre --exclude __pycache__
uglifyjs build/test.js -o build/test.js
root/.built: \
......@@ -232,40 +161,12 @@ $(CPYTHONLIB): emsdk/emsdk/emsdk
make -C $(CPYTHONROOT)
$(NUMPY_LIBS): $(CPYTHONLIB)
make -C numpy
$(PANDAS_LIBS): $(NUMPY_LIBS)
make -C pandas
$(MATPLOTLIB_LIBS): $(NUMPY_LIBS)
make -C matplotlib
$(DATEUTIL_LIBS): $(CPYTHONLIB)
make -C dateutil
$(PYTZ_LIBS): $(CPYTHONLIB)
make -C pytz
$(SIX_LIBS): $(CPYTHONLIB)
make -C six
$(PYPARSING_LIBS): $(CPYTHONLIB)
make -C pyparsing
$(CYCLER_LIBS): $(CPYTHONLIB)
make -C cycler
$(KIWISOLVER_LIBS): $(CPYTHONLIB)
make -C kiwisolver
build/packages.json: $(CPYTHONLIB)
make -C packages
emsdk/emsdk/emsdk:
......
export PATH := $(PYODIDE_ROOT)/emsdk/emsdk:$(PYODIDE_ROOT)/emsdk/emsdk/clang/tag-e-1.38.4/build_tag-e1.38.4_64/bin:$(PYODIDE_ROOT)/emsdk/emsdk/node/8.9.1_64bit/bin:$(PYODIDE_ROOT)/emsdk/emsdk/emscripten/tag-1.38.4:$(PYODIDE_ROOT)/emsdk/emsdk/binaryen/tag-1.38.4_64bit_binaryen/bin:$(PATH)
export EMSDK = $(PYODIDE_ROOT)/emsdk/emsdk
export EM_CONFIG = $(PYODIDE_ROOT)/emsdk/emsdk/.emscripten
export EM_CACHE = $(PYODIDE_ROOT)/emsdk/emsdk/.emscripten_cache
......@@ -9,10 +8,10 @@ export BINARYEN_ROOT = $(PYODIDE_ROOT)/emsdk/emsdk/binaryen/tag-1.38.4_64bit_bin
export PYVERSION=3.6.4
export PYMINOR=$(basename $(PYVERSION))
export HOSTPYTHONINSTALL=$(PYODIDE_ROOT)/cpython/build/$(PYVERSION)/host
export HOSTPYTHON=$(HOSTPYTHONINSTALL)/bin/python3
export HOSTPYTHONROOT=$(PYODIDE_ROOT)/cpython/build/$(PYVERSION)/host
export HOSTPYTHON=$(HOSTPYTHONROOT)/bin/python3
export TARGETPYTHONROOT=$(PYODIDE_ROOT)/cpython/installs/python-$(PYVERSION)
export PYTHONINCLUDE=$(PYODIDE_ROOT)/cpython/installs/python-$(PYVERSION)/include/python$(PYMINOR)
export PLATFORMSLUG=$(shell $(HOSTPYTHON) -c "import sysconfig; print(sysconfig.get_platform())")-$(PYMINOR)
export SIDE_LDFLAGS=\
-O3 \
......
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
CYCLERVERSION=0.10.0
ROOT=$(abspath .)
SRC=$(ROOT)/cycler-$(CYCLERVERSION)
BUILD=$(SRC)/build/lib/dateutil
TARBALL=$(ROOT)/downloads/cycler-$(CYCLERVERSION).tgz
URL=https://files.pythonhosted.org/packages/c2/4b/137dea450d6e1e3d474e1d873cd1d4f7d3beed7e0dc973b06e8e10d32488/cycler-0.10.0.tar.gz
all: $(BUILD)/__init__.py
clean:
-rm -fr downloads
-rm -fr $(SRC)
$(TARBALL):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(SRC)/setup.py: $(TARBALL)
tar -C . -xf $(TARBALL)
touch $(SRC)/setup.py
$(BUILD)/__init__.py: $(ROOT)/.patched
( \
cd $(SRC) ; \
$(HOSTPYTHON) setup.py build ; \
touch build/lib/cycler.py \
)
$(ROOT)/.patched: $(SRC)/setup.py
cat patches/*.patch | (cd $(SRC) ; patch -p1)
touch $@
4cb42917ac5007d1cdff6cccfe2d016b downloads/cycler-0.10.0.tgz
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
DATEUTILVERSION=2.7.2
ROOT=$(abspath .)
SRC=$(ROOT)/python-dateutil-$(DATEUTILVERSION)
BUILD=$(SRC)/build/lib/dateutil
TARBALL=$(ROOT)/downloads/python-dateutil-$(DATEUTILVERSION).tgz
URL=https://files.pythonhosted.org/packages/c5/39/4da7c2dbc4f023fba5fb2325febcadf0d0ce0efdc8bd12083a0f65d20653/python-dateutil-2.7.2.tar.gz
all: $(BUILD)/__init__.py
clean:
-rm -fr downloads
-rm -fr $(SRC)
$(TARBALL):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(SRC)/setup.py: $(TARBALL)
tar -C . -xf $(TARBALL)
touch $(SRC)/setup.py
$(BUILD)/__init__.py: $(ROOT)/.patched
( \
cd $(SRC) ; \
$(HOSTPYTHON) setup.py build ; \
touch build/lib/dateutil/__init__.py \
)
$(ROOT)/.patched: $(SRC)/setup.py
cat patches/*.patch | (cd $(SRC) ; patch -p1)
touch $@
03a08c8bcf0a2b29f1cd21b9de4d12fb ./downloads/python-dateutil-2.7.2.tgz
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
KIWIVERSION=1.0.1
NPYVERSION=1.14.1
ROOT=$(abspath .)
HOSTROOT=$(ROOT)/host
HOSTDIR=$(HOSTROOT)/kiwisolver-$(KIWIVERSION)
HOSTBUILD=$(HOSTDIR)/build
HOSTSRC=$(HOSTDIR)/src
BUILD=$(ROOT)/build
TARBALL=$(ROOT)/downloads/kiwisolver-$(KIWIVERSION).tar.gz
URL=https://files.pythonhosted.org/packages/31/60/494fcce70d60a598c32ee00e71542e52e27c978e5f8219fae0d4ac6e2864/kiwisolver-1.0.1.tar.gz
CC=emcc
CXX=em++
AR=emar
CFLAGS=-Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I$(HOSTSRC) -I../numpy/host/numpy-$(NPYVERSION)/build/src.$(PLATFORMSLUG)/numpy/core/include/numpy -I$(PYTHONINCLUDE) -I$(HOSTDIR) -Wno-unused-function
OBJECTS= \
$(BUILD)/kiwisolver.so
all:
make $(ROOT)/.patched
make $(OBJECTS)
clean:
rm -fr $(HOSTROOT)
rm -fr $(BUILD)
$(TARBALL):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(HOSTDIR)/setup.py: $(TARBALL)
[ -d $(HOSTROOT) ] || mkdir $(HOSTROOT)
tar -xf $(TARBALL) -C $(HOSTROOT)
touch $(HOSTDIR)/setup.py
$(BUILD)/kiwisolver.so: \
$(HOSTDIR)/py/kiwisolver.bc \
$(HOSTDIR)/py/constraint.bc \
$(HOSTDIR)/py/expression.bc \
$(HOSTDIR)/py/solver.bc \
$(HOSTDIR)/py/strength.bc \
$(HOSTDIR)/py/term.bc \
$(HOSTDIR)/py/variable.bc \
| .patched
[ -d $(ROOT)/build ] || mkdir $(ROOT)/build
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
rm $@.wasm.pre
$(ROOT)/.patched: $(HOSTDIR)/setup.py
cat patches/*.patch | (cd $(HOSTDIR) ; patch -p1)
touch $@
%.bc: %.c
$(CC) $(CFLAGS) -c $< -o $@
%.bc: %.cpp
$(CXX) $(CFLAGS) -c $< -o $@
e2a1718b837e2cd001f7c06934616fcd downloads/kiwisolver-1.0.1.tar.gz
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
MPLVERSION=2.2.2
NPYVERSION=1.14.1
ROOT=$(abspath .)
HOSTROOT=$(ROOT)/host
HOSTDIR=$(HOSTROOT)/matplotlib-$(MPLVERSION)
HOSTBUILD=$(HOSTDIR)/build
HOSTSRC=$(HOSTDIR)/src
HOSTLIB=$(HOSTDIR)/lib/matplotlib
AGGINC=$(HOSTDIR)/extern/agg24-svn/include
AGGSRC=$(HOSTDIR)/extern/agg24-svn/src
TTCONVSRC=$(HOSTDIR)/extern/ttconv
QHULLSRC=$(HOSTDIR)/extern/libqhull
BUILD=$(ROOT)/build/matplotlib
TARBALL=$(ROOT)/downloads/matplotlib-$(MPLVERSION).tar.gz
URL=https://files.pythonhosted.org/packages/ec/ed/46b835da53b7ed05bd4c6cae293f13ec26e877d2e490a53a709915a9dcb7/matplotlib-2.2.2.tar.gz
CC=emcc
CXX=em++
AR=emar
CFLAGS=-Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I$(HOSTSRC) -I../numpy/host/numpy-$(NPYVERSION)/numpy/core/include -I../numpy/config -I../numpy/host/numpy-$(NPYVERSION)/build/src.$(PLATFORMSLUG)/numpy/core/include/numpy -I$(PYTHONINCLUDE) -Wno-unused-function -s USE_FREETYPE=1 -s USE_LIBPNG=1 -s USE_ZLIB=1 -I$(AGGINC) -I$(HOSTDIR)/extern -I$(HOSTDIR) -DMPL_DEVNULL=/dev/null -D__STDC_FORMAT_MACROS=1 -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION
OBJECTS= \
$(BUILD)/ft2font.so \
$(BUILD)/_png.so \
$(BUILD)/_image.so \
$(BUILD)/ttconv.so \
$(BUILD)/_path.so \
$(BUILD)/_contour.so \
$(BUILD)/backends/_backend_agg.so \
$(BUILD)/_tri.so \
$(BUILD)/_qhull.so
AGGOBJECTS = \
$(AGGSRC)/agg_bezier_arc.bc \
$(AGGSRC)/agg_curves.bc \
$(AGGSRC)/agg_image_filters.bc \
$(AGGSRC)/agg_trans_affine.bc \
$(AGGSRC)/agg_vcgen_contour.bc \
$(AGGSRC)/agg_vcgen_dash.bc \
$(AGGSRC)/agg_vcgen_stroke.bc \
$(AGGSRC)/agg_vpgen_segmentator.bc
all:
make $(BUILD)/__init__.py
make $(OBJECTS)
clean:
rm -fr $(HOSTROOT)
rm -fr $(BUILD)
$(TARBALL):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(HOSTDIR)/setup.py: $(TARBALL)
[ -d $(HOSTROOT) ] || mkdir $(HOSTROOT)
tar -xf $(TARBALL) -C $(HOSTROOT)
cp $(ROOT)/setup.cfg $(HOSTDIR)
touch $(HOSTDIR)/setup.py
$(HOSTBUILD)/lib.$(PLATFORMSLUG)/matplotlib/__init__.py: $(ROOT)/.patched
( \
cd $(HOSTDIR); \
$(HOSTPYTHON) setup.py build \
)
$(BUILD)/__init__.py: $(HOSTBUILD)/lib.$(PLATFORMSLUG)/matplotlib/__init__.py
[ -d $(ROOT)/build ] || mkdir $(ROOT)/build
cp -r $(HOSTBUILD)/lib.$(PLATFORMSLUG)/matplotlib $(ROOT)/build && \
cp $(ROOT)/fontList.json $(BUILD)
cp $(ROOT)/src/wasm_backend.py $(BUILD)/backends
( \
cd $(BUILD); \
find . -name "*.so" -type f -delete; \
rm -rf backends/qt_editor; \
rm -rf backends/web_backend; \
rm -rf sphinxext; \
)
$(ROOT)/.patched: $(HOSTDIR)/setup.py
cat patches/*.patch | (cd $(HOSTDIR) ; patch -p1)
touch $@
$(BUILD)/ft2font.so: \
$(HOSTSRC)/ft2font.bc \
$(HOSTSRC)/ft2font_wrapper.bc \
$(HOSTSRC)/mplutils.bc
$(CC) $(SIDE_LDFLAGS) -lfreetype $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_png.so: \
$(HOSTSRC)/_png.bc
$(CC) ../emsdk/emsdk/.emscripten_cache/asmjs/libpng.bc $^ -o $@.wasm $(SIDE_LDFLAGS)
mv $@.wasm $@
$(BUILD)/_image.so: \
$(HOSTSRC)/_image.bc \
$(HOSTSRC)/_image_wrapper.bc \
$(HOSTSRC)/mplutils.bc \
$(HOSTSRC)/py_converters.bc \
$(AGGOBJECTS)
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/ttconv.so: \
$(HOSTSRC)/_ttconv.bc \
$(TTCONVSRC)/pprdrv_tt.bc \
$(TTCONVSRC)/pprdrv_tt2.bc \
$(TTCONVSRC)/ttutil.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_path.so: \
$(HOSTSRC)/py_converters.bc \
$(HOSTSRC)/_path_wrapper.bc \
$(AGGOBJECTS)
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_contour.so: \
$(HOSTSRC)/_contour.bc \
$(HOSTSRC)/_contour_wrapper.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_qhull.so: \
$(HOSTSRC)/qhull_wrap.bc \
$(QHULLSRC)/geom.bc \
$(QHULLSRC)/geom2.bc \
$(QHULLSRC)/global.bc \
$(QHULLSRC)/io.bc \
$(QHULLSRC)/libqhull.bc \
$(QHULLSRC)/mem.bc \
$(QHULLSRC)/merge.bc \
$(QHULLSRC)/poly.bc \
$(QHULLSRC)/poly2.bc \
$(QHULLSRC)/qset.bc \
$(QHULLSRC)/random.bc \
$(QHULLSRC)/rboxlib.bc \
$(QHULLSRC)/stat.bc \
$(QHULLSRC)/user.bc \
$(QHULLSRC)/usermem.bc \
$(QHULLSRC)/userprintf.bc \
$(QHULLSRC)/userprintf_rbox.bc
$(CC) $(SIDE_LDFLAGS) -lm $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_tri.so: \
$(HOSTLIB)/tri/_tri.bc \
$(HOSTLIB)/tri/_tri_wrapper.bc \
$(HOSTSRC)/mplutils.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/backends/_backend_agg.so: \
$(HOSTSRC)/mplutils.bc \
$(HOSTSRC)/py_converters.bc \
$(HOSTSRC)/_backend_agg.bc \
$(HOSTSRC)/_backend_agg_wrapper.bc \
$(AGGOBJECTS)
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
%.bc: %.c
$(CC) -DPY_ARRAY_UNIQUE_SYMBOL=_path_array_api $(CFLAGS) -c $< -o $@
%.bc: %.cpp
$(CXX) -DPY_ARRAY_UNIQUE_SYMBOL=_path_array_api $(CFLAGS) -c $< -o $@
dd1e49e041309a7fd4e32be8bf17c3b6 ./downloads/matplotlib-2.2.2.tar.gz
\ No newline at end of file
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
NPYVERSION=1.14.1
ROOT=$(abspath .)
HOSTROOT=$(ROOT)/host
HOSTDIR=$(HOSTROOT)/numpy-$(NPYVERSION)
HOSTBUILD=$(HOSTDIR)/build
BUILD=$(ROOT)/build
BUILDCORE=$(BUILD)/numpy/core
BUILDLINALG=$(BUILD)/numpy/linalg
BUILDFFT=$(BUILD)/numpy/fft
BUILDRANDOM=$(BUILD)/numpy/random
ZIPFILE=$(ROOT)/downloads/numpy-$(NPYVERSION).zip
URL=https://pypi.python.org/packages/a3/99/74aa456fc740a7e8f733af4e8302d8e61e123367ec660cd89c53a3cd4d70/numpy-1.14.1.zip
INCLUDE=$(HOSTDIR)/numpy/core/include
SRC=$(HOSTDIR)/numpy/core/src
GENINCLUDE=$(HOSTBUILD)/src.$(PLATFORMSLUG)/numpy/core/include
GENSRC=$(HOSTBUILD)/src.$(PLATFORMSLUG)/numpy/core/src
LINALG_SRC=$(HOSTDIR)/numpy/linalg
LINALG_GENSRC=$(HOSTBUILD)/src.$(PLATFORMSLUG)/numpy/linalg
FFT_SRC=$(HOSTDIR)/numpy/fft
RANDOM_SRC=$(HOSTDIR)/numpy/random
CC=emcc
AR=emar
CFLAGS=-O3 -Werror -std=c99 -DNPY_INTERNAL_BUILD=1 -DHAVE_NPY_CONFIG_H=1 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -I$(ROOT)/config -I$(INCLUDE) -I$(GENINCLUDE)/numpy -I$(INCLUDE)/private -I$(SRC) -I$(SRC)/.. -I$(SRC)/private -I$(SRC)/npymath -I$(SRC)/multiarray -I$(SRC)/umath -I$(SRC)/npysort -I$(PYTHONINCLUDE) -I$(GENSRC)/private -I$(GENSRC)/npymath -I$(GENSRC)/umath
OBJECTS= \
$(BUILDCORE)/multiarray.so \
$(BUILDCORE)/umath.so \
$(BUILDLINALG)/lapack_lite.so \
$(BUILDLINALG)/_umath_linalg.so \
$(BUILDRANDOM)/mtrand.so \
$(BUILDFFT)/fftpack_lite.so
all:
make $(BUILD)/numpy/__init__.py
make $(OBJECTS)
clean:
rm -fr $(HOSTROOT)
rm -fr $(BUILD)
$(ZIPFILE):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(HOSTDIR)/setup.py: $(ZIPFILE)
[ -d $(HOSTROOT) ] || mkdir $(HOSTROOT)
unzip $(ZIPFILE) -d $(HOSTROOT)
touch $(HOSTDIR)/setup.py
$(HOSTBUILD)/lib.$(PLATFORMSLUG)/numpy/__init__.py: $(ROOT)/.patched
( \
cd $(HOSTDIR); \
$(HOSTPYTHON) setup.py install; \
touch $(HOSTBUILD)/lib.$(PLATFORMSLUG)/numpy/__init__.py \
)
$(BUILD)/numpy/__init__.py: $(HOSTBUILD)/lib.$(PLATFORMSLUG)/numpy/__init__.py
[ -d $(BUILD) ] || mkdir $(BUILD)
cp -r $(HOSTBUILD)/lib.$(PLATFORMSLUG)/numpy $(BUILD) && \
cd $(BUILD); find . -name "*.so" -type f -delete
$(ROOT)/.patched: $(HOSTDIR)/setup.py
cat patches/*.patch | (cd $(HOSTDIR) ; patch -p1)
touch $@
NPYMATH_SRC=\
$(GENSRC)/npymath/ieee754.bc \
$(GENSRC)/npymath/npy_math_complex.bc \
$(SRC)/npymath/halffloat.bc \
$(SRC)/npymath/npy_math.bc \
NPYSORT_SRC=\
$(GENSRC)/npysort/binsearch.bc \
$(GENSRC)/npysort/heapsort.bc \
$(GENSRC)/npysort/mergesort.bc \
$(GENSRC)/npysort/quicksort.bc \
$(GENSRC)/npysort/selection.bc \
MULTIARRAY_SRC=\
$(GENSRC)/multiarray/arraytypes.bc \
$(GENSRC)/multiarray/einsum.bc \
$(GENSRC)/multiarray/lowlevel_strided_loops.bc \
$(GENSRC)/multiarray/nditer_templ.bc \
$(GENSRC)/multiarray/scalartypes.bc \
$(SRC)/multiarray/alloc.bc \
$(SRC)/multiarray/array_assign.bc \
$(SRC)/multiarray/array_assign_array.bc \
$(SRC)/multiarray/array_assign_scalar.bc \
$(SRC)/multiarray/arrayobject.bc \
$(SRC)/multiarray/buffer.bc \
$(SRC)/multiarray/calculation.bc \
$(SRC)/multiarray/common.bc \
$(SRC)/multiarray/compiled_base.bc \
$(SRC)/multiarray/conversion_utils.bc \
$(SRC)/multiarray/convert.bc \
$(SRC)/multiarray/convert_datatype.bc \
$(SRC)/multiarray/ctors.bc \
$(SRC)/multiarray/datetime.bc \
$(SRC)/multiarray/datetime_busday.bc \
$(SRC)/multiarray/datetime_busdaycal.bc \
$(SRC)/multiarray/datetime_strings.bc \
$(SRC)/multiarray/descriptor.bc \
$(SRC)/multiarray/dragon4.bc \
$(SRC)/multiarray/dtype_transfer.bc \
$(SRC)/multiarray/flagsobject.bc \
$(SRC)/multiarray/getset.bc \
$(SRC)/multiarray/hashdescr.bc \
$(SRC)/multiarray/item_selection.bc \
$(SRC)/multiarray/iterators.bc \
$(SRC)/multiarray/mapping.bc \
$(SRC)/multiarray/methods.bc \
$(SRC)/multiarray/multiarraymodule.bc \
$(SRC)/multiarray/nditer_api.bc \
$(SRC)/multiarray/nditer_constr.bc \
$(SRC)/multiarray/nditer_pywrap.bc \
$(SRC)/multiarray/number.bc \
$(SRC)/multiarray/numpyos.bc \
$(SRC)/multiarray/refcount.bc \
$(SRC)/multiarray/scalarapi.bc \
$(SRC)/multiarray/sequence.bc \
$(SRC)/multiarray/shape.bc \
$(SRC)/multiarray/strfuncs.bc \
$(SRC)/multiarray/temp_elide.bc \
$(SRC)/multiarray/ucsnarrow.bc \
$(SRC)/multiarray/usertypes.bc \
$(SRC)/multiarray/vdot.bc \
$(SRC)/private/mem_overlap.bc \
$(SRC)/private/npy_longdouble.bc \
$(SRC)/private/ufunc_override.bc
UMATH_SRC=\
$(GENSRC)/umath/loops.bc \
$(GENSRC)/umath/scalarmath.bc \
$(SRC)/private/mem_overlap.bc \
$(SRC)/private/npy_longdouble.bc \
$(SRC)/private/ufunc_override.bc \
$(SRC)/umath/extobj.bc \
$(SRC)/umath/override.bc \
$(SRC)/umath/reduction.bc \
$(SRC)/umath/ufunc_object.bc \
$(SRC)/umath/ufunc_type_resolution.bc \
$(SRC)/umath/umathmodule.bc \
LAPACK_BLAS_SRC=\
$(LINALG_SRC)/lapack_lite/python_xerbla.bc \
$(LINALG_SRC)/lapack_lite/f2c_z_lapack.bc \
$(LINALG_SRC)/lapack_lite/f2c_d_lapack.bc \
$(LINALG_SRC)/lapack_lite/f2c_s_lapack.bc \
$(LINALG_SRC)/lapack_lite/f2c_c_lapack.bc \
$(LINALG_SRC)/lapack_lite/f2c_lapack.bc \
$(LINALG_SRC)/lapack_lite/f2c_blas.bc \
$(LINALG_SRC)/lapack_lite/f2c_config.bc \
$(LINALG_SRC)/lapack_lite/f2c.bc
LAPACK_LITE_SRC=\
$(LINALG_SRC)/lapack_litemodule.bc
UMATH_LINALG_SRC=\
$(LINALG_GENSRC)/umath_linalg.bc
FFTPACK_LITE_SRC=\
$(FFT_SRC)/fftpack_litemodule.bc \
$(FFT_SRC)/fftpack.bc
MTRAND_SRC=\
$(RANDOM_SRC)/mtrand/mtrand.bc \
$(RANDOM_SRC)/mtrand/randomkit.bc \
$(RANDOM_SRC)/mtrand/initarray.bc \
$(RANDOM_SRC)/mtrand/distributions.bc
$(BUILDCORE)/multiarray.so: $(MULTIARRAY_SRC) $(NPYMATH_SRC) $(NPYSORT_SRC)
$(CC) $(SIDE_LDFLAGS) $^ -o $(BUILDCORE)/multiarray.wasm
mv $(BUILDCORE)/multiarray.wasm $(BUILDCORE)/multiarray.so
$(BUILDCORE)/umath.so: $(UMATH_SRC) $(NPYMATH_SRC)
$(CC) $(SIDE_LDFLAGS) $^ -o $(BUILDCORE)/umath.wasm
mv $(BUILDCORE)/umath.wasm $(BUILDCORE)/umath.so
$(BUILDLINALG)/lapack_lite.so: $(LAPACK_LITE_SRC) $(LAPACK_BLAS_SRC) $(NPYMATH_SRC)
$(CC) $(SIDE_LDFLAGS) $^ -o $(BUILDLINALG)/lapack_lite.wasm
mv $(BUILDLINALG)/lapack_lite.wasm $(BUILDLINALG)/lapack_lite.so
$(BUILDLINALG)/_umath_linalg.so: $(UMATH_LINALG_SRC) $(LAPACK_BLAS_SRC) $(NPYMATH_SRC)
$(CC) $(SIDE_LDFLAGS) $^ -o $(BUILDLINALG)/_umath_linalg.wasm
mv $(BUILDLINALG)/_umath_linalg.wasm $(BUILDLINALG)/_umath_linalg.so
$(BUILDFFT)/fftpack_lite.so: $(FFTPACK_LITE_SRC)
$(CC) $(SIDE_LDFLAGS) $^ -o $(BUILDFFT)/fftpack_lite.wasm
mv $(BUILDFFT)/fftpack_lite.wasm $(BUILDFFT)/fftpack_lite.so
$(BUILDRANDOM)/mtrand.so: $(MTRAND_SRC)
$(CC) $(SIDE_LDFLAGS) $^ -o $(BUILDRANDOM)/mtrand.wasm
mv $(BUILDRANDOM)/mtrand.wasm $(BUILDRANDOM)/mtrand.so
%.bc: %.c
$(CC) $(CFLAGS) -include math.h -c $< -o $@
b8324ef90ac9064cd0eac46b8b388674 ./downloads/numpy-1.14.1.zip
\ No newline at end of file
#!/bin/sh
python2 emsdk/emsdk/emscripten/tag-1.38.4/tools/file_packager.py build/$1.data --preload $2 --js-output=build/$1.js --export-name=pyodide --exclude \*.wasm.pre --exclude __pycache__
uglifyjs build/$1.js -o build/$1.js
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
all:
../tools/buildall . ../build --ldflags="$(SIDE_LDFLAGS)" --host=$(HOSTPYTHONROOT) --target=$(TARGETPYTHONROOT)
clean:
rm -rf */build
package:
name: cycler
version: 0.10.0
source:
url: https://files.pythonhosted.org/packages/c2/4b/137dea450d6e1e3d474e1d873cd1d4f7d3beed7e0dc973b06e8e10d32488/cycler-0.10.0.tar.gz
md5: 4cb42917ac5007d1cdff6cccfe2d016b
package:
name: kiwisolver
version: 1.0.1
source:
url: https://files.pythonhosted.org/packages/31/60/494fcce70d60a598c32ee00e71542e52e27c978e5f8219fae0d4ac6e2864/kiwisolver-1.0.1.tar.gz
md5: e2a1718b837e2cd001f7c06934616fcd
package:
name: matplotlib
version: 2.2.2
source:
url: https://files.pythonhosted.org/packages/ec/ed/46b835da53b7ed05bd4c6cae293f13ec26e877d2e490a53a709915a9dcb7/matplotlib-2.2.2.tar.gz
md5: dd1e49e041309a7fd4e32be8bf17c3b6
patches:
- patches/disable_bz2.patch
- patches/dummy_threading.patch
- patches/font_name_encoding.patch
- patches/force_malloc_free.patch
- patches/hardcoded_font_cache.patch
- patches/reduce_cpp_exceptions.patch
extras:
-
- src/wasm_backend.py
- lib/matplotlib/backends/wasm_backend.py
-
- src/setup.cfg
- ./setup.cfg
build:
cflags: -s USE_FREETYPE=1 -s USE_LIBPNG=1 -s USE_ZLIB=1
ldflags: ../../../../emsdk/emsdk/.emscripten_cache/asmjs/libpng.bc
post: |
rm -rf $BUILD/matplotlib/backends/qt_editor
rm -rf $BUILD/matplotlib/backends/web_backend
rm -rf $BUILD/sphinxext
cp $PKGDIR/src/fontList.json $BUILD/matplotlib
requirements:
run:
- cycler
- kiwisolver
- numpy
- pyparsing
- python-dateutil
- pytz
package:
name: numpy
version: 1.14.1
source:
url: https://pypi.python.org/packages/a3/99/74aa456fc740a7e8f733af4e8302d8e61e123367ec660cd89c53a3cd4d70/numpy-1.14.1.zip
md5: b8324ef90ac9064cd0eac46b8b388674
patches:
- patches/add-emscripten-cpu.patch
- patches/disable-maybe-uninitialized.patch
- patches/dont-include-execinfo.patch
- patches/fix-enums.patch
- patches/fix-longdouble.patch
- patches/fix-static-init-of-nditer-pywrap.patch
- patches/force_malloc.patch
- patches/init-alloc-cache.patch
- patches/pass-along-errors-from-init.patch
- patches/use-dummy-threading.patch
build:
cflags: -include math.h -I../../config
package:
name: pandas
version: 0.22.0
source:
url: https://pypi.python.org/packages/08/01/803834bc8a4e708aedebb133095a88a4dad9f45bbaf5ad777d2bea543c7e/pandas-0.22.0.tar.gz
md5: c7a2757b607748255f3270221ac61d59
patches:
- patches/avoid-mmap.patch
build:
cflags: -include ../../src/state.h
requirements:
run:
- numpy
- python-dateutil
- pytz
package:
name: pyparsing
version: 2.2.0
source:
url: https://files.pythonhosted.org/packages/3c/ec/a94f8cf7274ea60b5413df054f82a8980523efd712ec55a59e7c3357cf7c/pyparsing-2.2.0.tar.gz
md5: 0214e42d63af850256962b6744c948d9
patches:
- patches/dummy_threading.patch
package:
name: python-dateutil
version: 2.7.2
source:
url: https://files.pythonhosted.org/packages/c5/39/4da7c2dbc4f023fba5fb2325febcadf0d0ce0efdc8bd12083a0f65d20653/python-dateutil-2.7.2.tar.gz
md5: 03a08c8bcf0a2b29f1cd21b9de4d12fb
patches:
- patches/dummy-thread-lock.patch
package:
name: pytz
version: '2018.4'
source:
url: https://files.pythonhosted.org/packages/10/76/52efda4ef98e7544321fd8d5d512e11739c1df18b0649551aeccfb1c8376/pytz-2018.4.tar.gz
md5: f054437920c895dd14a4509fabafe029
patches:
- patches/dummy-threading.patch
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
PDVERSION=0.22.0
NPYVERSION=1.14.1
ROOT=$(abspath .)
HOSTROOT=$(ROOT)/host
HOSTDIR=$(HOSTROOT)/pandas-$(PDVERSION)
HOSTBUILD=$(HOSTDIR)/build
BUILD=$(ROOT)/build/pandas
TARBALL=$(ROOT)/downloads/pandas-$(PDVERSION).tar.gz
URL=https://pypi.python.org/packages/08/01/803834bc8a4e708aedebb133095a88a4dad9f45bbaf5ad777d2bea543c7e/pandas-0.22.0.tar.gz
CC=emcc
CXX=em++
AR=emar
CFLAGS=-Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I$(HOSTDIR)/pandas/_libs/src/klib -I$(HOSTDIR)/pandas/_libs/src -I../numpy/host/numpy-$(NPYVERSION)/numpy/core/include -I../numpy/config -I../numpy/host/numpy-$(NPYVERSION)/build/src.$(PLATFORMSLUG)/numpy/core/include/numpy -I$(PYTHONINCLUDE) -I$(HOSTDIR)/pandas/_libs/src/ujson/lib -I$(HOSTDIR)/pandas/_libs/src/datetime -Wno-unused-function
OBJECTS = \
$(BUILD)/_libs/algos.so \
$(BUILD)/_libs/groupby.so \
$(BUILD)/_libs/hashtable.so \
$(BUILD)/_libs/index.so \
$(BUILD)/_libs/interval.so \
$(BUILD)/_libs/join.so \
$(BUILD)/_libs/reshape.so \
$(BUILD)/_libs/json.so \
$(BUILD)/_libs/lib.so \
$(BUILD)/_libs/parsers.so \
$(BUILD)/_libs/period.so \
$(BUILD)/_libs/tslibs/parsing.so \
$(BUILD)/_libs/properties.so \
$(BUILD)/_libs/sparse.so \
$(BUILD)/_libs/hashing.so \
$(BUILD)/_libs/tslib.so \
$(BUILD)/_libs/tslibs/fields.so \
$(BUILD)/_libs/tslibs/frequencies.so \
$(BUILD)/_libs/tslibs/strptime.so \
$(BUILD)/_libs/tslibs/timedeltas.so \
$(BUILD)/_libs/tslibs/timezones.so \
$(BUILD)/_libs/window.so \
$(BUILD)/io/msgpack/_packer.so \
$(BUILD)/io/msgpack/_unpacker.so \
$(BUILD)/_libs/testing.so \
$(BUILD)/io/sas/_sas.so \
$(BUILD)/util/_move.so \
all:
make $(BUILD)/__init__.py
make $(OBJECTS)
clean:
rm -fr $(HOSTROOT)
rm -fr $(BUILD)
$(TARBALL):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(HOSTDIR)/setup.py: $(TARBALL)
[ -d $(HOSTROOT) ] || mkdir $(HOSTROOT)
tar -xf $(TARBALL) -C $(HOSTROOT)
touch $(HOSTDIR)/setup.py
$(HOSTBUILD)/lib.$(PLATFORMSLUG)/pandas/__init__.py: $(ROOT)/.patched
( \
cd $(HOSTDIR); \
$(HOSTPYTHON) setup.py build \
)
$(BUILD)/__init__.py: $(HOSTBUILD)/lib.$(PLATFORMSLUG)/pandas/__init__.py
[ -d $(ROOT)/build ] || mkdir $(ROOT)/build
cp -r $(HOSTBUILD)/lib.$(PLATFORMSLUG)/pandas $(ROOT)/build && \
cd $(BUILD); find . -name "*.so" -type f -delete
$(ROOT)/.patched: $(HOSTDIR)/setup.py
cat patches/*.patch | (cd $(HOSTDIR) ; patch -p1)
touch $@
$(BUILD)/_libs/lib.so: $(HOSTDIR)/pandas/_libs/lib.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/properties.so: $(HOSTDIR)/pandas/_libs/properties.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/hashtable.so: $(HOSTDIR)/pandas/_libs/hashtable.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/tslibs/strptime.so: \
$(HOSTDIR)/pandas/_libs/tslibs/strptime.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime_strings.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/tslib.so: \
$(HOSTDIR)/pandas/_libs/tslib.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime_strings.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/tslibs/timedeltas.so: \
$(HOSTDIR)/pandas/_libs/tslibs/timedeltas.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/tslibs/timezones.so: \
$(HOSTDIR)/pandas/_libs/tslibs/timezones.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/tslibs/fields.so: \
$(HOSTDIR)/pandas/_libs/tslibs/fields.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime_strings.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/period.so: \
$(HOSTDIR)/pandas/_libs/period.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime_strings.bc \
$(HOSTDIR)/pandas/_libs/src/period_helper.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/tslibs/parsing.so: \
$(HOSTDIR)/pandas/_libs/tslibs/parsing.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/tslibs/frequencies.so: \
$(HOSTDIR)/pandas/_libs/tslibs/frequencies.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/index.so: \
$(HOSTDIR)/pandas/_libs/index.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime_strings.bc \
$(HOSTDIR)/pandas/_libs/src/period_helper.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/algos.so: \
$(HOSTDIR)/pandas/_libs/algos.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/groupby.so: \
$(HOSTDIR)/pandas/_libs/groupby.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/join.so: \
$(HOSTDIR)/pandas/_libs/join.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/reshape.so: \
$(HOSTDIR)/pandas/_libs/reshape.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/interval.so: \
$(HOSTDIR)/pandas/_libs/interval.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/window.so: \
$(HOSTDIR)/pandas/_libs/window.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/parsers.so: \
$(HOSTDIR)/pandas/_libs/parsers.bc \
$(HOSTDIR)/pandas/_libs/src/parser/tokenizer.bc \
$(HOSTDIR)/pandas/_libs/src/parser/io.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/sparse.so: \
$(HOSTDIR)/pandas/_libs/sparse.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/hashing.so: \
$(HOSTDIR)/pandas/_libs/hashing.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/io/sas/_sas.so: \
$(HOSTDIR)/pandas/io/sas/sas.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/testing.so: \
$(HOSTDIR)/pandas/_libs/testing.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/io/msgpack/_packer.so: \
$(HOSTDIR)/pandas/io/msgpack/_packer.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/io/msgpack/_unpacker.so: \
$(HOSTDIR)/pandas/io/msgpack/_unpacker.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/_libs/json.so: \
$(HOSTDIR)/pandas/_libs/src/ujson/python/ujson.bc \
$(HOSTDIR)/pandas/_libs/src/ujson/python/objToJSON.bc \
$(HOSTDIR)/pandas/_libs/src/ujson/python/JSONtoObj.bc \
$(HOSTDIR)/pandas/_libs/src/ujson/lib/ultrajsonenc.bc \
$(HOSTDIR)/pandas/_libs/src/ujson/lib/ultrajsondec.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime.bc \
$(HOSTDIR)/pandas/_libs/src/datetime/np_datetime_strings.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
$(BUILD)/util/_move.so: \
$(HOSTDIR)/pandas/util/move.bc
$(CC) $(SIDE_LDFLAGS) $^ -o $@.wasm
mv $@.wasm $@
%.bc: %.c
$(CC) $(CFLAGS) -include src/state.h -c $< -o $@
%.bc: %.cpp
$(CXX) $(CFLAGS) -include src/state.h -c $< -o $@
c7a2757b607748255f3270221ac61d59 ./downloads/pandas-0.22.0.tar.gz
\ No newline at end of file
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
PYPARSINGVERSION=2.2.0
ROOT=$(abspath .)
SRC=$(ROOT)/pyparsing-$(PYPARSINGVERSION)
BUILD=$(SRC)/build/lib/dateutil
TARBALL=$(ROOT)/downloads/pyparsing-$(PYPARSINGVERSION).tgz
URL=https://files.pythonhosted.org/packages/3c/ec/a94f8cf7274ea60b5413df054f82a8980523efd712ec55a59e7c3357cf7c/pyparsing-2.2.0.tar.gz
all: $(BUILD)/__init__.py
clean:
-rm -fr downloads
-rm -fr $(SRC)
$(TARBALL):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(SRC)/setup.py: $(TARBALL)
tar -C . -xf $(TARBALL)
touch $(SRC)/setup.py
$(BUILD)/__init__.py: $(ROOT)/.patched
( \
cd $(SRC) ; \
$(HOSTPYTHON) setup.py build ; \
touch build/lib/pyparsing.py \
)
$(ROOT)/.patched: $(SRC)/setup.py
cat patches/*.patch | (cd $(SRC) ; patch --binary -p1)
touch $@
0214e42d63af850256962b6744c948d9 downloads/pyparsing-2.2.0.tgz
PYODIDE_ROOT=$(abspath ..)
include ../Makefile.envs
PYTZVERSION=2018.4
ROOT=$(abspath .)
SRC=$(ROOT)/pytz-$(PYTZVERSION)
BUILD=$(SRC)/build/lib/pytz
TARBALL=$(ROOT)/downloads/pytz-$(PYTZVERSION).tgz
URL=https://files.pythonhosted.org/packages/10/76/52efda4ef98e7544321fd8d5d512e11739c1df18b0649551aeccfb1c8376/pytz-$(PYTZVERSION).tar.gz
all: $(BUILD)/__init__.py
clean:
-rm -fr downloads
-rm -fr $(SRC)
$(TARBALL):
[ -d $(ROOT)/downloads ] || mkdir $(ROOT)/downloads
wget -q -O $@ $(URL)
md5sum --quiet --check checksums || (rm $@; false)
$(SRC)/setup.py: $(TARBALL)
tar -C . -xf $(TARBALL)
touch $(SRC)/setup.py
$(BUILD)/__init__.py: $(ROOT)/.patched
( \
cd $(SRC) ; \
$(HOSTPYTHON) setup.py build ; \
touch build/lib/pytz/__init__.py \
)
$(ROOT)/.patched: $(SRC)/setup.py
cat patches/*.patch | (cd $(SRC) ; patch -p1)
touch $@
f054437920c895dd14a4509fabafe029 ./downloads/pytz-2018.4.tgz
......@@ -14,7 +14,6 @@ URL=https://files.pythonhosted.org/packages/16/d8/bc6316cf98419719bd59c91742194c
all: $(BUILD)/__init__.py
clean:
-rm -fr downloads
-rm -fr $(SRC)
......
Six is a special case package, since it's so commonly used, we want to include
it in the main Python package.
......@@ -10,21 +10,12 @@ var languagePluginLoader = new Promise((resolve, reject) => {
////////////////////////////////////////////////////////////
// Package loading
const packages = {
'cycler' : [],
'dateutil' : [],
'kiwisolver' : [],
'matplotlib' :
[ 'numpy', 'dateutil', 'pytz', 'kiwisolver', 'cycler', 'pyparsing' ],
'numpy' : [],
'pandas' : [ 'numpy', 'dateutil', 'pytz' ],
'pyparsing' : [],
'pytz' : [],
'test' : []
};
var packages = undefined;
let loadedPackages = new Set();
let loadPackage = (names) => {
// DFS to find all dependencies of the requested packages
let packages = window.pyodide.packages.dependencies;
let queue = new Array(names);
let toLoad = new Set();
while (queue.length) {
......@@ -89,7 +80,12 @@ var languagePluginLoader = new Promise((resolve, reject) => {
Module.filePackagePrefixURL = baseURL;
Module.postRun = () => {
delete window.Module;
resolve();
fetch(`${baseURL}packages.json`)
.then((response) => response.json())
.then((json) => {
window.pyodide.packages = json;
resolve();
});
};
let data_script = document.createElement('script');
......
......@@ -197,7 +197,8 @@ python2js_int(PyObject* x)
}
int
python2js(PyObject* x) {
python2js(PyObject* x)
{
int result = python2js_int(x);
if (result == -1) {
return pythonexc2js();
......
......@@ -3,7 +3,6 @@ Various common utilities for testing.
"""
import pathlib
import time
try:
import pytest
......@@ -58,10 +57,9 @@ class SeleniumWrapper:
def load_package(self, packages):
self.run_js(
'window.done = false\n'
'pyodide.loadPackage({!r}).then(window.done = true)'.format(
packages))
time.sleep(2)
'window.done = false\n' +
'pyodide.loadPackage({!r})'.format(packages) +
'.then(function() { window.done = true; })')
self.wait.until(PackageLoaded())
@property
......
import pytest
@pytest.mark.skip
def test_pandas(selenium):
selenium.load_package("pandas")
assert len(selenium.run("import pandas\ndir(pandas)")) == 179
@pytest.mark.skip
def test_extra_import(selenium):
selenium.load_package("pandas")
selenium.run("from pandas import Series, DataFrame, Panel")
ar
c++
cc
cxx
gcc
ld
#!/usr/bin/env python3
"""
Build all of the packages in a given directory.
"""
import argparse
import json
import os
import shutil
import common
import buildpkg
def build_package(pkgname, dependencies, packagesdir, args):
reqs = dependencies[pkgname]
# Make sure all of the package's requirements are built first
for req in reqs:
build_package(req, dependencies, packagesdir, args)
if not os.path.isfile(
os.path.join(packagesdir, pkgname, 'build', '.packaged')):
print("BUILDING PACKAGE: " + pkgname)
buildpkg.build_package(
os.path.join(packagesdir, pkgname, 'meta.yaml'), args)
shutil.copyfile(
os.path.join(packagesdir, pkgname, 'build', pkgname + '.data'),
os.path.join(args.output[0], pkgname + '.data'))
shutil.copyfile(
os.path.join(packagesdir, pkgname, 'build', pkgname + '.js'),
os.path.join(args.output[0], pkgname + '.js'))
def build_packages(packagesdir, args):
# We have to build the packages in the correct order (dependencies first),
# so first load in all of the package metadata and build a dependency map.
dependencies = {}
for pkgdir in os.listdir(packagesdir):
pkgdir = os.path.join(packagesdir, pkgdir)
pkgpath = os.path.join(pkgdir, 'meta.yaml')
if os.path.isdir(pkgdir) and os.path.isfile(pkgpath):
pkg = common.parse_package(pkgpath)
name = pkg['package']['name']
reqs = pkg.get('requirements', {}).get('run', [])
dependencies[name] = reqs
for pkgname in dependencies.keys():
build_package(pkgname, dependencies, packagesdir, args)
# This is done last so the main Makefile can use it as a completion token
with open(os.path.join(args.output[0], 'packages.json'), 'w') as fd:
json.dump({'dependencies': dependencies}, fd)
def parse_args():
parser = argparse.ArgumentParser(
"Build all of the packages in a given directory")
parser.add_argument(
'dir', type=str, nargs=1,
help='Input directory containing a tree of package definitions')
parser.add_argument(
'output', type=str, nargs=1,
help='Output directory in which to put all built packages')
parser.add_argument(
'--cflags', type=str, nargs='?', default=common.DEFAULTCFLAGS,
help='Extra compiling flags')
parser.add_argument(
'--ldflags', type=str, nargs='?', default=common.DEFAULTLDFLAGS,
help='Extra linking flags')
parser.add_argument(
'--host', type=str, nargs='?', default=common.HOSTPYTHON,
help='The path to the host Python installation')
parser.add_argument(
'--target', type=str, nargs='?', default=common.TARGETPYTHON,
help='The path to the target Python installation')
return parser.parse_args()
def main(args):
packagesdir = os.path.abspath(args.dir[0])
build_packages(packagesdir, args)
if __name__ == '__main__':
args = parse_args()
main(args)
#!/usr/bin/env python3
"""
Builds a Pyodide package.
"""
import argparse
import hashlib
import os
import shutil
import subprocess
import common
ROOTDIR = os.path.abspath(os.path.dirname(__file__))
def check_checksum(path, pkg):
"""
Checks that a tarball matches the checksum in the package metadata.
"""
if 'md5' not in pkg['source']:
return
checksum = pkg['source']['md5']
CHUNK_SIZE = 1 << 16
h = hashlib.md5()
with open(path, 'rb') as fd:
while True:
chunk = fd.read(CHUNK_SIZE)
h.update(chunk)
if len(chunk) < CHUNK_SIZE:
break
if h.hexdigest() != checksum:
raise ValueError("Invalid checksum")
def download_and_extract(buildpath, packagedir, pkg, args):
tarballpath = os.path.join(
buildpath, os.path.basename(pkg['source']['url']))
if not os.path.isfile(tarballpath):
subprocess.run([
'wget', '-q', '-O', tarballpath, pkg['source']['url']
], check=True)
check_checksum(tarballpath, pkg)
srcpath = os.path.join(buildpath, packagedir)
if not os.path.isdir(srcpath):
shutil.unpack_archive(tarballpath, buildpath)
return srcpath
def patch(path, srcpath, pkg, args):
if os.path.isfile(os.path.join(srcpath, '.patched')):
return
# Apply all of the patches
orig_dir = os.getcwd()
pkgdir = os.path.abspath(os.path.dirname(path))
os.chdir(srcpath)
try:
for patch in pkg['source'].get('patches', []):
subprocess.run([
'patch', '-p1', '--binary', '-i', os.path.join(pkgdir, patch)
], check=True)
finally:
os.chdir(orig_dir)
# Add any extra files
for src, dst in pkg['source'].get('extras', []):
shutil.copyfile(os.path.join(pkgdir, src), os.path.join(srcpath, dst))
with open(os.path.join(srcpath, '.patched'), 'wb') as fd:
fd.write(b'\n')
def get_libdir(srcpath, args):
# Get the name of the build/lib.XXX directory that distutils wrote its
# output to
slug = subprocess.check_output([
os.path.join(args.host, 'bin', 'python3'),
'-c',
'import sysconfig, sys; '
'print("{}-{}.{}".format('
'sysconfig.get_platform(), '
'sys.version_info[0], '
'sys.version_info[1]))']).decode('ascii').strip()
purelib = os.path.join(srcpath, 'build', 'lib')
if os.path.isdir(purelib):
libdir = purelib
else:
libdir = os.path.join(srcpath, 'build', 'lib.' + slug)
return libdir
def compile(path, srcpath, pkg, args):
if os.path.isfile(os.path.join(srcpath, '.built')):
return
orig_dir = os.getcwd()
os.chdir(srcpath)
try:
subprocess.run([
os.path.join(args.host, 'bin', 'python3'),
os.path.join(ROOTDIR, 'pywasmcross'),
'--cflags',
args.cflags + ' ' +
pkg.get('build', {}).get('cflags', ''),
'--ldflags',
args.ldflags + ' ' +
pkg.get('build', {}).get('ldflags', ''),
'--host', args.host,
'--target', args.target], check=True)
finally:
os.chdir(orig_dir)
post = pkg.get('build', {}).get('post')
if post is not None:
libdir = get_libdir(srcpath, args)
pkgdir = os.path.abspath(os.path.dirname(path))
env = {
'BUILD': libdir,
'PKGDIR': pkgdir
}
subprocess.run([
'bash', '-c', post], env=env, check=True)
with open(os.path.join(srcpath, '.built'), 'wb') as fd:
fd.write(b'\n')
def package_files(buildpath, srcpath, pkg, args):
if os.path.isfile(os.path.join(buildpath, '.packaged')):
return
name = pkg['package']['name']
libdir = get_libdir(srcpath, args)
subprocess.run([
'python2',
os.path.join(os.environ['EMSCRIPTEN'], 'tools', 'file_packager.py'),
os.path.join(buildpath, name + '.data'),
'--preload',
'{}@/lib/python3.6/site-packages'.format(libdir),
'--js-output={}'.format(os.path.join(buildpath, name + '.js')),
'--export-name=pyodide',
'--exclude', '*.wasm.pre',
'--exclude', '__pycache__'], check=True)
subprocess.run([
'uglifyjs',
os.path.join(buildpath, name + '.js'),
'-o',
os.path.join(buildpath, name + '.js')], check=True)
with open(os.path.join(buildpath, '.packaged'), 'wb') as fd:
fd.write(b'\n')
def build_package(path, args):
pkg = common.parse_package(path)
packagedir = pkg['package']['name'] + '-' + pkg['package']['version']
dirpath = os.path.dirname(path)
orig_path = os.getcwd()
os.chdir(dirpath)
try:
buildpath = os.path.join(dirpath, 'build')
if not os.path.exists(buildpath):
os.makedirs(buildpath)
srcpath = download_and_extract(buildpath, packagedir, pkg, args)
patch(path, srcpath, pkg, args)
compile(path, srcpath, pkg, args)
package_files(buildpath, srcpath, pkg, args)
finally:
os.chdir(orig_path)
def parse_args():
parser = argparse.ArgumentParser('Build a pyodide package.')
parser.add_argument(
'package', type=str, nargs=1,
help="Path to meta.yaml package description")
parser.add_argument(
'--cflags', type=str, nargs='?', default=common.DEFAULTCFLAGS,
help='Extra compiling flags')
parser.add_argument(
'--ldflags', type=str, nargs='?', default=common.DEFAULTLDFLAGS,
help='Extra linking flags')
parser.add_argument(
'--host', type=str, nargs='?', default=common.HOSTPYTHON,
help='The path to the host Python installation')
parser.add_argument(
'--target', type=str, nargs='?', default=common.TARGETPYTHON,
help='The path to the target Python installation')
return parser.parse_args()
def main(args):
path = os.path.abspath(args.package[0])
build_package(path, args)
if __name__ == '__main__':
args = parse_args()
main(args)
import os
ROOTDIR = os.path.abspath(os.path.dirname(__file__))
HOSTPYTHON = os.path.abspath(
os.path.join(ROOTDIR, '..', 'cpython', 'build', '3.6.4', 'host'))
TARGETPYTHON = os.path.abspath(
os.path.join(ROOTDIR, '..', 'cpython', 'installs', 'python-3.6.4'))
DEFAULTCFLAGS = ''
DEFAULTLDFLAGS = ' '.join([
'-O3',
'-s', "BINARYEN_METHOD='native-wasm'",
'-Werror',
'-s', 'EMULATED_FUNCTION_POINTERS=1',
'-s', 'EMULATE_FUNCTION_POINTER_CASTS=1',
'-s', 'SIDE_MODULE=1',
'-s', 'WASM=1',
'--memory-init-file', '0'
])
def parse_package(package):
# Import yaml here because pywasmcross needs to run in the built native
# Python, which won't have PyYAML
import yaml
# TODO: Validate against a schema
with open(package) as fd:
return yaml.load(fd)
#!/usr/bin/env python3
"""Helper for cross-compiling distutils-based Python extensions.
distutils has never had a proper cross-compilation story. This is a hack, which
miraculously works, to get around that.
The gist is:
- Compile the package natively, replacing calls to the compiler and linker with
wrappers that store the arguments in a log, and then delegate along to the
real native compiler and linker.
- Remove all of the native build products.
- Play back the log, replacing the native compiler with emscripten and
adjusting include paths and flags as necessary for cross-compiling to
emscripten. This overwrites the results from the original native compilation.
While this results in more work than strictly necessary (it builds a native
version of the package, even though we then throw it away), it seems to be the
only reliable way to automatically build a package that interleaves
configuration with build.
"""
import argparse
import importlib.machinery
import json
import os
import re
import subprocess
import sys
import common
ROOTDIR = os.path.abspath(os.path.dirname(__file__))
symlinks = set(['cc', 'c++', 'ld', 'ar', 'gcc'])
def collect_args(basename):
"""
This is called when this script is called through a symlink that looks like
a compiler or linker.
It writes the arguments to the build.log, and then delegates to the real
native compiler or linker.
"""
# Remove the symlink compiler from the PATH, so we can delegate to the
# native compiler
env = dict(os.environ)
path = env['PATH']
while ROOTDIR + ':' in path:
path = path.replace(ROOTDIR + ':', '')
env['PATH'] = path
with open('build.log', 'a') as fd:
json.dump([basename] + sys.argv[1:], fd)
fd.write('\n')
sys.exit(
subprocess.run(
[basename] + sys.argv[1:],
env=env).returncode)
def make_symlinks(env):
"""
Makes sure all of the symlinks that make this script look like a compiler
exist.
"""
exec_path = os.path.abspath(__file__)
for symlink in symlinks:
symlink_path = os.path.join(ROOTDIR, symlink)
if not os.path.exists(symlink_path):
os.symlink(exec_path, symlink_path)
if symlink == 'c++':
var = 'CXX'
else:
var = symlink.upper()
env[var] = symlink
def capture_compile(args):
env = dict(os.environ)
make_symlinks(env)
env['PATH'] = ROOTDIR + ':' + os.environ['PATH']
result = subprocess.run(
[os.path.join(args.host, 'bin', 'python3'),
'setup.py',
'install'], env=env)
if result.returncode != 0:
if os.path.exists('build.log'):
os.remove('build.log')
sys.exit(result.returncode)
def handle_command(line, args):
# This is a special case to skip the compilation tests in numpy that aren't
# actually part of the build
for arg in line:
if r'/file.c' in arg or '_configtest' in arg:
return
if arg == '-print-multiarch':
return
if line[0] == 'ar':
new_args = ['emar']
elif line[0] == 'c++':
new_args = ['em++']
else:
new_args = ['emcc']
# distutils doesn't use the c++ compiler when compiling c++ <sigh>
if any(arg.endswith('.cpp') for arg in line):
new_args = ['em++']
shared = '-shared' in line
if shared:
new_args.extend(args.ldflags.split())
elif new_args[0] in ('emcc', 'em++'):
new_args.extend(args.cflags.split())
# Go through and adjust arguments
for arg in line[1:]:
if arg.startswith('-I'):
# Don't include any system directories
if arg[2:].startswith('/usr'):
continue
if (os.path.abspath(arg[2:]).startswith(args.host) and
'site-packages' not in arg):
arg = arg.replace('-I' + args.host, '-I' + args.target)
# Don't include any system directories
if arg.startswith('-L/usr'):
continue
# The native build is possibly multithreaded, but the emscripten one
# definitely isn't
arg = re.sub(r'/python([0-9]\.[0-9]+)m', r'/python\1', arg)
if arg.endswith('.o'):
arg = arg[:-2] + '.bc'
if shared and arg.endswith('.so'):
arg = arg[:-3] + '.wasm'
output = arg
new_args.append(arg)
print(' '.join(new_args))
result = subprocess.run(new_args)
if result.returncode != 0:
sys.exit(result.returncode)
# Emscripten .so files shouldn't have the native platform slug
if shared:
renamed = output[:-5] + '.so'
for ext in importlib.machinery.EXTENSION_SUFFIXES:
if ext == '.so':
continue
if renamed.endswith(ext):
renamed = renamed[:-len(ext)] + '.so'
break
os.rename(output, renamed)
def replay_compile(args):
# If pure Python, there will be no build.log file, which is fine -- just do
# nothing
if os.path.isfile('build.log'):
with open('build.log', 'r') as fd:
for line in fd:
line = json.loads(line)
handle_command(line, args)
def clean_out_native_artifacts():
for root, dirs, files in os.walk('.'):
for file in files:
path = os.path.join(root, file)
basename, ext = os.path.splitext(file)
if ext in ('.o', '.so', '.a'):
os.remove(path)
def build_wrap(args):
if not os.path.isfile('build.log'):
capture_compile(args)
clean_out_native_artifacts()
replay_compile(args)
def parse_args():
parser = argparse.ArgumentParser(
'Cross compile a Python distutils package. '
'Run from the root directory of the package\'s source')
parser.add_argument(
'--cflags', type=str, nargs='?', default=common.DEFAULTCFLAGS,
help='Extra compiling flags')
parser.add_argument(
'--ldflags', type=str, nargs='?', default=common.DEFAULTLDFLAGS,
help='Extra linking flags')
parser.add_argument(
'--host', type=str, nargs='?', default=common.HOSTPYTHON,
help='The path to the host Python installation')
parser.add_argument(
'--target', type=str, nargs='?', default=common.TARGETPYTHON,
help='The path to the target Python installation')
args = parser.parse_args()
return args
if __name__ == '__main__':
basename = os.path.basename(sys.argv[0])
if basename in symlinks:
collect_args(basename)
else:
args = parse_args()
build_wrap(args)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment