/

메타가 Llama 모델 가중치를 공개하는 구조적 이유는 특정 자선 행위가 아니라, 폐쇄형 경쟁사 생태계에 종속되지 않으면서 개발자 표준을 선점하고 자사 AI 제품 스택의 비용 효율을 높이려는 전략으로 설명됩니다. 이 글은 메타 공식 발표와 개발자 FAQ 원문을 기준으로 메타 Llama 오픈소스 전략을 정리하며, 라이선스 조건이나 배포 규모처럼 원문에서 확인되지 않는 세부 사항은 본문에 넣지 않고 [ask-dongjin]으로 표시합니다. 주가·목표주가·매수매도 의견은 다루지 않습니다.

Meta·Llama는 무엇인가?

한 줄 답: Llama는 메타가 개발해 가중치를 공개하는 AI 모델군(Llama 3.1, Llama 4 등)이며, 마크 저커버그는 오픈소스 AI가 앞으로 나아갈 길이라고 주장합니다.

2024년 7월 23일 메타 공식 발표에서 마크 저커버그는 오픈소스 AI를 리눅스에 빗대며, 개발자들이 특정 폐쇄형 벤더에 종속되지 않는 개방형 표준이 산업 발전에 유리하다고 밝혔습니다. 같은 발표에서 Llama 3.1 405B·70B·8B 모델이 공개되었습니다. [회사 주장]
메타는 이 발표에서 경쟁력 있는 모델을 공개해도 영구적인 우위를 넘겨주는 것이 아니며, 오히려 생태계를 구축하고 미세조정(fine-tune)·증류(distill) 관점에서 비용 대비 성능을 끌어올릴 수 있다고 설명했습니다. [회사 주장]

Llama 공개가 개발자 생태계에 무엇을 바꾸나?

한 줄 답: 개발자가 폐쇄형 모델에 갇히지 않고 자체 데이터로 미세조정·증류를 수행할 수 있는 생태계가 만들어진다는 것이 메타의 설명입니다.

메타는 가중치를 공개하면 개발자들이 모델 내부 구조에 접근해 자신의 서비스에 맞게 조정할 수 있고, 이 과정에서 메타가 제시한 아키텍처와 도구가 사실상의 개발 표준으로 자리잡을 여지가 생긴다고 설명합니다. 이는 개발자 마인드셰어 확보 측면에서 메타에 유리하다는 분석입니다. [회사 주장] [분석]
다만 실제로 얼마나 많은 개발자·기업이 Llama를 채택해 자체 서비스에 반영했는지에 대한 구체적 수치는 이번 조사 자료에서 확인되지 않았습니다. [확인 필요]

클라우드·칩 파트너와 어떻게 맞물리나?

한 줄 답: 모델 가중치가 공개되어 있어 하드웨어·클라우드 파트너들이 자사 인프라에 Llama를 최적화해 제공할 수 있고, 이는 결과적으로 메타의 학습·추론 인프라 선택지도 넓히는 구조로 이어진다는 분석입니다.

Llama 4 공식 블로그에 따르면 Llama 4 Scout·Maverick은 오픈 가중치 멀티모달 MoE 모델로 공개되었고, Behemoth는 교사 모델로 프리뷰되었습니다. 모델은 llama.com과 Hugging Face에서 제공되며, 파트너 클라우드·서비스 지원이 뒤따를 예정이라고 안내되어 있습니다. [사실]
메타가 모델을 직접 API 형태로만 파는 대신 가중치를 공개함으로써, 특정 클라우드나 칩 벤더에 인프라를 전적으로 의존하지 않고 여러 파트너가 참여하는 개방형 협력 구조를 만든다는 것이 이 조사 자료가 제시하는 분석입니다. 구체적인 파트너사별 계약 조건이나 도입 규모는 확인되지 않았습니다. [분석] [확인 필요]

경쟁사 폐쇄 모델과 위치는 어떻게 다르나?

한 줄 답: 프론티어 API 토큰 판매로 수익을 내는 경쟁 랩들과 달리, 메타는 광고·소셜 등 기존 제품 스택을 고도화하는 데 오픈 생태계를 활용한다는 것이 이 조사 자료의 분석입니다.

메타 공식 발표는 오픈소스 공개가 메타 자신에게도, 개발자에게도, 세계에도 이득이라는 입장을 반복적으로 밝히고 있습니다. 이는 모델 자체를 유료 API로 판매해 매출을 내는 비즈니스 모델과는 다른 접근입니다. [회사 주장]
즉 메타는 모델 판매가 아니라 산업 전반의 기술 기반을 넓히고 이를 자사 서비스(광고, 소셜 제품 등)에 내재화하는 쪽에 가깝다는 것이 분석입니다. 이 구조가 실제 매출이나 이익에 얼마나 기여하는지에 대한 수치는 이번 조사 자료에 포함되어 있지 않으며, 주가·실적 전망은 다루지 않습니다. [분석]

