diff --git a/dev/tasks/r/github.linux.r-wasm.yml b/dev/tasks/r/github.linux.r-wasm.yml new file mode 100644 index 000000000000..ee38740bb47d --- /dev/null +++ b/dev/tasks/r/github.linux.r-wasm.yml @@ -0,0 +1,75 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +{% import 'macros.jinja' as macros with context %} + +{{ macros.github_header() }} + +jobs: + r-universe-wasm: + name: "R-universe Wasm build" + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + {{ macros.github_checkout_arrow()|indent }} + + - uses: r-lib/actions/setup-r@v2 + with: + install-r: true + + - name: Build Arrow R source package + shell: bash + run: | + cd arrow/r + make sync-cpp + R CMD build --no-build-vignettes . + + - name: Pull the R-universe Wasm image + shell: bash + run: docker pull ghcr.io/r-universe-org/build-wasm:latest + + - name: Build Wasm binary in the R-universe container + shell: bash + run: | + docker run --rm \ + -v "${PWD}/arrow/r:/work" \ + -w /work \ + ghcr.io/r-universe-org/build-wasm:latest \ + bash -lc ' + set -euxo pipefail + R -q -e "if (!requireNamespace(\"pak\", quietly = TRUE)) install.packages(\"pak\", repos = \"https://cloud.r-project.org\"); if (!requireNamespace(\"rwasm\", quietly = TRUE)) pak::pak(\"r-wasm/rwasm\"); rwasm::build(\".\")" \ + 2>&1 | tee build-wasm.log + ' + + - name: List generated artifacts + if: always() + shell: bash + run: | + ls -lh arrow/r/arrow_*.tar.gz + ls -lh arrow/r/arrow_*.tgz || true + ls -lh arrow/r/build-wasm.log || true + + - name: Upload Wasm build artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: r-wasm-build + path: | + arrow/r/arrow_*.tar.gz + arrow/r/arrow_*.tgz + arrow/r/build-wasm.log diff --git a/dev/tasks/tasks.yml b/dev/tasks/tasks.yml index 9647e5531da3..2d2b9ae39e41 100644 --- a/dev/tasks/tasks.yml +++ b/dev/tasks/tasks.yml @@ -651,6 +651,10 @@ tasks: env: CMAKE_BUILD_TYPE: MinSizeRel + test-r-wasm: + ci: github + template: r/github.linux.r-wasm.yml + test-r-devdocs: ci: github template: r/github.devdocs.yml diff --git a/r/inst/build_arrow_static.sh b/r/inst/build_arrow_static.sh index 241994223d3e..349531b75fd9 100755 --- a/r/inst/build_arrow_static.sh +++ b/r/inst/build_arrow_static.sh @@ -62,9 +62,12 @@ case "$CXX" in ;; esac +# Used for Emscripten +: ${CMAKE_WRAPPER:=""} + mkdir -p "${BUILD_DIR}" pushd "${BUILD_DIR}" -${CMAKE} -DARROW_BOOST_USE_SHARED=OFF \ +${CMAKE_WRAPPER} ${CMAKE} -DARROW_BOOST_USE_SHARED=OFF \ -DARROW_SNAPPY_USE_SHARED=OFF \ -DARROW_BUILD_TESTS=OFF \ -DARROW_BUILD_SHARED=OFF \ @@ -74,6 +77,8 @@ ${CMAKE} -DARROW_BOOST_USE_SHARED=OFF \ -DARROW_CSV=ON \ -DARROW_DATASET=${ARROW_DATASET:-ON} \ -DARROW_DEPENDENCY_SOURCE=${ARROW_DEPENDENCY_SOURCE:-AUTO} \ + -DARROW_DEPENDENCY_USE_SHARED=${ARROW_DEPENDENCY_USE_SHARED:-ON} \ + -DARROW_ENABLE_THREADING=${ARROW_ENABLE_THREADING:-ON} \ -DAWSSDK_SOURCE=${AWSSDK_SOURCE:-} \ -DBoost_SOURCE=${Boost_SOURCE:-} \ -Dlz4_SOURCE=${lz4_SOURCE:-} \ diff --git a/r/tools/nixlibs.R b/r/tools/nixlibs.R index 947bb6c3f5cc..ba705e03ad7e 100644 --- a/r/tools/nixlibs.R +++ b/r/tools/nixlibs.R @@ -616,6 +616,7 @@ build_libarrow <- function(src_dir, dst_dir) { } env_var_list <- with_cloud_support(env_var_list) + env_var_list <- with_wasm_support(env_var_list) # turn_off_all_optional_features() needs to happen after # with_cloud_support(), since it might turn features ON. @@ -883,6 +884,40 @@ is_feature_requested <- function(env_varname, env_var_list, default = env_is("LI requested } +with_wasm_support <- function(env_var_list) { + cc <- env_var_list[["CC"]] + cxx <- env_var_list[["CXX"]] + if (!grepl("emcc", cc) && !grepl("em\\+\\+", cxx)) { + return(env_var_list) + } + + lg("Emscripten compiler detected; configuring for WASM build", .indent = "****") + + if (!nzchar(Sys.which("emcmake"))) { + stop("emcmake is required for Emscripten/webR builds but was not found in PATH") + } + + wasm_overrides <- c( + CMAKE_WRAPPER = "emcmake", + ARROW_DEPENDENCY_SOURCE = "BUNDLED", + ARROW_DEPENDENCY_USE_SHARED = "OFF", + ARROW_ENABLE_THREADING = "OFF", + ARROW_GCS = "OFF", + ARROW_JEMALLOC = "OFF", + ARROW_MIMALLOC = "OFF", + ARROW_S3 = "OFF", + ARROW_WITH_BROTLI = "OFF", + ARROW_WITH_BZ2 = "OFF", + ARROW_WITH_ZSTD = "OFF", + N_JOBS = "2", + EXTRA_CMAKE_FLAGS = paste( + env_var_list[["EXTRA_CMAKE_FLAGS"]], + "-DARROW_SIMD_LEVEL=NONE -DARROW_RUNTIME_SIMD_LEVEL=NONE" + ) + ) + replace(env_var_list, names(wasm_overrides), wasm_overrides) +} + with_cloud_support <- function(env_var_list) { arrow_s3 <- is_feature_requested("ARROW_S3", env_var_list) arrow_gcs <- is_feature_requested("ARROW_GCS", env_var_list)