"깊이"가 다른 게임개발자 허민영

유저에서 게임까지, 철학에서 코딩까지, 본질을 보는 게임개발

소프트웨어 공학/코딩

유니티] 어셈블리 정의 asmdef파일

허민영 2025. 6. 16. 08:01

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개의 주요 어셈블리들을 자동 생성합니다:

  1. Assembly-CSharp-firstpass.dll: Plugins 폴더와 Standard Assets 폴더의 스크립트들 (먼저 컴파일됨)
  2. Assembly-CSharp-Editor-firstpass.dll: Plugins/Editor 폴더와 Standard Assets/Editor 폴더의 스크립트들
  3. Assembly-CSharp-Editor.dll: Editor 폴더의 스크립트들
  4. 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) 이해하기

파일 생성 방법

  1. Unity 에디터에서: 우클릭 → Create → Scripting → Assembly Definition
  2. 직접 생성: .asmdef 확장자로 JSON 파일 생성

기본 구조 예제

 
json
{
    "name": "MyGameplay",
    "references": [
        "MyUtilities",
        "MyAI"
    ],
    "includePlatforms": [],
    "excludePlatforms": [],
    "allowUnsafeCode": false,
    "overrideReferences": false,
    "precompiledReferences": [],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}

주요 설정 설명

name (필수)

어셈블리의 이름입니다.

 
json
"name": "MyGameplay"  // 결과: MyGameplay.dll

references (중요!)

이 어셈블리가 참조할 다른 어셈블리들입니다.

 
json
"references": [
    "MyUtilities",      // 다른 커스텀 어셈블리
    "Unity.InputSystem"  // Unity 패키지 어셈블리
]

⚠️ 주의: 참조에 추가하지 않으면 해당 어셈블리의 코드를 사용할 수 없습니다!

autoReferenced (정정된 설명)

predefined assemblies(기본 어셈블리들)가 이 어셈블리를 자동으로 참조할 수 있는지 설정합니다.

 
json
"autoReferenced": false  // predefined assemblies가 이 어셈블리를 자동 참조하지 않음
  • true: Assembly-CSharp.dll 등에서 자동으로 이 어셈블리 사용 가능
  • false: predefined assemblies에서 이 어셈블리를 직접 사용할 수 없음 (성능상 이점)

includePlatforms / excludePlatforms

어떤 플랫폼에서 컴파일할지 지정합니다.

 
json
// 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 (기반 유틸리티)

 
json
{
    "name": "Utilities",
    "references": [],
    "autoReferenced": true  // 다른 어셈블리에서 자동 참조 가능
}

2. Player.asmdef (플레이어 시스템)

 
json
{
    "name": "Player",
    "references": [
        "Utilities"  // 유틸리티 어셈블리 사용
    ],
    "autoReferenced": false
}

3. AI.asmdef (AI 시스템)

 
json
{
    "name": "AI",
    "references": [
        "Utilities",
        "Player"  // 플레이어 정보 접근 필요
    ],
    "autoReferenced": false
}

4. UI.asmdef (UI 시스템)

 
json
{
    "name": "UI",
    "references": [
        "Utilities",
        "Player"  // 플레이어 상태 표시
    ],
    "autoReferenced": false
}

5. 테스트 어셈블리 특별 설정

테스트 전용 어셈블리

Unity는 다음 조건을 만족하면 자동으로 테스트 어셈블리로 인식합니다:

  • nunit.framework.dll에 대한 참조가 있음
  • UnityEngine.TestRunner와 UnityEditor.TestRunner에 대한 어셈블리 정의 참조가 있음

Edit Mode 테스트 예제:

 
json
{
    "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 테스트 예제:

 
json
{
    "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에 필요한 어셈블리 추가

 
json
{
    "name": "MyAssembly",
    "references": [
        "MissingAssembly"  // ← 이것을 추가해야 함
    ]
}

문제 2: 순환 참조 에러

원인: A가 B를 참조하고, B가 A를 참조
해결: 공통 부분을 별도 어셈블리로 분리

 
Before: A ↔ B (순환 참조)
After:  A → Common ← B (공통 어셈블리로 해결)

문제 3: Unity 패키지를 찾을 수 없음

원인: Unity 패키지 어셈블리 참조 누락
해결: Package Manager에서 패키지명 확인 후 추가

 
json
{
    "references": [
        "Unity.InputSystem",     // New Input System
        "Unity.Addressables",    // Addressables
        "Unity.Timeline"         // Timeline
    ]
}

문제 4: Editor 폴더가 런타임에 컴파일되는 문제

원인: 어셈블리 정의가 있는 폴더 하위의 Editor 폴더는 특별 취급되지 않음
해결: Editor 폴더에 별도의 어셈블리 정의 생성

 
json
{
    "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

특정 패키지 버전에 따라 조건부 컴파일이 가능합니다:

 
json
{
    "versionDefines": [
        {
            "name": "com.unity.render-pipelines.high-definition",
            "expression": "7.1.0",
            "define": "HDRP_7_1_0_OR_NEWER"
        }
    ]
}

Define Constraints

특정 심볼이 정의되었을 때만 어셈블리를 포함:

 
json
{
    "defineConstraints": [
        "UNITY_INCLUDE_TESTS",
        "!UNITY_WEBGL"  // WebGL이 아닐 때만
    ]
}

Override References

수동으로 precompiled 어셈블리 참조 관리:

 
json
{
    "overrideReferences": true,
    "precompiledReferences": [
        "MyCustomLibrary.dll"
    ]
}

9. 디버깅과 확인 방법

스크립트가 어떤 어셈블리에 속하는지 확인

  1. Project 창에서 C# 스크립트 선택
  2. Inspector 창의 "Assembly Information" 섹션 확인
  3. 어셈블리 파일명과 Assembly Definition 정보 표시

컴파일 파이프라인 정보 확인

 
csharp
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 프로젝트를 체계적으로 관리하는 핵심 도구입니다. 올바르게 구성하면 개발 효율성과 코드 품질이 크게 향상됩니다!