콘텐츠로 이동
Search

Pointcept:BuildMatrix

Pointcept 사전 빌드 휠 매트릭스 (amd64 · arm64)

작성일: 2026-09-28 · 대상: app.cvp.run Pointcept 에이전트 앱의 pointcept-wheelhouse 패키지

개요

Pointcept 에이전트 앱은 레지스트리에 올린 pointcept-wheelhouse만으로 환경을 만든다(로드맵 결정 R5). 호스트에 맞는 wheelhouse가 없으면 소스 빌드로 넘어가지 않고 차단 상태로 멈춘다. 따라서 에이전트가 다운로드만으로 동작하려면 호스트 조합별 wheelhouse를 미리 빌드해서 올려 두어야 한다.

PyPI와 PyG 인덱스에는 CUDA 13(cu130)용 휠과 arm64용 휠이 대부분 없다. 이 문서는 scripts/build_wheels.sh로 미리 빌드할 amd64·arm64 매트릭스와, 실제로 빌드하고 실행하며 확인한 제약을 정리한다.

결론: 조합을 많이 만드는 것보다 accel마다 wheelhouse 하나를 넓은 cuda_arch로 빌드하는 것이 커버리지를 가장 넓힌다. amd64 3~4개, arm64 3~4개면 충분하다.

에이전트의 wheelhouse 선택 규칙

app.cvp.run/cli/src/pointcept/packages.ts의 wheelhouseFits·selectWheelhouse 기준이다.

규칙

매트릭스에 미치는 영향

os·arch 태그가 호스트와 같아야 한다

os는 linux 하나라서 배포판(glibc)을 구분하지 못한다. 아래 glibc 호환성 참고

python 태그로는 거르지 않고, 태그에 적힌 버전으로 venv를 만든다

cp312 하나면 된다. 다른 python 조합은 같은 조건의 후보를 중복시킬 뿐이다

accel의 CUDA 버전이 드라이버 CUDA 이하여야 한다

호스트의 드라이버 하한을 accel별로 하나씩 덮으면 된다

cuda_arch 목록에 GPU의 compute capability가 정확히 들어 있어야 한다

8.0 휠이 8.6에서 돌더라도 태그에 8.6이 없으면 고르지 않는다. 대상 GPU를 모두 나열해야 한다

후보가 여럿이면 torch → CUDA → 버전 순으로 높은 것을 고른다

torch 2.13에 12.1을 태그해 게시하면 GB10이 그것을 골라 죽는다. torch는 2.9.1 하나로 통일한다

권장 빌드 매트릭스

모든 행은 python 3.12, torch 2.9.1이다.

#

arch

accel

cuda_arch 태그 (권장)

대상 GPU

최소 드라이버

소스 컴파일 대상

상태

A1

amd64

cu126

7.5† 8.0 8.6 8.9 9.0

T4, A100, RTX30/40, L4, H100

12.6

flash-attn, swin3d, 로컬 5종 (spconv·cumm·PyG는 prebuilt 있음)

미빌드

A2

amd64

cu128

7.5† 8.0 8.6 8.9 9.0 10.0 12.0

A1 + B200, RTX50, RTX PRO Blackwell

12.8

A1 + spconv (spconv-cu128 없음)

미빌드

A3

amd64

cu129

A2 + 10.3

B300

12.9

A2 + PyG (pt29cu129 없음)

선택

A4

amd64

cu130

7.5† 8.0 8.6 8.9 9.0 10.0 10.3 12.0

드라이버 13.x 전부

13.0

A1 + cumm, spconv

검증됨 (12.0만, 게시 2026.09.11) → 넓혀 다시 빌드

B1

arm64

cu126

8.0 8.6 8.9 9.0

GH200, Arm 서버 + A100/L40

12.6

전부 (pccm·torch-geometric·ocnn 제외)

미빌드

B2

arm64

cu128

8.0 8.6 8.9 9.0 10.0 12.0

B1 + GB200, Arm + RTX PRO

12.8

전부

미빌드

B3

arm64

cu129

B2 + 10.3 12.1

GB300, 드라이버 12.9인 GB10

12.9

전부

선택

B4

arm64

cu130

8.0 8.6 8.9 9.0 10.0 10.3 12.0 12.1

DGX Spark (GB10), GB200/300

13.0

전부

검증됨 (12.1만, 60 epoch 완주) → 넓혀 다시 빌드