라이선스는 완전한 오픈소스인가?

한 줄 답: Llama는 전통적인 OSI 기준의 완전한 오픈소스가 아니라, 메타가 정한 맞춤형 상업·커뮤니티 라이선스를 따릅니다.

메타 개발자 FAQ는 Llama가 자체적으로 정의한 라이선스(bespoke license)를 사용하며, 폭넓은 상업적 사용을 허용하되 "Built with Llama" 표기 등 일정 조건을 요구한다고 설명합니다. 이는 OSI가 정의하는 오픈소스 라이선스와 동일하지 않습니다. [사실]
라이선스에 포함된 것으로 알려진 월간활성사용자(MAU) 기준이나 세부 조항 번호 등은 이번 조사 자료에서 원문 그대로 확정할 수 없어 본문에 구체적으로 적지 않습니다. 라이선스 전문과 최신 조건은 원문에서 직접 확인해야 합니다. [ask-dongjin]

투자자·독자가 확인할 것

한 줄 답: 주가나 실적 전망이 아니라, Llama 4 후속 모델의 공개 범위와 클라우드·하드웨어 파트너 지원 일정을 제품·생태계 관점에서 확인해야 합니다.

Llama 4 공식 블로그는 Scout·Maverick이 llama.com과 Hugging Face에서 제공되고, Behemoth는 프리뷰 단계이며 파트너 지원이 이어질 예정이라고 안내합니다. 실제 파트너별 배포 시점과 지원 범위는 각 파트너 공지에서 별도로 확인이 필요합니다. [사실] [확인 필요]
이 글은 특정 종목의 매수·매도를 권유하지 않으며, 감사된 매출이나 주가 목표치 등은 다루지 않습니다. 독자는 공식 발표와 라이선스 원문을 직접 확인한 뒤 판단해야 합니다. [확인 필요]

FAQ

한 줄 답: 메타 Llama 오픈소스의 라이선스 조건, 비즈니스 모델, 생태계 전략에 대해 자주 나오는 질문을 정리합니다.

Q. Llama는 완전한 오픈소스인가?

아닙니다. 메타가 정한 맞춤형 상업·커뮤니티 라이선스를 따르며, OSI 기준의 오픈소스와는 조건이 다릅니다. [사실]

Q. 메타는 오픈소스 공개로 어떻게 이익을 얻는가?

모델을 직접 판매하는 대신 개발자 생태계와 파트너 저변을 넓히고, 이를 광고·소셜 등 자사 제품 강화에 활용한다는 것이 메타의 설명이자 이 글의 분석입니다. [회사 주장] [분석]

Q. 메타는 왜 API 토큰 판매 중심 사업을 하지 않는가?

메타의 핵심 사업은 광고·소셜 제품이며, 오픈 모델 공개를 통한 생태계 확장이 별도의 API 판매 사업보다 자사 전략에 부합한다는 것이 분석입니다. [분석]

Q. 라이선스의 MAU 제한 등 세부 조항은 어떻게 되는가?

이번 조사 자료로는 세부 조항을 원문 그대로 확정할 수 없어 본문에 포함하지 않았습니다. 최신 라이선스 원문에서 직접 확인해야 합니다. [ask-dongjin]

출처

한 줄 답: Llama 전략과 라이선스, 모델 공개 정보는 메타 공식 발표와 개발자 FAQ 원문을 기준으로 작성되었습니다.

투자 책임 고지

이 글은 특정 종목의 매수·매도를 권유하기 위한 글이 아니라, 공개자료를 바탕으로 기업 전략(메타 Llama 오픈소스)을 이해하기 위한 정보성 분석 글입니다. 투자 판단과 책임은 투자자 본인에게 있습니다.

📌 답변 먼저 보기

Cursor MCP 연결 실패 시 가장 먼저 Output 패널의 MCP Logs(Mac: Cmd+Shift+U, Windows/Linux: Ctrl+Shift+U)를 확인합니다. 그다음 mcp.json 경로와 환경변수를 점검하고, 여전히 안 되면 Customize > MCPs에서 서버를 제거 후 다시 추가합니다.

이 글은 mcp.json을 이미 작성한 상태에서 서버가 목록에 뜨지 않거나 연결에 실패할 때의 진단·복구 절차만 다룹니다. 처음부터 서버를 추가하는 기본 설정 튜토리얼은 다루지 않습니다.

서버 목록에 안 뜨면 어디를 보나?

한 줄 답: mcp.json 파일 위치를 다시 확인하고, Output 패널의 MCP Logs에서 에러 메시지를 읽습니다.

