https://drehzr.tistory.com/1190
Unity)Asmdef (어셈블리 정의)
Asmdef (어셈블리 정의) Unity에서 어셈블리로 따로 정의해서 파일을 만들 수 있다. 어셈블리 파일로 관리를 하게되면 특정 스크립트만 따로 재 빌드해서 컴파일 시간을 단축할 수 있다. 어셈블리
drehzr.tistory.com
https://docs.unity3d.com/kr/2021.3/Manual/ScriptCompilationAssemblyDefinitionFiles.html
어셈블리 정의 - Unity 매뉴얼
어셈블리 정의 및 어셈블리 레퍼런스는 스크립트를 어셈블리로 구성할 수 있는 에셋입니다.
docs.unity3d.com
Unity 어셈블리 정의 완벽 가이드
1. 어셈블리란 무엇인가?
기본 개념
**어셈블리(Assembly)**는 컴파일된 코드가 들어있는 .dll 파일입니다. Unity에서는 C# 스크립트들이 모여서 하나의 어셈블리를 만듭니다.
C# 스크립트들 → 컴파일 → 어셈블리(.dll)
Unity의 기본 어셈블리 (공식 정정)
Unity는 기본적으로 다음 4개의 주요 어셈블리들을 자동 생성합니다:
- Assembly-CSharp-firstpass.dll: Plugins 폴더와 Standard Assets 폴더의 스크립트들 (먼저 컴파일됨)
- Assembly-CSharp-Editor-firstpass.dll: Plugins/Editor 폴더와 Standard Assets/Editor 폴더의 스크립트들
- Assembly-CSharp-Editor.dll: Editor 폴더의 스크립트들
- Assembly-CSharp.dll: 나머지 모든 Assets 폴더의 C# 스크립트들
Assets/
├── Scripts/
│ ├── Player.cs ← Assembly-CSharp.dll
│ └── GameManager.cs ← Assembly-CSharp.dll
├── Editor/
│ └── CustomTool.cs ← Assembly-CSharp-Editor.dll
├── Plugins/
│ └── ThirdParty.cs ← Assembly-CSharp-firstpass.dll
└── Plugins/Editor/
└── EditorPlugin.cs ← Assembly-CSharp-Editor-firstpass.dll
2. 어셈블리 정의가 필요한 이유
문제 상황: 거대한 단일 어셈블리
모든 스크립트가 하나의 어셈블리에 들어가면:
❌ 문제점들
- 컴파일 시간 증가: 한 스크립트만 수정해도 전체 재컴파일
- 의존성 혼란: 어떤 코드가 어떤 코드를 참조하는지 불분명
- 배포 어려움: 패키지나 모듈 단위로 분리하기 어려움
- 테스트 제약: 테스트 전용 라이브러리 사용 불가
해결책: 어셈블리 정의로 분리
✅ 장점들
- 빠른 컴파일: 변경된 어셈블리와 그에 의존하는 어셈블리만 재컴파일
- 명확한 의존성: 어셈블리 간 참조 관계가 명확
- 모듈화: 기능별로 독립적인 모듈 구성
- 재사용성: 다른 프로젝트에서 쉽게 재사용
3. 어셈블리 정의 파일(.asmdef) 이해하기
파일 생성 방법
- Unity 에디터에서: 우클릭 → Create → Scripting → Assembly Definition
- 직접 생성: .asmdef 확장자로 JSON 파일 생성
기본 구조 예제
{
"name": "MyGameplay",
"references": [
"MyUtilities",
"MyAI"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
주요 설정 설명
name (필수)
어셈블리의 이름입니다.
"name": "MyGameplay" // 결과: MyGameplay.dll
references (중요!)
이 어셈블리가 참조할 다른 어셈블리들입니다.
"references": [
"MyUtilities", // 다른 커스텀 어셈블리
"Unity.InputSystem" // Unity 패키지 어셈블리
]
⚠️ 주의: 참조에 추가하지 않으면 해당 어셈블리의 코드를 사용할 수 없습니다!
autoReferenced (정정된 설명)
predefined assemblies(기본 어셈블리들)가 이 어셈블리를 자동으로 참조할 수 있는지 설정합니다.
"autoReferenced": false // predefined assemblies가 이 어셈블리를 자동 참조하지 않음
- true: Assembly-CSharp.dll 등에서 자동으로 이 어셈블리 사용 가능
- false: predefined assemblies에서 이 어셈블리를 직접 사용할 수 없음 (성능상 이점)
includePlatforms / excludePlatforms
어떤 플랫폼에서 컴파일할지 지정합니다.
// Editor에서만 컴파일
"includePlatforms": ["Editor"]
// 모바일에서 제외
"excludePlatforms": ["Android", "iOS"]
4. 실전 예제: 게임 프로젝트 구조화
Before: 단일 어셈블리
Assets/
└── Scripts/
├── Player/
│ ├── PlayerController.cs
│ └── PlayerHealth.cs
├── AI/
│ ├── EnemyAI.cs
│ └── AIUtilities.cs
├── UI/
│ ├── MainMenu.cs
│ └── HUD.cs
└── Utilities/
├── MathHelper.cs
└── Extensions.cs
→ 모든 파일이 Assembly-CSharp.dll에 포함
After: 모듈별 어셈블리 분리
Assets/
└── Scripts/
├── Utilities/
│ ├── Utilities.asmdef ← 유틸리티 어셈블리
│ ├── MathHelper.cs
│ └── Extensions.cs
├── Player/
│ ├── Player.asmdef ← 플레이어 어셈블리
│ ├── PlayerController.cs
│ └── PlayerHealth.cs
├── AI/
│ ├── AI.asmdef ← AI 어셈블리
│ ├── EnemyAI.cs
│ └── AIUtilities.cs
└── UI/
├── UI.asmdef ← UI 어셈블리
├── MainMenu.cs
└── HUD.cs
의존성 설정 예제
1. Utilities.asmdef (기반 유틸리티)
{
"name": "Utilities",
"references": [],
"autoReferenced": true // 다른 어셈블리에서 자동 참조 가능
}
2. Player.asmdef (플레이어 시스템)
{
"name": "Player",
"references": [
"Utilities" // 유틸리티 어셈블리 사용
],
"autoReferenced": false
}
3. AI.asmdef (AI 시스템)
{
"name": "AI",
"references": [
"Utilities",
"Player" // 플레이어 정보 접근 필요
],
"autoReferenced": false
}
4. UI.asmdef (UI 시스템)
{
"name": "UI",
"references": [
"Utilities",
"Player" // 플레이어 상태 표시
],
"autoReferenced": false
}
5. 테스트 어셈블리 특별 설정
테스트 전용 어셈블리
Unity는 다음 조건을 만족하면 자동으로 테스트 어셈블리로 인식합니다:
- nunit.framework.dll에 대한 참조가 있음
- UnityEngine.TestRunner와 UnityEditor.TestRunner에 대한 어셈블리 정의 참조가 있음
Edit Mode 테스트 예제:
{
"name": "Tests.EditMode",
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"Player", // 테스트할 어셈블리
"AI" // 테스트할 어셈블리
],
"includePlatforms": ["Editor"],
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll" // NUnit 라이브러리
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS" // 테스트 빌드에서만 포함
]
}
Play Mode 테스트 예제:
{
"name": "Tests.PlayMode",
"references": [
"UnityEngine.TestRunner",
"Player",
"AI"
],
"includePlatforms": [],
"excludePlatforms": [],
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
]
}
중요한 테스트 설정들:
- includePlatforms: ["Editor"] - 에디터에서만 컴파일 (Edit Mode)
- overrideReferences: true - 수동으로 라이브러리 지정
- precompiledReferences - NUnit 등 테스트 라이브러리 포함
- defineConstraints - 테스트 환경에서만 활성화
6. 자주 발생하는 문제와 해결책
문제 1: "The type or namespace name 'XXX' could not be found"
원인: 어셈블리 참조가 누락됨
해결: references에 필요한 어셈블리 추가
{
"name": "MyAssembly",
"references": [
"MissingAssembly" // ← 이것을 추가해야 함
]
}
문제 2: 순환 참조 에러
원인: A가 B를 참조하고, B가 A를 참조
해결: 공통 부분을 별도 어셈블리로 분리
Before: A ↔ B (순환 참조)
After: A → Common ← B (공통 어셈블리로 해결)
문제 3: Unity 패키지를 찾을 수 없음
원인: Unity 패키지 어셈블리 참조 누락
해결: Package Manager에서 패키지명 확인 후 추가
{
"references": [
"Unity.InputSystem", // New Input System
"Unity.Addressables", // Addressables
"Unity.Timeline" // Timeline
]
}
문제 4: Editor 폴더가 런타임에 컴파일되는 문제
원인: 어셈블리 정의가 있는 폴더 하위의 Editor 폴더는 특별 취급되지 않음
해결: Editor 폴더에 별도의 어셈블리 정의 생성
{
"name": "MyProject.Editor",
"references": ["MyProject"],
"includePlatforms": ["Editor"]
}
7. 모범 사례 (Best Practices)
✅ 좋은 어셈블리 구조
- 기능별 분리: UI, Gameplay, AI 등 논리적 단위로 분리
- 의존성 방향: 상위 → 하위로만 참조 (순환 참조 금지)
- 공통 유틸리티: 모든 곳에서 사용되는 코드는 별도 어셈블리
- 플랫폼 분리: Editor 전용 코드는 별도 어셈블리
- 적절한 크기: 너무 세분화하지 말고 논리적 단위로 그룹화
❌ 피해야 할 패턴
- 과도한 분리: 너무 작은 단위로 나누면 관리 복잡도 증가
- 순환 참조: A ↔ B 형태의 상호 참조
- autoReferenced 남용: 모든 어셈블리를 자동 참조로 설정
- 잘못된 의존성: 하위 레벨이 상위 레벨을 참조하는 구조
권장 프로젝트 구조
Assets/
├── Core/ ← 핵심 시스템
│ ├── Core.asmdef
│ └── GameManager.cs
├── Utilities/ ← 공통 유틸리티
│ ├── Utilities.asmdef
│ └── Extensions.cs
├── Gameplay/ ← 게임플레이 로직
│ ├── Gameplay.asmdef
│ └── Player/
├── UI/ ← 사용자 인터페이스
│ ├── UI.asmdef
│ └── MainMenu.cs
├── Editor/ ← 에디터 도구
│ ├── Editor.asmdef
│ └── CustomInspector.cs
└── Tests/ ← 테스트 코드
├── EditMode/
│ ├── Tests.EditMode.asmdef
│ └── GameplayTests.cs
└── PlayMode/
├── Tests.PlayMode.asmdef
└── IntegrationTests.cs
8. 고급 기능
Version Defines
특정 패키지 버전에 따라 조건부 컴파일이 가능합니다:
{
"versionDefines": [
{
"name": "com.unity.render-pipelines.high-definition",
"expression": "7.1.0",
"define": "HDRP_7_1_0_OR_NEWER"
}
]
}
Define Constraints
특정 심볼이 정의되었을 때만 어셈블리를 포함:
{
"defineConstraints": [
"UNITY_INCLUDE_TESTS",
"!UNITY_WEBGL" // WebGL이 아닐 때만
]
}
Override References
수동으로 precompiled 어셈블리 참조 관리:
{
"overrideReferences": true,
"precompiledReferences": [
"MyCustomLibrary.dll"
]
}
9. 디버깅과 확인 방법
스크립트가 어떤 어셈블리에 속하는지 확인
- Project 창에서 C# 스크립트 선택
- Inspector 창의 "Assembly Information" 섹션 확인
- 어셈블리 파일명과 Assembly Definition 정보 표시
컴파일 파이프라인 정보 확인
using UnityEditor;
using UnityEditor.Compilation;
public static class AssemblyLister
{
[MenuItem("Tools/List Player Assemblies")]
public static void PrintAssemblyNames()
{
Debug.Log("== Player Assemblies ==");
Assembly[] playerAssemblies =
CompilationPipeline.GetAssemblies(AssembliesType.Player);
foreach (var assembly in playerAssemblies)
{
Debug.Log($"{assembly.name}: {assembly.sourceFiles.Length} files");
}
}
}
10. 다음 단계
어셈블리 정의를 마스터했다면:
- 패키지 제작: 자신만의 Unity 패키지 만들기
- 성능 최적화: 컴파일 시간 단축 전략
- CI/CD 구축: 자동화된 빌드 시스템 구성
- 고급 기능: Runtime Assembly 로딩 등
어셈블리 정의는 Unity 프로젝트를 체계적으로 관리하는 핵심 도구입니다. 올바르게 구성하면 개발 효율성과 코드 품질이 크게 향상됩니다!
'소프트웨어 공학 > 코딩' 카테고리의 다른 글
| Unity] 라이프사이클 (Awake, OnEnable, Start)에 대한 실험결과 (1) | 2025.07.25 |
|---|---|
| CS] 메모리, 배열vs리스트, 커널, 코어와스레드, 멀티스레딩과 비동기 (2) | 2025.07.23 |
| 기술 학습자료 링크 (2) | 2025.06.05 |
| 관심사의 분리(Separation of Concerns) (0) | 2025.05.02 |
| 유니티 커스텀 어트리뷰트 (0) | 2025.05.01 |