apple clang vs llvm clang

mac 에서 cmake 빌드시 -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ 로 llvm clang 을 사용하면 다음과 같은 에러가 발생한다.

rapidjson/document.h:319:82: error: cannot assign to
      non-static data member 'length' with const-qualified type 'const SizeType' (aka 'const unsigned int')

rapidjson/document.h:319:82: error: cannot assign to
      non-static data member 'length' with const-qualified type 'const SizeType' (aka 'const unsigned int')

DCMAKE_CXX_COMPILER 옵션을 제거해 기본 apple clang 을 사용하도록 하면 된다.

Apple Clang
- 출처: Apple이 Xcode에 포함하여 배포
- 버전: 독자적 버전 체계 (예: Apple clang 16.x)
- 업데이트: Xcode 업데이트에 종속, 느림
- 기능: Apple 플랫폼 최적화 (Obj-C, Metal, arm64e 등)
- 엄격함: 상대적으로 관대
- libc++: Apple 자체 패치된 libc++
- 경로
/usr/bin/clang --version
/usr/bin/c++ --version
/Library/Developer/CommandLineTools/usr/bin/c++ --version
Apple clang version 17.0.0 (clang-1700.6.4.2)
Target: arm64-apple-darwin25.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

LLVM Clang (Homebrew)
- 출처: llvm.org 공식 릴리스
- 버전: 업스트림 버전 그대로 (예: clang 19.x)
- 업데이트: 최신 LLVM 릴리스 바로 반영
- 기능: 최신 C++ 표준, sanitizer, 경고 규칙 반영 빠름
- 엄격함: 더 엄격한 경고/에러 정책
- libc++: 업스트림 libc++
- 경로
/opt/homebrew/opt/llvm/bin/clang --version
/opt/homebrew/opt/llvm/bin/clang++ --version
Homebrew clang version 22.1.0
Target: arm64-apple-darwin25.3.0
Thread model: posix
InstalledDir: /opt/homebrew/Cellar/llvm/22.1.0/bin
Configuration file: /opt/homebrew/etc/clang/arm64-apple-darwin25.cfg

docker virtiofs volume mount symlink creation failure

## 증상
macOS Docker 에서 bind mount(-v) 된 경로에서 tar 압축 해제 시 symlink 포함 파일이 Permission denied 로 실패한다.
tar: re2-2025-11-05/python/LICENSE: Cannot open: Permission denied
tar: Exiting with failure status due to previous errors

ls 로 확인하면 symlink 대신 퍼미션 ---------- 인 0바이트 파일이 생성되어 있다.
---------- 1 root root 0 Aug 17 23:47 LICENSE

## 원인

Docker for Mac 은 호스트와 컨테이너 간 파일 공유에 VirtioFS 드라이버를 사용한다.

VirtioFS 는 호스트와 가상머신(VM) 간 파일 공유를 위한 파일시스템 프로토콜이다.
QEMU/KVM 의 virtio 가상화 프레임워크 위에서 동작하며, FUSE 프로토콜을 기반으로 호스트 파일시스템을 VM 내부에 마운트한다.
Docker for Mac 은 Linux VM 위에서 컨테이너를 실행하는데, -v bind mount 시 macOS 호스트 파일을 이 Linux VM 에 공유해야 한다.
이전에는 gRPC-FUSE 를 사용했으나, 성능 개선을 위해 VirtioFS 가 기본 파일 공유 드라이버로 채택되었다.
macOS (호스트) ←→ VirtioFS ←→ Linux VM ←→ 컨테이너

VirtioFS 는 gRPC-FUSE 대비 파일 I/O 성능이 크게 향상되지만, 일부 POSIX 파일시스템 동작(퍼미션 000 파일 생성, symlink 등)에서 호환성 문제가 있다.

tar 가 symlink 를 풀 때 내부적으로 다음 순서로 동작한다.
1. openat("dst", O_CREAT|O_EXCL, 000)  ← placeholder 파일 생성 (퍼미션 000)
2. 실제 타겟 파일 생성
3. unlinkat("dst")                       ← placeholder 삭제
4. symlinkat("../src", "dst")            ← symlink 생성

VirtioFS 는 퍼미션 000 으로 파일을 생성하는 openat() 호출을 Permission denied 로 거부한다.
1단계에서 실패하므로 symlink 가 만들어지지 않고 깨진 0바이트 파일만 남게 된다.
이 문제는 같은 디렉토리 내 symlink 에서는 발생하지 않고, 다른 디렉토리를 가리키는 symlink(예: python/LICENSE → ../LICENSE) 에서만 발생한다.

