Skip to content

Commit 9fc2aa5

Browse files
authored
Merge pull request #1840 from shimat/linux_packages
Linux: portable manylinux build, vcpkg for Linux, slim profile expansion
2 parents 9a36419 + 1399367 commit 9fc2aa5

37 files changed

Lines changed: 1226 additions & 655 deletions

.devcontainer/manylinux/Dockerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
FROM quay.io/pypa/manylinux_2_28_x86_64
2+
3+
USER root
4+
5+
# Same tools as CI workflow (manylinux.yml) + GitHub CLI
6+
RUN dnf install -y \
7+
git \
8+
zip \
9+
unzip \
10+
nasm \
11+
yasm \
12+
pkg-config \
13+
ninja-build \
14+
kernel-headers \
15+
perl-IPC-Cmd \
16+
perl-Time-Piece \
17+
gtk3-devel \
18+
&& dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo \
19+
&& dnf install -y gh \
20+
&& dnf clean all
21+
22+
# vcpkg bootstrap (package install is done later via postCreateCommand
23+
# using /work/vcpkg.json from the mounted workspace)
24+
RUN git clone --filter=blob:none --depth=1 https://github.com/microsoft/vcpkg.git /opt/vcpkg \
25+
&& /opt/vcpkg/bootstrap-vcpkg.sh -disableMetrics
26+
27+
# .NET SDK 10 — builds and runs net8.0 targets (SDK cross-targeting)
28+
RUN curl -fsSL https://dot.net/v1/dotnet-install.sh \
29+
| bash -s -- --channel 10.0 --install-dir /usr/local/dotnet
30+
ENV PATH="${PATH}:/usr/local/dotnet"
31+
ENV DOTNET_ROOT=/usr/local/dotnet
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env bash
2+
# build_extern.sh — first-time setup inside the manylinux_2_28 devcontainer.
3+
# Called automatically by postCreateCommand when the container is first created.
4+
# Safe to re-run manually; each step is skipped if its output already exists.
5+
#
6+
# Steps:
7+
# 1. vcpkg install (x64-linux-static)
8+
# 2. Static FFmpeg
9+
# 3. OpenCV (full, static, with contrib)
10+
#
11+
# OpenCvSharpExtern is intentionally NOT built here — run the VS Code task
12+
# "Build OpenCvSharpExtern" (Ctrl+Shift+B) or build_opencvsharpextern.sh manually.
13+
14+
set -euxo pipefail
15+
16+
# ---------------------------------------------------------------------------
17+
# 1. vcpkg packages
18+
# ---------------------------------------------------------------------------
19+
/opt/vcpkg/vcpkg install \
20+
--triplet x64-linux-static \
21+
--overlay-triplets=/work/cmake/triplets \
22+
--x-install-root=/opt/vcpkg-installed
23+
24+
# ---------------------------------------------------------------------------
25+
# 2. Static FFmpeg (skipped if already built)
26+
# ---------------------------------------------------------------------------
27+
bash /work/docker/manylinux/build_static_deps.sh
28+
29+
# ---------------------------------------------------------------------------
30+
# 3. OpenCV (full, static)
31+
# ---------------------------------------------------------------------------
32+
if [[ ! -f /opt/opencv_artifacts/lib64/pkgconfig/opencv4.pc ]] && \
33+
[[ ! -f /opt/opencv_artifacts/lib/pkgconfig/opencv4.pc ]]; then
34+
cmake \
35+
-G Ninja \
36+
-C /work/cmake/opencv_build_options.cmake \
37+
-S /work/opencv \
38+
-B /tmp/opencv-build \
39+
-D OPENCV_EXTRA_MODULES_PATH=/work/opencv_contrib/modules \
40+
-D CMAKE_INSTALL_PREFIX=/opt/opencv_artifacts \
41+
-D CMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake \
42+
-D VCPKG_TARGET_TRIPLET=x64-linux-static \
43+
-D VCPKG_INSTALLED_DIR=/opt/vcpkg-installed \
44+
-D CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON \
45+
-D CMAKE_PREFIX_PATH="/opt/vcpkg-installed/x64-linux-static;/opt/ffmpeg" \
46+
-D BUILD_JPEG=OFF \
47+
-D BUILD_PNG=OFF \
48+
-D BUILD_TIFF=OFF \
49+
-D BUILD_WEBP=OFF \
50+
-D BUILD_ZLIB=ON \
51+
-D WITH_TBB=OFF \
52+
-D WITH_OPENEXR=OFF \
53+
-D WITH_JASPER=OFF
54+
cmake --build /tmp/opencv-build -j4
55+
cmake --install /tmp/opencv-build
56+
rm -rf /tmp/opencv-build
57+
fi
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env bash
2+
# build_opencvsharpextern.sh — configure & build OpenCvSharpExtern inside the
3+
# manylinux_2_28 devcontainer. Run directly or via the VS Code task
4+
# "Build OpenCvSharpExtern" (Ctrl+Shift+B).
5+
#
6+
# Output: /work/src/build/OpenCvSharpExtern/libOpenCvSharpExtern.so
7+
8+
set -euxo pipefail
9+
10+
cmake \
11+
-G Ninja \
12+
-S /work/src \
13+
-B /work/src/build \
14+
-D CMAKE_BUILD_TYPE=Release \
15+
-D CMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake \
16+
-D VCPKG_TARGET_TRIPLET=x64-linux-static \
17+
-D VCPKG_INSTALLED_DIR=/opt/vcpkg-installed \
18+
-D OpenCV_DIR=/opt/opencv_artifacts/lib64/cmake/opencv4 \
19+
-D CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON \
20+
"-D CMAKE_PREFIX_PATH=/opt/opencv_artifacts;/opt/ffmpeg;/opt/vcpkg-installed/x64-linux-static" \
21+
"-D ZLIB_LIBRARY=/opt/vcpkg-installed/x64-linux-static/lib/libz.a" \
22+
"-D ZLIB_INCLUDE_DIR=/opt/vcpkg-installed/x64-linux-static/include" \
23+
"-D CMAKE_SHARED_LINKER_FLAGS=-L/opt/vcpkg-installed/x64-linux-static/lib"
24+
25+
cmake --build /work/src/build -j4
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Dev container that reproduces the manylinux_2_28 CI build environment.
2+
// Workspace is bind-mounted at /work. All build caches live inside the container.
3+
//
4+
// On first container creation, postCreateCommand runs build_extern.sh which does:
5+
// 1. vcpkg install (x64-linux-static)
6+
// 2. Static FFmpeg build
7+
// 3. OpenCV full build -> /opt/opencv_artifacts/
8+
// 4. OpenCvSharpExtern build -> /work/src/build/
9+
//
10+
// To run the OCR test after setup:
11+
// cd /work/test/OpenCvSharp.Tests
12+
// cp /work/src/build/OpenCvSharpExtern/libOpenCvSharpExtern.so .
13+
// LD_LIBRARY_PATH=. dotnet test OpenCvSharp.Tests.csproj -c Release -f net8.0 \
14+
// --filter "FullyQualifiedName~OCRTesseractTest"
15+
{
16+
"name": "manylinux_2_28 (build)",
17+
"build": {
18+
"dockerfile": "Dockerfile"
19+
},
20+
21+
// Mount the workspace at /work — same path as CI (GITHUB_WORKSPACE → /work)
22+
"workspaceMount": "source=${localWorkspaceFolder},target=/work,type=bind,consistency=cached",
23+
"workspaceFolder": "/work",
24+
25+
"remoteUser": "root",
26+
27+
// First-time setup: vcpkg install -> FFmpeg -> OpenCV -> OpenCvSharpExtern
28+
// Safe to re-run manually: bash /work/.devcontainer/manylinux/build_extern.sh
29+
"postCreateCommand": "bash /work/.devcontainer/manylinux/build_extern.sh",
30+
31+
"customizations": {
32+
"vscode": {
33+
"extensions": [
34+
"ms-vscode.cpptools",
35+
"ms-vscode.cmake-tools",
36+
"timonwong.shellcheck"
37+
],
38+
"settings": {
39+
"terminal.integrated.defaultProfile.linux": "bash"
40+
}
41+
}
42+
}
43+
}

.dockerignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Exclude everything by default; only allow what the Dockerfile COPYs.
2+
**
3+
4+
# OpenCvSharp managed and native sources
5+
!src/
6+
src/build*/
7+
src/uwpOpenCvSharpExtern/
8+
9+
# cmake option files needed by Dockerfiles
10+
!cmake/opencv_build_options.cmake
11+
!cmake/opencv_build_options_slim.cmake
12+
13+
# Test projects
14+
!test/

.github/copilot-instructions.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,28 @@ All source files in this repository use **UTF-8 with BOM** (`EF BB BF`).
44

55
When creating or editing files, always save them as UTF-8 with BOM. This applies to `.cs`, `.csproj`, `.yml`, `.md`, `.json`, and all other text files.
66

7-
Do **not** save files as UTF-8 without BOM, ANSI, or Shift-JIS — doing so will corrupt Japanese content and break Visual Studio / MSBuild tooling.
7+
**Exception — Linux tooling files: use UTF-8 without BOM.**
8+
The following file types are processed by Linux tools (Docker, bash, VS Code Dev Containers) that do not tolerate a BOM and must be saved **without** BOM:
9+
- `Dockerfile` and any file named `*.Dockerfile`
10+
- Shell scripts (`.sh`)
11+
- `devcontainer.json` and all files under `.devcontainer/`
12+
13+
Do **not** save files as UTF-8 without BOM, ANSI, or Shift-JIS — doing so will corrupt Japanese content and break Visual Studio / MSBuild tooling (for the files above that require BOM).
14+
15+
### Editing workflow requirement
16+
17+
Maintain correct encoding **during each edit/create step** — do not correct it in a follow-up step.
18+
19+
Do not rely on a final "bulk conversion/check" step at the end of the task.
20+
21+
**Important:** The `create_file` tool does **not** interpret `\uFEFF` in the content string as BOM bytes — it writes the literal six characters `\uFEFF`. Never place `\uFEFF` (or any Unicode escape for U+FEFF) directly in the `content` parameter. Instead, create the file first (BOM-free), then immediately apply the PowerShell conversion command below for files that require BOM.
822