† 7.5(Turing)는 에이전트를 먼저 고쳐야 넣을 수 있다. flash-attn 참고.

제외를 권장하는 조합

조합

이유

cu130/cu132 + torch 2.13.0 (arm64)

GB10에서 merge_sort: failed to synchronize: cudaErrorIllegalAddress로 죽는다(2026-09-21, verify_mlops.sh A/B 비교). torch가 높은 쪽을 먼저 고르는 규칙 때문에 게시만 해도 GB10이 이 조합을 고른다

cu132

torch 2.12 이상이 필수라 2.9.1로 통일할 수 없다. 드라이버 13.2 호스트는 cu130 휠로 충분하다

cu131

PyTorch 인덱스가 없어 torch를 cu130에서 받는다. cu130보다 요구 드라이버만 높아지고 얻는 것이 없다

cu118 · cu121 · cu124

torch 2.9.1이 없고(각각 ≤2.7.1, ≤2.5.1, ≤2.6.0), sm_100 이상을 컴파일할 수 없다. aarch64 torch도 없다

Jetson Orin (8.7)

에이전트가 download.pytorch.org에서 받는 aarch64 torch는 SBSA 빌드라 Jetson용 L4T에서 돌지 않는다

Thor (11.0)

flash-attn 커널이 없고, torch aarch64 cu130 휠의 컴파일 범위(8.0–12.0)에도 들지 않는다. 미검증

확인한 제약

torch 휠 인덱스

2026-09-28 기준 download.pytorch.org/whl/<accel>/torch/의 cp312 휠 목록이다.

accel

x86_64

aarch64

cu118

2.2–2.7.1

없음

cu121

2.2–2.5.1

없음

cu124

2.4–2.6.0

없음

cu126

2.6–2.14

2.6, 2.9.0–2.14 (2.7·2.8 없음)

cu128

2.7–2.11

2.7, 2.9–2.11 (2.8 없음)

cu129

2.8–2.13 (2.12.0 없음)

2.8–2.13 (2.12.0 없음)

cu130

2.9–2.14

2.9–2.14

cu132

2.12–2.14

2.12–2.14

cu126·cu128·cu129·cu130과 두 arch 모두에 공통으로 있는 버전은 2.9.x, 2.10, 2.11이다. 이 중 검증된 것은 2.9.1뿐이다.

빌더가 거르는 torch 하한(cuda_min_torch): cu126 ≥ 2.6.0, cu128 ≥ 2.7.0, cu129 ≥ 2.8.0, cu130 ≥ 2.9.0, cu132 ≥ 2.12.0.

PyPI · PyG prebuilt 공백

패키지

prebuilt가 있는 범위

비고

spconv

cu118·cu121·cu124·cu126, x86_64만 (2.3.8)

cu128·cu129·cu130 패키지 자체가 없다

cumm

cu126·cu128, x86_64만 (0.8.2)

cu130 패키지가 없다

torch-scatter / torch-sparse / torch-cluster

data.pyg.org, x86_64만

aarch64는 전혀 없다. cu129는 torch 2.8까지만 있다. cu130은 torch 2.9–2.14까지 있다

flash-attn

없음 (sdist만 있음)

모든 조합에서 소스로 컴파일한다

따라서 arm64는 네이티브 패키지 12종을 전부 소스로 컴파일한다. 순수 파이썬 패키지인 pccm, torch-geometric, ocnn만 prebuilt를 쓴다.

패키지별 고정과 패치

패키지

검증된 버전

제약

pccm

0.4.16

cumm의 setup.py가 import하므로 venv에 먼저 설치해야 한다

cumm

cumm-cu130 0.8.2

자체 arch 표가 8.8·10.3·11.0·12.1을 모른다. 빌더가 가장 가까운 하위 arch의 PTX로 낮춘다(12.1 → 12.0+PTX, 드라이버 JIT)

spconv

spconv-cu130 2.3.8

fork 패치로 cumm 상한을 <0.9.0으로 완화했다. GB10에서 학습할 때는 ConvAlgo.Native를 강제해야 한다(MaskImplicitGemm은 sm_121에서 죽는다)

torch-scatter / sparse / cluster

2.1.2 / 0.6.18 / 1.6.3

arm64에서는 소스로 컴파일한다

torch-geometric

2.7.0

<2.8로 고정. 2.8부터 voxel_grid가 pyg-lib을 요구하는데 pyg-lib에 aarch64 휠이 없다

flash-attn

