Skip to content

Commit

Permalink
Sync main to release-1.7 as much as possible, in prep for #2158 (#…
Browse files Browse the repository at this point in the history
…2165)

* Sync `main` to `release-1.7` as much as possible

* add new files
  • Loading branch information
johnkerl authored Feb 22, 2024
1 parent ec8fc2e commit 0641874
Show file tree
Hide file tree
Showing 28 changed files with 639 additions and 1,228 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Workflow derived from https://github.com/r-lib/actions/tree/master/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help

on:
#push:
# # To publish docs from your branch: list the branch name here instead of main.
Expand All @@ -9,6 +10,8 @@ on:
# branches: [main]
release:
types: [published]
schedule:
- cron: "42 9 * * *"
workflow_dispatch:

name: pkgdown
Expand All @@ -31,8 +34,12 @@ jobs:
use-public-rspm: true
working-directory: "apis/r"

# Run this daily to surface errors as tracked at
# https://github.com/single-cell-data/TileDB-SOMA/issues/2052
- name: Install dependencies
run: ./apis/r/tools/install-pkgdown-dependencies.sh

# Run this on releases, or on workflow dispatch
- name: Deploy package
if: github.event_name != 'schedule'
run: ./apis/r/tools/deploy-pkgdown.sh
125 changes: 125 additions & 0 deletions .github/workflows/python-so-copying.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Confirm shared object copying when building the Python package
# https://github.com/single-cell-data/TileDB-SOMA/pull/1937

name: Python SO copying

on:
push:
paths:
- '.github/workflows/python-so-copying.yml'
- 'apis/python/**'
- 'libtiledbsoma/cmake/**'
pull_request:
paths:
- '.github/workflows/python-so-copying.yml'
- 'apis/python/**'
- 'libtiledbsoma/cmake/**'
workflow_dispatch:

defaults:
run:
shell: bash

