cl-asdf-system

cxxxr's avatarfrom cxxxr

ASDFシステム定義のベストプラクティス。.asdファイル作成・編集時に使用

⭐1stars🔀0forks📁View on GitHub🕐Updated Dec 20, 2025

When & Why to Use This Skill

This Claude skill provides expert guidance and standardized templates for ASDF (Another System Definition Facility), the essential build system for Common Lisp. It streamlines the creation and maintenance of .asd files by implementing industry best practices for project architecture, dependency management, and automated testing integration.

Use Cases

  • Bootstrapping new Common Lisp projects with standardized directory structures and metadata to ensure Quicklisp compatibility.
  • Configuring complex system dependencies, including version-specific requirements and platform-dependent conditional loading (e.g., SBCL vs. Clozure CL).
  • Architecting large-scale Lisp applications using modular components and pathnames to prevent circular dependencies and improve code maintainability.
  • Integrating testing frameworks like Rove into the ASDF system definition to enable seamless 'test-op' execution from the REPL or CLI.
  • Optimizing build sequences and component loading orders using :serial and explicit :depends-on configurations for reliable compilation.
namecl-asdf-system
descriptionASDFシステム定義のベストプラクティス。.asdファイル作成・編集時に使用
allowed-toolsRead, Grep, Glob

ASDF System Definition

基本構造

標準的なシステム定義

(defsystem "my-project"
  :version "0.1.0"
  :author "Your Name <your@email.com>"
  :maintainer "Your Name <your@email.com>"
  :license "MIT"
  :homepage "https://github.com/you/my-project"
  :bug-tracker "https://github.com/you/my-project/issues"
  :source-control (:git "https://github.com/you/my-project.git")
  :description "Short description of the project"
  :long-description "Longer description with more details."
  :depends-on ("alexandria"
               "cl-ppcre"
               "dexador")
  :pathname "src/"
  :serial t
  :components ((:file "package")
               (:file "conditions")
               (:file "utils")
               (:file "core")
               (:file "api"))
  :in-order-to ((test-op (test-op "my-project/tests"))))

テストシステム

(defsystem "my-project/tests"
  :description "Tests for my-project"
  :depends-on ("my-project"
               "rove")
  :pathname "tests/"
  :serial t
  :components ((:file "package")
               (:file "test-utils")
               (:file "core-tests")
               (:file "api-tests"))
  :perform (test-op (o c)
             (symbol-call :rove :run c)))

ディレクトリ構成

推奨構造

my-project/
├── my-project.asd          # システム定義
├── src/
│   ├── package.lisp        # パッケージ定義
│   ├── conditions.lisp     # 条件/エラー定義
│   ├── utils.lisp          # ユーティリティ
│   ├── core.lisp           # コアロジック
│   └── api.lisp            # 公開API
├── tests/
│   ├── package.lisp        # テスト用パッケージ
│   ├── test-utils.lisp     # テストユーティリティ
│   └── core-tests.lisp     # テスト
├── docs/                   # ドキュメント
├── examples/               # 使用例
├── README.md
├── LICENSE
└── .gitignore

大規模プロジェクト

my-project/
├── my-project.asd
├── src/
│   ├── package.lisp
│   ├── core/
│   │   ├── types.lisp
│   │   ├── protocols.lisp
│   │   └── implementation.lisp
│   ├── http/
│   │   ├── client.lisp
│   │   └── server.lisp
│   └── db/
│       ├── connection.lisp
│       └── queries.lisp
└── tests/
    ├── package.lisp
    ├── core/
    └── http/

コンポーネント指定

:serial オプション

;; serial t - 順番に依存
:serial t
:components ((:file "a")   ; 最初
             (:file "b")   ; aに依存
             (:file "c"))  ; a, bに依存

;; serial nil - 明示的な依存
:serial nil
:components ((:file "a")
             (:file "b" :depends-on ("a"))
             (:file "c" :depends-on ("a" "b")))

モジュール

:components
((:module "core"
  :pathname "src/core/"
  :serial t
  :components ((:file "types")
               (:file "protocols")
               (:file "impl")))
 (:module "http"
  :pathname "src/http/"
  :depends-on ("core")
  :components ((:file "client")
               (:file "server"))))

条件付きコンポーネント

:components
((:file "package")
 (:file "core")
 ;; SBCLのみ
 #+sbcl (:file "sbcl-specific")
 ;; Unix系のみ
 #+(or linux darwin) (:file "unix-utils"))

依存関係

基本的な依存

:depends-on ("alexandria"        ; ユーティリティ
             "cl-ppcre"          ; 正規表現
             "local-time"        ; 日時処理
             (:version "dexador" "0.9.0"))  ; バージョン指定

フィーチャー依存

:depends-on ("alexandria"
             (:feature :sbcl "sb-concurrency")
             (:feature (:not :windows) "osicat"))

弱い依存 (オプショナル)

:weakly-depends-on ("swank")  ; なくても動作

テスト統合

Rove統合

(defsystem "my-project/tests"
  :depends-on ("my-project" "rove")
  :pathname "tests/"
  :components ((:file "package")
               (:file "main"))
  :perform (test-op (o c)
             (symbol-call :rove :run c)))

テスト実行

# コマンドライン
rove my-project.asd

# REPL
(asdf:test-system :my-project)

ベストプラクティス

1. バージョニング

;; セマンティックバージョニング
:version "1.2.3"

;; 開発版
:version "0.0.1-dev"

2. メタデータ

;; 必須
:license "MIT"
:description "..."

;; 推奨
:author "Name <email>"
:homepage "https://..."

3. パッケージ分離

;; Good - パッケージ定義は別ファイル
:components ((:file "package")  ; defpackageのみ
             (:file "main"))    ; 実装

;; Bad - 実装ファイル内でdefpackage

4. 循環依存の回避

;; Good - 一方向の依存
;; core -> utils (OK)
;; utils -> core (NG: 循環)

;; 解決策: 共通部分を抽出
;; core -> common
;; utils -> common

Quicklispへの登録

準備

  1. GitHubでリポジトリ公開
  2. タグでバージョン管理
  3. README.mdに説明を記載

申請

https://github.com/quicklisp/quicklisp-projects/issues

必要情報:

  • プロジェクト名
  • リポジトリURL
  • 簡単な説明