diff --git a/Dockerfile.manylinux_2_28_x86_64 b/Dockerfile.manylinux_2_28_x86_64 index 2d14d0e8e2..1297f8ed05 100644 --- a/Dockerfile.manylinux_2_28_x86_64 +++ b/Dockerfile.manylinux_2_28_x86_64 @@ -29,16 +29,14 @@ FROM quay.io/pypa/manylinux_2_28_x86_64 ARG MEDIAPIPE_DISABLE_GPU=1 ENV MEDIAPIPE_DISABLE_GPU=${MEDIAPIPE_DISABLE_GPU} -RUN yum install -y java-11-openjdk-devel zip +RUN yum install -y java-21-openjdk-devel zip +ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk WORKDIR /tmp/bazel_build -ADD https://github.com/bazelbuild/bazel/releases/download/7.4.1/bazel-7.4.1-dist.zip bazel.zip -RUN unzip bazel.zip -RUN rm -f bazel.zip +RUN curl -fL --retry 5 --retry-delay 5 --retry-connrefused \ + -o /usr/local/bin/bazel https://github.com/bazelbuild/bazel/releases/download/7.4.1/bazel-7.4.1-linux-x86_64 && \ + chmod +x /usr/local/bin/bazel + ENV PATH="/opt/python/cp36-cp36m/bin:${PATH}" -ENV EXTRA_BAZEL_ARGS="--host_javabase=@local_jdk//:jdk" -ENV BAZEL_LINKLIBS=-lm:-lstdc++ -RUN ./compile.sh -RUN cp /tmp/bazel_build/output/bazel /bin/bazel # Install Clang 18 @@ -47,6 +45,12 @@ RUN mkdir /tmp/llvm-project && wget -qO - https://github.com/llvm/llvm-project/a mkdir /tmp/llvm-project/build && cd /tmp/llvm-project/build && cmake -DLLVM_ENABLE_PROJECTS='clang;lld' -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/lib/llvm-18/ ../llvm && \ make -j$(nproc) && make -j$(nproc) install && rm -rf /tmp/llvm-project +# Install newer libstdc++ headers/libs for C++20 support. +RUN yum install -y gcc-toolset-14-gcc gcc-toolset-14-gcc-c++ gcc-toolset-14-libstdc++-devel +ENV CPLUS_INCLUDE_PATH="/opt/rh/gcc-toolset-14/root/usr/include/c++/14:/opt/rh/gcc-toolset-14/root/usr/include/c++/14/x86_64-redhat-linux:/opt/rh/gcc-toolset-14/root/usr/include/c++/14/backward" +ENV LIBRARY_PATH="/opt/rh/gcc-toolset-14/root/usr/lib64" +ENV LD_LIBRARY_PATH="/opt/rh/gcc-toolset-14/root/usr/lib64" + # Install OpenGL RUN yum install -y mesa-libGL mesa-libGL-devel mesa-libEGL mesa-libEGL-devel RUN yum install -y mesa-libGLES-devel @@ -56,8 +60,9 @@ RUN yum install -y epel-release && yum install -y java-11-openjdk \ java-11-openjdk-devel zip emacs portaudio-devel # Copy Protobuf Compiler binary -ARG PROTOC_ZIP=protoc-25.1-linux-x86_64.zip -RUN curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v25.1/$PROTOC_ZIP +ARG PROTOC_VERSION=28.3 +ARG PROTOC_ZIP=protoc-${PROTOC_VERSION}-linux-x86_64.zip +RUN curl -fLo $PROTOC_ZIP https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/$PROTOC_ZIP RUN unzip -o $PROTOC_ZIP -d /usr/local bin/protoc RUN unzip -o $PROTOC_ZIP -d /usr/local 'include/*' RUN rm -f $PROTOC_ZIP @@ -71,7 +76,7 @@ RUN cd /tmp/bazel_build/opencv && git checkout 4.10.0 && cd release && cmake .. -DCMAKE_C_COMPILER=/usr/lib/llvm-18/bin/clang -DCMAKE_CXX_COMPILER=/usr/lib/llvm-18/bin/clang++ \ -DCMAKE_BUILD_TYPE=RELEASE -DCMAKE_INSTALL_PREFIX=/usr/local \ -DBUILD_SHARED_LIBS=OFF -DBUILD_LIST=imgproc,core \ - -DWITH_ITT=OFF -DWITH_IPP=OFF -DBUILD_EXAMPLES=OFF \ + -DWITH_ITT=OFF -DWITH_IPP=OFF -DBUILD_EXAMPLES=OFF -DBUILD_opencv_apps=OFF \ -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_opencv_ts=OFF \ -DCV_ENABLE_INTRINSICS=ON -DWITH_EIGEN=ON -DWITH_PTHREADS=ON -DWITH_PTHREADS_PF=ON RUN cd /tmp/bazel_build/opencv/release && make -j 16 && make install @@ -85,12 +90,46 @@ RUN export MP_VERSION_NUMBER=$(awk '/MEDIAPIPE_FULL_VERSION/ {split($0, a, "="); # Set build flags for MediaPipe and OpenCV. RUN echo "build --client_env=CC=/usr/lib/llvm-18/bin/clang++" >> .bazelrc && \ + echo "build --action_env=LIBRARY_PATH=/opt/rh/gcc-toolset-14/root/usr/lib64" >> .bazelrc && \ + echo "build --action_env=LD_LIBRARY_PATH=/opt/rh/gcc-toolset-14/root/usr/lib64" >> .bazelrc && \ + echo "build --linkopt=-L/opt/rh/gcc-toolset-14/root/usr/lib64" >> .bazelrc && \ + echo "build --linkopt=-lstdc++" >> .bazelrc && \ + echo "build --host_action_env=CC=/opt/rh/gcc-toolset-14/root/usr/bin/gcc" >> .bazelrc && \ + echo "build --host_action_env=CXX=/opt/rh/gcc-toolset-14/root/usr/bin/g++" >> .bazelrc && \ + echo "build --host_linkopt=-L/opt/rh/gcc-toolset-14/root/usr/lib64" >> .bazelrc && \ + echo "build --host_linkopt=-lstdc++" >> .bazelrc && \ + echo "build --cxxopt=--gcc-toolchain=/opt/rh/gcc-toolset-14/root/usr" >> .bazelrc && \ + echo "build --linkopt=--gcc-toolchain=/opt/rh/gcc-toolset-14/root/usr" >> .bazelrc && \ + echo "build --host_cxxopt=--gcc-toolchain=/opt/rh/gcc-toolset-14/root/usr" >> .bazelrc && \ + echo "build --host_linkopt=--gcc-toolchain=/opt/rh/gcc-toolset-14/root/usr" >> .bazelrc && \ echo "build --define=xnn_enable_avxvnniint8=false" >> .bazelrc && \ echo 'cc_library(name = "opencv", srcs = ["local/lib64/libopencv_imgproc.a", "local/lib64/libopencv_core.a"],hdrs = glob(["local/include/opencv4/opencv2/**/*.h*"]), includes = ["local/include/opencv4/"], linkstatic = 1, visibility = ["//visibility:public"])' > third_party/opencv_linux.BUILD && \ sed -i "s|bazel_command.append('--define=OPENCV=source')|pass|g" setup.py # Apply diff to reduce the number of OpenCV dependencies. -RUN patch -p1 < mediapipe_python_build.diff +ARG MEDIAPIPE_PYTHON_BUILD_DIFF_URL="" +RUN if [ ! -f mediapipe_python_build.diff ] && [ -n "${MEDIAPIPE_PYTHON_BUILD_DIFF_URL}" ]; then \ + DIFF_URL="${MEDIAPIPE_PYTHON_BUILD_DIFF_URL}"; \ + case "${DIFF_URL}" in \ + https://github.com/*/blob/*) \ + DIFF_URL="$(echo "${DIFF_URL}" | sed -e 's|^https://github.com/|https://raw.githubusercontent.com/|' -e 's|/blob/|/|')"; \ + ;; \ + esac; \ + if ! curl -fsSL "${DIFF_URL}" -o mediapipe_python_build.diff; then \ + echo "Failed to download mediapipe_python_build.diff; continuing without patch." >&2; \ + rm -f mediapipe_python_build.diff; \ + fi; \ + fi && \ + if [ -s mediapipe_python_build.diff ]; then \ + patch -p1 < mediapipe_python_build.diff; \ + else \ + echo "mediapipe_python_build.diff not found; skipping OpenCV dependency reduction patch." >&2; \ + fi + +# Disable GenAI converter targets when not needed. +RUN sed -i '/genai\\/converter/d' mediapipe/tasks/c/BUILD && \ + sed -i "s/ENABLE_ODML_CONVERTER=1/ENABLE_ODML_CONVERTER=0/g" setup.py && \ + rm -rf mediapipe/tasks/c/genai ARG PYTHON_BIN="/opt/python/cp312-cp312/bin/python3.12" RUN $PYTHON_BIN -m pip install --upgrade pip setuptools diff --git a/build_manylinux_wheel.sh b/build_manylinux_wheel.sh new file mode 100644 index 0000000000..860e48ec33 --- /dev/null +++ b/build_manylinux_wheel.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Builds the manylinux image and extracts wheels into ./wheelhouse. +IMAGE_NAME="${IMAGE_NAME:-mp_manylinux}" +PYTHON_BIN="${PYTHON_BIN:-/opt/python/cp312-cp312/bin/python3.12}" +MEDIAPIPE_PYTHON_BUILD_DIFF_URL="${MEDIAPIPE_PYTHON_BUILD_DIFF_URL:-}" +CONTAINER_NAME="${CONTAINER_NAME:-mp_pip_package_container}" + +DOCKER_BUILDKIT=1 docker build \ + -f Dockerfile.manylinux_2_28_x86_64 \ + -t "${IMAGE_NAME}" . \ + --build-arg "PYTHON_BIN=${PYTHON_BIN}" \ + --build-arg "MEDIAPIPE_PYTHON_BUILD_DIFF_URL=${MEDIAPIPE_PYTHON_BUILD_DIFF_URL}" + +docker create -ti --name "${CONTAINER_NAME}" "${IMAGE_NAME}:latest" >/dev/null +mkdir -p wheelhouse +docker cp "${CONTAINER_NAME}:/wheelhouse/." wheelhouse/ +docker rm -f "${CONTAINER_NAME}" >/dev/null diff --git a/mediapipe/__init__.py b/mediapipe/__init__.py index bf29fed398..c9e6337fc7 100644 --- a/mediapipe/__init__.py +++ b/mediapipe/__init__.py @@ -11,3 +11,31 @@ # 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 warnings + +try: + import mediapipe.tasks.python as tasks + from mediapipe.tasks.python.vision.core.image import Image + from mediapipe.tasks.python.vision.core.image import ImageFormat +except Exception as e: # pragma: no cover - optional tasks dependencies + tasks = None + Image = None + ImageFormat = None + warnings.warn( + "MediaPipe tasks APIs could not be imported. Some functionality may be " + f"unavailable. Original error: {e}", + RuntimeWarning, + ) + +try: + from mediapipe.python import solutions +except Exception as e: # pragma: no cover - optional solutions dependencies + solutions = None + warnings.warn( + "MediaPipe solutions APIs could not be imported. Some functionality may " + f"be unavailable. Original error: {e}", + RuntimeWarning, + ) + + +__version__ = '0.10.32' \ No newline at end of file diff --git a/mediapipe/tasks/c/BUILD b/mediapipe/tasks/c/BUILD index 76613d0735..cd5a44e237 100644 --- a/mediapipe/tasks/c/BUILD +++ b/mediapipe/tasks/c/BUILD @@ -43,8 +43,6 @@ cc_binary( ":mediapipe_tasks_c_version_script.lds", "//mediapipe/tasks/c/audio/audio_classifier:audio_classifier_c_lib", "//mediapipe/tasks/c/core:common", - "//mediapipe/tasks/c/genai/bundler:llm_bundler_utils_c_lib", - "//mediapipe/tasks/c/genai/converter:llm_converter_c_lib", "//mediapipe/tasks/c/metadata:flatbuffer_api_c_lib", "//mediapipe/tasks/c/text/language_detector:language_detector_c_lib", "//mediapipe/tasks/c/text/text_classifier:text_classifier_c_lib", diff --git a/mediapipe/tasks/python/__init__.py b/mediapipe/tasks/python/__init__.py index 1861d1049f..7a40148cc7 100644 --- a/mediapipe/tasks/python/__init__.py +++ b/mediapipe/tasks/python/__init__.py @@ -14,14 +14,34 @@ """MediaPipe Tasks API.""" -from . import audio -from . import components -from . import core -from . import genai -from . import text -from . import vision +import importlib +import warnings -BaseOptions = core.base_options.BaseOptions + +def _safe_import(name: str): + try: + return importlib.import_module(name) + except Exception as e: # pragma: no cover - optional modules + warnings.warn( + f"MediaPipe Tasks submodule '{name}' could not be imported: {e}", + RuntimeWarning, + ) + return None + + +audio = _safe_import(__name__ + ".audio") +components = _safe_import(__name__ + ".components") +core = _safe_import(__name__ + ".core") +genai = _safe_import(__name__ + ".genai") +text = _safe_import(__name__ + ".text") +vision = _safe_import(__name__ + ".vision") + +if core is not None: + BaseOptions = core.base_options.BaseOptions +else: + BaseOptions = None # Remove unnecessary modules to avoid duplication in API docs. -del core +if core is not None: + del core + diff --git a/mediapipe/tasks/python/metadata/metadata.py b/mediapipe/tasks/python/metadata/metadata.py index 611f6195f8..81c8d1540e 100644 --- a/mediapipe/tasks/python/metadata/metadata.py +++ b/mediapipe/tasks/python/metadata/metadata.py @@ -30,7 +30,10 @@ import flatbuffers -from mediapipe.tasks.cc.metadata.python import _pywrap_metadata_version +try: + from mediapipe.tasks.cc.metadata.python import _pywrap_metadata_version +except ModuleNotFoundError: # pragma: no cover - optional native extension + _pywrap_metadata_version = None from mediapipe.tasks.metadata import metadata_schema_py_generated as _metadata_fb from mediapipe.tasks.metadata import schema_py_generated as _schema_fb from mediapipe.tasks.python.core import mediapipe_c_bindings @@ -391,6 +394,12 @@ def load_metadata_buffer(self, metadata_buf): self._validate_metadata(metadata_buf) # Gets the minimum metadata parser version of the metadata_buf. + if _pywrap_metadata_version is None: + raise RuntimeError( + "Metadata population requires mediapipe.tasks.cc, which is not " + "available in this build. Use a MediaPipe build that ships the " + "native metadata bindings or avoid metadata export." + ) min_version = _pywrap_metadata_version.GetMinimumMetadataParserVersion( bytes(metadata_buf)) diff --git a/setup.py b/setup.py index 2c5a77c4d6..b828c1eb44 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ from setuptools.command import build_py from setuptools.command import install -__version__ = 'dev' + MP_DISABLE_GPU = os.environ.get('MEDIAPIPE_DISABLE_GPU') != '0' IS_WINDOWS = (platform.system() == 'Windows') IS_MAC = (platform.system() == 'Darwin') @@ -39,6 +39,17 @@ MP_THIRD_PARTY_BUILD = os.path.join(MP_ROOT_PATH, 'third_party/BUILD') MP_ROOT_INIT_PY = os.path.join(MP_ROOT_PATH, '__init__.py') +def _read_version(): + version_file = os.path.join(MP_ROOT_PATH, 'mediapipe', 'version.bzl') + with open(version_file, 'r') as f: + for line in f: + if line.startswith('MEDIAPIPE_FULL_VERSION'): + return line.split('=')[1].strip().strip('"') + return 'dev' + + +__version__ = _read_version() + GPU_OPTIONS_DISABLED = ['--define=MEDIAPIPE_DISABLE_GPU=1'] GPU_OPTIONS_ENABLED = [ '--copt=-DTFLITE_GPU_EXTRA_GLES_DEPS', @@ -134,18 +145,7 @@ def _add_mp_init_files(): """Add __init__.py to mediapipe root directories to make the subdirectories indexable.""" open(MP_ROOT_INIT_PY, 'w').close() # Save the original mediapipe/__init__.py file. - shutil.copyfile(MP_DIR_INIT_PY, _get_backup_file(MP_DIR_INIT_PY)) - mp_dir_init_file = open(MP_DIR_INIT_PY, 'a') - mp_dir_init_file.writelines([ - '\n', - 'import mediapipe.tasks.python as tasks\n', - 'from mediapipe.tasks.python.vision.core.image import Image\n', - 'from mediapipe.tasks.python.vision.core.image import ImageFormat\n', - '\n\n', - "__version__ = '{}'".format(__version__), - '\n', - ]) - mp_dir_init_file.close() + def _copy_to_build_lib_dir(build_lib, file): @@ -412,3 +412,13 @@ def run(self): license='Apache 2.0', keywords='mediapipe', ) +def _read_version(): + version_file = os.path.join(MP_ROOT_PATH, 'mediapipe', 'version.bzl') + with open(version_file, 'r') as f: + for line in f: + if line.startswith('MEDIAPIPE_FULL_VERSION'): + return line.split('=')[1].strip().strip('"') + return 'dev' + + +__version__ = _read_version() diff --git a/third_party/BUILD b/third_party/BUILD index 2ab0a7d00e..d7579f0039 100644 --- a/third_party/BUILD +++ b/third_party/BUILD @@ -202,7 +202,7 @@ OPENCV_MODULES = [ # still only builds the shared libraries, so we have to choose one or the # other. We build shared libraries by default, but this variable can be used # to switch to static libraries. -OPENCV_SHARED_LIBS = True +OPENCV_SHARED_LIBS = False OPENCV_SO_VERSION = "3.4"