Cursor는 프로젝트 단위(.cursor/mcp.json)와 글로벌 단위(~/.cursor/mcp.json) 두 곳에서 설정 파일을 읽습니다. 파일명이나 경로에 오타가 있으면 서버 자체가 목록에 나타나지 않습니다. 경로가 맞는데도 보이지 않는다면 백그라운드에서 발생한 에러를 로그로 확인해야 합니다.

확인 방법은 다음과 같습니다.

  1. Mac은 Cmd+Shift+U, Windows/Linux는 Ctrl+Shift+U를 눌러 Output 패널을 엽니다.
  2. 패널 우측 상단 드롭다운에서 MCP Logs를 선택합니다.
  3. 서버가 시작될 때 출력된 에러 메시지(명령어를 찾을 수 없음, 인증 실패 등)를 확인합니다.

이 로그에 원인이 대부분 남아 있으므로, 목록에 서버가 안 보이는 문제는 항상 이 단계에서 시작합니다.

권한·경로·환경변수는 어떻게 점검하나?

한 줄 답: 실행 명령어가 시스템 PATH에 있는지, 셸 환경변수가 Cursor에 전달됐는지, 원격 서버라면 인증 헤더가 맞는지 확인합니다.

로그에서 원인을 찾았다면 아래 세 가지 항목을 순서대로 점검합니다.

  1. 명령어 경로: 로컬 서버라면 mcp.jsoncommand 값(예: npx, python)이 실제로 시스템 PATH에 등록되어 있는지 터미널에서 직접 실행해 확인합니다.
  2. 환경변수: 서버가 .zshrc, .bashrc 같은 셸 프로필의 환경변수에 의존한다면, 셸 프로필을 수정한 뒤 반드시 셸을 재시작(터미널을 새로 열거나 로그아웃 후 재로그인)한 다음 Cursor도 재시작해야 변수가 반영됩니다.
  3. 인증 헤더: 원격(URL) 방식 서버는 mcp.jsonheaders 항목에 넣은 API 키(Authorization: Bearer ... 등)가 누락되거나 만료되지 않았는지 확인합니다.
셸 프로필에 환경변수를 새로 추가했다면, 그 변수는 셸이 재시작된 이후에 열린 Cursor에서만 인식됩니다. Cursor만 재시작하고 셸 프로필은 그대로면 변수가 여전히 비어 있을 수 있습니다.

재시작·캐시 초기화 순서는?

한 줄 답: 단순 재시작만으로 해결되지 않으면 Customize > MCPs에서 토글을 껐다 켜고, 안 되면 서버를 제거 후 다시 추가합니다.

설정을 고쳐도 기존 백그라운드 프로세스나 캐시 때문에 바로 반영되지 않는 경우가 있습니다. 다음 순서대로 진행합니다.

권장 순서

  1. 사이드바에서 Customize를 열고 MCPs 섹션으로 이동합니다.
  2. 문제가 있는 서버의 토글 스위치를 껐다가 다시 켭니다(enable/disable).
  3. 토글만으로 해결되지 않으면 해당 서버를 목록에서 제거(Remove)합니다.
  4. 셸 프로필이나 환경변수를 수정했다면, Cursor를 완전히 종료한 뒤 다시 실행합니다.
  5. 다시 Customize > MCPs에서 Add to Cursor로 서버를 재추가합니다.

이 순서(토글 → 제거 → Cursor 재시작 → 재추가)를 지키면 캐시나 잔여 프로세스로 인한 연결 실패를 대부분 해소할 수 있습니다.

마무리

정리하면 순서는 ① MCP Logs 확인 → ② 경로·환경변수·인증 점검 → ③ 토글/제거/재시작입니다. 서버 추가 자체가 처음이라면 기본 설정 방법은 별도의 mcp.json 작성 가이드를 참고하시고, 이 글은 연결이 이미 실패한 상태를 되돌리는 데에만 활용하시기 바랍니다.

📌 답변 먼저 보기

Orca worktree는 작업마다 디스크상의 별도 git worktree를 만들어 에이전트가 같은 파일을 밟지 않게 하는 단위입니다. CLI에서는 orca worktree create로 만들고 --agent로 첫 터미널 에이전트를 고릅니다. 병렬은 “한 체크아웃에서 여러 채팅”이 아니라 “worktree 여러 개”입니다.

이 글은 WorktreesCLI reference에 적힌 생성·에이전트 지정·충돌 지점만 정리합니다. 가격·후기는 없습니다. 불확실한 플래그는 넣지 않습니다.

worktree create는 어떻게?

한 줄 답: 레포를 고르고 이름을 준 뒤 orca worktree create를 실행합니다. --json을 붙이면 스크립트가 결과를 읽기 쉽습니다.