2.8.3.post1

아래 flash-attn 참고

swin3d

1.0.0

cvprun/Swin3D fork를 쓴다. 업스트림은 새 torch에서 .type() API 때문에 컴파일에 실패한다

pointgroup_ops

0.0.0

libsparsehash-dev가 필요하며, 빌더가 직접 설치한다

ocnn

2.3.3

순수 파이썬

flash-attn

  • flash-attn 2.x는 sm_80, 90, 100, 120용 cubin만 만든다. 8.6·8.7·8.9는 sm_80 cubin으로 돈다.
  • 10.3과 12.1은 Blackwell family가 달라 cubin이 로드되지 않는다. 빌더가 100+PTX, 120+PTX로 빌드해 드라이버 JIT로 도달한다(커밋 c35c4d4, 2026-09-10).
    • DGX Spark(sm_121)에서 빌드되고 동작한다. 2026-09-11 이후 manifest에 compiled flash_attn-2.8.3.post1-…-linux_aarch64.whl로 남아 있고, 2026-09-21 enable_flash=True로 60 epoch 학습을 완주했다.
    • 2026-09-10 이전에는 12.1에 대응하는 arch가 없어 조용히 건너뛰었다.
  • 7.5(Turing), 11.0(Thor), Orin만 대상인 빌드는 컴파일할 대상이 없어 건너뛴다.
  • 에이전트는 import flash_attn이 되는지로만 flash 사용을 판단한다(scripts.ts). 그래서 flash-attn이 든 wheelhouse의 태그에 7.5를 넣으면 T4에서 flash가 켜져 실패한다. 7.5를 넣으려면 에이전트가 capability ≥ 8.0일 때만 flash를 켜도록 먼저 고쳐야 한다.
  • PTX는 첫 로드 때 JIT로 컴파일되므로 CUDA_CACHE_PATH를 쓰기 가능한 경로로 두어야 JIT 비용을 한 번만 치른다.
  • 빌드 시간이 가장 긴 패키지다. GB10에서 12.1 하나만 빌드해도 약 18.7분이 걸렸다. cubin이 최대 4개라 arch 목록을 넓혀도 비용이 끝없이 늘지는 않는다.

glibc 호환성

2026-09-28 갱신: build_wheels.sh 기본값이 --os manylinux_2_28로 바뀌어 이 문제는 해결됐다. 아래는 그 전 ubuntu24.04 빌드(현재 레지스트리에 게시된 2026.09.11 포함)의 측정값이다. manylinux_2_28 빌드 참고.

현재 휠은 ubuntu24.04 컨테이너에서 빌드된다. objdump로 확인한 최대 심볼 버전은 다음과 같다(amd64 cu130).

휠

GLIBC

GLIBCXX

cumm_cu130

2.38

3.4.32

spconv_cu130

2.34

3.4.32

pointops

2.32

3.4.21

flash_attn

2.32

3.4.21

Ubuntu 22.04 호스트(glibc 2.35, GLIBCXX 3.4.30)에서는 cumm·spconv import가 실패한다. 에이전트의 os 태그는 linux뿐이라 이런 호스트를 미리 걸러내지 못한다. 대안은 둘이다.

  1. --os ubuntu22.04로 빌드한다. 22.04에서 만든 휠은 24.04에서도 돈다. 아직 빌드해 본 적 없다.
  2. 태그에 glibc 버전을 추가하고 wheelhouseFits에서 검사한다.

prebuilt와 태그 정확성

A1·A2처럼 amd64에서 prebuilt spconv·cumm·PyG를 받으면, 그 휠의 arch 집합은 업스트림이 정한 것이라 cuda_arch 태그와 다를 수 있다. 태그를 정확히 맞추려면 --force-source를 쓴다. 대신 빌드 시간이 늘어난다.

업로드 크기

arch 목록을 넓히면 cumm·spconv 휠이 커진다. 관리자 패키지 업로드 릴레이의 Workers CPU 한도 문제(pointcept-agent-app-roadmap.md)가 해결됐는지 먼저 확인해야 한다.

빌드 방법

amd64는 amd64 호스트에서, arm64는 DGX Spark에서 직접 빌드한다. QEMU 교차 빌드는 nvcc가 10~30배 느려서 쓰지 않는다. 기존 단일 arch 결과와 섞이지 않도록 출력 디렉터리를 분리한다. 같은 디렉터리를 쓰면 manifest.txt가 이어 붙는다.

