SQL interface for Clang AST databases. Query C/C++ source code using SQL.
Part of the xsql project family.
- Parse C/C++ source files with libclang
- Query AST entities via SQL: functions, classes, methods, variables, enums
- Multi-translation-unit support with schema prefixes
- AST caching for fast repeated queries
- HTTP and MCP server modes for remote analysis
- Cross-platform: Windows, macOS, Linux
- Consistent xsql API patterns
# Parse a file and list functions
clangsql main.cpp -e "SELECT name FROM functions"
# With compiler flags
clangsql main.cpp -- -std=c++17 -I./include
# Interactive mode
clangsql main.cpp -i
# Multi-file with schema prefixes (each file gets prefixed tables)
clangsql lib/utils.cpp:utils src/main.cpp:main -i
# Glob patterns for multiple files
clangsql "src/**/*.cpp" -- -std=c++17 -I./include
# CMake project (uses compile_commands.json)
clangsql --compile-commands build/compile_commands.json -i
clangsql --build-dir build -i # Auto-find compile_commands.jsonclangsql <files...> [options] [clang-args...]
| Mode | Command | Description |
|---|---|---|
| Query | clangsql file.cpp -e "SQL" |
Execute query, exit |
| REPL | clangsql file.cpp -i |
Interactive mode |
| HTTP | clangsql file.cpp --http [port] |
Host SQL over HTTP |
| MCP | clangsql file.cpp --mcp [port] |
Host SQL over MCP (SSE) |
Local Options:
-e <sql> Execute SQL query and exit
-i Interactive mode (REPL)
--http [port] Start HTTP REST server (default: 8080)
--mcp [port] Start MCP server over SSE (default: random 9000-9999)
--bind <addr> Bind address for server (default: 127.0.0.1)
--token <token> Auth token for HTTP server mode
-h, --help Show help
--version Show version
Project Options:
--compile-commands <path> Load compile_commands.json
--build-dir <path> Load from build directory
--project <dir> Parse entire directory (unified schema)
--pattern <glob> File patterns for --project
--exclude <dir> Directories to exclude
'src/**/*.cpp' Glob pattern for source files
Cache Options:
--cache Enable AST caching (faster re-parses)
--no-cache Disable AST caching (default)
--cache-dir <path> Set cache directory
--clear-cache Clear all cached AST files
--cache-verbose Show cache hit/miss messages
- CMake 3.20+
- C++17 compiler
- libclang (via vcpkg or system)
vcpkg install llvm[clang] nlohmann-json
cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
cmake --build buildcmake -S <parent-project-root> -B build
cmake --build build --target clangsqlgit submodule update --init external/libxsql
cmake -B build
cmake --build buildEnable caching to avoid re-parsing unchanged files. Recommended for project mode where you'll run multiple queries against the same codebase.
# Enable caching for single file
clangsql main.cpp --cache -e "SELECT name FROM functions"
# Enable caching for project mode (big speedup on re-runs!)
clangsql --project ./src --cache -i
# Show cache hit/miss messages
clangsql --project ./src --cache --cache-verbose -i
# Custom cache directory
clangsql --project ./src --cache-dir /path/to/cache -i
# Clear all cached files
clangsql --clear-cacheCache location: %LOCALAPPDATA%\clangsql\cache (Windows) or ~/.cache/clangsql (Linux/macOS)
What's validated: Cache is invalidated when source files, any included headers, compiler args, or Clang version change. Each file's mtime is checked, so only modified files are re-parsed.
Any CMake project can generate a compile_commands.json — a database of exact compiler flags for every source file. clangsql uses this to parse your code with the correct includes, defines, and standards, just like your compiler sees it.
Add -DCMAKE_EXPORT_COMPILE_COMMANDS=ON when configuring your project. This requires a single-config generator like Ninja or Unix Makefiles (Visual Studio generators don't produce it):
# Using clangsql's own source as the example project:
cd clangsql
cmake -B build -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ONThis creates build/compile_commands.json — a JSON array with one entry per source file containing the exact compiler command, flags, and include paths.
# Point clangsql at the compile_commands.json
clangsql --compile-commands build/compile_commands.json -i
# Or just point at the build directory (auto-finds compile_commands.json)
clangsql --build-dir build -iEach source file from the database is attached as a schema-prefixed set of tables (e.g., main_functions, tables_functions). You can query individual files or join across them.
-- List all parsed source files
SELECT name FROM pragma_database_list WHERE name != 'main';
-- Functions defined in a specific file
SELECT name, return_type, line FROM tables_functions WHERE is_system = 0;
-- All user-defined classes across the project
SELECT name, kind FROM main_classes WHERE is_system = 0
UNION ALL
SELECT name, kind FROM tables_classes WHERE is_system = 0;For a single merged view without schema prefixes, use --project with --build-dir to combine directory scanning with compile_commands.json flags:
# Unified schema — all files merged into one set of tables
clangsql --project src --build-dir build --cache -i-- Now tables have no prefix — one unified view
SELECT name, return_type FROM functions WHERE is_system = 0;
-- Functions with their source files
SELECT f.name, fi.path
FROM functions f JOIN files fi ON f.file_id = fi.id
WHERE f.is_system = 0
ORDER BY fi.path, f.line;- Use
--cachefor repeated queries — first parse writes the cache, subsequent runs skip unchanged files. - Use
--excludeto skip directories likebuild,third_party, orexternalin project mode. - Filter with
is_system = 0— without it, you'll get thousands of symbols from system headers. - Ninja is recommended over Makefiles for faster builds and better compile_commands.json support on all platforms.
clangsql is a plain SQL CLI — it does not embed or run its own AI agent. To let an external agent or LLM (Claude, Copilot, or any assistant) drive clangsql, point it at the tool two ways:
- As a system prompt: feed
prompts/clangsql_agent.mdto your model as its system/instruction prompt. It documents the full SQL schema, every table and column, and worked query patterns, so the model can translate natural-language questions into clangsql SQL and run them via-e/--http/--mcp. - Over MCP: start
clangsql file.cpp --mcpand connect any MCP client (see the MCP Server section). The client's own model does the reasoning; clangsql exposes theclangsql_querytool that executes SQL against the parsed AST.
Host a parsed AST over HTTP for remote querying:
# Start server (default port 8080)
clangsql main.cpp --http
# Query from another terminal
curl -X POST http://localhost:8080/query -d "SELECT name FROM functions"Start an HTTP server for REST-based querying:
# Start HTTP server at launch
clangsql main.cpp --http 8080| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Welcome message |
/help |
GET | API documentation |
/status |
GET | Health check |
/query |
POST | Execute SQL (body = raw SQL) |
/shutdown |
POST | Graceful shutdown |
All /query responses use the canonical script envelope — single statement = array of one entry:
{
"success": true,
"statement_count": <N>,
"results": [
{ "statement_index": 0, "success": true, "columns": [...], "rows": [...],
"row_count": <N>, "elapsed_ms": <ms>, "error": null }
],
"row_count_total": <N>,
"elapsed_ms_total": <ms>,
"first_error_index": null
}Bodies can be multi-statement (semicolon-separated); each results[i] has its own columns/rows/row_count/error. Fail-fast is the default; pass ?continue_on_error=1 to run every statement regardless of earlier failures.
Start an MCP (Model Context Protocol) server for integration with Claude Desktop and other MCP clients:
# Start MCP server (random port 9000-9999, or pass an explicit port)
clangsql main.cpp --mcp
clangsql main.cpp --mcp 9123| Tool | Description |
|---|---|
clangsql_query |
Execute a SQL query directly against the parsed AST |
Add to your Claude Desktop config (the port is printed when the server starts):
{
"mcpServers": {
"clangsql": {
"url": "http://127.0.0.1:<port>/sse"
}
}
}-- Who calls what (use USR for cross-table joins)
SELECT f.name as caller, c.callee_name as calls
FROM calls c
JOIN functions f ON c.caller_usr = f.usr
WHERE c.is_system = 0;caller | calls
-------+-------------
main | Circle
main | process_data
main | add
-- Find inheritance tree from base class
WITH RECURSIVE hierarchy AS (
SELECT usr, name, 0 as depth
FROM classes WHERE name = 'Shape'
UNION ALL
SELECT c.usr, c.name, h.depth + 1
FROM hierarchy h
JOIN inheritance i ON i.base_usr = h.usr
JOIN classes c ON c.usr = i.derived_usr
)
SELECT name, depth FROM hierarchy ORDER BY depth;name | depth
-------+------
Shape | 0
Circle | 1
-- Find all virtual and pure virtual methods
SELECT qualified_name, access,
CASE WHEN is_pure_virtual THEN 'pure'
WHEN is_virtual THEN 'virtual'
END as virt
FROM methods
WHERE is_virtual = 1 AND is_system = 0;qualified_name | access | virt
---------------+--------+--------
Shape::~Shape | public | virtual
Shape::area | public | pure
Shape::draw | public | virtual
Circle::area | public | virtual
Circle::draw | public | virtual
-- Largest functions by line count
SELECT name, end_line - line + 1 as lines
FROM functions
WHERE is_definition = 1 AND is_system = 0
ORDER BY lines DESC;name | lines
-------------+------
main | 9
process_data | 6
add | 3
clangsql supports parsing entire projects with multiple translation units. Each file gets a schema prefix, making tables like utils_functions, main_classes, etc.
Cross-file queries work via USR (Unified Symbol Resolution) - a unique identifier consistent across translation units.
# Schema prefix syntax: file.cpp:schema_name
clangsql lib/utils.cpp:utils src/main.cpp:main -i
# Glob patterns (recursive)
clangsql "src/**/*.cpp" -- -std=c++17
# CMake projects with compile_commands.json
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
clangsql --compile-commands build/compile_commands.json -i-- Find utils functions that are called from main
SELECT DISTINCT u.name as function_called
FROM utils_functions u
JOIN main_calls c ON c.callee_usr = u.usr
WHERE u.is_system = 0;function_called
---------------
log_info
compute_area
-- Aggregate function counts across all schemas
SELECT COUNT(*) as total_functions FROM (
SELECT name FROM utils_functions WHERE is_system = 0
UNION ALL
SELECT name FROM main_functions WHERE is_system = 0
);-- Cross-file inheritance (class in main inherits from utils)
SELECT m.derived_name, u.name as base_class
FROM main_inheritance m
JOIN utils_classes u ON m.base_usr = u.usr;-- Field offsets in bits
SELECT name, type, access, offset_bits
FROM fields WHERE is_system = 0;name | type | access | offset_bits
--------+--------+-----------+------------
x | double | public | 0
y | double | public | 64
name_ | string | protected | 64
radius_ | double | private | 320
files- Source files (path, is_main_file, is_header, is_system)functions- Functions with USR, name, return_type, line positionsparameters- Function parameters (name, type, index_, has_default)classes- Classes, structs, unions (kind, is_abstract)fields- Class data members (type, access, offset_bits)methods- Class methods (access, is_virtual, is_pure_virtual, is_const)variables- Variables (scope_kind: global/local, storage_class)enums- Enums (underlying_type, is_scoped for enum class)enum_values- Enum constants (name, value)
calls- Call graph (caller_usr, callee_usr, callee_name, is_virtual)inheritance- Class hierarchy (derived_usr, base_usr, access, is_virtual)
All tables have is_system column (1=system header, 0=user code). Always filter with WHERE is_system = 0 for user code only.
#include <clangsql/clangsql.hpp>
// Parse a file
clangsql::Index index;
clangsql::TranslationUnit tu(index.get(), "main.cpp", {"-std=c++17"});
// Query with SQL
clangsql::Session session;
session.attach("main.cpp", "main");
auto result = session.database().exec("SELECT name FROM main.functions");find_package(clangsql CONFIG REQUIRED)
target_link_libraries(myapp PRIVATE clangsql::clangsql)In short: you may read, build, evaluate, benchmark, package, and use unmodified clangsql, including commercially, if you preserve notices and follow the license terms. You may fork or patch it to prepare bug fixes, optimizations, features, tests, or documentation improvements for contribution back within the license's contribution-purpose rules.
You may not maintain a divergent private fork, port, rebrand, clone, API-compatible replacement, competing implementation, or use clangsql as AI input to recreate or improve a derivative implementation without prior written permission from Elias Bachaalany. Independent implementations that are not copied from, materially derived from, or substantially informed by clangsql in the license's defined sense are not prohibited.
Permission requests: open a GitHub issue at 0xeb/clangsql/issues.
If clangsql materially informs a distributed project, preserve the human origin: credit clangsql and Elias Bachaalany visibly in your README/docs and in About/credits UI when applicable. The license includes an examples/FAQ section for common allowed and permission-required uses. Third-party dependencies fetched at build time (libxsql, libclang/LLVM, and their transitive dependencies) remain under their own licenses.
See the full Human-Origin Source License v1.0.
clangsql is part of a family of tools that expose different binary-analysis and debug-information platforms through the same SQL surface, all built on the shared libxsql virtual-table framework. A query you learn against one tool largely carries over to the others.
Reverse-engineering platforms
- idasql — IDA Pro databases as SQL.
- bnsql — Binary Ninja databases as SQL.
- ghidrasql — Ghidra databases as SQL.
Debug info & compiler data
Core
- libxsql — the C++ SQLite virtual-table framework every tool above is built on.