문서 예시입니다. <repoId>orca repo list --json에서 온 값으로 바꿉니다.

orca worktree list --repo id:<repoId> --json
orca worktree ps --json
orca worktree create --repo id:<repoId> --name fix-login --json
orca worktree current --json

셀렉터는 긴 ID 대신 active, path:/abs/path, branch:feature-name, issue:123을 받을 수 있습니다. 스크립트가 대상 worktree 밖에서 돌면 명시 셀렉터를 씁니다.

UI에서 만들면 다이얼로그를 닫은 뒤 git fetchgit worktree add가 백그라운드에서 이어집니다. 사이드바에 진행 줄이 생기고, 실패하면 Retry가 뜹니다. CLI로 만든 worktree는 사이드바 필터에 “CLI-created”로 구분됩니다.

이미 Orca worktree 안에서 create를 치면 자식으로 기록될 수 있습니다. 관계를 분명히 하려면 --parent-worktree active, 독립 작업이면 --no-parent입니다.

시작 기준(start-from)은 레포 base ref(보통 origin/main), 다른 로컬 브랜치, 커밋 SHA, 원격 브랜치입니다. 대량 생성 전에는 orca repo set-base-ref로 base를 맞춰 두는 것이 문서 습관입니다.

삭제는 디렉터리와 브랜치를 함께 지웁니다(확인 있음). 머지되지 않은 커밋 때문에 git이 브랜치를 남기면 Review N Branches 같은 검토 단계가 열릴 수 있습니다.

에이전트는 어떻게 고르나?

한 줄 답: create 때 --agent로 첫 터미널 에이전트를 띄우고, --prompt로 첫 일을 넣습니다. UI는 Agent selector에서 기본값을 정할 수 있습니다.

orca worktree create --name child-task --agent codex --prompt "Investigate the flaky login test" --json
orca worktree create --name review-api --agent claude --setup run --json
orca worktree create --name quick-check --agent codex --prompt "Summarize the diff" --setup skip --json
orca worktree create --name hidden-setup --setup inherit --json

문서가 정의한 플래그입니다.

  • --agent: 고른 에이전트를 첫 터미널에서 실행합니다. UI에서 Blank Terminal을 고르면 일반 셸만 뜹니다.
  • --prompt: 그 에이전트에 초기 작업을 보냅니다.
  • --setup run|skip|inherit: 레포 setup 훅입니다. inherit은 레포 정책을 따릅니다.

Orca는 모델을 팔지 않습니다. Claude Code, Codex, OpenCode, Grok, Cursor CLI 등 이미 쓰는 에이전트 CLI를 꽂습니다. 계정은 데스크톱 Add account 또는 헤드리스에서 orca account add(기본 Claude, Codex는 --agent codex)입니다.

여러 에이전트를 “추적되는 디스패치”로 돌리려면 문서는 일반 terminal send보다 Orchestration을 쓰라고 합니다. 터미널만 나열하는 것과 역할이 다릅니다.

진행 메모는 orca worktree set --worktree active --comment "..." --json입니다.

병렬 시 충돌은?

한 줄 답: 소스 파일은 worktree가 갈라 주지만, gitignore 경로·공유 디렉터리·같은 원격 브랜치·부모/자식 관계에서 겹칩니다.

Worktrees의 모델은 이렇습니다. 각 worktree는 자체 브랜치, 자체 디스크 파일, 자체 에이전트 터미널을 가집니다. 그래서 같은 버그를 세 에이전트에 나눠 주고 승자를 고르는 패턴이 안전합니다.

그래도 남는 충돌입니다.

  • 깨끗한 체크아웃: 새 worktree에는 gitignore된 의존성·캐시·로컬 시크릿이 없습니다. node_modulesorca.yamlworktree.sharedDirectories(심볼릭/공유), .env는 루트 .worktreeinclude(복사)로 채웁니다. 이미 공유된 경로는 include가 다시 복사하지 않습니다. 추적 중이거나 없는 경로는 건너뜁니다.
  • 같은 원격/PR: 두 worktree가 같은 브랜치를 밀면 git 쪽에서 충돌합니다. 작업 이름을 다르게 두고 start-from을 명시합니다.
  • 부모/자식: 추론된 자식은 사이드바 중첩일 뿐 git 히스토리를 바꾸지 않습니다. 독립이면 --no-parent.
  • 호스트: 원격 런타임은 id:<serverId>:<id> 또는 path: 같은 서버 쪽 셀렉터를 씁니다. 로컬 cwd가 원격에 없을 수 있습니다.
  • 터미널 핸들: 런타임 범위입니다. 재시작 후 stale이면 orca terminal list --json으로 다시 잡습니다.

