diff --git a/recipes/libclang_mojo/README.md b/recipes/libclang_mojo/README.md new file mode 100644 index 00000000..50ec0c46 --- /dev/null +++ b/recipes/libclang_mojo/README.md @@ -0,0 +1,137 @@ +# mojo_libclang + +High-level Mojo bindings for LLVM `libclang`. + +`mojo_libclang` provides a Python `clang.cindex`-style API for source-code tooling in Mojo. + +## Highlights + +- Exposes most of `libclang` API for `C`, `C++`, and some `obj-C` +- Parse C and C++ source files with libclang. +- Inspect cursor spelling, kind, location, extent, parents, and type. +- Read diagnostics with formatted messages. +- Query canonical types, pointee types, result types, fields, and declarations. + +## Example + +```c +//math_api.h +typedef struct Point { int x; int y; } Point; +int add(int a, int b); +``` + +```mojo +# main.mojo +from clang.cindex import CursorKind, Index + + +def main() raises: + var index = Index.create() + var tu = index.parse("math_api.h") + + for diagnostic in tu.diagnostics(): + print(diagnostic.format()) + + for cursor in tu.cursor(): + if cursor.kind() == CursorKind.FUNCTION_DECL: + print("function: ", cursor.spelling(), sep="") + elif cursor.kind() == CursorKind.TYPEDEF_DECL: + print("typedef: ", cursor.spelling(), sep="") +``` + +```bash +pixi run mojo run main.mojo +``` + +## Installation + +Install Pixi: + +```bash +curl -fsSL https://pixi.sh/install.sh | sh +``` + +Create a new Mojo project and add the package channels: + +```bash +pixi init clang-demo +cd clang-demo +pixi workspace channel add conda-forge https://conda.modular.com/max https://repo.prefix.dev/modular-community +``` + +```bash +pixi add mojo libclang_mojo +``` + +## Developing From Source + +Clone this repository and install the development environment: + +```bash +git clone https://github.com/MoSafi2/mojo_libclang.git +cd mojo_libclang +pixi install -e dev +``` + +Run the wrapper test suite through the local shim: + +```bash +pixi run -e dev run-test test/test_translation_unit.mojo +``` + +For build-only checks: + +```bash +pixi run -e dev build-test test/_ffi_layout_tests.mojo +``` + +### Regenerate Low-Level Bindings + +Regenerate only when updating LLVM/libclang +coverage or changing ABI handling: + +```bash +pixi run -e dev generate +``` + +Generation updates: + +- `clang/_ffi.mojo` +- `test/_ffi_layout_tests.mojo` +- `shim/libclang_mojo_shim.h` +- `shim/libclang_mojo_shim.c` +- `shim/libclang_mojo_shim.so` + +Do not edit generated low-level files by hand, either update the generator or +add a deterministic patch. + +## Packaging + +This repository builds the conda package `libclang_mojo`: + +```mojo +from clang.cindex import Index +``` + +The staged Modular Community recipe lives in +`packaging/modular-community/libclang_mojo/`. To mirror the recipe install +layout locally: + +```bash +pixi run -e dev build-package +``` + +To build the staged recipe for a prefix.dev channel: + +```bash +pixi install -e package +PREFIX_CHANNEL=your-channel pixi run -e package render-recipe +PREFIX_CHANNEL=your-channel pixi run -e package build-recipe +``` + +Upload is explicit and only uploads existing `.conda` artifacts from +`dist/conda/`: + +```bash +PREFIX_CHANNEL=your-channel PREFIX_API_KEY=... pixi run -e package upload-recipe +``` diff --git a/recipes/libclang_mojo/image.jpg b/recipes/libclang_mojo/image.jpg new file mode 100644 index 00000000..f3a2a3e1 Binary files /dev/null and b/recipes/libclang_mojo/image.jpg differ diff --git a/recipes/libclang_mojo/recipe.yaml b/recipes/libclang_mojo/recipe.yaml new file mode 100644 index 00000000..0ff53d2c --- /dev/null +++ b/recipes/libclang_mojo/recipe.yaml @@ -0,0 +1,76 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/prefix-dev/recipe-format/main/schema.json +context: + version: "0.1.0" + mojo_version: "=1.0.0b2" + llvm_version: "18.*" + rev: "a14c2ee9a576463dbd5739e80e66407e94263c5d" + +package: + name: "libclang_mojo" + version: ${{ version }} + +source: + - git: https://github.com/MoSafi2/mojo_libclang.git + rev: ${{ rev }} + +build: + number: 0 + script: + interpreter: bash + content: + - | + set -euo pipefail + mkdir -p "${PREFIX}/lib" "${PREFIX}/lib/mojo" + if [[ "$(uname -s)" == "Darwin" ]]; then + "${CC}" -dynamiclib \ + -I"${PREFIX}/include" -Ishim \ + -o "${PREFIX}/lib/libclang_mojo_shim.dylib" \ + shim/libclang_mojo_shim.c \ + -L"${PREFIX}/lib" -lclang \ + -Wl,-rpath,"${PREFIX}/lib" + else + "${CC}" -shared -fPIC \ + -I"${PREFIX}/include" -Ishim \ + -o "${PREFIX}/lib/libclang_mojo_shim.so" \ + shim/libclang_mojo_shim.c \ + -L"${PREFIX}/lib" -lclang \ + -Wl,-rpath,"${PREFIX}/lib" + fi + mojo precompile clang -o "${PREFIX}/lib/mojo/clang.mojoc" + +requirements: + build: + - ${{ compiler('c') }} + - mojo-compiler ${{ mojo_version }} + host: + - clangdev ${{ llvm_version }} + - libclang ${{ llvm_version }} + - mojo-compiler ${{ mojo_version }} + run: + - libclang ${{ llvm_version }} + - ${{ pin_compatible('mojo-compiler') }} + +tests: + - files: + recipe: + - test_cindex_smoke.mojo + script: + interpreter: bash + content: + - | + set -euo pipefail + export LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH:-}" + export DYLD_LIBRARY_PATH="${PREFIX}/lib:${DYLD_LIBRARY_PATH:-}" + mojo run -I "${PREFIX}/lib/mojo" test_cindex_smoke.mojo + +about: + homepage: https://github.com/MoSafi2/mojo_libclang + license: MIT + license_file: LICENSE + summary: High-level Mojo bindings for LLVM libclang + repository: https://github.com/MoSafi2/mojo_libclang + +extra: + maintainers: + - MoSafi2 + project_name: mojo_libclang diff --git a/recipes/libclang_mojo/test_cindex_smoke.mojo b/recipes/libclang_mojo/test_cindex_smoke.mojo new file mode 100644 index 00000000..c63d1094 --- /dev/null +++ b/recipes/libclang_mojo/test_cindex_smoke.mojo @@ -0,0 +1,7 @@ +from clang.cindex import Index + + +def main() raises: + var index = Index.create() + _ = index + print("libclang_mojo package smoke test passed")