아래 두 반복문은 저장소에 scripts/build_matrix_amd64.sh, scripts/build_matrix_arm64.sh로 들어 있다. 출력은 wheelhouse-wide/(git 무시 대상)로 가고, 뒤에 붙인 인자는 build_wheels.sh로 넘어간다(예: --jobs 8, --dry-run).

# amd64
for spec in "cu126|8.0 8.6 8.9 9.0" \
            "cu128|8.0 8.6 8.9 9.0 10.0 12.0" \
            "cu130|8.0 8.6 8.9 9.0 10.0 10.3 12.0"; do
  bash scripts/build_wheels.sh build --arch amd64 --accel "${spec%%|*}" \
    --torch 2.9.1 --python 3.12 --cuda-arch "${spec#*|}" \
    --force-source --out wheelhouse-wide --keep-going -y
done

# arm64 (DGX Spark)
for spec in "cu126|8.0 8.6 8.9 9.0" \
            "cu128|8.0 8.6 8.9 9.0 10.0 12.0" \
            "cu130|8.0 8.6 8.9 9.0 10.0 10.3 12.0 12.1"; do
  bash scripts/build_wheels.sh build --arch arm64 --accel "${spec%%|*}" \
    --torch 2.9.1 --python 3.12 --cuda-arch "${spec#*|}" \
    --out wheelhouse-wide --keep-going -y
done

A3·B3(cu129)을 넣으려면 같은 형식으로 "cu129|… 10.3 12.1"을 추가한다.

검증과 게시

  1. scripts/verify_wheels.sh <wheelhouse 디렉터리>로 설치, import, 커널, PTv3 forward를 확인한다.
  2. 가능하면 scripts/verify_mlops.sh로 학습까지 확인한다.
  3. 레지스트리에 조합마다 고유한 version으로 게시하고 태그를 붙인다.
{"os":"linux","arch":"arm64","accel":"cu130","torch":"2.9.1","python":"3.12",
 "cuda_arch":"8.0 8.6 8.9 9.0 10.0 10.3 12.0 12.1"}

실제 GPU에서 검증된 것은 sm_120(RTX PRO 2000)과 sm_121(GB10) 둘뿐이다. 나머지 arch는 컴파일만 된 상태이니 패키지 description에 "미검증"이라고 적어 둔다.

실행 조건: arch와 GPU만 맞으면 되는가

그렇지 않다. 위 매트릭스가 모두 빌드됐다고 가정해도 호스트 쪽 조건이 더 있고, 일부 GPU는 휠이 맞아도 에이전트 코드가 바뀌어야 제대로 돈다.

호스트 조건

조건

이유

안 맞을 때

Linux

os 태그가 linux뿐이다. Windows와 macOS용 wheelhouse는 없다

선택 단계에서 no_match로 차단

NVIDIA 드라이버 CUDA ≥ accel

wheelhouseFits가 비교한다. 예를 들어 드라이버 12.4는 cu126을 받을 수 없다

no_match (12.6 미만은 매트릭스 밖)

nvidia-smi가 동작

probeHost가 드라이버 버전과 compute_cap을 여기서 읽는다

no_gpu

glibc ≥ 2.28

manylinux_2_28로 빌드하면 torch와 같은 하한이다. ubuntu24.04로 빌드한 기존 휠은 glibc 2.38, GLIBCXX 3.4.32를 요구한다

manylinux 휠은 pip이 설치 단계에서 거절한다. 기존 휠은 설치까지 된 뒤 import에서 실패한다(Ubuntu 22.04, RHEL 8·9 등)

인터넷 접속

레지스트리에는 torch가 없어서 download.pytorch.org에서 받는다(약 3 GB). spconv가 요구하는 ccimport·fire·pybind11과 순수 파이썬 의존성 13종은 PyPI에서 받는다(--no-index 미사용)

설치 실패. 폐쇄망에서는 쓸 수 없다

디스크 약 5 GB 이상

torch 3 GB, 휠 130 MB 이상(arch 목록을 넓히면 더 커짐), 가중치(모델마다 555 MB)가 필요하다

설치 실패

GPU 메모리

휠과 무관한 조건이다. flash-attn이 없으면 8 GB 카드에서 OOM이 났다

요청 단위 OOM

플랜

패키지의 min_plan

plan_required

에이전트가 먼저 바뀌어야 하는 GPU

대상

문제

필요한 조치

sm_121 (DGX Spark), sm_103 (B300)