외부에서 git worktree add한 것은 숨김일 수 있습니다. Non-Orca worktrees에서 Show를 고릅니다. 일반 git(status, rebase)은 다음 렌더에 반영됩니다.

병렬의 검수 지점은 start-from 대비 diff입니다. 문서 수명 주기는 Create → Work → Review → Ship → Archive/Delete입니다. 한 사람이 통합·테스트를 맡는 편이 안전합니다.

출처

📌 답변 먼저 보기

AI 에이전트 실무의 출발점은 검색창과 역할을 나누는 일입니다. 검색은 설명을 모으고, 에이전트는 파일·터미널·브라우저에서 작업을 실행합니다. 이 글은 도구 후기나 요금 없이, 맡기기 좋은 일과 사람이 남길 검수만 개요로 정리합니다.

범위는 “무엇을 넘기고 무엇을 읽을까”입니다. 특정 제품의 설치 플래그·가격은 시리즈의 도구 편과 공식 문서를 따릅니다.

검색창과 뭐가 다르나?

한 줄 답: 검색(또는 일반 채팅)은 질문에 답하고, 에이전트는 목표·범위·완료 기준을 받아 저장소나 문서에서 손을 움직입니다.

검색형 사용은 보통 한 턴입니다. “이 에러가 뭐야?”, “피벗은 어떻게 만들지?”에 설명·링크가 돌아옵니다. 복붙과 적용은 사람이 합니다.

에이전트형 사용은 작업입니다. 대상 경로, 하지 말 것, 끝난 뒤 보여줄 산출물(diff, 표, 초안)을 같이 줍니다. ADE나 CLI 에이전트는 worktree·터미널·브라우저를 붙일 수 있어서, 답이 아니라 변경과 로그가 나옵니다.

실무에서 헷갈리는 지점은 “똑똑한 검색창”과 “실행 권한을 준 에이전트”를 같은 창에 두는 경우입니다. 읽기만 필요한 조사는 검색·Ask에 두고, 파일을 바꿀 때만 Agent/워크트리로 올리는 편이 역할이 분명합니다. 권한을 넓힐수록 검수 비용도 같이 커집니다.

한 줄로 나누면 다음과 같습니다.

  • 검색/채팅: 개념, API 이름, 에러 해석, 초안 아이디어.
  • 에이전트: 재현, 패치, 테스트 실행, 문서 초안을 파일로 쓰기, 반복 리팩터.
  • 사람: 목표 확정, 비밀·권한, 머지, 대외 메시지.

어떤 일을 맡기나?

한 줄 답: 범위가 닫혀 있고, 입출력이 파일이며, 실패해도 되돌리기 쉬운 일부터 맡깁니다.

맡기기 좋은 예입니다.

  • 닫힌 버그: 재현 절차와 실패 로그가 있는 경우. “로그인 플래키 테스트 원인 후보와 최소 패치.”
  • 기계적 변환: 포맷, import 정리, 테스트 스캐폴드, 주석을 문서 목차로 옮기기.
  • 조사 후 요약: 지정한 디렉터리만 읽고, 표나 체크리스트로 반환. 쓰기 권한은 끄거나 worktree를 따로 둡니다.
  • 초안: 커밋 메시지, PR 설명, 회의록 뼈대, 슬라이드 목차. 최종 문장은 사람이 고칩니다.

아직 이릅니다.

  • 프로덕션 시크릿이 있는 디렉터리, 결제·권한·개인정보.
  • “코드베이스를 더 좋게”처럼 완료가 없는 요청.
  • 배포, 강제 푸시, 권한 변경처럼 되돌리기 비싼 명령.

도구를 고를 때는 모델 브랜드보다 실행 표면을 봅니다. 채팅만 되는 창, 로컬 diff가 보이는 IDE, worktree가 갈라지는 ADE는 같은 “에이전트”라도 사고 반경이 다릅니다. 이미 구독 중인 CLI가 있으면 그 구독을 실행기에 붙이는 구성(bring your own agent)이 흔합니다.

한 번에 여러 에이전트를 쓸 때는 일당 하나 목표, 쓰기 권한은 worktree별로, 통합은 사람 하나가 맡는 패턴이 안전합니다. 병렬은 속도가 아니라 충돌을 어디에 모을지를 정하는 문제입니다.

사람 검수는 어디에?

한 줄 답: 시작 전 목표·금지, 실행 중 권한·로그, 끝나기 전 diff·사실·톤, 머지 전 테스트·비밀입니다.

검수를 “느낌”이 아니라 지점으로 고정합니다.

  1. 지시 전: 목표 한 문장, 대상 경로, 하지 말 것(다른 패키지, 포맷터 전체 실행, 원격 푸시). 완료 기준은 “테스트 X 통과”처럼 관찰 가능하게.
  2. 실행 중: 네트워크·sudo·프로덕션 자격 증명이 필요하면 그 순간 사람이 허가합니다. 로그가 멈추면 추측으로 재지시하기 전에 출력을 읽습니다.
  3. 산출물: 소스 diff, 숫자·인용, 대외 문구. 에이전트는 그럴듯한 문장을 잘 만들고, 잘못된 수치를 같이 넣습니다.
  4. 통합: 병렬 작업은 한 브랜치로 모을 때 충돌이 납니다. rebase/머지와 CI는 사람 소유입니다.

읽기 전용 조사와 쓰기 작업을 세션으로 나누면 검수가 줄어듭니다. “일단 고쳐 봐”는 검색창 습관이 실행 권한에 붙는 경우입니다. 실패 시에는 같은 목표를 더 좁히거나, 재현만 다시 맡기고 패치는 사람이 씁니다.

이 개요의 다음 단계는 검색 문장을 작업 단위로 바꾸는 연습입니다. 도구별 클릭보다 역할 분담을 문장으로 쓰는 습관이 먼저입니다.

출처

  • 역할 모델은 시리즈 공통(검색 → 지시 → 검수). 특정 제품 명령은 해당 공식 문서를 따릅니다.
  • Orca ADE 맥락: What is Orca?, Worktrees

요약

aarch64 등 타깃 보드용으로 크로스 컴파일할 때는 CMAKE_TOOLCHAIN_FILE로 타깃 시스템 정보와 컴파일러를 지정하고, CMAKE_SYSROOT로 타깃 루트 파일 시스템을 잡은 뒤, CMAKE_FIND_ROOT_PATH_MODE_* 변수로 find_package() 등이 호스트 라이브러리를 잘못 집어오는 문제를 막습니다.

이 글은 CMake 공식 문서(cmake-toolchains 매뉴얼 및 관련 변수 문서)를 기준으로 정리한 일반 설명이며, 실제 툴체인·SDK 경로는 사용 중인 크로스 컴파일러 배포판에 맞게 바꿔야 합니다.

toolchain 파일에 무엇을 넣나?

한 줄 답: CMAKE_SYSTEM_NAME으로 크로스 컴파일 모드를 켜고, CMAKE_SYSTEM_PROCESSORCMAKE_C_COMPILER/CMAKE_CXX_COMPILER로 타깃 아키텍처와 컴파일러를 지정합니다.

CMake는 기본적으로 지금 빌드가 실행되는 호스트 머신을 대상으로 빌드시스템을 구성합니다. 크로스 컴파일이 필요하면 CMAKE_TOOLCHAIN_FILE 캐시 변수로 별도의 .cmake 파일을 가리켜 설정 단계 초반에 이 값들을 미리 채워 넣어야 합니다.

CMAKE_SYSTEM_NAME에 타깃 운영체제 이름(예: Linux)을 넣으면, 이 값이 호스트 시스템 이름과 다르다는 것만으로 CMake는 크로스 컴파일 모드로 동작합니다. 여기에 CMAKE_SYSTEM_PROCESSOR로 타깃 아키텍처(aarch64)를 지정하고, CMAKE_C_COMPILER·CMAKE_CXX_COMPILER에 각각 aarch64-linux-gnu-gcc, aarch64-linux-gnu-g++ 같은 크로스 컴파일러 경로를 넣습니다.

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