jobs:
build:
runs-on: ubuntu-latest
name: "TILEDB_EXISTS: ${{ matrix.TILEDB_EXISTS }} TILEDBSOMA_EXISTS: ${{ matrix.TILEDBSOMA_EXISTS }}"
strategy:
fail-fast: false
matrix:
TILEDB_EXISTS: ["no", "yes"]
TILEDBSOMA_EXISTS: ["no", "yes"]
exclude:
- TILEDB_EXISTS: "no"
TILEDBSOMA_EXISTS: "yes"
container:
image: ubuntu:22.04
steps:
- name: Docker image info
run: |
uname -a
cat /etc/lsb-release
- name: Setup
run: |
apt-get update
apt-get install --yes cmake git python-is-python3 python3 python3-pip python3-venv unzip wget
- uses: actions/checkout@v4
with:
fetch-depth: 0 # for setuptools-scm
- name: Configure Git
run: |
# This is a permissions quirk due to running Git as root inside of a Docker container
git config --global --add safe.directory $(pwd)
git branch
- name: Install pre-built libtiledb
if: ${{ matrix.TILEDB_EXISTS == 'yes' }}
run: |
mkdir -p external
wget --quiet https://github.com/TileDB-Inc/TileDB/releases/download/2.19.1/tiledb-linux-x86_64-2.19.1-29ceb3e7.tar.gz
tar -C external -xzf tiledb-linux-x86_64-*.tar.gz
ls external/lib/
echo "LD_LIBRARY_PATH=$(pwd)/external/lib" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=$(pwd)/external/lib/pkgconfig" >> $GITHUB_ENV
echo "TILEDB_PATH=$(pwd)/external" >> $GITHUB_ENV
- name: Build and install libtiledbsoma
if: ${{ matrix.TILEDBSOMA_EXISTS == 'yes' }}
run: |
cmake -S libtiledbsoma -B build-libtiledbsoma \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_PREFIX_PATH=$(pwd)/external/ \
-D CMAKE_INSTALL_PREFIX:PATH=$(pwd)/external/ \
-D OVERRIDE_INSTALL_PREFIX=OFF \
-D DOWNLOAD_TILEDB_PREBUILT=OFF \
-D FORCE_BUILD_TILEDB=OFF
cmake --build build-libtiledbsoma -j $(nproc)
cmake --build build-libtiledbsoma --target install-libtiledbsoma
ls external/lib/
echo "TILEDBSOMA_PATH=$(pwd)/external" >> $GITHUB_ENV
- name: Setup Python
run: |
python --version
python -m venv ./venv-soma
./venv-soma/bin/python -m pip install --prefer-binary pybind11-global typeguard sparse wheel
./venv-soma/bin/python -m pip list
- name: Build wheel
run: |
echo env vars: $LD_LIBRARY_PATH $PKG_CONFIG_PATH $TILEDB_PATH $TILEDBSOMA_PATH
cd apis/python
../../venv-soma/bin/python setup.py bdist_wheel
- name: Inspect wheel
run: unzip -l apis/python/dist/tiledbsoma-*.whl | grep '\.so'
- name: Confirm libtiledb.so is copied
if: ${{ matrix.TILEDB_EXISTS == 'no' }}
run: unzip -l apis/python/dist/tiledbsoma-*.whl | grep -q libtiledb.so
- name: Confirm libtiledb.so is **not** copied when using external shared object
if: ${{ matrix.TILEDB_EXISTS == 'yes' }}
run: |
if unzip -l apis/python/dist/tiledbsoma-*.whl | grep -q libtiledb.so
then
echo "libtiledb.so was copied into the wheel when it was built against an external shared object"
exit 1
fi
- name: Confirm libtiledbsoma.so is copied
if: ${{ matrix.TILEDBSOMA_EXISTS == 'no' }}
run: unzip -l apis/python/dist/tiledbsoma-*.whl | grep -q libtiledbsoma.so
- name: Confirm libtiledbsoma.so is **not** copied when using external shared object
if: ${{ matrix.TILEDBSOMA_EXISTS == 'yes' }}
run: |
if unzip -l apis/python/dist/tiledbsoma-*.whl | grep -q libtiledbsoma.so
then
echo "libtiledbsoma.so was copied into the wheel when it was built against an external shared object"
exit 1
fi
- name: Install wheel
run: ./venv-soma/bin/python -m pip install --prefer-binary apis/python/dist/tiledbsoma-*.whl
- name: Check linking and RPATH
run: |
ldd ./venv-soma/lib/python*/site-packages/tiledbsoma/pytiledbsoma.*.so
readelf -d ./venv-soma/lib/python*/site-packages/tiledbsoma/pytiledbsoma.*.so | grep R*PATH
- name: Runtime test
run: ./venv-soma/bin/python -c "import tiledbsoma; print(tiledbsoma.pytiledbsoma.version())"
- name: Confirm linking to installed shared objects
run: |
rm -fr build/ build-libtiledbsoma/ dist/ apis/python/build apis/python/src/tiledbsoma/*tile*.so*
find . -name '*tile*.so*' # should only show shared objects installed in virtual env
./venv-soma/bin/python -c "import tiledbsoma; print(tiledbsoma.pytiledbsoma.version())"
114 changes: 75 additions & 39 deletions apis/python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,11 @@

import version # noqa E402

# tiledb_dir and libtiledbsoma_dir may be specified by either environment variable
# tiledb_dir and tiledbsoma_dir may be specified by either environment variable
# or command-line argument. If both are provided, the latter wins.

tiledb_dir: Optional[pathlib.Path] = None
libtiledbsoma_dir: Optional[pathlib.Path] = None

tiledb_dir = pathlib.Path(os.environ.get("TILEDB_PATH", this_dir))
libtiledbsoma_dir = os.environ.get("TILEDBSOMA_PATH", None)
tiledbsoma_dir: Optional[pathlib.Path] = None

args = sys.argv[:]
for arg in args:
Expand All @@ -56,16 +53,37 @@
tiledb_dir = pathlib.Path(last)
sys.argv.remove(arg)
if (start, eq) == ("--libtiledbsoma", "="):
libtiledbsoma_dir = pathlib.Path(last)
tiledbsoma_dir = pathlib.Path(last)
sys.argv.remove(arg)

if libtiledbsoma_dir is None:
tiledb_dir = os.environ.get("TILEDB_PATH", None)
tiledb_given = tiledb_dir is not None
tiledbsoma_dir = os.environ.get("TILEDBSOMA_PATH", None)

if tiledbsoma_dir is not None and tiledb_dir is None:
raise ValueError(
"If TILEDBSOMA_PATH is set, then TILEDB_PATH must be "
"also be set. TILEDB_PATH must be set to the location of "
"the TileDB shared object library linked to the "
"TileDB-SOMA shared object library"
)

if tiledbsoma_dir is None:
scripts_dir = this_dir / "dist_links" / "scripts"
scripts_dir = scripts_dir.resolve()

libtiledbsoma_dir = scripts_dir.parent / "dist"
tiledbsoma_dir = scripts_dir.parent / "dist"
else:
libtiledbsoma_dir = pathlib.Path(libtiledbsoma_dir)
tiledbsoma_dir = pathlib.Path(tiledbsoma_dir)

if tiledb_dir is None:
# tiledb_dir = pathlib.Path(this_dir)
scripts_dir = this_dir / "dist_links" / "scripts"
scripts_dir = scripts_dir.resolve()

tiledb_dir = scripts_dir.parent / "dist"
else:
tiledb_dir = pathlib.Path(tiledb_dir)


def get_libtiledbsoma_library_name():
Expand Down Expand Up @@ -106,12 +124,12 @@ def libtiledbsoma_exists():
:return: The path to the TileDB-SOMA library, or None.
"""
# Check if TileDB-SOMA is installed in user given path
dist_dirs = [libtiledbsoma_dir / "lib"]
dist_dirs = [tiledbsoma_dir / "lib"]
if sys.platform.startswith("linux"):
dist_dirs.append(libtiledbsoma_dir / "lib64")
dist_dirs.append(libtiledbsoma_dir / "lib" / "x86_64-linux-gnu")
dist_dirs.append(tiledbsoma_dir / "lib64")
dist_dirs.append(tiledbsoma_dir / "lib" / "x86_64-linux-gnu")
elif os.name == "nt":
dist_dirs.append(libtiledbsoma_dir / "bin")
dist_dirs.append(tiledbsoma_dir / "bin")

for lib_dir in dist_dirs:
full_lib_path = lib_dir / get_libtiledbsoma_library_name()
Expand Down Expand Up @@ -148,25 +166,42 @@ def find_or_build_package_data(setuptools_cmd):
#
# See `.github/workflows/python-ci-single.yml` for configuration.
if os.name == "nt":
subprocess.run(["pwsh.exe", "./bld.ps1"], cwd=scripts_dir, check=True)
bld_command = ["pwsh.exe", "./bld.ps1"]
if tiledb_dir is not None:
bld_command.append(f"TileDBLocation={tiledb_dir}")
else:
subprocess.run(["./bld"], cwd=scripts_dir, check=True)
bld_command = ["./bld"]
if tiledb_dir is not None:
bld_command.append(f"--tiledb={tiledb_dir}")

subprocess.run(bld_command, cwd=scripts_dir, check=True)

lib_dir = libtiledbsoma_exists()
assert lib_dir, "error when building libtiledbsoma from source"

# Copy native libs into the package dir so they can be found by package_data
package_data = []
src_dir = this_dir / "src" / "tiledbsoma"
for f in lib_dir.glob("*tiledbsoma*"):
if f.suffix != ".a": # skip static library
print(f" copying file {f} to {src_dir}")
shutil.copy(f, src_dir)
package_data.append(f.name)
assert package_data, f"libtiledbsoma artifacts absent from {lib_dir}"

# Install shared libraries inside the Python module via package_data.
print(f" adding to package_data: {package_data}")
setuptools_cmd.distribution.package_data["tiledbsoma"] = package_data
# If we are building from source, then we are likely building wheels.
# Copy both the tiledbsoma and tiledb shared objects into the
# package dir so they can be found by package_data
package_data = []
src_dir = this_dir / "src" / "tiledbsoma"
for f in lib_dir.glob("*tiledbsoma.*"):
if f.suffix != ".a": # skip static library
print(f" copying file {f} to {src_dir}")
shutil.copy(f, src_dir)
package_data.append(f.name)
assert package_data, f"tiledbsoma artifacts absent from {lib_dir}"

if not tiledb_given:
for f in lib_dir.glob("*tiledb.*"):
if f.suffix != ".a": # skip static library
print(f" copying file {f} to {src_dir}")
shutil.copy(f, src_dir)
package_data.append(f.name)
assert package_data, f"tiledb artifacts absent from {lib_dir}"

# Install shared libraries inside the Python module via package_data.
print(f" adding to package_data: {package_data}")
setuptools_cmd.distribution.package_data["tiledbsoma"] = package_data


class build_ext(setuptools.command.build_ext.build_ext):
Expand All @@ -185,34 +220,33 @@ def run(self):
"dist_links/libtiledbsoma/include",
"dist_links/libtiledbsoma/external/include",
"../../build/externals/install/include",
str(libtiledbsoma_dir / "include"),
str(libtiledbsoma_dir.parent / "build/externals/install/include"),
str(tiledbsoma_dir / "include"),
str(tiledbsoma_dir.parent / "build/externals/install/include"),
str(tiledbsoma_dir / "include"),
str(tiledb_dir / "include"),
]

LIB_DIRS = [
str(libtiledbsoma_dir / "lib"),
str(tiledbsoma_dir / "lib"),
str(tiledb_dir / "lib"),
]

CXX_FLAGS = []

if os.name != "nt":
CXX_FLAGS.append(f'-Wl,-rpath,{str(libtiledbsoma_dir / "lib")}')
CXX_FLAGS.append(f'-Wl,-rpath,{str(tiledbsoma_dir / "lib")}')
CXX_FLAGS.append(f'-Wl,-rpath,{str(tiledb_dir / "lib")}')

if sys.platform == "darwin":
CXX_FLAGS.append("-mmacosx-version-min=10.14")
CXX_FLAGS.append("-mmacosx-version-min=11.0")

if os.name == "posix" and sys.platform != "darwin":
LIB_DIRS.append(str(libtiledbsoma_dir / "lib" / "x86_64-linux-gnu"))
LIB_DIRS.append(str(libtiledbsoma_dir / "lib64"))
LIB_DIRS.append(str(tiledbsoma_dir / "lib" / "x86_64-linux-gnu"))
LIB_DIRS.append(str(tiledbsoma_dir / "lib64"))
LIB_DIRS.append(str(tiledb_dir / "lib" / "x86_64-linux-gnu"))
LIB_DIRS.append(str(tiledb_dir / "lib64"))
CXX_FLAGS.append(
f'-Wl,-rpath,{str(libtiledbsoma_dir / "lib" / "x86_64-linux-gnu")}'
)
CXX_FLAGS.append(f'-Wl,-rpath,{str(libtiledbsoma_dir / "lib64")}')
CXX_FLAGS.append(f'-Wl,-rpath,{str(tiledbsoma_dir / "lib" / "x86_64-linux-gnu")}')
CXX_FLAGS.append(f'-Wl,-rpath,{str(tiledbsoma_dir / "lib64")}')
CXX_FLAGS.append(f'-Wl,-rpath,{str(tiledb_dir / "lib" / "x86_64-linux-gnu")}')
CXX_FLAGS.append(f'-Wl,-rpath,{str(tiledb_dir / "lib64")}')

Expand Down Expand Up @@ -263,6 +297,8 @@ def run(self):
"src/tiledbsoma/soma_array.cc",
"src/tiledbsoma/soma_object.cc",
"src/tiledbsoma/soma_dataframe.cc",
"src/tiledbsoma/soma_dense_ndarray.cc",
"src/tiledbsoma/soma_sparse_ndarray.cc",
"src/tiledbsoma/pytiledbsoma.cc",
],
include_dirs=INC_DIRS,
Expand Down
42 changes: 42 additions & 0 deletions apis/python/src/tiledbsoma/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,48 @@
# crucial that we include a separator (e.g. "Classes and functions") to make an entry in the
# readthedocs table of contents.

import ctypes
import os
import sys


# Load native libraries. On wheel builds, we may have a shared library
# already linked. In this case, we can import directly
try:
from . import pytiledbsoma as clib

del clib
except ImportError:
if os.name == "nt":
libtiledb_name = "tiledb.dll"
elif sys.platform == "darwin":
libtiledb_name = "libtiledb.dylib"
else:
libtiledb_name = "libtiledb.so"

try:
# Try loading the bundled native library.
lib_dir = os.path.dirname(os.path.abspath(__file__))
ctypes.CDLL(os.path.join(lib_dir, libtiledb_name), mode=ctypes.RTLD_GLOBAL)
except OSError:
# Otherwise try loading by name only.
ctypes.CDLL(libtiledb_name, mode=ctypes.RTLD_GLOBAL)

if os.name == "nt":
libtiledbsoma_name = "tiledbsoma.dll"
elif sys.platform == "darwin":
libtiledbsoma_name = "libtiledbsoma.dylib"
else:
libtiledbsoma_name = "libtiledbsoma.so"

try:
# Try loading the bundled native library.
lib_dir = os.path.dirname(os.path.abspath(__file__))
ctypes.CDLL(os.path.join(lib_dir, libtiledbsoma_name))
except OSError:
# Otherwise try loading by name only.
ctypes.CDLL(libtiledbsoma_name)

from somacore import AxisColumnNames, AxisQuery, ExperimentAxisQuery
from somacore.options import ResultOrder

Expand Down
Loading

0 comments on commit 0641874

Please sign in to comment.