Skip to content

Instantly share code, notes, and snippets.

@pangyuteng
Last active November 1, 2024 08:42
Show Gist options
  • Save pangyuteng/e942648579ebfd3c6e07c50eb81f42ac to your computer and use it in GitHub Desktop.
Save pangyuteng/e942648579ebfd3c6e07c50eb81f42ac to your computer and use it in GitHub Desktop.
Sample code to build a cython module via Scikit Build; Dockfile also contains instructions for building ITK VTK Boost (with Python 3.7 via Conda) Zlib with CMake in Ubuntu.

Dockerfile for building a cython module via Scikit Build; Dockfile also contains instructions for building ITK VTK Boost (with Python 3.7 via Conda) Zlib with CMake in Ubuntu.

sudo docker build -t myimage .

sudo docker container run -it myimage
cd _skbuild/linux-x86_64-3.7/cmake-install/hello
python
from _hello import hello
print(hello("ok"))

References

https://gist.github.com/MihaiTheCoder/d1bbe52e81112c6ffe240d74011e786c https://gist.github.com/ndevenish/ff771feb6817f7debfa728386110f567 https://gist.github.com/marcinwol/089d4a91f1a1279e33f9 https://itk.org/Wiki/ITK_Configuring_and_Building_for_Ubuntu_Linux https://stackoverflow.com/questions/47367496/how-to-install-cmake-file-offline-without-updates-on-ubuntu https://github.com/scikit-build/scikit-build-sample-projects/tree/master/projects/hello-cython https://barre.nom.fr/medical/samples/#CT-MONO2-16-chest