923
### Verification
1024

25+
Do not run the verification/conversion commands on every edit by default.
26+
Prevent encoding issues through edit/create operations that preserve UTF-8 BOM.
27+
Run the commands below only when preservation cannot be guaranteed or when troubleshooting is required.
28+
1129
```powershell
1230
# Check whether a file has UTF-8 BOM
1331
$b = [System.IO.File]::ReadAllBytes("path\to\file")

.github/workflows/docker-test-ubuntu.yml

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ name: Docker Test
33
on:
44
pull_request:
55
types: [synchronize, opened]
6+
push:
7+
branches:
8+
- main
69

710
env:
811
DEBIAN_FRONTEND: noninteractive
912
OPENCV_VERSION: 4.13.0
10-
DOCKER_BUILD_CONTEXT: ./docker/ubuntu24-dotnet10-opencv4.13.0
13+
DOCKER_BUILD_CONTEXT_FULL: ./docker/ubuntu24-dotnet10-opencv4.13.0
14+
DOCKER_BUILD_CONTEXT_SLIM: ./docker/ubuntu24-dotnet10-opencv4.13.0-slim
1115

1216
jobs:
13-
build:
17+
build_full:
1418
runs-on: ubuntu-latest
1519
timeout-minutes: 60
1620

@@ -19,15 +23,37 @@ jobs:
1923

2024
- uses: docker/setup-buildx-action@v3
2125

22-
- name: Build with Docker
26+
- name: Build with Docker (full)
2327
uses: docker/build-push-action@v6
2428
with:
25-
context: ${{ env.DOCKER_BUILD_CONTEXT }}
29+
context: .
30+
file: ${{ env.DOCKER_BUILD_CONTEXT_FULL }}/Dockerfile
2631
build-args: |
2732
OPENCV_VERSION=${{ env.OPENCV_VERSION }}
28-
OPENCVSHARP_REF=${{ github.head_ref || github.ref_name }}
2933
outputs: type=docker,name=shimat/ubuntu24-dotnet10-opencv4.13.0:latest
3034
cache-from: |
31-
type=gha,scope=${{ github.ref_name }}
32-
type=gha,scope=main
33-
cache-to: type=gha,mode=min,scope=${{ github.ref_name }}
35+
type=gha,scope=full-${{ github.ref_name }}
36+
type=gha,scope=full-main
37+
cache-to: type=gha,mode=min,scope=full-${{ github.ref_name }}
38+
39+
build_slim:
40+
runs-on: ubuntu-latest
41+
timeout-minutes: 60
42+
43+
steps:
44+
- uses: actions/checkout@v6
45+
46+
- uses: docker/setup-buildx-action@v3
47+
48+
- name: Build with Docker (slim)
49+
uses: docker/build-push-action@v6
50+
with:
51+
context: .
52+
file: ${{ env.DOCKER_BUILD_CONTEXT_SLIM }}/Dockerfile
53+
build-args: |
54+
OPENCV_VERSION=${{ env.OPENCV_VERSION }}
55+
outputs: type=docker,name=shimat/ubuntu24-dotnet10-opencv4.13.0-slim:latest
56+
cache-from: |
57+
type=gha,scope=slim-${{ github.ref_name }}
58+
type=gha,scope=slim-main
59+
cache-to: type=gha,mode=min,scope=slim-${{ github.ref_name }}

.github/workflows/linux-arm.yml

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ on:
1010
env:
1111
DEBIAN_FRONTEND: noninteractive
1212
OPENCV_VERSION: 4.13.0
13+
CACHE_VERSION: "2"
1314

1415
jobs:
1516
build:
@@ -46,7 +47,8 @@ jobs:
4647
libopencore-amrnb-dev \
4748
libopencore-amrwb-dev \
4849
libx264-dev \
49-
libtesseract-dev
50+
libtesseract-dev \
51+
ninja-build
5052
5153
- name: Restore OpenCV cache
5254
id: opencv-cache
@@ -55,19 +57,40 @@ jobs:
5557
path: |
5658
${{ github.workspace }}/opencv_artifacts/include
5759
${{ github.workspace }}/opencv_artifacts/lib
58-
key: opencv-arm-${{ env.OPENCV_VERSION }}-${{ hashFiles('.github/workflows/linux-arm.yml') }}
59-
restore-keys: |
60-
opencv-arm-${{ env.OPENCV_VERSION }}-
60+
key: opencv-arm-v${{ env.CACHE_VERSION }}-${{ env.OPENCV_VERSION }}-${{ hashFiles('cmake/opencv_build_options.cmake', '.github/workflows/linux-arm.yml') }}
6161

62-
- name: Build OpenCV
62+
- name: Configure OpenCV
6363
if: steps.opencv-cache.outputs.cache-hit != 'true'
6464
run: |
6565
cmake \
66+
-G Ninja \
6667
-C cmake/opencv_build_options.cmake \
6768
-S opencv \
6869
-B opencv/build \
6970
-D OPENCV_EXTRA_MODULES_PATH=${GITHUB_WORKSPACE}/opencv_contrib/modules \
70-
-D CMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/opencv_artifacts
71+
-D CMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/opencv_artifacts \
72+
2>&1 | tee /tmp/opencv-configure.log
73+
74+
- name: Verify OpenCV cmake features
75+
if: steps.opencv-cache.outputs.cache-hit != 'true'
76+
run: |
77+
log=/tmp/opencv-configure.log
78+
fail=0
79+
for feature in Tesseract FFMPEG JPEG PNG TIFF WEBP; do
80+
val=$(grep -E "^--\s+${feature}:\s+" "$log" | tail -1 | sed -E "s/^.*${feature}:[[:space:]]+//")
81+
if [[ -n "$val" ]] && [[ "$val" != NO* ]]; then
82+
echo "OK: $feature = $val"
83+
else
84+
echo "MISSING or DISABLED: $feature"
85+
grep -iE "${feature}" "$log" | tail -3 || true
86+
fail=1
87+
fi
88+
done
89+
[ "$fail" -eq 0 ]
90+
91+
- name: Build OpenCV
92+
if: steps.opencv-cache.outputs.cache-hit != 'true'
93+
run: |
7194
cmake --build opencv/build -j 3
7295
cmake --install opencv/build
7396
sudo ldconfig
@@ -80,11 +103,12 @@ jobs:
80103
path: |
81104
${{ github.workspace }}/opencv_artifacts/include
82105
${{ github.workspace }}/opencv_artifacts/lib
83-
key: opencv-arm-${{ env.OPENCV_VERSION }}
106+
key: opencv-arm-v${{ env.CACHE_VERSION }}-${{ env.OPENCV_VERSION }}-${{ hashFiles('cmake/opencv_build_options.cmake', '.github/workflows/linux-arm.yml') }}
84107

85108
- name: Build OpenCvSharpExtern
86109
run: |
87110
cmake \
111+
-G Ninja \
88112
-S src \
89113
-B src/build \
90114
-D CMAKE_BUILD_TYPE=Release \
@@ -105,7 +129,7 @@ jobs:
105129
- name: Install .NET
106130
uses: actions/setup-dotnet@v5
107131
with:
108-
dotnet-version: '8.0.x'
132+
dotnet-version: '10.0.x'
109133

110134
- name: Create NuGet package
111135
env:
@@ -129,8 +153,8 @@ jobs:
129153
- name: Test
130154
run: |
131155
cd ${GITHUB_WORKSPACE}/test/OpenCvSharp.Tests
132-
dotnet build -c Release -f net8.0
133-
cp ${GITHUB_WORKSPACE}/nuget/libOpenCvSharpExtern.so ${GITHUB_WORKSPACE}/test/OpenCvSharp.Tests/bin/Release/net8.0/
156+
dotnet build -c Release -f net10.0
157+
cp ${GITHUB_WORKSPACE}/nuget/libOpenCvSharpExtern.so ${GITHUB_WORKSPACE}/test/OpenCvSharp.Tests/bin/Release/net10.0/
134158
cp ${GITHUB_WORKSPACE}/nuget/libOpenCvSharpExtern.so ${GITHUB_WORKSPACE}/test/OpenCvSharp.Tests/
135159
sudo cp ${GITHUB_WORKSPACE}/nuget/libOpenCvSharpExtern.so /usr/lib/
136-
LD_LIBRARY_PATH=. dotnet test OpenCvSharp.Tests.csproj -c Release -f net8.0 --runtime linux-arm64 --logger "trx;LogFileName=test-results.trx" < /dev/null
160+
LD_LIBRARY_PATH=. dotnet test OpenCvSharp.Tests.csproj -c Release -f net10.0 --runtime linux-arm64 --logger "trx;LogFileName=test-results.trx" < /dev/null

0 commit comments

Comments
 (0)