cumm이 이 arch를 몰라서 spconv가 PTX로만 빌드된다(12.1 → 12.0+PTX, 10.3 → 10.0+PTX). mlops에서 이 조건의 MaskImplicitGemm 커널이 무작위 iteration(42, 67)에서 죽었다. mlops는 GeoSpconvAlgo 훅으로 ConvAlgo.Native를 강제해 100 epoch를 완주했다. app.cvp.run 에이전트에는 이 처리가 없다(cli/src/pointcept/에서 ConvAlgo를 찾으면 결과 0건)

에이전트의 학습·추론 스크립트에 Native 고정을 추가해야 한다. 그 전에는 GB10에서 휠이 맞아도 학습이 중간에 죽을 수 있다

sm_75 (T4, RTX20)

flash-attn 커널이 없는데, 에이전트는 import가 되면 flash를 켠다

capability ≥ 8.0일 때만 flash를 켜도록 고치기 전에는 태그에 7.5를 넣지 않는다

여러 GPU가 섞인 호스트

모든 GPU의 capability가 한 태그 안에 있어야 한다

예: RTX 3090(8.6)과 RTX 5090(12.0)이 함께 있으면 cu128·cu130만 맞는다

Jetson Orin, Thor

torch가 SBSA 빌드라 동작하지 않는다

지원하지 않는다

검증 상태

"빌드됨"과 "실행됨"은 다르다. 실제 GPU에서 end-to-end로 확인한 조합은 amd64 cu130 sm_120과 arm64 cu130 sm_121(mlops에서, Native 고정 포함) 둘뿐이다. 나머지 arch는 nvcc가 컴파일에 성공했다는 것까지만 확인된 상태다. cubin으로 빌드되는 8.0~9.0, 10.0, 12.0은 위험이 낮지만, PTX JIT에 기대는 10.3·12.1은 실기 검증이 필요하다.

정리

Linux, 드라이버 CUDA ≥ accel, glibc 2.28 이상(manylinux 빌드 기준), 인터넷 접속을 갖춘 호스트라면 arch·GPU만 맞으면 설치와 추론까지는 된다. 다만 다음 두 가지가 먼저 필요하다.

  1. GB10과 B300: 에이전트에 spconv Native 고정을 추가해야 한다.
  2. Ubuntu 22.04·RHEL 호스트: wheelhouse를 manylinux_2_28로 다시 빌드해 게시해야 한다. 지금 게시된 2026.09.11은 ubuntu24.04 빌드다.

단일 번들 배포 (sudo 없이 한 번 받아서 실행)

에이전트가 훈련과 추론에 쓰는 모든 것을 (arch, accel)마다 하나로 묶어, 받아서 풀기만 하면 실행되게 할 수 있다. NVIDIA 드라이버와 glibc는 번들에 넣을 수 없어서 호스트에 있어야 한다. 형식은 AppImage보다 (arch, accel)별 압축 아카이브(tar.zst)를 권장한다.

번들에 넣을 수 있는 것과 없는 것

구성 요소

번들 가능

비고

Python 인터프리터

✓

python-build-standalone을 쓴다. uv가 설치하는 python이 바로 이것이고, 경로를 옮겨도 동작한다

torch, torchvision

✓

약 1.1 GB

CUDA 런타임, cuDNN, NCCL, cuBLAS

✓

cu12·cu13 torch는 nvidia-* pip 휠로 함께 설치된다(약 2.7 GB). 호스트에 CUDA toolkit이 필요 없다

Pointcept 휠 15종, 소스, 순수 파이썬 의존성

✓

약 200 MB

libstdc++.so.6

✓

manylinux로 빌드하면 애초에 새 버전이 필요 없다. 아래 manylinux_2_28 빌드 참고

libgomp

✓

torch가 이미 함께 넣어 둔다

libGL, libglib (open3d)

필요 없음

에이전트가 open3d 대신 스텁을 쓴다

C 컴파일러 (Triton JIT)

△

Triton은 처음 실행될 때 시스템의 cc로 작은 런처를 컴파일한다. mlops 이미지는 이 때문에 gcc를 런타임 의존성으로 넣었다. Pointcept 학습·추론 경로가 실제로 Triton을 타는지는 아직 확인하지 않았다. 탄다면 ziglang 휠을 넣고 CC로 지정해 번들 안에서 해결한다

NVIDIA 커널 드라이버와 libcuda.so

✗

커널 모듈과 짝이라 호스트 것을 써야 한다. 드라이버 CUDA ≥ accel 조건은 그대로 남는다

glibc

✗ (사실상)

번들 전체가 빌드한 베이스의 glibc를 하한으로 갖는다. manylinux_2_28로 빌드하면 하한은 2.28이다

AppImage를 권장하지 않는 이유

  • AppImage는 FUSE로 마운트해야 실행된다. libfuse2가 없는 호스트에서는 sudo apt install libfuse2가 필요해서 목적과 어긋난다. 컨테이너에는 /dev/fuse가 없는 경우가 많다. --appimage-extract-and-run을 쓰면 결국 매번 압축을 푸는 셈이다.
  • 번들이 5 GB대라, 실행할 때마다 squashfs를 마운트하는 이점이 없다.
  • 에이전트에는 이미 필요한 구조가 있다. 레지스트리의 archive 종류, CLI의 extractAll, 버전 마커, ~/.cache/cvp/<app> 루트가 그대로 쓰인다. 아카이브를 한 번 받아 풀고 bin/python3로 실행하면 sudo, FUSE, 네트워크(PyPI, download.pytorch.org) 어느 것도 필요 없다.

권장 구조

pointcept-runtime-<arch>-<accel>.tar.zst   # 예: arm64-cu130
└─ runtime/
   ├─ python/          # python-build-standalone 3.12. venv가 아니라 이 python의 site-packages에 직접 설치
   │  └─ lib/python3.12/site-packages/   # torch, nvidia-*, Pointcept 휠, 순수 의존성
   ├─ lib/             # 호스트보다 새 공유 라이브러리가 필요할 때만
   ├─ src/pointcept/   # 고정 커밋 소스
   ├─ scripts/         # 추론·학습 워커
   └─ env.sh           # PYTHONPATH, LD_LIBRARY_PATH, TRITON_CACHE_DIR, CUDA_CACHE_PATH
  • venv는 쓰지 않는다. pyvenv.cfg와 스크립트 shebang에 절대 경로가 박혀 있어 위치를 옮기면 깨진다. 실행은 항상 python/bin/python3 -m … 또는 스크립트 경로로 한다.
  • 크기: 지금 에이전트의 rfdetr·sam2 venv가 풀린 상태로 4.7~5.3 GB다(torch 1.1 + nvidia 2.7 + triton 0.7 GB). Pointcept는 여기에 약 0.2 GB가 더해져 압축 후 약 2.5~3 GB로 예상한다. 권장 매트릭스 6개 조합이면 합계 약 15~18 GB다.
  • 가중치는 번들에 넣지 않는다. 모델마다 555 MB이고 선택적이라, 지금처럼 별도 패키지로 둔다.
  • 재사용: torch와 nvidia 부분(약 4.5 GB)은 rfdetr·sam2와 같다. 나중에 여러 앱을 번들로 옮긴다면 "(arch, accel)별 torch 베이스"와 "앱 레이어" 두 층으로 나누면 다운로드와 디스크를 공유할 수 있다. 지금은 python 버전이 다르다(rfdetr·sam2는 3.11, Pointcept는 3.12).

남는 호스트 조건

  1. Linux, 그리고 (arch, accel)에 맞는 NVIDIA 드라이버. nvidia-smi가 동작해야 한다.
  2. 빌드 베이스로 정해지는 glibc 하한 이상 (manylinux_2_28이면 2.28)
  3. 디스크 약 8 GB 이상 (압축 파일과 푼 결과)
  4. GB10·B300은 에이전트 스크립트에 spconv ConvAlgo.Native 고정이 필요하다. 번들과는 무관한 코드 문제다.

걸리는 점

  • 업로드: 수 GB짜리 파일을 레지스트리에 올리려면 관리자 업로드 릴레이의 Workers CPU 한도 문제가 먼저 해결돼야 한다. presigned 직접 업로드로 바꾸는 방법이 있다.
  • 검증 방법: 아무것도 설치하지 않은 베이스 이미지에서 받아서 푸는 과정부터 추론·학습까지 돌려 본다. docker run --gpus all ubuntu:22.04, debian:12, rockylinux:9처럼 드라이버만 nvidia-container-toolkit으로 주입한 상태를 말한다. Triton이 컴파일러를 찾는지도 이 단계에서 드러난다.

manylinux_2_28 빌드