cpdef void hello(str strArg):
"Prints back 'Hello <param>', for example example: hello.hello('you')"
print("Hello, {}!)".format(strArg))
cpdef long elevation():
"Returns elevation of Nevado Sajama."
return 21463L
cmake_minimum_required(VERSION 3.5)
project(_hello)
# Find python and Boost - both are required dependencies
find_package(PythonLibs REQUIRED)
find_package(PythonInterp REQUIRED)
find_package(PythonExtensions REQUIRED)
find_package(Cython REQUIRED)
find_package(ZLIB REQUIRED)
find_package(DCMTK REQUIRED)
find_package(Boost COMPONENTS python REQUIRED)
find_package(ITK REQUIRED)
find_package(VTK REQUIRED)
# Without this, any build libraries automatically have names "lib{x}.so"
set(CMAKE_SHARED_MODULE_PREFIX "")
#get numpy include path
execute_process(
COMMAND
${PYTHON_EXECUTABLE} -c "import numpy; print(numpy.get_include())"
OUTPUT_VARIABLE NUMPY_INCLUDE_PATH
RESULT_VARIABLE NUMPY_ERR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NUMPY_ERR)
message(SEND_ERROR "WARNING: NumPy header not found.")
endif(NUMPY_ERR)
# Add a shared module - modules are intended to be imported at runtime.
# - This is where you add the source files
add_cython_target(_hello CXX)
add_library(_hello MODULE ${_hello})
python_extension_module(_hello)
# Set up the libraries and header search paths for this target
target_link_libraries(_hello ${PYTHON_LIBRARIES} ${Boost_LIBRARIES})# ${DCMTK_LIBRARIES} ${ZLIB_LIBRARIES} ${ITK_LIBRARIES} ${VTK_LIBRARIES})
target_include_directories(_hello PRIVATE ${PYTHON_INCLUDE_DIRS})# ${Boost_INCLUDE_DIRS} ${DCMTK_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} ${ITK_INCLUDE_DIRS} ${VTK_INCLUDE_DIRS})
install(TARGETS _hello LIBRARY DESTINATION hello)
message(STATUS "===================")
message(STATUS ${Boost_FOUND})
message(STATUS ${Boost_INCLUDE_DIRS})
message(STATUS ${VTK_FOUND})
message(STATUS ${VTK_INCLUDE_DIRS})
message(STATUS ${ITK_FOUND})
message(STATUS ${ITK_INCLUDE_DIRS})
message(STATUS ${ZLIB_FOUND})
message(STATUS ${ZLIB_INCLUDE_DIR})
message(STATUS ${DCMTK_FOUND})
message(STATUS ${DCMTK_INCLUDE_DIRS})
message(STATUS "===================")
FROM ubuntu:18.04
ARG MYPATH=/usr/local
ARG MYLIBPATH=/usr/lib
RUN apt-get update && apt-get install -y --no-install-recommends \
autotools-dev \
build-essential \
ca-certificates \
cmake \
git \
wget && \
rm -rf /var/lib/apt/lists/*
# abuse opt directory.
WORKDIR /opt
# install miniconda.
RUN wget --quiet --no-check-certificate https://repo.continuum.io/miniconda/Miniconda3-4.6.14-Linux-x86_64.sh --no-check-certificate -O ~/miniconda.sh && \
/bin/bash ~/miniconda.sh -b -p /opt/conda
# create and activate python virtual env with desired version
RUN /opt/conda/bin/conda create -n py python=3.7.2
RUN echo "source /opt/conda/bin/activate py" > ~/.bashrc
ENV PATH /opt/conda/envs/py/bin:$PATH
RUN /bin/bash -c "source /opt/conda/bin/activate py"
# install cmake
WORKDIR /opt
RUN wget --quiet --no-check-certificate https://github.com/Kitware/CMake/releases/download/v3.15.0-rc4/cmake-3.15.0-rc4-Linux-x86_64.sh
RUN bash cmake-3.15.0-rc4-Linux-x86_64.sh --skip-license --prefix=$MYPATH
RUN mkdir -p /opt/sources
# build zlib
WORKDIR /opt/sources
RUN wget --quiet --no-check-certificate https://zlib.net/zlib-1.2.11.tar.gz -O zlib.tar.gz && \
tar xfz zlib.tar.gz
WORKDIR /opt/sources/zlib-1.2.11
RUN ./configure --prefix=$MYPATH && make -j"$(nproc)" && make install -j"$(nproc)"
# build dcmtk
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --fix-missing --no-install-recommends \
libtiff5-dev \
libpng-dev \
libjpeg-dev \
libgif-dev \
libxml2-dev \
libssl-dev \
zlib1g-dev \
libwrap0-dev \
libssl-dev
WORKDIR /opt/sources
RUN wget --quiet --no-check-certificate https://github.com/DCMTK/dcmtk/archive/DCMTK-3.6.4.tar.gz -O dcmtk.tar.gz && \
tar xfz dcmtk.tar.gz
WORKDIR /opt/sources/dcmtk-DCMTK-3.6.4
RUN mkdir build
WORKDIR /opt/sources/dcmtk-DCMTK-3.6.4/build
RUN cmake .. -DCMAKE_INSTALL_PREFIX=$MYPATH -DCMAKE_LIBRARY_PATH=$MYLIBPATH
RUN make -j"$(nproc)" && make install -j"$(nproc)"
# build vtk
#likely not needed# RUN sudo apt-get install mesa-common-dev libgl1-mesa-dev freeglut3-devWORKDIR /opt/sources
WORKDIR /opt/sources
RUN wget --quiet --no-check-certificate http://www.vtk.org/files/release/7.0/VTK-7.0.0.tar.gz -O vtk.tar.gz && \
tar xfz vtk.tar.gz
WORKDIR /opt/sources/VTK-7.0.0
RUN sed -i 's/\[345\]/[34567]/g' CMake/vtkCompilerExtras.cmake
RUN sed -i 's/\[345\]/[34567]/g' CMake/GenerateExportHeader.cmake
RUN mkdir build
WORKDIR /opt/sources/VTK-7.0.0/build
RUN cmake .. -DCMAKE_INSTALL_PREFIX=$MYPATH -DCMAKE_BUILD_TYPE=Release \
-DVTK_Group_Rendering:BOOL=OFF -DVTK_Group_StandAlone:BOOL=ON -DVTK_RENDERING_BACKEND=None
RUN make -j"$(nproc)" && make install -j"$(nproc)"
# build itk
WORKDIR /opt/sources
RUN wget --quiet --no-check-certificate https://github.com/InsightSoftwareConsortium/ITK/releases/download/v5.0.0/InsightToolkit-5.0.0.tar.gz -O itk.tar.gz && \
tar xfz itk.tar.gz
WORKDIR /opt/sources/InsightToolkit-5.0.0
RUN mkdir build
WORKDIR /opt/sources/InsightToolkit-5.0.0/build
RUN cmake .. -DCMAKE_INSTALL_PREFIX=$MYPATH -DCMAKE_BUILD_TYPE=Release \
-DBUILD_DOXYGEN=OFF -DBUILD_EXAMPLES=OFF \
-DBUILD_SHARED_LIBS=OFF -DITK_DYNAMIC_LOADING=OFF -DBUILD_TESTING=OFF \
-DCMAKE_BACKWARDS_COMPATIBILITY=3.1 -DITK_USE_KWSTYLE=OFF \
-DITK_BUILD_ALL_MODULES=ON -DModule_ITKVtkGlue=ON -DITK_USE_REVIEW=ON
RUN make -j"$(nproc)" && make install -j"$(nproc)"
# build boost
WORKDIR /opt/sources
RUN wget --quiet --no-check-certificate http://sourceforge.net/projects/boost/files/boost/1.60.0/boost_1_60_0.tar.gz -O boost.tar.gz && \
tar xfz boost.tar.gz
WORKDIR /opt/sources/boost_1_60_0
ENV CPLUS_INCLUDE_PATH /opt/conda/envs/py/include/python3.7m/
RUN ./bootstrap.sh --prefix=$MYPATH --with-python=python3.7 --with-libraries=python,filesystem,system,test
# PATCH for python 3.7 compliance - see https://github.com/boostorg/python/commit/660487c43fde76f3e64f1cb2e644500da92fe582 for detail
RUN wget https://raw.githubusercontent.com/boostorg/python/660487c43fde76f3e64f1cb2e644500da92fe582/src/converter/builtin_converters.cpp
RUN mv libs/python/src/converter/builtin_converters.cpp libs/python/src/converter/builtin_converters.BAK
RUN mv builtin_converters.cpp libs/python/src/converter/builtin_converters.cpp
RUN ./b2 install
RUN /bin/bash -c "source /opt/conda/bin/activate py && conda install cython numpy -y && pip install scikit-build"
RUN mkdir -p /opt/sources/myproject
WORKDIR /opt/sources/myproject
COPY CMakeLists.txt CMakeLists.txt
COPY _hello.pyx _hello.pyx
COPY setup.py setup.py
RUN /bin/bash -c "source /opt/conda/bin/activate py && python setup.py build"
import sys
from skbuild import setup
setup(
name="hello-world",
version="1.2.3",
description="a minimal example package",
author='pangyuteng',
license="MIT",
packages=["hello"],
install_requires=['cython'],
)
@bgailleton
Copy link

Hi, Thanks a lot for the scikit-build + cython example!

Just a quick note: I wanted to run it locally without docker, and I had to remove target_link_libraries(_hello ${PYTHON_LIBRARIES}) otherwise it segfaults at import. I am putting that here in case anyone else struggle with that.

@pangyuteng
Copy link
Author

pangyuteng commented Aug 21, 2022

thanks for the note! @bgailleton glad this was helpful :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment