From 985e136b7cc13676b975cc68343a081c437b2ba9 Mon Sep 17 00:00:00 2001 From: Julien Lamy Date: Sun, 14 Apr 2024 14:20:16 +0200 Subject: [PATCH] Add Conda CI --- .ci/brew/build | 24 ---------------------- .ci/brew/install | 23 --------------------- .ci/brew/post_build | 38 ----------------------------------- .ci/build/conda.py | 9 +++++++++ .ci/build/post_build.py | 38 ++++++++++++++++++----------------- .ci/conda_mac/build | 22 -------------------- .ci/conda_mac/install | 6 ------ .ci/conda_mac/post_build | 40 ------------------------------------- .ci/deb/post_build | 38 ----------------------------------- .github/workflows/build.yml | 20 +++++++++++++++---- src/CMakeLists.txt | 12 ++++++----- tests/CMakeLists.txt | 8 ++++---- tests/tools/CMakeLists.txt | 7 ++----- 13 files changed, 58 insertions(+), 227 deletions(-) delete mode 100755 .ci/brew/build delete mode 100755 .ci/brew/install delete mode 100755 .ci/brew/post_build create mode 100644 .ci/build/conda.py delete mode 100755 .ci/conda_mac/build delete mode 100755 .ci/conda_mac/install delete mode 100755 .ci/conda_mac/post_build delete mode 100755 .ci/deb/post_build diff --git a/.ci/brew/build b/.ci/brew/build deleted file mode 100755 index 96944be5..00000000 --- a/.ci/brew/build +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -set -ev - -export WORKSPACE=${WORKSPACE:?} -export BUILD_DIR="${WORKSPACE}/${BUILD_DIR:-build}" -export INSTALL_DIR="${WORKSPACE}/${INSTALL_DIR:-install}" - -mkdir -p ${BUILD_DIR} -mkdir -p ${INSTALL_DIR} - -cd ${BUILD_DIR} - -export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig - -cmake \ - -G Ninja \ - -D CMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ - -DCMAKE_BUILD_TYPE=Release \ - -D ICU_ROOT=/usr/local/opt/icu4c/ \ - -D PYTHON_EXECUTABLE=/usr/local/bin/python3 \ - ${CMAKE_OPTIONS} \ - .. -cmake --build . --target install diff --git a/.ci/brew/install b/.ci/brew/install deleted file mode 100755 index 414d6888..00000000 --- a/.ci/brew/install +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -set -ev - -export PYTHON=${PYTHON:-python} - -for PACKAGE in boost cmake dcmtk icu4c jsoncpp ninja pkg-config pybind11; do - VERSIONS=$(brew ls --versions ${PACKAGE} || true) - if [ -z "${VERSIONS}" ]; then - COMMAND="install" - else - OUTDATED=$(brew outdated ${PACKAGE} || true) - if [ -z "${OUTDATED}" ]; then - COMMAND="" - else - COMMAND="upgrade" - fi - fi - - if [ -n "${COMMAND}" ]; then - brew ${COMMAND} ${PACKAGE} - fi -done diff --git a/.ci/brew/post_build b/.ci/brew/post_build deleted file mode 100755 index f757693d..00000000 --- a/.ci/brew/post_build +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -set -v - -export WORKSPACE=${WORKSPACE:?} -export BUILD_DIR="${WORKSPACE}/${BUILD_DIR:-build}" -export INSTALL_DIR="${WORKSPACE}/${INSTALL_DIR:-install}" - -PYTHON=$(awk -F= '$0 ~ /^PYTHON_EXECUTABLE:/ { print $2 }' ${BUILD_DIR}/CMakeCache.txt) - -export LD_LIBRARY_PATH=${INSTALL_DIR}/lib -export PYTHONPATH=${INSTALL_DIR}/$(${PYTHON} -c "from distutils.sysconfig import *; print(get_python_lib(True, prefix=''))") - -export ODIL_OWN_AET=LOCAL -export ODIL_PEER_HOST_NAME=127.0.0.1 -export ODIL_PEER_PORT=11112 -export ODIL_PEER_AET=REMOTE -export PATH=${WORKSPACE}/tests/tools:${PATH} - -cd "${WORKSPACE}/tests/data" -dcmqridx ./ dataset.dcm -dcmqrscp -ll error -c dcmqrscp.config 11112 & -sleep 1 - -cd "${BUILD_DIR}" - -ctest --output-on-failure -R1=$? - -${PYTHON} -m unittest discover -s ${WORKSPACE}/tests/wrappers/ -R2=$? - -kill %1 -cd "${WORKSPACE}/tests/data" -rm -f index.dat RAW_*.dcm - -RETURNCODE=$(if test ${R2} -gt ${R1}; then echo ${R2} ; else echo ${R1}; fi) -exit ${RETURNCODE} diff --git a/.ci/build/conda.py b/.ci/build/conda.py new file mode 100644 index 00000000..6bf5d62f --- /dev/null +++ b/.ci/build/conda.py @@ -0,0 +1,9 @@ +import subprocess +import sys + +conda = sys.argv[1] if len(sys.argv) >= 2 else "conda" + +subprocess.check_call([ + conda, "install", "--yes", "-c", "conda-forge", + "boost", "cmake", "dcmtk", "icu", "jsoncpp", "ninja", "pkg-config", + "pybind11", "zlib"]) diff --git a/.ci/build/post_build.py b/.ci/build/post_build.py index d2cf9287..e81bde75 100644 --- a/.ci/build/post_build.py +++ b/.ci/build/post_build.py @@ -26,37 +26,39 @@ cwd=os.path.join(workspace, "tests/data")) time.sleep(1) -# Set-up environment: C++ library, Python module and test data location. -for name in ["DYLD_LIBRARY_PATH", "LD_LIBRARY_PATH"]: - os.environ[name] = os.pathsep.join([ - *os.environ.get(name, "").split(os.pathsep), lib_dir]) -os.environ["PATH"] = os.pathsep.join([ - *os.environ.get("PATH", "").split(os.pathsep), bin_dir]) -os.environ["PYTHONPATH"] = os.pathsep.join([ - *os.environ.get("PYTHONPATH", "").split(os.pathsep), python_lib_dir]) - -os.environ |= { - "ODIL_OWN_AET": "LOCAL", - "ODIL_PEER_HOST_NAME": "127.0.0.1", - "ODIL_PEER_PORT": "11112", - "ODIL_PEER_AET": "REMOTE"} -os.environ["PATH"] = os.pathsep.join([ - *os.environ["PATH"].split(os.pathsep), +# Set-up environment: test-related variables +environment = os.environ.copy() +environment["ODIL_OWN_AET"] = "LOCAL" +environment["ODIL_PEER_HOST_NAME"] = "127.0.0.1" +environment["ODIL_PEER_PORT"] = "11112" +environment["ODIL_PEER_AET"] = "REMOTE" +environment["PATH"] = os.pathsep.join([ + *environment["PATH"].split(os.pathsep), os.path.join(workspace, "tests/tools")]) # Run C++ and Python tests even if the former fails, return non-zero if any # failed. return_code = 0 + +# No extra environment needed for C++ part return_code = max( return_code, subprocess.call( ["ctest", "--output-on-failure"], - cwd=build_dir, stderr=subprocess.STDOUT)) + cwd=build_dir, stderr=subprocess.STDOUT, env=environment)) + +# Python tests require lib configuration +for name in ["DYLD_LIBRARY_PATH", "LD_LIBRARY_PATH"]: + environment[name] = os.pathsep.join([ + *environment.get(name, "").split(os.pathsep), lib_dir]) +environment["PYTHONPATH"] = os.pathsep.join([ + *environment.get("PYTHONPATH", "").split(os.pathsep), python_lib_dir]) + return_code = max( return_code, subprocess.call( [sys.executable, "-m", "unittest", "discover", "-s", python_tests_dir], - cwd=build_dir, stderr=subprocess.STDOUT)) + cwd=build_dir, stderr=subprocess.STDOUT, env=environment)) server.terminate() os.remove(os.path.join(workspace, "tests/data", "index.dat")) diff --git a/.ci/conda_mac/build b/.ci/conda_mac/build deleted file mode 100755 index f456de2b..00000000 --- a/.ci/conda_mac/build +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -set -ev - -conda activate odil - -export WORKSPACE=${WORKSPACE:?} -export BUILD_DIR="${WORKSPACE}/${BUILD_DIR:-build}" -export INSTALL_DIR="${WORKSPACE}/${INSTALL_DIR:-install}" - -mkdir -p ${BUILD_DIR} -mkdir -p ${INSTALL_DIR} - -cd ${BUILD_DIR} - -cmake \ - -G Ninja \ - -D CMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ - -D PYTHON_EXECUTABLE=$(which python3) \ - ${CMAKE_OPTIONS} \ - .. -cmake --build . --target install diff --git a/.ci/conda_mac/install b/.ci/conda_mac/install deleted file mode 100755 index 1fb864b1..00000000 --- a/.ci/conda_mac/install +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -set -ev - -conda create --name odil --yes -c conda-forge -c bioconda \ - boost cmake dcmtk icu jsoncpp ninja pkg-config pybind11 diff --git a/.ci/conda_mac/post_build b/.ci/conda_mac/post_build deleted file mode 100755 index a5d673f0..00000000 --- a/.ci/conda_mac/post_build +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -set -v - -conda activate odil - -export WORKSPACE=${WORKSPACE:?} -export BUILD_DIR="${WORKSPACE}/${BUILD_DIR:-build}" -export INSTALL_DIR="${WORKSPACE}/${INSTALL_DIR:-install}" - -PYTHON=$(awk -F= '$0 ~ /^PYTHON_EXECUTABLE:/ { print $2 }' ${BUILD_DIR}/CMakeCache.txt) - -export LD_LIBRARY_PATH=${INSTALL_DIR}/lib -export PYTHONPATH=${INSTALL_DIR}/$(${PYTHON} -c "from distutils.sysconfig import *; print(get_python_lib(True, prefix=''))") - -export ODIL_OWN_AET=LOCAL -export ODIL_PEER_HOST_NAME=127.0.0.1 -export ODIL_PEER_PORT=11112 -export ODIL_PEER_AET=REMOTE -export PATH=${WORKSPACE}/tests/tools:${PATH} - -cd "${WORKSPACE}/tests/data" -dcmqridx ./ dataset.dcm -dcmqrscp -ll error -c dcmqrscp.config 11112 & -sleep 1 - -cd "${BUILD_DIR}" - -ctest --output-on-failure -R1=$? - -${PYTHON} -m unittest discover -s ${WORKSPACE}/tests/wrappers/ -R2=$? - -kill %1 -cd "${WORKSPACE}/tests/data" -rm -f index.dat RAW_*.dcm - -RETURNCODE=$(if test ${R2} -gt ${R1}; then echo ${R2} ; else echo ${R1}; fi) -exit ${RETURNCODE} diff --git a/.ci/deb/post_build b/.ci/deb/post_build deleted file mode 100755 index 58cbffca..00000000 --- a/.ci/deb/post_build +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -set -v - -export WORKSPACE=${WORKSPACE:?} -export BUILD_DIR="${WORKSPACE}/${BUILD_DIR:-build}" -export INSTALL_DIR="${WORKSPACE}/${INSTALL_DIR:-install}" - -PYTHON=$(awk -F= '$0 ~ /^PYTHON_EXECUTABLE:/ { print $2 }' ${BUILD_DIR}/CMakeCache.txt) - -export LD_LIBRARY_PATH=${INSTALL_DIR}/lib -export PYTHONPATH=${INSTALL_DIR}/$(${PYTHON} -c 'import os; import sysconfig; print(sysconfig.get_path("purelib", {"posix":"posix_prefix", "nt":"nt"}[os.name], {"base": "."}))') - -export ODIL_OWN_AET=LOCAL -export ODIL_PEER_HOST_NAME=127.0.0.1 -export ODIL_PEER_PORT=11112 -export ODIL_PEER_AET=REMOTE -export PATH=${WORKSPACE}/tests/tools:${PATH} - -cd "${WORKSPACE}/tests/data" -dcmqridx ./ dataset.dcm -dcmqrscp -ll error -c dcmqrscp.config 11112 & -sleep 1 - -cd "${BUILD_DIR}" - -ctest --output-on-failure -R1=$? - -${PYTHON} -m unittest discover -s ${WORKSPACE}/tests/wrappers/ -R2=$? - -kill %1 -cd "${WORKSPACE}/tests/data" -rm -f index.dat RAW_*.dcm - -RETURNCODE=$(if test ${R2} -gt ${R1}; then echo ${R2} ; else echo ${R1}; fi) -exit ${RETURNCODE} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b741dce3..2278cb9b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,16 +10,20 @@ jobs: fail-fast: false matrix: include: - - { os: "ubuntu-latest", container: "debian:bullseye", packaging: "apt", python: "python3" } - - { os: "ubuntu-latest", container: "debian:bookworm", packaging: "apt", cmake_options: "-DCMAKE_CXX_STANDARD=17", python: "python3" } - - { os: "ubuntu-latest", container: "ubuntu:focal", packaging: "apt", python: "python3" } - - { os: "ubuntu-latest", container: "ubuntu:jammy", packaging: "apt", cmake_options: "-DCMAKE_CXX_STANDARD=17", python: "python3" } + - { os: "ubuntu-latest", container: "debian:bullseye", packaging: "apt", python: "python3" } + - { os: "ubuntu-latest", container: "debian:bookworm", packaging: "apt", cmake_options: "-DCMAKE_CXX_STANDARD=17", python: "python3" } + - { os: "ubuntu-latest", container: "ubuntu:focal", packaging: "apt", python: "python3" } + - { os: "ubuntu-latest", container: "ubuntu:jammy", packaging: "apt", cmake_options: "-DCMAKE_CXX_STANDARD=17", python: "python3" } + - { os: "ubuntu-latest", packaging: "conda", cmake_options: "-DCMAKE_CXX_STANDARD=17", python: "python" } # - name: "macOS 11 (Big Sur) + Homebrew" # os: macos-11 # ci_type: brew env: WORKSPACE: "${{ github.workspace }}" CMAKE_OPTIONS: "${{ matrix.cmake_options }}" + defaults: + run: + shell: ${{ contains(matrix.os, 'windows') && 'pwsh' || 'bash -l {0}' }} steps: - name: Provision (Debian, Ubuntu) # Install Python and Git. macOS workers already have this, however for @@ -29,6 +33,14 @@ jobs: DEBIAN_FRONTEND=noninteractive apt-get install -y git python3 if: ${{ contains(matrix.packaging, 'apt') }} + - name: Provision (Micromamba) + uses: mamba-org/setup-micromamba@v1 + with: + init-shell: bash powershell + environment-name: dicomifier + create-args: python=3.11 + if: ${{ contains(matrix.packaging, 'conda') }} + - name: Checkout latest revision uses: actions/checkout@v4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49c87dac..f22cdc20 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ find_package(ICU REQUIRED COMPONENTS uc) find_package(JsonCpp REQUIRED) if(WITH_DCMTK) find_package(DCMTK REQUIRED) + find_package(ZLIB REQUIRED) endif() file(GLOB_RECURSE Header_Files "*.h") @@ -24,7 +25,7 @@ add_library(libodil ${Source_Files} ${Header_Files} ${templates}) target_compile_definitions( libodil PUBLIC - BOOST_ASIO_SEPARATE_COMPILATION ${DCMTK_DEFINITIONS} + BOOST_ASIO_SEPARATE_COMPILATION ODIL_VERSION_MAJOR=${Odil_VERSION_MAJOR} $<$:BOOST_ALL_DYN_LINK> $<$:BOOST_UUID_FORCE_AUTO_LINK> @@ -34,21 +35,22 @@ target_compile_definitions( target_include_directories( libodil PUBLIC - $ $ - "$<$:${DCMTK_INCLUDE_DIRS}>") + $ $) target_link_libraries( libodil PUBLIC Boost::date_time Boost::exception Boost::filesystem Boost::log - "$<$:${DCMTK_LIBRARIES}>" ICU::uc JsonCpp::JsonCpp $<$:netapi32> # WARNING Need to link with bcrypt explicitly, # cf. https://github.com/boostorg/uuid/issues/68#issuecomment-430173245 # Not sure why iphlpapi is not linked. "$<$:bcrypt;iphlpapi>") - +if(WITH_DCMTK) + target_link_libraries(libodil PUBLIC DCMTK::DCMTK ZLIB::ZLIB) +endif() + if(APPLE) # WARNING: Boost::log may add -licudata -licui18n -licuu, which cause # problems with macOS/brew diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d9f52784..c35993c5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ find_package( Boost COMPONENTS exception filesystem log unit_test_framework REQUIRED) find_package(DCMTK REQUIRED) +find_package(ZLIB REQUIRED) find_package(JsonCpp REQUIRED) add_subdirectory(tools) @@ -36,17 +37,16 @@ foreach(test_file ${tests}) target_compile_definitions( test_${test} PRIVATE - BOOST_ASIO_SEPARATE_COMPILATION ${DCMTK_DEFINITIONS} + BOOST_ASIO_SEPARATE_COMPILATION ODIL_VERSION_MAJOR=${Odil_VERSION_MAJOR} $<$:BOOST_ALL_DYN_LINK>) - target_include_directories( - test_${test} PRIVATE ${CMAKE_SOURCE_DIR}/src ${DCMTK_INCLUDE_DIRS}) + target_include_directories(test_${test} PRIVATE ${CMAKE_SOURCE_DIR}/src) target_link_libraries( test_${test} PRIVATE - Boost::unit_test_framework ${DCMTK_LIBRARIES} JsonCpp::JsonCpp + Boost::unit_test_framework DCMTK::DCMTK JsonCpp::JsonCpp ZLIB::ZLIB libodil $<$:Ws2_32>) diff --git a/tests/tools/CMakeLists.txt b/tests/tools/CMakeLists.txt index e3ec9c10..8be31847 100644 --- a/tests/tools/CMakeLists.txt +++ b/tests/tools/CMakeLists.txt @@ -1,14 +1,11 @@ find_package(DCMTK REQUIRED) - -add_definitions(${DCMTK_DEFINITIONS}) -include_directories(${DCMTK_INCLUDE_DIRS}) -link_directories(${DCMTK_LIBRARY_DIRS}) +find_package(ZLIB REQUIRED) file(GLOB headers *.h) file(GLOB files "*.cc") if(USE_BUILTIN_DCMTK_GETSCU) add_executable(dcmtk_getscu ${files} ${headers}) - target_link_libraries(dcmtk_getscu ${DCMTK_LIBRARIES}) + target_link_libraries(dcmtk_getscu DCMTK::DCMTK ZLIB::ZLIB) set_target_properties(dcmtk_getscu PROPERTIES OUTPUT_NAME getscu) endif()