manylinux는 glibc 의존을 없애는 방식이 아니다. 오래된 glibc 위에서 빌드해서 하한을 낮추는 방식을 표준화한 것이다. build_wheels.sh는 이제 이것을 기본값(--os manylinux_2_28)으로 쓴다.

manylinux가 실제로 하는 일

단계

내용

효과

1. 오래된 베이스에서 빌드

manylinux_2_28은 glibc 2.28 기반이다. 여기서는 nvidia/cuda:*-devel-rockylinux8을 쓴다

링크되는 glibc 심볼이 2.28 이하로 묶인다

2. gcc-toolset으로 컴파일

새 C++ 기능은 libstdc++_nonshared.a로 정적 링크하고, 공유 라이브러리로는 시스템(RHEL 8)의 옛 libstdc++만 참조한다

GLIBCXX_3.4.32 문제가 사라진다(3.4.25 이하)

3. auditwheel repair

그 밖의 .so는 휠 안에 복사해 넣고, 파일명에 manylinux_2_28_<arch> 태그를 붙인다

호스트에 별도 라이브러리가 필요 없어진다

4. 정책 검사

repair가 정책을 넘는 휠을 거절한다

호스트에서 import가 실패하는 대신 빌드가 실패한다

결과적으로 glibc 2.28 이상인 모든 Linux(RHEL 8·9, Ubuntu 20.04 이상, Debian 10 이상)에서 동작한다. 이 하한은 torch 휠 자체의 하한(manylinux_2_28)과 같으므로 Pointcept 휠 때문에 생기는 추가 제약은 0이다. 업스트림 spconv-cu124·cu126과 cumm-cu126도 manylinux_2_28로 배포되고 있다.

휠 파일명에 플랫폼 태그가 붙으므로, glibc가 모자란 호스트에서는 pip이 설치 단계에서 이유를 밝히며 거절한다. import 단계에서 알 수 없는 오류로 죽던 문제가 사라진다.

빌드 베이스 이미지

nvidia/cuda:<버전>-devel-rockylinux8은 CUDA 11.8, 12.1, 12.4, 12.6, 12.8, 12.9, 13.0, 13.1, 13.2 모두 amd64와 arm64로 배포된다(Docker Hub, 2026-09-28 확인). CPU 대상은 rockylinux:8을 쓴다.

PyTorch가 자기 휠을 빌드할 때 쓰는 pytorch/manylinux2_28-builder(x86_64)와 pytorch/manylinuxaarch64-builder(aarch64)도 있다. 하지만 아키텍처마다 저장소가 달라서, 한 이름으로 두 플랫폼을 받는 rockylinux8 이미지를 골랐다.

build_wheels.sh의 동작

  • --os 기본값은 manylinux_2_28이다. ubuntu24.04, ubuntu22.04도 그대로 쓸 수 있다.
  • 컨테이너 안에서는 dnf로 EPEL과 PowerTools를 켜고 gcc-toolset, cmake, git, openblas-devel, sparsehash-devel을 설치한다.
  • gcc-toolset 버전은 nvcc가 허용하는 범위에 맞춘다. cu118은 11, cu121은 12, 그 밖에는 13이다.
  • 컴파일한 휠과 linux_* 태그의 prebuilt 휠(PyG 등)은 모두 auditwheel repair --plat manylinux_2_28_<arch>를 거친다. prebuilt가 정책을 통과하지 못하면 그 패키지는 소스로 컴파일한다.
  • repair에서 제외하는 라이브러리: libtorch*, libc10*, libshm*, libcaffe2*, libgomp*(torch가 제공), libcudart*, libnvrtc*, libcublas*, libcusparse*, libcurand*, libcufft*, libcusolver*, libnvJitLink*, libnvToolsExt*, libcudnn*, libnccl*, libcupti*, libnvshmem*(nvidia-* 휠이 제공), libcuda.so*(드라이버가 제공). 이것들을 휠에 넣으면 torch가 쓰는 것과 다른 사본이 로드돼 충돌한다.
  • ROCm은 Ubuntu 이미지만 있다. --os를 주지 않으면 ubuntu24.04로 빌드하고(태그 없음), --os manylinux_2_28을 명시하면 그 조합을 건너뛴다.
  • --native 빌드는 호스트의 OS로 빌드하므로 manylinux 태그를 붙이지 않는다.
  • 출력 경로는 OS를 구분하지 않는다(<out>/linux-<arch>/<accel>/torch<ver>-cp<py>/). 같은 디렉터리에 다시 빌드하면 예전 ubuntu 휠이 manylinux 휠로 교체된다.