컨테이너 내부 경로(/tmp등)에서는 Linux 네이티브 파일시스템(overlay2)을 사용하므로 정상 동작한다.
./openat ./mounted/demo   → Permission denied (VirtioFS)
./openat /tmp/demo         → OK (overlay2)

## 해결 방법
1. named volume 사용 (권장)

bind mount 대신 Docker named volume 을 사용하면 Docker VM 내부 파일시스템이 사용되어 symlink 가 정상 동작한다.

# named volume 생성해서 마운트
docker volume create my_source_vol
docker run -dit \
    -v my_source_vol:/workspace/source \
    my_image

# 호스트 소스를 named volume 으로 복사
docker cp ./source/. "container_name:/workspace/source"

2. 컨테이너 내부 경로에서 빌드

소스를 컨테이너 내부 경로(`/tmp` 등)로 복사한 후 빌드한다.

docker exec -it my_container /bin/bash -c "
    cp -a /mounted/source /tmp/source &&
    cd /tmp/source &&
    ./build.sh /mounted/output"

3. VirtioFS 대신 다른 마운트 방식 사용
VirtioFS 를 사용하지 않으면 symlink 가 정상 생성된다. 다만 파일 I/O 성능이 저하될 수 있다.

# Docker Desktop 사용 시
Docker Desktop → Settings → General → "VirtioFS" 체크 해제

# Colima 사용 시
Colima 는 vmType 에 따라 사용 가능한 마운트 방식이 다르다.

vmType 종류
vz: macOS 자체 가상화 프레임워크(Virtualization.Framework) 사용. 네이티브라 빠르지만 macOS 13+ 필요
qemu: 오픈소스 하드웨어 에뮬레이터. CPU, 메모리, 디스크 등을 소프트웨어로 에뮬레이션한다. vz 보다 느리지만 다양한 마운트 타입 지원

mountType 종류:
virtiofs: macOS Virtualization.Framework 기반, 가장 빠름 (vmType vz 전용)
sshfs: SSH 기반 파일 전송, virtiofs 보다 느리지만 안정적 (vmType qemu 전용)
9p: Plan 9 프로토콜 기반, 가장 안정적 (vmType qemu 전용)

vmType vz 를 사용하는 경우 virtiofs 만 지원되므로 마운트 타입 변경으로는 해결할 수 없다.
이 경우 해결 방법 1(named volume) 또는 2(컨테이너 내부 경로에서 빌드)를 사용해야 한다.

현재 마운트 타입 확인:

# json 출력에서 mount_type, driver(vmType) 확인
colima status --json | jq '{mount_type, driver}'

# 또는 설정 파일 직접 확인
# colima.yaml 위치: ~/.config/colima/default/colima.yaml
grep -E 'mountType|vmType' ~/.config/colima/default/colima.yaml

vmType qemu 로 변경하면 sshfs 또는 9p 를 사용할 수 있지만 비추천한다.
macOS 에서 QEMU 바이너리에 com.apple.security.hypervisor entitlement 서명이 필요한데, 서명 에러가 발생하는 경우가 많고 vz 대비 성능도 떨어진다.

# qemu 시작 시 서명 에러 예시
"QEMU binary does not seem properly signed with the com.apple.security.hypervisor entitlement"

또한 mountType 은 VM 생성 후 변경 불가하므로 삭제 후 재생성해야 한다.

# colima start --mount-type 만으로는 변경되지 않는다
WARN[0001] 'volume mount type' cannot be updated after initial setup, discarded

qemu 로 변경 시도 후 다시 vz 로 되돌리려면 VM 을 삭제하고 재생성해야 한다.

# 기존 VM 삭제
colima delete --force

# vz + virtiofs 로 재생성 (기존 옵션에 맞게 조정)
colima start --vm-type vz --mount-type virtiofs --cpu 10 --memory 4 --disk 100

결론: Colima + vz 환경에서는 마운트 타입 변경이 현실적이지 않으므로 해결 방법 1(named volume) 또는 2(컨테이너 내부 경로에서 빌드)를 사용하자.

integrate OpenCode and ClaudeCode into neovim

opencode, claudecode 를 별도의 터미널 창에서 사용하다 보면 특정 코드 block/range 를 지시할때 copy & paste 를 사용하는데 좀 불편하다.
neovim(nvim)에서 opencode, claudecode 띄우고 코드를 보면서 특정 코드영역을 바로 넘겨서 질의할 수 있는 환경을 만들 수 있다.

opencode 의 경우 다음 플러그인을 설치하자.
opencode 가 nvim window 으로 표시된다.
<leader>or 로 코드 블럭을 opencode 프롬프트로 전달

claudecode 의 경우 다음 플러그인을 설치하자.
claudecode 가 nvim snacks_terminal 로 실행된다.
<leader>as 로 코드 블럭을 opencode 프롬프트로 전달