set(CMAKE_C_COMPILER   aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

이 4줄만으로 CMake는 "지금 만들 결과물은 호스트가 아니라 aarch64 타깃용"이라는 사실을 인식하고, 이후 컴파일러 탐색이나 라이브러리 탐색 로직을 크로스 컴파일 방식으로 바꿉니다.

sysroot는 어떻게 맞추나?

한 줄 답: CMAKE_SYSROOT에 타깃 루트 파일 시스템 경로를 지정하면, CMake가 컴파일러·링커에 --sysroot=<path> 플래그를 자동으로 넘깁니다.

크로스 컴파일러 자체는 호스트 머신에서 실행되지만, 헤더와 라이브러리는 타깃 환경 것을 써야 합니다. CMAKE_SYSROOT는 이 타깃 루트 파일 시스템의 위치를 CMake에게 알려주는 변수입니다.

set(CMAKE_SYSROOT /opt/aarch64-sysroot)

이 값을 설정하면 CMake는 컴파일러와 링커를 호출할 때 --sysroot=/opt/aarch64-sysroot를 자동으로 붙여줍니다. 그 결과 컴파일러는 기본 경로인 호스트의 /usr/include, /usr/lib 대신 지정한 sysroot 안의 include·lib를 먼저 찾게 됩니다.

sysroot는 실제로 타깃 보드에서 복사해 오거나, 사용 중인 크로스 컴파일 SDK가 함께 제공하는 루트 파일 시스템 디렉터리를 그대로 가리키면 됩니다. 경로가 잘못되면 헤더를 못 찾는 오류로 바로 드러나므로 확인이 비교적 쉽습니다.

find_package가 호스트 라이브러리를 집을 때 어떻게 막나?

한 줄 답: CMAKE_FIND_ROOT_PATH_MODE_PROGRAMNEVER로, LIBRARY·INCLUDE·PACKAGEONLY로 설정해 검색 범위를 완전히 분리합니다.

크로스 컴파일에서 가장 흔히 겪는 문제는 find_package()find_library()가 sysroot가 아니라 호스트 시스템(예: x86_64) 경로에서 라이브러리를 찾아버리는 현상입니다. 이 문제는 CMAKE_FIND_ROOT_PATH_MODE_* 변수 네 가지로 검색 대상을 명확히 나눠서 막습니다.

실행 파일과 라이브러리는 검색 범위가 달라야 합니다

빌드 중에 실행해야 하는 코드 생성기 같은 프로그램은 호스트에서 돌아가야 하므로, CMAKE_FIND_ROOT_PATH_MODE_PROGRAMNEVER로 두어 호스트 경로에서만 찾도록 합니다. 반대로 링크에 쓸 라이브러리·헤더·패키지 설정은 타깃 sysroot 안에만 있어야 하므로, 나머지 세 변수는 ONLY로 지정해 sysroot 바깥은 아예 보지 않게 만듭니다.

set(CMAKE_FIND_ROOT_PATH /opt/aarch64-sysroot)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

이렇게 설정해 두면 find_package(), find_library(), find_path() 같은 명령이 CMAKE_FIND_ROOT_PATH로 지정한 sysroot 안에서만 라이브러리·헤더·패키지 설정 파일을 찾고, 호스트 시스템의 /usr/lib/usr/include는 건너뜁니다.

변수권장 값이유
CMAKE_FIND_ROOT_PATH_MODE_PROGRAMNEVER빌드 중 실행할 프로그램은 호스트에서 실행되어야 합니다.
CMAKE_FIND_ROOT_PATH_MODE_LIBRARYONLY링크용 라이브러리는 타깃 sysroot에만 있어야 합니다.
CMAKE_FIND_ROOT_PATH_MODE_INCLUDEONLY헤더도 타깃 sysroot 기준으로만 찾아야 합니다.
CMAKE_FIND_ROOT_PATH_MODE_PACKAGEONLY패키지 설정 파일도 호스트 경로를 침범하지 않아야 합니다.
이 네 변수를 빼먹으면, 빌드는 되지만 실제로는 호스트용 라이브러리가 링크되어 타깃 보드에서 실행할 때만 문제가 드러나는 경우가 있습니다. 크로스 컴파일 toolchain 파일에서는 처음부터 이 설정을 넣어 두는 것이 안전합니다.

FAQ

toolchain 파일은 어디에 두고 어떻게 지정합니까?

파일 자체는 프로젝트 안이든 밖이든 원하는 위치에 .cmake 파일로 두면 되고, 설정 단계에서 cmake -S <source> -B <build> -DCMAKE_TOOLCHAIN_FILE=/path/to/aarch64-toolchain.cmake처럼 캐시 변수로 지정합니다.

sysroot 없이 그냥 컴파일러 경로만 지정해도 됩니까?

동작할 수는 있지만 권장하지 않습니다. sysroot를 지정하지 않으면 컴파일러가 헤더나 라이브러리를 찾을 때 기본 검색 경로(호스트 경로)에 의존하게 되어, 위 CMAKE_FIND_ROOT_PATH_MODE_* 설정과 별개로 헤더·라이브러리 버전이 뒤섞일 위험이 남습니다.

CMAKE_FIND_ROOT_PATH_MODE_PROGRAM만 NEVER로 두는 이유는 무엇입니까?

빌드 중간에 실행되는 코드 생성기 같은 프로그램은 타깃 아키텍처(aarch64) 바이너리가 아니라 호스트에서 바로 실행 가능한 바이너리여야 하기 때문입니다. 이 값을 ONLY로 두면 오히려 호스트에서 실행 불가능한 타깃용 실행 파일을 찾다가 빌드가 깨질 수 있습니다.

정리하며

aarch64 크로스 컴파일 toolchain 파일은 결국 세 가지 역할로 요약됩니다. CMAKE_SYSTEM_NAME·CMAKE_SYSTEM_PROCESSOR·컴파일러 경로로 크로스 컴파일 모드를 켜고, CMAKE_SYSROOT로 타깃 루트 파일 시스템을 잡고, CMAKE_FIND_ROOT_PATH_MODE_* 네 변수로 프로그램 탐색과 라이브러리·헤더·패키지 탐색의 범위를 분리하는 것입니다. 이 세 부분만 정확히 채워 두면 호스트 라이브러리가 실수로 링크되는 문제를 대부분 예방할 수 있습니다.

출처

한 줄 답: 본문의 변수와 동작 방식은 CMake 공식 문서(cmake-toolchains 매뉴얼과 관련 변수 문서)를 기준으로 확인했습니다.

|

C++20에서 추가된 std::jthread는 소멸 시 자동으로 join()을 호출하고, 내부에 std::stop_source를 들고 있어 협력적 취소(cooperative cancellation) 신호를 함께 전달합니다. 이 글은 cppreference를 기준으로 std::jthread stop_token을 이용해 스레드를 안전하게 취소하는 방법만 얇게 정리합니다.

atomic이나 RAII 자체에 대한 기본 설명은 다루지 않고, jthread의 자동 조인과 stop_token을 넘기고 확인하는 부분만 다룹니다.

jthread는 thread와 무엇이 다르나?

한 줄 답: 소멸 시 자동으로 join()을 호출하며, 내부에 std::stop_source를 내장하여 협력적 취소를 기본 지원합니다.

std::thread는 소멸 전에 join()이나 detach()를 명시적으로 호출하지 않으면 std::terminate가 호출되어 프로그램이 비정상 종료됩니다. 호출 경로가 여러 개이거나 예외가 섞이면 이 호출을 빠짐없이 챙기기가 쉽지 않습니다.

std::jthread는 소멸자에서 join()을 자동으로 호출합니다. 객체가 스코프를 벗어나는 순간 실행 중인 스레드를 안전하게 정리하므로, 명시적인 조인 호출을 잊어서 생기는 문제가 사라집니다.

또한 jthread 인스턴스는 내부에 std::stop_source 상태를 함께 들고 있습니다. 이 상태 덕분에 외부에서 request_stop()을 호출해 스레드에 취소를 요청할 수 있는 기반이 생성 시점부터 마련됩니다.

std::jthread worker([](std::stop_token st) {
    while (!st.stop_requested()) {
        // 작업 수행
    }
});
// worker가 스코프를 벗어나면 자동으로 join() 호출

stop_token은 어떻게 넘기나?

한 줄 답: 작업 함수(callable)의 첫 번째 매개변수로 std::stop_token을 받도록 선언하면 생성 시점에 알아서 전달됩니다.

취소는 스레드 외부에서 jthread 객체의 request_stop() 메서드를 호출하는 방식으로 시작합니다.

이 요청을 받으려면 스레드 작업 루틴(람다 또는 함수)의 첫 번째 인자로 std::stop_token을 받게끔 시그니처를 작성해야 합니다. jthread가 스레드를 실행할 때 이 토큰을 자동으로 주입합니다.

스레드 내부 작업 루프에서는 stop_token.stop_requested()를 주기적으로 폴링(poll)하고, true가 반환되면 루프를 안전하게 탈출(return)하도록 구현합니다.

void run(std::stop_token st) {
    while (!st.stop_requested()) {
        // 반복 작업
    }
    // 정리 후 반환
}

std::jthread t(run);
t.request_stop();

취소가 안 먹을 때 무엇을 점검하나?

한 줄 답: 스레드 내부 루프에서 stop_requested()를 주기적으로 검사하는지, 그리고 블로킹 대기에 condition_variable_any를 썼는지 확인합니다.

stop_token은 강제 종료(kill)가 아니라 협력적 취소입니다. 스레드 내부에서 상태를 확인하고 스스로 종료하지 않으면 취소 요청은 그대로 무시됩니다.

루프 안에 오래 걸리는 무거운 작업이 있다면, 그 사이사이에 stop_requested()를 확인하는 지점을 추가해야 합니다. 확인 지점이 드물면 취소 요청이 온 뒤에도 한참 뒤에야 반영됩니다.

블로킹 I/O나 조건 변수 대기 상태에 머물러 있는지도 점검 대상입니다. stop_token으로 인터럽트 가능한 대기(interruptible wait)를 구현하려면 기존 std::condition_variable 대신 std::condition_variable_any를 사용해야 합니다.

점검 항목 확인할 내용
폴링 주기 루프 안에서 stop_requested()를 충분히 자주 호출하는지 확인합니다.
블로킹 대기 condition_variable_any로 인터럽트 가능한 대기를 구성했는지 확인합니다.
취소 방식 강제 종료가 아닌 협력적 취소임을 전제로 스레드가 스스로 반환하는지 확인합니다.

즉시 반응이 필요하다면 std::stop_callback을 등록해 취소 요청 시점에 콜백을 바로 실행하는 방법도 있습니다.

출처

+ Recent posts