다른 방법과 비교

방법

판단

manylinux_2_28 빌드와 auditwheel

채택. torch와 하한이 같고, 업계 표준이며, 업스트림에서 검증됐다

manylinux2014 (glibc 2.17)로 더 낮추기

이점이 없다. torch가 2.6부터 2.28을 요구하므로 하한은 결국 2.28이다

번들에 glibc와 ld-linux를 함께 넣기 (nix-bundle 방식)

가능은 하지만 권장하지 않는다. 호스트 드라이버의 libcuda.so가 같은 프로세스에 로드되어 두 glibc가 섞이고, NSS·locale·dlopen 경로 문제가 생긴다

zig cc로 옛 glibc를 겨냥해 교차 빌드

nvcc의 호스트 컴파일러로 쓰기에는 불안정하다

검증 결과 (2026-09-28, amd64 · cu130 · torch 2.9.1 · sm_120)

--os manylinux_2_28로 pccm, cumm, spconv, torch-scatter, pointops를 빌드했다.

휠

auditwheel 태그

최대 GLIBC

최대 GLIBCXX

추가로 넣은 라이브러리

cumm_cu130 0.8.2

manylinux_2_24 · 2_28

2.14

3.4.21

없음

spconv_cu130 2.3.8

manylinux_2_27 · 2_28

2.14

3.4.21

없음

torch_scatter 2.1.2

manylinux_2_24 · 2_28

2.14

3.4.21

없음

pointops 1.0

manylinux_2_24 · 2_28

2.14

3.4.21

없음

같은 조합을 ubuntu24.04로 빌드했을 때는 cumm이 GLIBC 2.38 / GLIBCXX 3.4.32를 요구했다.

PyG prebuilt는 정책을 통과하지 못했다. torch_scatter-2.1.2+pt29cu130-…-linux_x86_64.whl(data.pyg.org)에 대해 auditwheel이 "too-recent versioned symbols"로 거절했고, 빌더가 소스 컴파일로 넘어갔다. 지금까지 amd64에서 쓰던 PyG prebuilt도 오래된 호스트에서는 깨질 수 있었다는 뜻이다. 대신 amd64 빌드 시간이 PyG 3종 컴파일만큼 늘어난다.

실행 확인 (docker run --gpus all, 아무것도 설치하지 않은 베이스 이미지에 uv, python 3.12, torch 2.9.1+cu130과 휠만 설치):

컨테이너

glibc

기존 ubuntu24.04 휠

manylinux 휠

ubuntu:22.04

2.35

cumm import 실패: GLIBC_2.38' not found

spconv SubMConv3d, torch_scatter scatter_mean, pointops knn_query 모두 GPU에서 성공

rockylinux:8

2.28

(시험 안 함)

위와 같이 모두 성공

아직 확인하지 않은 것

  • manylinux로 빌드한 flash-attn, swin3d, torch-sparse, torch-cluster, pointops2, pointgroup_ops, pointseg, pointrope
  • arm64 (DGX Spark) manylinux 빌드
  • gcc-toolset-11·12를 쓰는 cu118·cu121

남은 결정

  • glibc: ubuntu22.04로 빌드할지, 태그로 구분할지 → manylinux_2_28 기본값으로 해결
  • 7.5(Turing): 에이전트가 capability로 flash 사용을 판단하도록 고친 뒤 태그에 넣을지
  • cu129(A3·B3)를 게시할지
  • 에이전트(app.cvp.run)에 spconv ConvAlgo.Native 고정을 추가할지. GB10·B300을 지원하려면 필요하다

참고

  • Pointcept
  • Pointcept fork: scripts/build_wheels.sh, scripts/verify_wheels.sh, scripts/verify_mlops.sh
  • mlops: src/geo_mlops/resources/training_runtime/Dockerfile.pointcept, src/geo_mlops/resources/training_runtime/pointcept_semseg.py(GeoSpconvAlgo),docs/plans/36_pointcept_training_runtime_plan.md, docs/plans/50_pointgroup_instance_segmentation_plan.md
  • app.cvp.run: cli/src/pointcept/packages.ts, cli/src/pointcept/env.ts, cli/src/pointcept/scripts.ts, docs/plans/pointcept-agent-app-roadmap.md
lastmod 2026-09-28created 2026-09-28author Zer0 sitemap