Skip to content

Commit 0fed473

Browse files
tomjakubowskitexodus
authored andcommitted
Add pyodide build
1 parent 58aef95 commit 0fed473

35 files changed

+374
-99
lines changed

.github/workflows/pyodide.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Adapted from https://raw.githubusercontent.com/numpy/numpy/main/.github/workflows/emscripten.yml
2+
name: Pyodide wheel build
3+
4+
on:
5+
push:
6+
branches:
7+
- '*pyodide*'
8+
pull_request:
9+
branches:
10+
- master
11+
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
14+
cancel-in-progress: true
15+
16+
permissions:
17+
contents: read # to fetch code (actions/checkout)
18+
19+
jobs:
20+
build-wasm-emscripten:
21+
runs-on: ubuntu-22.04
22+
env:
23+
PYODIDE_VERSION: 0.23.2
24+
# PYTHON_VERSION and EMSCRIPTEN_VERSION are determined by PYODIDE_VERSION.
25+
# The appropriate versions can be found in the Pyodide repodata.json
26+
# "info" field, or in Makefile.envs:
27+
# https://github.com/pyodide/pyodide/blob/main/Makefile.envs#L2
28+
PYTHON_VERSION: 3.11.2
29+
EMSCRIPTEN_VERSION: 3.1.32
30+
steps:
31+
- name: Checkout perspective
32+
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
33+
34+
- name: set up python
35+
id: setup-python
36+
uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # v4.6.0
37+
with:
38+
python-version: ${{ env.PYTHON_VERSION }}
39+
40+
- uses: mymindstorm/setup-emsdk@ab889da2abbcbb280f91ec4c215d3bb4f3a8f775 # v12
41+
with:
42+
version: ${{ env.EMSCRIPTEN_VERSION }}
43+
actions-cache-folder: emsdk-cache
44+
45+
- name: copy files
46+
run: |
47+
npm install -g yarn
48+
yarn --frozen-lockfile
49+
yarn build_python --setup-only
50+
51+
- name: Linux init steps
52+
run: sudo node scripts/install_tools.js
53+
54+
- name: Install pyodide-build
55+
run: pip install pyodide-build==$PYODIDE_VERSION
56+
57+
- name: Build
58+
# Without --exports=pyinit, pyodide-build tries to export all symbols from every .o,
59+
# which causes the em++ linker command line invocation to be so long
60+
# that the command fails.
61+
run: pyodide build python/perspective --exports=pyinit
62+
63+
- name: Upload pyodide wheel
64+
uses: actions/upload-artifact@v3
65+
with:
66+
name: perspective-python-dist-pyodide
67+
path: dist/*.whl

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,4 @@ test-results/
215215
playwright-report/
216216
playwright/.cache/
217217

218+
.pyodide-xbuildenv

cmake/arrow/CMakeLists.txt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ set(ARROW_SRCS
109109
${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/util/tracing.cc
110110
${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/util/trie.cc
111111
${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/util/unreachable.cc
112-
${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/util/uri.cc
112+
# ${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/util/uri.cc
113113
${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/util/utf8.cc
114114
${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/util/value_parsing.cc
115115
${CMAKE_BINARY_DIR}/arrow-src/cpp/src/arrow/vendored/base64.cpp
@@ -277,11 +277,7 @@ target_compile_definitions(arrow PUBLIC ARROW_STATIC)
277277

278278
# will need built boost filesystem and system .lib to work, even though
279279
# perspective itself does not use those dependencies
280-
target_link_libraries(arrow
281-
${double-conversion_LIBRARIES}
282-
${Boost_FILESYSTEM_LIBRARY}
283-
${Boost_SYSTEM_LIBRARY}
284-
${ARROW_TEST_LINK_TOOLCHAIN})
280+
target_link_libraries(arrow)
285281

286282
# find_package(Flatbuffers)
287283

cmake/modules/FindNumPy.cmake

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ execute_process(
2020

2121
find_path(PYTHON_NUMPY_INCLUDE_DIR numpy/arrayobject.h
2222
HINTS "${__numpy_path}" "${PYTHON_INCLUDE_PATH}" NO_DEFAULT_PATH)
23+
if(PSP_PYODIDE)
24+
# In a pyodide build, find_path fails for some reason, even though
25+
# ${__numpy_path}/numpy/arrayobject.h
26+
# exists
27+
# execute_process (COMMAND bash -c "ls -l ${__numpy_path}/numpy/arrayobject.h")
28+
set(PYTHON_NUMPY_INCLUDE_DIR "${__numpy_path}")
29+
endif()
2330

2431
if(PYTHON_NUMPY_INCLUDE_DIR)
2532
set(PYTHON_NUMPY_FOUND 1 CACHE INTERNAL "Python numpy found")

cpp/perspective/CMakeLists.txt

Lines changed: 83 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
cmake_minimum_required(VERSION 3.7.2)
1+
cmake_minimum_required(VERSION 3.18.2)
22
project(psp)
33
include(CheckCCompilerFlag)
44

5-
set(CMAKE_BUILD_TYPE "Release")
65
set(CMAKE_CXX_STANDARD 14)
76
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
87

@@ -108,12 +107,14 @@ endif()
108107
if(NOT DEFINED PSP_PYTHON_BUILD)
109108
set(PSP_PYTHON_BUILD OFF)
110109
elseif(PSP_PYTHON_BUILD)
111-
# PSP_PYTHON_BUILD will always run PSP_CPP_BUILD
112-
set(PSP_CPP_BUILD ON)
113-
114110
if(NOT DEFINED PSP_PYTHON_VERSION)
115111
set(PSP_PYTHON_VERSION 3.10)
116112
endif()
113+
if($ENV{PYODIDE})
114+
set(PSP_PYODIDE 1)
115+
else()
116+
set(PSP_PYODIDE 0)
117+
endif()
117118
endif()
118119

119120
if(NOT DEFINED PSP_CPP_BUILD_STRICT)
@@ -212,10 +213,10 @@ if(PSP_WASM_BUILD)
212213
list(APPEND CMAKE_PREFIX_PATH /usr/local)
213214

214215
# Assumes that Boost includes will be in this folder.
215-
include_directories("/usr/local/include" SYSTEM)
216+
include_directories(SYSTEM "/usr/local/include")
216217

217218
# Include this docker-only directory.
218-
include_directories("/boost_includes")
219+
include_directories(SYSTEM "/boost_includes")
219220

220221
set(EXTENDED_FLAGS " \
221222
-Wall \
@@ -258,28 +259,45 @@ elseif(PSP_CPP_BUILD OR PSP_PYTHON_BUILD)
258259
endif()
259260
else()
260261
if(CMAKE_BUILD_TYPE_LOWER STREQUAL debug)
261-
set(OPT_FLAGS " \
262-
-O0 \
263-
-g3 \
264-
")
262+
if (PSP_PYODIDE)
263+
set(OPT_FLAGS " \
264+
-O0 \
265+
-g3 \
266+
-gsource-map \
267+
--profiling \
268+
-Wcast-align \
269+
-Wover-aligned \
270+
")
271+
else ()
272+
set(OPT_FLAGS " \
273+
-O0 \
274+
-g3 \
275+
")
276+
endif ()
265277
else()
266278
set(OPT_FLAGS " \
267279
-O3 \
268280
-g1 \
269281
")
282+
if (PSP_PYODIDE)
283+
set(OPT_FLAGS "${OPT_FLAGS} -flto")
284+
endif ()
270285
endif()
271286
endif()
272287

273288
set(ASYNC_MODE_FLAGS "")
274289

275290
# Boost is a system dependency and must be present and built on the system.
291+
if(PSP_PYODIDE)
292+
set(CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH};/usr/local/")
293+
endif()
276294
find_package(Boost REQUIRED)
277295

278296
if(NOT Boost_FOUND)
279297
message(FATAL_ERROR "${Red}Boost could not be located${ColorReset}")
280298
else()
281299
psp_build_message("${Cyan}Found Boost: `Boost_INCLUDE_DIRS`: ${Boost_INCLUDE_DIRS}, `Boost_LIBRARY_DIRS` - ${Boost_LIBRARY_DIRS} ${ColorReset}")
282-
include_directories(${Boost_INCLUDE_DIRS})
300+
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
283301

284302
if(WIN32)
285303
add_definitions(-DBOOST_UUID_FORCE_AUTO_LINK)
@@ -316,16 +334,13 @@ elseif(PSP_CPP_BUILD OR PSP_PYTHON_BUILD)
316334
psp_build_message("${Red}Manylinux build has no python shared libraries${ColorReset}")
317335
find_package(Python ${PSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter)
318336
find_package(PythonHeaders ${PSP_PYTHON_VERSION} EXACT REQUIRED)
319-
320-
# Run with exact version so its cached for pybind
321-
find_package(PythonInterp ${PSP_PYTHON_VERSION} EXACT REQUIRED)
322337
else()
323338
psp_build_message("${Cyan}Use python shared libraries${ColorReset}")
324-
find_package(Python ${PSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development)
325-
326-
# Run with exact version so its cached for pybind
327-
find_package(PythonInterp ${PSP_PYTHON_VERSION} EXACT REQUIRED)
328-
find_package(PythonLibs ${PSP_PYTHON_VERSION} EXACT REQUIRED)
339+
if(PSP_PYODIDE)
340+
find_package(Python ${PSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter)
341+
else()
342+
find_package(Python ${PSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
343+
endif()
329344

330345
link_directories(${Python_LIBRARY_DIRS})
331346
endif()
@@ -335,7 +350,7 @@ elseif(PSP_CPP_BUILD OR PSP_PYTHON_BUILD)
335350

336351
psp_build_dep("pybind11" "${PSP_CMAKE_MODULE_PATH}/Pybind.txt.in")
337352

338-
find_package(NumPy)
353+
find_package(NumPy REQUIRED)
339354

340355
if(NOT PYTHON_NUMPY_FOUND)
341356
message(FATAL_ERROR "${Red}Numpy could not be located${ColorReset}")
@@ -373,14 +388,18 @@ psp_build_dep("re2" "${PSP_CMAKE_MODULE_PATH}/re2.txt.in")
373388
psp_build_dep("exprtk" "${PSP_CMAKE_MODULE_PATH}/exprtk.txt.in")
374389

375390
# ####################
376-
set(CMAKE_C_FLAGS_RELEASE " \
391+
set(CMAKE_C_FLAGS_DEBUG "")
392+
set(CMAKE_C_FLAGS " \
377393
${CMAKE_C_FLAGS} \
378394
${EXTENDED_FLAGS} \
379395
${OPT_FLAGS} \
380396
")
381397

382-
set(CMAKE_CXX_FLAGS_RELEASE " \
383-
${CMAKE_C_FLAGS} \
398+
# prevents the default debug flags from overriding the debug flags we
399+
# set in OPT_FLAGS
400+
set(CMAKE_CXX_FLAGS_DEBUG "")
401+
set(CMAKE_CXX_FLAGS " \
402+
${CMAKE_CXX_FLAGS} \
384403
${EXTENDED_FLAGS} \
385404
${OPT_FLAGS} \
386405
")
@@ -410,6 +429,7 @@ set(SOURCE_FILES
410429
${PSP_CPP_SRC}/src/cpp/compat.cpp
411430
${PSP_CPP_SRC}/src/cpp/compat_impl_linux.cpp
412431
${PSP_CPP_SRC}/src/cpp/compat_impl_osx.cpp
432+
${PSP_CPP_SRC}/src/cpp/compat_impl_wasm.cpp
413433
${PSP_CPP_SRC}/src/cpp/compat_impl_win.cpp
414434
${PSP_CPP_SRC}/src/cpp/computed_expression.cpp
415435
${PSP_CPP_SRC}/src/cpp/computed_function.cpp
@@ -545,6 +565,27 @@ if(PSP_WASM_BUILD)
545565
set_target_properties(perspective_esm PROPERTIES RUNTIME_OUTPUT_DIRECTORY "./web/")
546566
set_target_properties(perspective_esm PROPERTIES OUTPUT_NAME "perspective.cpp")
547567
elseif(PSP_CPP_BUILD OR PSP_PYTHON_BUILD)
568+
if (PSP_PYODIDE)
569+
# TODO(tom): this is a straight copy of PSP_WASM_BUILD, merge them
570+
# TODO(tom): determine which of these we shouldn't bother setting
571+
# because pyodide's pywasmcross.py overrides them
572+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \
573+
--bind \
574+
--source-map-base \"\" \
575+
--memory-init-file 0 \
576+
--no-entry \
577+
-s EXPORT_ES6=1 \
578+
-s NO_EXIT_RUNTIME=1 \
579+
-s NO_FILESYSTEM=1 \
580+
-s ALLOW_MEMORY_GROWTH=1 \
581+
-s MODULARIZE=1 \
582+
-s EXPORT_NAME=\"load_perspective\" \
583+
-s MAXIMUM_MEMORY=4gb \
584+
-s USE_ES6_IMPORT_META=0 \
585+
-s ERROR_ON_UNDEFINED_SYMBOLS=1 \
586+
-s ENVIRONMENT=web,webview,worker \
587+
")
588+
endif ()
548589
if(NOT WIN32)
549590
set(CMAKE_SHARED_LIBRARY_SUFFIX .so)
550591

@@ -569,8 +610,15 @@ elseif(PSP_CPP_BUILD OR PSP_PYTHON_BUILD)
569610
# #######################
570611
# Python extra targets #
571612
# #######################
572-
add_library(psp SHARED ${PYTHON_SOURCE_FILES})
613+
add_library(psp STATIC ${PYTHON_SOURCE_FILES})
573614
add_library(binding SHARED ${PYTHON_BINDING_SOURCE_FILES})
615+
if(PSP_PYODIDE)
616+
set(PSP_PYTHON_DEFS PSP_ENABLE_WASM=1)
617+
else()
618+
set(PSP_PYTHON_DEFS PSP_ENABLE_PYTHON_THREADING=1)
619+
endif()
620+
target_compile_definitions(psp PRIVATE ${PSP_PYTHON_DEFS})
621+
target_compile_definitions(binding PRIVATE ${PSP_PYTHON_DEFS})
574622

575623
include_directories(${PSP_PYTHON_SRC}/include)
576624

@@ -583,13 +631,16 @@ elseif(PSP_CPP_BUILD OR PSP_PYTHON_BUILD)
583631

584632
# .dll not importable
585633
set_property(TARGET binding PROPERTY SUFFIX .pyd)
634+
elseif(PSP_PYODIDE)
635+
target_compile_options(psp PRIVATE -fvisibility=hidden)
636+
target_compile_options(binding PRIVATE -fvisibility=hidden)
586637
elseif(MACOS OR NOT MANYLINUX)
587638
target_compile_options(binding PRIVATE -Wdeprecated-declarations)
588639
set_property(TARGET psp PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_RPATH} ${module_origin_path})
589640
set_property(TARGET binding PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_RPATH} ${module_origin_path})
590641

591642
target_compile_options(psp PRIVATE -fvisibility=hidden)
592-
target_compile_options(binding PRIVATE -fvisibility=hidden)
643+
target_compile_options(binding PRIVATE -fvisibility=hidden)
593644
else()
594645
target_compile_options(binding PRIVATE -Wdeprecated-declarations)
595646
endif()
@@ -612,15 +663,15 @@ elseif(PSP_CPP_BUILD OR PSP_PYTHON_BUILD)
612663
endif()
613664

614665
if(PSP_CPP_BUILD_STRICT AND NOT WIN32)
615-
target_compile_options(psp PRIVATE -Wall -Werror)
616-
target_compile_options(psp PRIVATE $<$<CONFIG:DEBUG>:-fPIC -O0>)
666+
# target_compile_options(psp PRIVATE -Wall -Werror)
667+
# target_compile_options(psp PRIVATE $<$<CONFIG:DEBUG>:-fPIC -O0>)
617668

618-
if(PSP_PYTHON_BUILD)
669+
if(PSP_PYTHON_BUILD AND NOT PSP_PYODIDE)
619670
target_compile_options(binding PRIVATE $<$<CONFIG:DEBUG>:-fPIC -O0>)
620671
endif()
621672
elseif(WIN32)
622-
target_compile_definitions(psp PRIVATE PERSPECTIVE_EXPORTS=1)
623-
target_compile_definitions(psp PRIVATE WIN32=1)
624-
target_compile_definitions(psp PRIVATE _WIN32=1)
673+
# target_compile_definitions(psp PRIVATE PERSPECTIVE_EXPORTS=1)
674+
# target_compile_definitions(psp PRIVATE WIN32=1)
675+
# target_compile_definitions(psp PRIVATE _WIN32=1)
625676
endif()
626677
endif()

cpp/perspective/src/cpp/base.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <perspective/base.h>
1212
#include <cstdint>
1313
#include <limits>
14-
#ifdef PSP_ENABLE_WASM
14+
#if defined PSP_ENABLE_WASM
1515
#include <emscripten.h>
1616
#else
1717
#include <perspective/exception.h>
@@ -21,7 +21,7 @@ namespace perspective {
2121

2222
void
2323
psp_abort(const std::string& message) {
24-
#ifdef PSP_ENABLE_WASM
24+
#if defined PSP_ENABLE_WASM
2525
std::string error = "Abort(): " + message;
2626
const char* error_cstr = error.c_str();
2727

cpp/perspective/src/cpp/column.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,20 +348,20 @@ t_column::reserve(t_uindex size) {
348348
// object storage, specialize only for std::uint64_t
349349
template <>
350350
void
351-
t_column::object_copied<std::uint64_t>(std::uint64_t ptr) const {}
351+
t_column::object_copied<std::uint64_t>(t_uindex ptr) const {}
352352

353353
void
354-
t_column::notify_object_copied(std::uint64_t idx) const {
354+
t_column::notify_object_copied(t_uindex idx) const {
355355
if (*get_nth_status(idx) == STATUS_VALID)
356356
object_copied<PSP_OBJECT_TYPE>(*(get_nth<std::uint64_t>(idx)));
357357
}
358358

359359
template <>
360360
void
361-
t_column::object_cleared<std::uint64_t>(std::uint64_t ptr) const {}
361+
t_column::object_cleared<std::uint64_t>(t_uindex ptr) const {}
362362

363363
void
364-
t_column::notify_object_cleared(std::uint64_t idx) const {
364+
t_column::notify_object_cleared(t_uindex idx) const {
365365
if (*get_nth_status(idx) == STATUS_VALID)
366366
object_cleared<PSP_OBJECT_TYPE>(*(get_nth<std::uint64_t>(idx)));
367367
}

0 commit comments

Comments
 (0)