Compare commits
23 Commits
v0.1.0-alp
...
v0.1.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc523b0681 | ||
|
|
b8da7e79db | ||
|
|
1da34574c9 | ||
|
|
cec13ec29b | ||
|
|
2214d53ea5 | ||
|
|
8f74adf2b9 | ||
|
|
2c11be9365 | ||
|
|
caf9a172d6 | ||
|
|
8aff090a08 | ||
|
|
f16867902c | ||
|
|
4d07bad2f2 | ||
|
|
4a2a6aa65a | ||
|
|
3c53d3bc72 | ||
|
|
9e1039f861 | ||
|
|
8a2ef62596 | ||
|
|
336ca639f0 | ||
|
|
9c43285d0d | ||
|
|
39ec9bf7c5 | ||
|
|
397eb71dad | ||
|
|
3b1e379408 | ||
|
|
8b998e658c | ||
|
|
9806e45fa3 | ||
|
|
7d71c0f689 |
@@ -73,7 +73,7 @@ SpaceBeforeParensOptions:
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: true
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
@@ -93,11 +93,50 @@ SpacesInParensOptions:
|
||||
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
WrapNamespaceBodyWithEmptyLines: Always
|
||||
# Order
|
||||
QualifierAlignment: Custom
|
||||
QualifierOrder: ["constexpr", "const", "inline", "static", "type"]
|
||||
SortIncludes: Never
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: Never
|
||||
IncludeBlocks: Merge
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^["<](spdlog|toml\+\+|coraing|cpptrace|flatbuffers)/'
|
||||
Priority: 30
|
||||
SortPriority: 31
|
||||
|
||||
- Regex: '^["<](llvm)/'
|
||||
Priority: 30
|
||||
SortPriority: 32
|
||||
|
||||
- Regex: '^["<](clang)/'
|
||||
Priority: 30
|
||||
SortPriority: 33
|
||||
|
||||
- Regex: '^["<](clang-tidy)/'
|
||||
Priority: 30
|
||||
SortPriority: 34
|
||||
|
||||
- Regex: '^["<](Test)/'
|
||||
Priority: 20
|
||||
SortPriority: 22
|
||||
|
||||
- Regex: "^<.*"
|
||||
Priority: 10
|
||||
SortPriority: 10
|
||||
|
||||
- Regex: '^".*/.*"'
|
||||
Priority: 20
|
||||
SortPriority: 23
|
||||
|
||||
- Regex: ".*"
|
||||
Priority: 20
|
||||
SortPriority: 21
|
||||
|
||||
ForEachMacros: ["REFLECTABLE_RECORD"]
|
||||
NamespaceMacros: [TEST_SUITE]
|
||||
|
||||
KeepEmptyLines:
|
||||
AtEndOfFile: false
|
||||
AtStartOfBlock: false
|
||||
AtStartOfFile: false
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
build/
|
||||
out/
|
||||
.cache
|
||||
|
||||
.clice/
|
||||
.llvm*/
|
||||
.xmake/
|
||||
.vscode/
|
||||
.vs/
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# SCM syntax highlighting & preventing 3-way merges
|
||||
pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff
|
||||
195
.github/workflows/build-llvm.yml
vendored
Normal file
195
.github/workflows/build-llvm.yml
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
name: build llvm
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
# if you want to run this workflow, change the branch name to main,
|
||||
# if you want to turn off it, change it to non existent branch.
|
||||
branches: [main-turn-off]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2025
|
||||
llvm_mode: Debug
|
||||
lto: OFF
|
||||
- os: windows-2025
|
||||
llvm_mode: RelWithDebInfo
|
||||
lto: OFF
|
||||
- os: windows-2025
|
||||
llvm_mode: RelWithDebInfo
|
||||
lto: ON
|
||||
|
||||
- os: ubuntu-24.04
|
||||
llvm_mode: Debug
|
||||
lto: OFF
|
||||
- os: ubuntu-24.04
|
||||
llvm_mode: RelWithDebInfo
|
||||
lto: OFF
|
||||
- os: ubuntu-24.04
|
||||
llvm_mode: RelWithDebInfo
|
||||
lto: ON
|
||||
|
||||
- os: macos-15
|
||||
llvm_mode: Debug
|
||||
lto: OFF
|
||||
- os: macos-15
|
||||
llvm_mode: RelWithDebInfo
|
||||
lto: OFF
|
||||
- os: macos-15
|
||||
llvm_mode: RelWithDebInfo
|
||||
lto: ON
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Free Disk Space
|
||||
if: runner.os == 'Linux'
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
|
||||
- name: Increase Swap Space
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
echo "===== Initial Status ====="
|
||||
sudo swapon --show
|
||||
free -h
|
||||
|
||||
echo "===== Creating Swap File ====="
|
||||
sudo swapoff -a
|
||||
sudo fallocate -l 16G /mnt/swapfile
|
||||
sudo chmod 600 /mnt/swapfile
|
||||
sudo mkswap /mnt/swapfile
|
||||
sudo swapon /mnt/swapfile
|
||||
|
||||
echo "===== Final Status ====="
|
||||
sudo swapon --show
|
||||
free -h
|
||||
df -h
|
||||
|
||||
- name: Setup Pixi
|
||||
uses: prefix-dev/setup-pixi@v0.9.3
|
||||
with:
|
||||
pixi-version: v0.59.0
|
||||
environments: package
|
||||
activate-environment: true
|
||||
cache: true
|
||||
locked: true
|
||||
|
||||
- name: Clone llvm-project (21.1.4)
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --branch llvmorg-21.1.4 --depth 1 https://github.com/llvm/llvm-project.git .llvm
|
||||
|
||||
- name: Build LLVM (install-distribution)
|
||||
shell: bash
|
||||
run: |
|
||||
pixi run build-llvm --llvm-src=.llvm --mode="${{ matrix.llvm_mode }}" --lto="${{ matrix.lto }}" --build-dir=build
|
||||
|
||||
- name: Build clice using installed LLVM
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -B build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.llvm_mode }} \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain.cmake \
|
||||
-DCLICE_ENABLE_TEST=ON \
|
||||
-DCLICE_CI_ENVIRONMENT=ON \
|
||||
-DCLICE_ENABLE_LTO=${{ matrix.lto }} \
|
||||
-DLLVM_INSTALL_PATH=".llvm/build-install"
|
||||
cmake --build build
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
EXE_EXT=""
|
||||
if [[ "${{ runner.os }}" == "Windows" ]]; then
|
||||
EXE_EXT=".exe"
|
||||
fi
|
||||
./build/bin/unit_tests${EXE_EXT} --test-dir="./tests/data"
|
||||
uv run --project tests pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice${EXE_EXT}
|
||||
|
||||
- name: Prune LLVM static libraries (Debug/RelWithDebInfo no LTO)
|
||||
if: matrix.llvm_mode == 'Debug' || (matrix.llvm_mode == 'RelWithDebInfo' && matrix.lto == 'OFF')
|
||||
shell: bash
|
||||
run: |
|
||||
MANIFEST="pruned-libs-${{ matrix.os }}.json"
|
||||
echo "LLVM_PRUNED_MANIFEST=${MANIFEST}" >> "${GITHUB_ENV}"
|
||||
python3 scripts/prune-llvm-bin.py \
|
||||
--action discover \
|
||||
--install-dir ".llvm/build-install/lib" \
|
||||
--build-dir "build" \
|
||||
--max-attempts 60 \
|
||||
--sleep-seconds 60 \
|
||||
--manifest "${MANIFEST}"
|
||||
|
||||
- name: Upload pruned-libs manifest
|
||||
if: matrix.llvm_mode == 'RelWithDebInfo' && matrix.lto == 'OFF'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: llvm-pruned-libs-${{ matrix.os }}
|
||||
path: ${{ env.LLVM_PRUNED_MANIFEST }}
|
||||
if-no-files-found: error
|
||||
compression-level: 0
|
||||
|
||||
- name: Apply pruned-libs manifest (RelWithDebInfo + LTO)
|
||||
if: matrix.llvm_mode == 'RelWithDebInfo' && matrix.lto == 'ON'
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
MANIFEST="pruned-libs-${{ matrix.os }}.json"
|
||||
python3 scripts/prune-llvm-bin.py \
|
||||
--action apply \
|
||||
--manifest "${MANIFEST}" \
|
||||
--install-dir ".llvm/build-install/lib" \
|
||||
--build-dir "build" \
|
||||
--gh-run-id "${{ github.run_id }}" \
|
||||
--gh-artifact "llvm-pruned-libs-${{ matrix.os }}" \
|
||||
--gh-download-dir "artifacts" \
|
||||
--max-attempts 60 \
|
||||
--sleep-seconds 60
|
||||
|
||||
- name: Package LLVM install directory
|
||||
shell: bash
|
||||
run: |
|
||||
MODE_TAG="releasedbg"
|
||||
if [[ "${{ matrix.llvm_mode }}" == "Debug" ]]; then
|
||||
MODE_TAG="debug"
|
||||
fi
|
||||
|
||||
ARCH="x64"
|
||||
PLATFORM="linux"
|
||||
TOOLCHAIN="gnu"
|
||||
if [[ "${{ matrix.os }}" == windows-* ]]; then
|
||||
PLATFORM="windows"
|
||||
TOOLCHAIN="msvc"
|
||||
elif [[ "${{ matrix.os }}" == macos-* ]]; then
|
||||
ARCH="arm64"
|
||||
PLATFORM="macos"
|
||||
TOOLCHAIN="clang"
|
||||
fi
|
||||
|
||||
SUFFIX=""
|
||||
if [[ "${{ matrix.lto }}" == "ON" ]]; then
|
||||
SUFFIX="-lto"
|
||||
fi
|
||||
if [[ "${{ matrix.llvm_mode }}" == "Debug" ]]; then
|
||||
SUFFIX="${SUFFIX}-asan"
|
||||
fi
|
||||
|
||||
ARCHIVE="${ARCH}-${PLATFORM}-${TOOLCHAIN}-${MODE_TAG}${SUFFIX}.tar.xz"
|
||||
|
||||
set -eo pipefail
|
||||
tar -C .llvm -cf - build-install | xz -T0 -9 -c > "${ARCHIVE}"
|
||||
echo "LLVM_INSTALL_ARCHIVE=${ARCHIVE}" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Upload LLVM install artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.LLVM_INSTALL_ARCHIVE }}
|
||||
path: ${{ env.LLVM_INSTALL_ARCHIVE }}
|
||||
if-no-files-found: error
|
||||
15
.github/workflows/check-format.yml
vendored
15
.github/workflows/check-format.yml
vendored
@@ -7,7 +7,6 @@ on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -16,15 +15,19 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v6
|
||||
- name: Setup Pixi
|
||||
uses: prefix-dev/setup-pixi@v0.9.3
|
||||
with:
|
||||
pixi-version: v0.61.0
|
||||
environments: develop
|
||||
activate-environment: true
|
||||
cache: true
|
||||
locked: true
|
||||
|
||||
- name: Run check
|
||||
id: precommit
|
||||
run: |
|
||||
uv venv
|
||||
uv pip install pre-commit
|
||||
uv run pre-commit run --all-files
|
||||
pixi run ci-check
|
||||
continue-on-error: true
|
||||
|
||||
- name: Show diff on failure
|
||||
|
||||
86
.github/workflows/cmake.yml
vendored
86
.github/workflows/cmake.yml
vendored
@@ -17,85 +17,41 @@ on:
|
||||
- "include/**"
|
||||
- "src/**"
|
||||
- "tests/**"
|
||||
- "config/**"
|
||||
- "CMakeLists.txt"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04, windows-2025, macos-15]
|
||||
include:
|
||||
- os: windows-2025
|
||||
build_type: RelWithDebInfo
|
||||
- os: ubuntu-24.04
|
||||
build_type: Debug
|
||||
- os: macos-15
|
||||
build_type: Debug
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Setup ninja
|
||||
if: matrix.os == 'windows-2025'
|
||||
uses: MinoruSekine/setup-scoop@v4.0.1
|
||||
with:
|
||||
buckets: main
|
||||
apps: ninja
|
||||
|
||||
- name: Setup llvm & libstdc++ & cmake & ninja
|
||||
if: matrix.os == 'ubuntu-24.04'
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y gcc-14 g++-14 libstdc++-14-dev
|
||||
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100
|
||||
|
||||
sudo update-alternatives --set gcc /usr/bin/gcc-14
|
||||
sudo update-alternatives --set g++ /usr/bin/g++-14
|
||||
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 20 all
|
||||
|
||||
sudo apt install -y cmake ninja-build
|
||||
|
||||
- name: Setup llvm@20 and lld
|
||||
if: matrix.os == 'macos-15'
|
||||
run: |
|
||||
brew install llvm@20 lld@20
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup msvc sysroot for cmake
|
||||
if: matrix.os == 'windows-2025'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Setup Pixi
|
||||
uses: prefix-dev/setup-pixi@v0.9.3
|
||||
with:
|
||||
pixi-version: v0.61.0
|
||||
environments: develop
|
||||
activate-environment: true
|
||||
cache: true
|
||||
locked: true
|
||||
|
||||
- name: Build clice (release, windows)
|
||||
if: matrix.os == 'windows-2025'
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCLICE_ENABLE_TEST=ON -DCLICE_CI_ENVIRONMENT=ON
|
||||
cmake --build build
|
||||
pixi run ci-cmake-build ${{ matrix.build_type }}
|
||||
|
||||
- name: Build clice (debug, linux)
|
||||
if: matrix.os == 'ubuntu-24.04'
|
||||
- name: Test
|
||||
run: |
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCLICE_ENABLE_TEST=ON -DCLICE_CI_ENVIRONMENT=ON
|
||||
cmake --build build
|
||||
|
||||
- name: Build clice (debug, macos)
|
||||
if: matrix.os == 'macos-15'
|
||||
run: |
|
||||
export PATH="/opt/homebrew/opt/llvm@20/bin:/opt/homebrew/opt/lld@20/bin:$PATH"
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCLICE_ENABLE_TEST=ON -DCLICE_CI_ENVIRONMENT=ON
|
||||
cmake --build build
|
||||
|
||||
- name: Install uv for integration tests
|
||||
uses: astral-sh/setup-uv@v6
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.os == 'windows-2025'
|
||||
run: |
|
||||
./build/bin/unit_tests.exe --test-dir="./tests/data"
|
||||
uv run pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice.exe
|
||||
shell: bash
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.os == 'ubuntu-24.04' || matrix.os == 'macos-15'
|
||||
run: |
|
||||
./build/bin/unit_tests --test-dir="./tests/data"
|
||||
uv run pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice
|
||||
pixi run ci-cmake-test
|
||||
|
||||
54
.github/workflows/docker.yml
vendored
54
.github/workflows/docker.yml
vendored
@@ -1,54 +0,0 @@
|
||||
name: docker
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
PLATFORMS: linux/amd64,darwin/arm64
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Docker buildx
|
||||
uses: docker/setup-buildx-action@v2.5.0
|
||||
with:
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v2.1.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4.3.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
# https://stackoverflow.com/questions/71157844/how-can-i-copy-git-directory-to-the-container-with-github-actions
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
with:
|
||||
push: true
|
||||
context: .
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
97
.github/workflows/package.yml
vendored
Normal file
97
.github/workflows/package.yml
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
name: package
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- ".github/workflows/package.yml"
|
||||
|
||||
jobs:
|
||||
package:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2025
|
||||
artifact_name: clice.zip
|
||||
asset_name: clice-x64-windows-msvc.zip
|
||||
symbol_artifact_name: clice-symbol.zip
|
||||
symbol_asset_name: clice-x64-windows-msvc-symbol.zip
|
||||
toolchain: clang-cl
|
||||
|
||||
- os: ubuntu-24.04
|
||||
artifact_name: clice.tar.gz
|
||||
asset_name: clice-x86_64-linux-gnu.tar.gz
|
||||
symbol_artifact_name: clice-symbol.tar.gz
|
||||
symbol_asset_name: clice-x86_64-linux-gnu-symbol.tar.gz
|
||||
toolchain: clang-20
|
||||
|
||||
- os: macos-15
|
||||
artifact_name: clice.tar.gz
|
||||
asset_name: clice-arm64-macos-darwin.tar.gz
|
||||
symbol_artifact_name: clice-symbol.tar.gz
|
||||
symbol_asset_name: clice-arm64-macos-darwin-symbol.tar.gz
|
||||
toolchain: clang
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup xmake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: 3.0.5
|
||||
actions-cache-folder: ".xmake-cache"
|
||||
actions-cache-key: ${{ matrix.os }}
|
||||
package-cache: true
|
||||
package-cache-key: ${{ matrix.os }}-pkg-release-v1
|
||||
build-cache: true
|
||||
build-cache-key: ${{ matrix.os }}-build-release-v1
|
||||
|
||||
- name: Setup Pixi
|
||||
uses: prefix-dev/setup-pixi@v0.9.3
|
||||
with:
|
||||
pixi-version: v0.61.0
|
||||
activate-environment: true
|
||||
cache: true
|
||||
locked: true
|
||||
|
||||
- name: Remove ci llvm toolchain on Windows
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
# @see https://github.com/xmake-io/xmake/issues/7158
|
||||
xmake lua os.rmdir "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/Llvm"
|
||||
xmake lua os.rmdir "C:/Program Files/LLVM"
|
||||
|
||||
- name: Package
|
||||
run: |
|
||||
pixi run package
|
||||
|
||||
- name: Upload Main Package to Release
|
||||
if: github.event_name == 'push'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: build/xpack/clice/${{ matrix.artifact_name }}
|
||||
asset_name: ${{ matrix.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
- name: Upload Symbol Package to Release
|
||||
if: github.event_name == 'push'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: build/xpack/clice/${{ matrix.symbol_artifact_name }}
|
||||
asset_name: ${{ matrix.symbol_asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
96
.github/workflows/release.yml
vendored
96
.github/workflows/release.yml
vendored
@@ -1,96 +0,0 @@
|
||||
name: release
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- ".github/workflows/release.yml"
|
||||
|
||||
jobs:
|
||||
package:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2025
|
||||
artifact_name: clice.7z
|
||||
asset_name: clice-x64-windows-msvc.7z
|
||||
toolchain: clang-cl
|
||||
|
||||
- os: ubuntu-24.04
|
||||
artifact_name: clice.tar.xz
|
||||
asset_name: clice-x86_64-linux-gnu.tar.xz
|
||||
toolchain: clang-20
|
||||
|
||||
- os: macos-15
|
||||
artifact_name: clice.tar.xz
|
||||
asset_name: clice-arm64-macos-darwin.tar.xz
|
||||
toolchain: clang
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Setup llvm & libstdc++ & cmake & ninja
|
||||
if: matrix.os == 'ubuntu-24.04'
|
||||
run: |
|
||||
sudo apt remove llvm-16-linker-tools llvm-16 llvm-17-linker-tools llvm-17 llvm-18-linker-tools llvm-18
|
||||
sudo apt update
|
||||
sudo apt install -y gcc-14 g++-14 libstdc++-14-dev cmake ninja-build
|
||||
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100
|
||||
sudo update-alternatives --set gcc /usr/bin/gcc-14
|
||||
sudo update-alternatives --set g++ /usr/bin/g++-14
|
||||
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 20 all
|
||||
|
||||
- name: Setup llvm@20
|
||||
if: matrix.os == 'macos-15'
|
||||
run: |
|
||||
brew install llvm@20
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup xmake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
actions-cache-folder: ".xmake-cache"
|
||||
actions-cache-key: ${{ matrix.os }}
|
||||
|
||||
- name: Package
|
||||
if: matrix.os != 'macos-15'
|
||||
run: |
|
||||
xmake config --yes --toolchain=${{ matrix.toolchain }} --enable_test=n --dev=n --release=y
|
||||
xmake pack
|
||||
|
||||
- name: Package
|
||||
if: matrix.os == 'macos-15'
|
||||
run: |
|
||||
xmake config --yes --toolchain=${{ matrix.toolchain }} --sdk=/opt/homebrew/opt/llvm@20 --enable_test=n --dev=n --release=y
|
||||
xmake pack
|
||||
|
||||
- name: Install uv for integration tests
|
||||
uses: astral-sh/setup-uv@v6
|
||||
|
||||
- name: Run tests
|
||||
run: xmake test --verbose
|
||||
|
||||
- name: Upload binaries to release
|
||||
if: github.event_name == 'push'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: build/xpack/clice/${{ matrix.artifact_name }}
|
||||
asset_name: ${{ matrix.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
38
.github/workflows/upload-llvm.yml
vendored
Normal file
38
.github/workflows/upload-llvm.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: upload-llvm
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
# if you want to run this workflow, change the branch name to main,
|
||||
# if you want to turn off it, change it to non existent branch.
|
||||
branches: [main-turn-off]
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
workflow_id:
|
||||
description: "Workflow run ID to pull artifacts from"
|
||||
required: true
|
||||
type: string
|
||||
version:
|
||||
description: "Release version/tag to publish (e.g., v1.2.3)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download artifacts from workflow
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: scripts/download-llvm.sh "${{ inputs.workflow_id }}"
|
||||
|
||||
- name: Recreate release with artifacts
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.UPLOAD_LLVM }}
|
||||
TARGET_REPO: clice-io/clice-llvm
|
||||
run: python3 scripts/upload-llvm.py "${{ inputs.version }}" "${TARGET_REPO}" "${{ inputs.workflow_id }}"
|
||||
55
.github/workflows/vscode.yml
vendored
Normal file
55
.github/workflows/vscode.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: CI/CD VS Code Extension
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
branches: ["main"]
|
||||
paths: ["editors/vscode/**"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
paths: ["editors/vscode/**"]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: editors/vscode
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Install vsce
|
||||
run: npm install -g vsce
|
||||
|
||||
- name: Publish and Package to Marketplace
|
||||
env:
|
||||
VSCE_PAT: ${{ secrets.VSCE_PAT }}
|
||||
run: |
|
||||
FLAG="${{ contains(github.ref_name, '-') && '--pre-release' || '' }}"
|
||||
npm run package -- $FLAG
|
||||
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
npm run publish -- -p "$VSCE_PAT" $FLAG
|
||||
fi
|
||||
|
||||
- name: Upload .vsix to Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: "editors/vscode/*.vsix"
|
||||
tag_name: ${{ github.ref }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
132
.github/workflows/xmake.yml
vendored
132
.github/workflows/xmake.yml
vendored
@@ -17,13 +17,19 @@ on:
|
||||
- "include/**"
|
||||
- "src/**"
|
||||
- "tests/**"
|
||||
- "config/**"
|
||||
- "xmake.lua"
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-2025]
|
||||
os: [windows-2025, ubuntu-24.04, macos-15]
|
||||
build_type: [debug, releasedbg]
|
||||
exclude:
|
||||
- os: windows-2025
|
||||
build_type: debug
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -34,120 +40,32 @@ jobs:
|
||||
- name: Setup xmake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
xmake-version: 3.0.5
|
||||
actions-cache-folder: ".xmake-cache"
|
||||
actions-cache-key: ${{ matrix.os }}
|
||||
package-cache: true
|
||||
package-cache-key: ${{ matrix.os }}
|
||||
package-cache-key: ${{ matrix.os }}-pixi
|
||||
build-cache: true
|
||||
build-cache-key: ${{ matrix.os }}-${{ matrix.build_type }}
|
||||
|
||||
- name: Xmake configure
|
||||
run: |
|
||||
xmake config --yes --ci=y --toolchain=clang
|
||||
|
||||
- name: Build clice
|
||||
run: |
|
||||
xmake build --verbose --diagnosis --all
|
||||
|
||||
- name: Install uv for integration tests
|
||||
uses: astral-sh/setup-uv@v6
|
||||
|
||||
- name: Run tests
|
||||
run: xmake test --verbose
|
||||
|
||||
linux:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
build_type: [release, debug]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Setup llvm & libstdc++ & cmake & ninja
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y gcc-14 g++-14 libstdc++-14-dev
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100
|
||||
sudo update-alternatives --set gcc /usr/bin/gcc-14
|
||||
sudo update-alternatives --set g++ /usr/bin/g++-14
|
||||
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 20 all
|
||||
|
||||
sudo apt install -y cmake ninja-build
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup xmake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
- name: Setup Pixi
|
||||
uses: prefix-dev/setup-pixi@v0.9.3
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
actions-cache-folder: ".xmake-cache"
|
||||
actions-cache-key: ${{ matrix.os }}
|
||||
package-cache: true
|
||||
package-cache-key: ${{ matrix.os }}
|
||||
build-cache: true
|
||||
build-cache-key: ${{ matrix.os }}-${{ matrix.build_type }}
|
||||
pixi-version: v0.61.0
|
||||
environments: develop
|
||||
activate-environment: true
|
||||
cache: true
|
||||
locked: true
|
||||
|
||||
- name: Xmake configure
|
||||
- name: Build
|
||||
run: |
|
||||
xmake config --yes --ci=y --mode=${{ matrix.build_type }} --toolchain=clang-20
|
||||
pixi run ci-xmake-build ${{ matrix.build_type }}
|
||||
|
||||
- name: Build clice
|
||||
- name: Test
|
||||
run: |
|
||||
xmake build --verbose --diagnosis --all
|
||||
pixi run xmake-test
|
||||
|
||||
- name: Install uv for integration tests
|
||||
uses: astral-sh/setup-uv@v6
|
||||
|
||||
- name: Run tests
|
||||
run: xmake test --verbose
|
||||
|
||||
macos:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-15]
|
||||
build_type: [release, debug]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup llvm
|
||||
run: |
|
||||
brew install llvm@20
|
||||
|
||||
- name: Setup xmake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
actions-cache-folder: ".xmake-cache"
|
||||
actions-cache-key: ${{ matrix.os }}
|
||||
package-cache: true
|
||||
package-cache-key: ${{ matrix.os }}
|
||||
build-cache: true
|
||||
build-cache-key: ${{ matrix.os }}-${{ matrix.build_type }}
|
||||
|
||||
- name: Xmake configure
|
||||
run: |
|
||||
xmake config --yes --ci=y --mode=${{ matrix.build_type }} --toolchain=clang --sdk=/opt/homebrew/opt/llvm@20
|
||||
|
||||
- name: Build clice
|
||||
run: |
|
||||
xmake build --verbose --diagnosis --all
|
||||
|
||||
- name: Install uv for integration tests
|
||||
uses: astral-sh/setup-uv@v6
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
# Workaround for MacOS
|
||||
export PATH="/opt/homebrew/opt/llvm@20/bin:/opt/homebrew/opt/lld@20/bin:$PATH"
|
||||
xmake test --verbose
|
||||
# Clean up llvm package to reduce cache size
|
||||
- name: Remove llvm package (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: xmake require --uninstall clice-llvm
|
||||
|
||||
48
.gitignore
vendored
48
.gitignore
vendored
@@ -16,10 +16,6 @@
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
@@ -31,25 +27,41 @@
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Evil things
|
||||
.claude
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# LSP & IDE
|
||||
compile_commands.json
|
||||
.vscode/
|
||||
.vs/
|
||||
.idea/
|
||||
|
||||
temp/
|
||||
# Build & Toolchain
|
||||
*build*/
|
||||
temp/
|
||||
.cache/
|
||||
.clice/
|
||||
.llvm*/
|
||||
.xmake/
|
||||
.llvm*/
|
||||
.clice/
|
||||
compile_commands.json
|
||||
perf.data
|
||||
flamegraph.svg
|
||||
|
||||
# Nodejs & Web
|
||||
*.vsix
|
||||
dist/
|
||||
out/
|
||||
cache/
|
||||
node_modules/
|
||||
.vscode-test/
|
||||
|
||||
# Python & Testing
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
tests/unit/Local/
|
||||
|
||||
**/node_modules
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
# IDEs & Editors
|
||||
/.vscode/
|
||||
.vs/
|
||||
.idea/
|
||||
.claude
|
||||
|
||||
# pixi environments
|
||||
.env
|
||||
.pixi/*
|
||||
!.pixi/config.toml
|
||||
|
||||
@@ -23,3 +23,9 @@ repos:
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types_or: [c++, c]
|
||||
|
||||
- repo: https://github.com/JohnnyMorganz/StyLua
|
||||
rev: v2.1.0
|
||||
hooks:
|
||||
- id: stylua-github # or stylua-system / stylua-github
|
||||
files: '(^xmake\.lua$|^editors/nvim/(lua|plugin|test)/.*\.lua$)'
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
3.13
|
||||
118
CMakeLists.txt
118
CMakeLists.txt
@@ -1,9 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(CLICE_PROJECT LANGUAGES C CXX)
|
||||
cmake_minimum_required(VERSION 3.30)
|
||||
|
||||
project(CLICE_PROJECT LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
@@ -11,6 +12,8 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
|
||||
|
||||
option(CLICE_ENABLE_LTO "Enable ThinLTO for all targets" OFF)
|
||||
|
||||
# Make sure all third libraries are affected by ABI related options
|
||||
if(CLICE_USE_LIBCXX)
|
||||
string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
|
||||
@@ -18,28 +21,89 @@ if(CLICE_USE_LIBCXX)
|
||||
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -stdlib=libc++")
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fsanitize=address")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address")
|
||||
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -fsanitize=address")
|
||||
if(CLICE_ENABLE_LTO)
|
||||
string(APPEND CMAKE_C_FLAGS " -flto=thin")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -flto=thin")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -flto=thin")
|
||||
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -flto=thin")
|
||||
string(APPEND CMAKE_MODULE_LINKER_FLAGS " -flto=thin")
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_options(-fsanitize=address)
|
||||
|
||||
if(NOT WIN32)
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address")
|
||||
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -fsanitize=address")
|
||||
endif()
|
||||
|
||||
if(MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} --print-resource-dir
|
||||
OUTPUT_VARIABLE CLANG_RESOURCE_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
set(ASAN_LIB_PATH "${CLANG_RESOURCE_DIR}/lib/windows")
|
||||
link_directories(${ASAN_LIB_PATH})
|
||||
|
||||
set(ASAN_LINK_FLAGS "")
|
||||
|
||||
list(APPEND ASAN_LINK_FLAGS "clang_rt.asan_dynamic-x86_64.lib")
|
||||
list(APPEND ASAN_LINK_FLAGS "/wholearchive:clang_rt.asan_dynamic_runtime_thunk-x86_64.lib")
|
||||
|
||||
foreach(flag ${ASAN_LINK_FLAGS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flag}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${flag}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${flag}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# https://conda-forge.org/docs/maintainer/knowledge_base/#newer-c-features-with-old-sdk
|
||||
string(APPEND CMAKE_CXX_FLAGS " -D_LIBCPP_DISABLE_AVAILABILITY=1")
|
||||
endif()
|
||||
|
||||
include("${PROJECT_SOURCE_DIR}/cmake/package.cmake")
|
||||
|
||||
add_library(clice_options INTERFACE)
|
||||
|
||||
if(CLICE_ENABLE_TEST)
|
||||
target_compile_definitions(clice_options INTERFACE CLICE_ENABLE_TEST=1)
|
||||
endif()
|
||||
|
||||
if(CLICE_CI_ENVIRONMENT)
|
||||
target_compile_definitions(clice_options INTERFACE CLICE_CI_ENVIRONMENT)
|
||||
target_compile_definitions(clice_options INTERFACE CLICE_CI_ENVIRONMENT=1)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(clice_options INTERFACE version ntdll)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
||||
target_link_options(clice_options INTERFACE -fuse-ld=lld-link)
|
||||
else()
|
||||
target_link_options(clice_options INTERFACE -fuse-ld=lld)
|
||||
target_link_options(clice_options INTERFACE
|
||||
-fuse-ld=lld-link
|
||||
-Wl,/OPT:REF
|
||||
#,/OPT:NOICF
|
||||
)
|
||||
elseif(APPLE)
|
||||
target_link_options(clice_options INTERFACE
|
||||
-fuse-ld=lld
|
||||
-Wl,-dead_strip
|
||||
)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_link_options(clice_options INTERFACE
|
||||
-fuse-ld=lld
|
||||
-static-libstdc++ -static-libgcc
|
||||
-Wl,--gc-sections
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if(MSVC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND
|
||||
CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
|
||||
target_compile_options(clice_options INTERFACE
|
||||
/GR-
|
||||
/EHsc-
|
||||
@@ -51,6 +115,8 @@ else()
|
||||
-fno-exceptions
|
||||
-Wno-deprecated-declarations
|
||||
-Wno-undefined-inline
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -69,6 +135,21 @@ add_custom_target(
|
||||
DEPENDS ${GENERATED_HEADER}
|
||||
)
|
||||
|
||||
set(CONFIG_SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/config/clang-tidy-config.h")
|
||||
set(CONFIG_GENERATED_FILE "${CMAKE_CURRENT_BINARY_DIR}/generated/clang-tidy-config.h")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CONFIG_GENERATED_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CONFIG_SOURCE_FILE} ${CONFIG_GENERATED_FILE}
|
||||
DEPENDS ${CONFIG_SOURCE_FILE}
|
||||
COMMENT "Generating C++ header from ${CONFIG_SOURCE_FILE}"
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
generate_config
|
||||
DEPENDS ${CONFIG_GENERATED_FILE}
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE CLICE_SOURCES CONFIGURE_DEPENDS
|
||||
"${PROJECT_SOURCE_DIR}/src/AST/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Async/*.cpp"
|
||||
@@ -80,7 +161,7 @@ file(GLOB_RECURSE CLICE_SOURCES CONFIGURE_DEPENDS
|
||||
"${PROJECT_SOURCE_DIR}/src/Support/*.cpp"
|
||||
)
|
||||
add_library(clice-core STATIC "${CLICE_SOURCES}")
|
||||
add_dependencies(clice-core generate_flatbuffers_schema)
|
||||
add_dependencies(clice-core generate_flatbuffers_schema generate_config)
|
||||
|
||||
target_include_directories(clice-core PUBLIC
|
||||
"${PROJECT_SOURCE_DIR}/include"
|
||||
@@ -101,12 +182,13 @@ target_link_libraries(clice PRIVATE clice-core)
|
||||
install(TARGETS clice RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
message(STATUS "Copying resource directory for development build")
|
||||
file(COPY
|
||||
"${LLVM_INSTALL_PATH}/lib/clang/20/"
|
||||
DESTINATION "${PROJECT_BINARY_DIR}/lib/clang/20"
|
||||
file(
|
||||
COPY "${LLVM_INSTALL_PATH}/lib/clang"
|
||||
DESTINATION "${PROJECT_BINARY_DIR}/lib"
|
||||
)
|
||||
install(DIRECTORY "${LLVM_INSTALL_PATH}/lib/clang/20/"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/clang/20"
|
||||
install(
|
||||
DIRECTORY "${LLVM_INSTALL_PATH}/lib/clang"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
)
|
||||
|
||||
if(CLICE_ENABLE_TEST)
|
||||
@@ -117,5 +199,5 @@ if(CLICE_ENABLE_TEST)
|
||||
"${PROJECT_SOURCE_DIR}/bin/unit_tests.cc"
|
||||
)
|
||||
target_include_directories(unit_tests PUBLIC "${PROJECT_SOURCE_DIR}")
|
||||
target_link_libraries(unit_tests PRIVATE clice-core)
|
||||
target_link_libraries(unit_tests PRIVATE clice-core cpptrace::cpptrace)
|
||||
endif()
|
||||
|
||||
39
Dockerfile
39
Dockerfile
@@ -1,39 +0,0 @@
|
||||
|
||||
FROM debian:13 AS builder
|
||||
|
||||
# Installs System Dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ninja-build cmake build-essential curl gcc-14 g++-14 git
|
||||
|
||||
# Installs LLVM 20
|
||||
RUN curl https://apt.llvm.org/llvm-snapshot.gpg.key | tee /usr/share/keyrings/llvm-snapshot.gpg.key && \
|
||||
echo "deb [signed-by=/usr/share/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/trixie/ llvm-toolchain-trixie main" >> /etc/apt/sources.list && \
|
||||
echo "deb [signed-by=/usr/share/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/trixie/ llvm-toolchain-trixie-20 main" >> /etc/apt/sources.list && \
|
||||
apt-get update && apt-get install -y \
|
||||
clang-20 lld-20
|
||||
RUN ln -s /usr/bin/lld-20 /usr/bin/lld
|
||||
|
||||
# Adds source code
|
||||
COPY include /app/include
|
||||
COPY cmake /app/cmake
|
||||
COPY src /app/src
|
||||
COPY tests /app/tests
|
||||
COPY CMakeLists.txt /app/CMakeLists.txt
|
||||
COPY scripts /app/scripts
|
||||
|
||||
WORKDIR /app
|
||||
# Initializes and installs dependencies
|
||||
RUN cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_BUILD_TYPE=Release -DCLICE_ENABLE_TEST=ON
|
||||
# Builds clice
|
||||
RUN cmake --build build -j && \
|
||||
cmake --install build --prefix=/opt/clice
|
||||
|
||||
FROM debian:13
|
||||
|
||||
COPY --from=builder /opt/clice /opt/clice/
|
||||
COPY LICENSE /opt/clice/LICENSE
|
||||
COPY README.md /opt/clice/README.md
|
||||
|
||||
RUN ln -s /opt/clice/bin/clice /usr/local/bin/clice
|
||||
|
||||
ENTRYPOINT ["clice"]
|
||||
99
bin/clice.cc
99
bin/clice.cc
@@ -1,12 +1,12 @@
|
||||
#include "Server/Version.h"
|
||||
#include "Server/Server.h"
|
||||
#include "Support/Logging.h"
|
||||
#include "Server/Version.h"
|
||||
#include "Support/Format.h"
|
||||
#include "Support/Logging.h"
|
||||
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
|
||||
namespace cl = llvm::cl;
|
||||
using namespace clice;
|
||||
@@ -48,13 +48,6 @@ cl::opt<unsigned int> port{
|
||||
cl::desc("The port to connect to"),
|
||||
};
|
||||
|
||||
cl::opt<std::string> resource_dir{
|
||||
"resource-dir",
|
||||
cl::cat(category),
|
||||
cl::value_desc("path"),
|
||||
cl::desc(R"(The path of the clang resource directory, default is "../../lib/clang/version")"),
|
||||
};
|
||||
|
||||
cl::opt<logging::ColorMode> log_color{
|
||||
"log-color",
|
||||
cl::cat(category),
|
||||
@@ -69,75 +62,43 @@ cl::opt<logging::ColorMode> log_color{
|
||||
cl::opt<logging::Level> log_level{
|
||||
"log-level",
|
||||
cl::cat(category),
|
||||
cl::value_desc("trace|debug|info|warn|fatal"),
|
||||
cl::value_desc("trace|debug|info|warn|error"),
|
||||
cl::init(logging::Level::info),
|
||||
cl::values(clEnumValN(logging::Level::trace, "trace", ""),
|
||||
clEnumValN(logging::Level::debug, "debug", ""),
|
||||
clEnumValN(logging::Level::info, "info", ""),
|
||||
clEnumValN(logging::Level::warn, "warn", ""),
|
||||
clEnumValN(logging::Level::err, "fatal", "")),
|
||||
clEnumValN(logging::Level::err, "error", ""),
|
||||
clEnumValN(logging::Level::off, "off", "")),
|
||||
cl::desc("The log level, default is info"),
|
||||
};
|
||||
|
||||
void init_log() {
|
||||
using namespace logging;
|
||||
options.color = log_color;
|
||||
options.level = log_level;
|
||||
logging::create_stderr_logger("clice", logging::options);
|
||||
}
|
||||
|
||||
/// Check the command line arguments and initialize the clice.
|
||||
bool check_arguments(int argc, const char** argv) {
|
||||
/// Hide unrelated options.
|
||||
cl::HideUnrelatedOptions(category);
|
||||
|
||||
// Set version printer and parse command line options
|
||||
cl::SetVersionPrinter([](llvm::raw_ostream& os) {
|
||||
os << std::format("clice version: {}\nllvm version: {}\n",
|
||||
clice::config::version,
|
||||
clice::config::llvm_version);
|
||||
});
|
||||
cl::ParseCommandLineOptions(argc,
|
||||
argv,
|
||||
"clice is a new generation of language server for C/C++");
|
||||
|
||||
init_log();
|
||||
|
||||
for(int i = 0; i < argc; ++i) {
|
||||
logging::info("argv[{}] = {}", i, argv[i]);
|
||||
}
|
||||
|
||||
// Initialize resource directory
|
||||
if(resource_dir.empty()) {
|
||||
logging::info("No resource directory specified, using default resource directory");
|
||||
// Try to initialize default resource directory
|
||||
if(auto result = fs::init_resource_dir(argv[0]); !result) {
|
||||
logging::warn("Cannot find default resource directory, because {}", result.error());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Set and check the specified resource directory
|
||||
fs::resource_dir = resource_dir.getValue();
|
||||
if(fs::exists(fs::resource_dir)) {
|
||||
logging::info("Resource directory found: {}", fs::resource_dir);
|
||||
} else {
|
||||
logging::warn("Resource directory not found: {}", fs::resource_dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
llvm::InitLLVM guard(argc, argv);
|
||||
llvm::setBugReportMsg(
|
||||
"Please report bugs to https://github.com/clice-io/clice/issues and include the crash backtrace");
|
||||
cl::SetVersionPrinter([](llvm::raw_ostream& os) {
|
||||
os << std::format("clice version: {}\nllvm version: {}\n",
|
||||
clice::config::version,
|
||||
clice::config::llvm_version);
|
||||
});
|
||||
cl::HideUnrelatedOptions(category);
|
||||
cl::ParseCommandLineOptions(argc,
|
||||
argv,
|
||||
"clice is a new generation of language server for C/C++");
|
||||
|
||||
if(!check_arguments(argc, argv)) {
|
||||
return 1;
|
||||
logging::options.color = log_color;
|
||||
logging::options.level = log_level;
|
||||
logging::stderr_logger("clice", logging::options);
|
||||
|
||||
if(auto result = fs::init_resource_dir(argv[0]); !result) {
|
||||
LOG_FATAL("Cannot find default resource directory, because {}", result.error());
|
||||
}
|
||||
|
||||
for(int i = 0; i < argc; ++i) {
|
||||
LOG_INFO("argv[{}] = {}", i, argv[i]);
|
||||
}
|
||||
|
||||
async::init();
|
||||
@@ -151,13 +112,13 @@ int main(int argc, const char** argv) {
|
||||
switch(mode) {
|
||||
case Mode::Pipe: {
|
||||
async::net::listen(loop);
|
||||
logging::info("Server starts listening on stdin/stdout");
|
||||
LOG_INFO("Server starts listening on stdin/stdout");
|
||||
break;
|
||||
}
|
||||
|
||||
case Mode::Socket: {
|
||||
async::net::listen(host.c_str(), port, loop);
|
||||
logging::info("Server starts listening on {}:{}", host.getValue(), port.getValue());
|
||||
LOG_INFO("Server starts listening on {}:{}", host.getValue(), port.getValue());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -169,7 +130,7 @@ int main(int argc, const char** argv) {
|
||||
|
||||
async::run();
|
||||
|
||||
logging::info("clice exit normally!");
|
||||
LOG_INFO("clice exit normally!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "Test/Test.h"
|
||||
#include "Support/Logging.h"
|
||||
#include "Support/GlobPattern.h"
|
||||
#include "Support/Logging.h"
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
@@ -9,16 +9,11 @@
|
||||
using namespace clice;
|
||||
using namespace clice::testing;
|
||||
|
||||
constexpr static std::string_view GREEN = "\033[32m";
|
||||
constexpr static std::string_view YELLOW = "\033[33m";
|
||||
constexpr static std::string_view RED = "\033[31m";
|
||||
constexpr static std::string_view CLEAR = "\033[0m";
|
||||
|
||||
namespace {
|
||||
|
||||
namespace cl = llvm::cl;
|
||||
|
||||
cl::OptionCategory unittest_category("Clice Unittest Options");
|
||||
cl::OptionCategory unittest_category("clice Unittest Options");
|
||||
|
||||
cl::opt<std::string> test_dir{
|
||||
"test-dir",
|
||||
@@ -28,12 +23,6 @@ cl::opt<std::string> test_dir{
|
||||
cl::cat(unittest_category),
|
||||
};
|
||||
|
||||
cl::opt<std::string> resource_dir{
|
||||
"resource-dir",
|
||||
cl::desc("Resource dir path"),
|
||||
cl::cat(unittest_category),
|
||||
};
|
||||
|
||||
cl::opt<std::string> test_filter{
|
||||
"test-filter",
|
||||
cl::desc("A glob pattern to run subset of tests"),
|
||||
@@ -46,167 +35,20 @@ cl::opt<bool> enable_example{
|
||||
cl::cat(unittest_category),
|
||||
};
|
||||
|
||||
std::optional<GlobPattern> pattern;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace clice::testing {
|
||||
|
||||
Runner& Runner::instance() {
|
||||
static Runner runner;
|
||||
return runner;
|
||||
}
|
||||
|
||||
void Runner::add_suite(std::string_view name, Suite suite) {
|
||||
suites[name].emplace_back(suite);
|
||||
}
|
||||
|
||||
void Runner::on_test(std::string_view name, Test test, bool skipped) {
|
||||
std::string full_name = std::format("{}.{}", curr_suite_name, name);
|
||||
|
||||
/// If this test if filter, directly return.
|
||||
if(pattern && !pattern->match(full_name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/// If there is any test in the suite, we print the suite start info.
|
||||
if(all_skipped) {
|
||||
std::println("{}[----------] tests from {}{}", GREEN, curr_suite_name, CLEAR);
|
||||
all_skipped = false;
|
||||
}
|
||||
|
||||
if(skipped) {
|
||||
/// If this test is marked as skipped, only print skip information.
|
||||
std::println("{}[ SKIPPED ] {}{}", YELLOW, full_name, CLEAR);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Reset whether this test is failed or fatal.
|
||||
curr_failed = false;
|
||||
curr_fatal = false;
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
std::println("{}[ RUN ] {}.{}{}", GREEN, curr_suite_name, name, CLEAR);
|
||||
auto begin = system_clock::now();
|
||||
|
||||
test();
|
||||
|
||||
auto duration = duration_cast<milliseconds>(system_clock::now() - begin);
|
||||
std::println("{}[ {} ] {} ({} ms){}",
|
||||
curr_failed ? RED : GREEN,
|
||||
curr_failed ? "FAILED" : " OK",
|
||||
full_name,
|
||||
duration.count(),
|
||||
CLEAR);
|
||||
|
||||
/// Update test information.
|
||||
curr_tests_count += 1;
|
||||
total_tests_count += 1;
|
||||
|
||||
curr_test_duration += duration;
|
||||
total_test_duration += duration;
|
||||
|
||||
if(curr_failed) {
|
||||
curr_failed_tests_count += 1;
|
||||
total_failed_tests_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Runner::fail(const may_failure& failure) {
|
||||
if(failure.failed) {
|
||||
curr_failed = true;
|
||||
std::println("{}Failure at {}:{}:{}! [{}]{}",
|
||||
RED,
|
||||
failure.location.file_name(),
|
||||
failure.location.line(),
|
||||
failure.location.column(),
|
||||
failure.expression,
|
||||
CLEAR);
|
||||
std::println("{}", failure.message);
|
||||
}
|
||||
|
||||
if(failure.fatal) {
|
||||
curr_fatal = true;
|
||||
std::println("{}--> Test stopped due to fatal error.{}", RED, CLEAR);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int Runner::run_tests() {
|
||||
/// Register all tests.
|
||||
std::println("{}[----------] Global test environment set-up.{}", GREEN, CLEAR);
|
||||
|
||||
for(auto& [suite_name, suite]: suites) {
|
||||
if(!enable_example && suite_name == "TEST.Example") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!test_filter.empty()) {
|
||||
auto pos = test_filter.find_first_of('.');
|
||||
if(pos != std::string::npos && test_filter.substr(0, pos) != suite_name) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
curr_fatal = false;
|
||||
all_skipped = true;
|
||||
curr_suite_name = suite_name;
|
||||
curr_tests_count = 0;
|
||||
curr_failed_tests_count = 0;
|
||||
curr_test_duration = std::chrono::milliseconds();
|
||||
|
||||
for(auto& callback: suite) {
|
||||
callback();
|
||||
}
|
||||
|
||||
/// If there is any test in the suite, we print the suite info.
|
||||
if(!all_skipped) {
|
||||
total_suites_count += 1;
|
||||
std::println("{}[----------] {} tests from {} ({} ms total)\n{}",
|
||||
GREEN,
|
||||
curr_tests_count,
|
||||
suite_name,
|
||||
total_test_duration.count(),
|
||||
CLEAR);
|
||||
}
|
||||
}
|
||||
|
||||
std::println("{}[----------] Global test environment tear-down{}", GREEN, CLEAR);
|
||||
std::println("{}[==========] {} tests from {} test suites ran. ({} ms total){}",
|
||||
GREEN,
|
||||
total_tests_count,
|
||||
total_suites_count,
|
||||
total_test_duration.count(),
|
||||
CLEAR);
|
||||
|
||||
return total_failed_tests_count != 0;
|
||||
}
|
||||
|
||||
} // namespace clice::testing
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
|
||||
llvm::cl::HideUnrelatedOptions(unittest_category);
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "clice test\n");
|
||||
|
||||
logging::create_stderr_logger("clice", logging::options);
|
||||
logging::stderr_logger("clice", logging::options);
|
||||
|
||||
if(!test_filter.empty()) {
|
||||
if(auto result = GlobPattern::create(test_filter)) {
|
||||
pattern.emplace(std::move(*result));
|
||||
}
|
||||
}
|
||||
|
||||
if(!resource_dir.empty()) {
|
||||
fs::resource_dir = resource_dir;
|
||||
} else {
|
||||
if(auto result = fs::init_resource_dir(argv[0]); !result) {
|
||||
std::println("Failed to get resource directory, because {}", result.error());
|
||||
return 1;
|
||||
}
|
||||
if(auto result = fs::init_resource_dir(argv[0]); !result) {
|
||||
std::println("Failed to get resource directory, because {}", result.error());
|
||||
return 1;
|
||||
}
|
||||
|
||||
using namespace clice::testing;
|
||||
return Runner::instance().run_tests();
|
||||
return Runner2::instance().run_tests(test_filter);
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/utils.cmake)
|
||||
|
||||
# Look up a Git tag's corresponding commit SHA from a GitHub repository
|
||||
function(github_lookup_tag_commit REPO_OWNER REPO_NAME TAG_NAME OUTPUT_VAR)
|
||||
set(GITHUB_API_URL "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/git/ref/tags/${TAG_NAME}")
|
||||
|
||||
message(STATUS "Fetching tag info from: ${GITHUB_API_URL}")
|
||||
|
||||
# Download tag info directly into a string
|
||||
download_to_string(${GITHUB_API_URL} TAG_JSON DOWNLOAD_RESULT)
|
||||
if(NOT DOWNLOAD_RESULT EQUAL "0")
|
||||
message(WARNING "Failed to fetch tag info. Result: ${DOWNLOAD_RESULT}")
|
||||
set(${OUTPUT_VAR} "NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Parse the JSON to get object type and SHA
|
||||
parse_json_field_from_string("${TAG_JSON}" object "type" OBJECT_TYPE)
|
||||
parse_json_field_from_string("${TAG_JSON}" object "sha" OBJECT_SHA)
|
||||
|
||||
if(OBJECT_TYPE STREQUAL "NOTFOUND" OR OBJECT_SHA STREQUAL "NOTFOUND")
|
||||
message(WARNING "Could not find object type or SHA in the JSON response.")
|
||||
set(${OUTPUT_VAR} "NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(COMMIT_SHA "NOTFOUND")
|
||||
|
||||
if(OBJECT_TYPE STREQUAL "commit")
|
||||
# Direct commit reference
|
||||
set(COMMIT_SHA ${OBJECT_SHA})
|
||||
elseif(OBJECT_TYPE STREQUAL "tag")
|
||||
# Annotated tag - need to fetch the actual commit
|
||||
set(TAG_API_URL "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/git/tags/${OBJECT_SHA}")
|
||||
|
||||
message(STATUS "Fetching annotated tag info from: ${TAG_API_URL}")
|
||||
|
||||
# Download annotated tag info directly into a string
|
||||
download_to_string(${TAG_API_URL} ANNOTATED_TAG_JSON TAG_DOWNLOAD_RESULT)
|
||||
if(NOT TAG_DOWNLOAD_RESULT EQUAL "0")
|
||||
message(WARNING "Failed to fetch annotated tag info. Result: ${TAG_DOWNLOAD_RESULT}")
|
||||
set(${OUTPUT_VAR} "NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Parse the annotated tag JSON to get the commit SHA
|
||||
parse_json_field_from_string("${ANNOTATED_TAG_JSON}" object "sha" COMMIT_SHA_FROM_TAG)
|
||||
|
||||
if(NOT COMMIT_SHA_FROM_TAG STREQUAL "NOTFOUND")
|
||||
set(COMMIT_SHA ${COMMIT_SHA_FROM_TAG})
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Unknown object type: ${OBJECT_TYPE}")
|
||||
endif()
|
||||
|
||||
set(${OUTPUT_VAR} ${COMMIT_SHA} PARENT_SCOPE)
|
||||
endfunction()
|
||||
108
cmake/llvm.cmake
Normal file
108
cmake/llvm.cmake
Normal file
@@ -0,0 +1,108 @@
|
||||
include_guard()
|
||||
|
||||
function(setup_llvm LLVM_VERSION)
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
|
||||
set(LLVM_SETUP_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/.llvm/setup-llvm.json")
|
||||
set(LLVM_SETUP_SCRIPT "${PROJECT_SOURCE_DIR}/scripts/setup-llvm.py")
|
||||
set(LLVM_SETUP_ARGS
|
||||
"--version" "${LLVM_VERSION}"
|
||||
"--build-type" "${CMAKE_BUILD_TYPE}"
|
||||
"--binary-dir" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"--manifest" "${PROJECT_SOURCE_DIR}/config/llvm-manifest.json"
|
||||
"--output" "${LLVM_SETUP_OUTPUT}"
|
||||
)
|
||||
|
||||
if(CLICE_ENABLE_LTO)
|
||||
list(APPEND LLVM_SETUP_ARGS "--enable-lto")
|
||||
endif()
|
||||
|
||||
if(DEFINED LLVM_INSTALL_PATH AND NOT LLVM_INSTALL_PATH STREQUAL "")
|
||||
list(APPEND LLVM_SETUP_ARGS "--install-path" "${LLVM_INSTALL_PATH}")
|
||||
endif()
|
||||
|
||||
if(DEFINED CLICE_OFFLINE_BUILD AND CLICE_OFFLINE_BUILD)
|
||||
list(APPEND LLVM_SETUP_ARGS "--offline")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND "${Python3_EXECUTABLE}" "${LLVM_SETUP_SCRIPT}" ${LLVM_SETUP_ARGS}
|
||||
RESULT_VARIABLE LLVM_SETUP_RESULT
|
||||
OUTPUT_VARIABLE LLVM_SETUP_STDOUT
|
||||
ERROR_VARIABLE LLVM_SETUP_STDERR
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
ECHO_ERROR_VARIABLE
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
|
||||
file(READ "${LLVM_SETUP_OUTPUT}" LLVM_SETUP_JSON)
|
||||
string(JSON LLVM_INSTALL_PATH GET "${LLVM_SETUP_JSON}" install_path)
|
||||
string(JSON LLVM_CMAKE_DIR GET "${LLVM_SETUP_JSON}" cmake_dir)
|
||||
set(LLVM_INSTALL_PATH "${LLVM_INSTALL_PATH}" CACHE PATH "Path to LLVM installation" FORCE)
|
||||
set(LLVM_CMAKE_DIR "${LLVM_CMAKE_DIR}" CACHE PATH "Path to LLVM CMake files" FORCE)
|
||||
|
||||
get_filename_component(LLVM_INSTALL_PATH "${LLVM_INSTALL_PATH}" ABSOLUTE)
|
||||
|
||||
if(NOT EXISTS "${LLVM_INSTALL_PATH}")
|
||||
message(FATAL_ERROR "Error: The specified LLVM_INSTALL_PATH does not exist: ${LLVM_INSTALL_PATH}")
|
||||
endif()
|
||||
|
||||
# set llvm include and lib path
|
||||
add_library(llvm-libs INTERFACE IMPORTED)
|
||||
|
||||
# add to include directories
|
||||
target_include_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/include")
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT WIN32)
|
||||
target_link_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/lib")
|
||||
target_link_libraries(llvm-libs INTERFACE
|
||||
LLVMSupport
|
||||
LLVMFrontendOpenMP
|
||||
LLVMOption
|
||||
LLVMTargetParser
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
clangDriver
|
||||
clangFormat
|
||||
clangFrontend
|
||||
clangLex
|
||||
clangSema
|
||||
clangSerialization
|
||||
clangTidy
|
||||
clangTidyUtils
|
||||
clangTidyAndroidModule
|
||||
clangTidyAbseilModule
|
||||
clangTidyAlteraModule
|
||||
clangTidyBoostModule
|
||||
clangTidyBugproneModule
|
||||
clangTidyCERTModule
|
||||
clangTidyConcurrencyModule
|
||||
clangTidyCppCoreGuidelinesModule
|
||||
clangTidyDarwinModule
|
||||
clangTidyFuchsiaModule
|
||||
clangTidyGoogleModule
|
||||
clangTidyHICPPModule
|
||||
clangTidyLinuxKernelModule
|
||||
clangTidyLLVMModule
|
||||
clangTidyLLVMLibcModule
|
||||
clangTidyMiscModule
|
||||
clangTidyModernizeModule
|
||||
clangTidyObjCModule
|
||||
clangTidyOpenMPModule
|
||||
clangTidyPerformanceModule
|
||||
clangTidyPortabilityModule
|
||||
clangTidyReadabilityModule
|
||||
clangTidyZirconModule
|
||||
clangTooling
|
||||
clangToolingCore
|
||||
clangToolingInclusions
|
||||
clangToolingInclusionsStdlib
|
||||
clangToolingSyntax
|
||||
)
|
||||
else()
|
||||
file(GLOB LLVM_LIBRARIES CONFIGURE_DEPENDS "${LLVM_INSTALL_PATH}/lib/*${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
target_link_libraries(llvm-libs INTERFACE ${LLVM_LIBRARIES})
|
||||
target_compile_definitions(llvm-libs INTERFACE CLANG_BUILD_STATIC=1)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1,213 +0,0 @@
|
||||
include_guard()
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/github.cmake)
|
||||
|
||||
# Check if LLVM version is supported
|
||||
function(check_llvm_version llvm_ver OUTPUT_VAR)
|
||||
if((NOT DEFINED llvm_ver) OR (llvm_ver STREQUAL ""))
|
||||
message(WARNING "LLVM version is not set.")
|
||||
set(${OUTPUT_VAR} FALSE PARENT_SCOPE)
|
||||
elseif(NOT (llvm_ver VERSION_GREATER_EQUAL "20.1" AND llvm_ver VERSION_LESS "20.2"))
|
||||
message(WARNING "Unsupported LLVM version: ${llvm_ver}. Only LLVM 20.1.x is supported.")
|
||||
set(${OUTPUT_VAR} FALSE PARENT_SCOPE)
|
||||
else()
|
||||
set(${OUTPUT_VAR} TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Look up LLVM version's corresponding commit SHA
|
||||
function(lookup_commit llvm_ver OUTPUT_VAR)
|
||||
set(LLVM_TAG "llvmorg-${llvm_ver}")
|
||||
github_lookup_tag_commit("llvm" "llvm-project" ${LLVM_TAG} COMMIT_SHA)
|
||||
set(${OUTPUT_VAR} ${COMMIT_SHA} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Fetch private Clang header files from LLVM source
|
||||
function(fetch_private_clang_files llvm_ver)
|
||||
set(PRIVATE_CLANG_FILE_LIST
|
||||
"Sema/CoroutineStmtBuilder.h"
|
||||
"Sema/TypeLocBuilder.h"
|
||||
"Sema/TreeTransform.h"
|
||||
)
|
||||
|
||||
# Check if all files already exist
|
||||
set(PRIVATE_FILE_EXISTS TRUE)
|
||||
foreach(FILE ${PRIVATE_CLANG_FILE_LIST})
|
||||
if(EXISTS "${LLVM_INSTALL_PATH}/include/clang/${FILE}")
|
||||
message(STATUS "Private clang file found in LLVM installation: ${FILE}")
|
||||
elseif(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/include/clang/${FILE}")
|
||||
message(STATUS "Private clang file already exists: ${FILE}")
|
||||
else()
|
||||
set(PRIVATE_FILE_EXISTS FALSE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(PRIVATE_FILE_EXISTS)
|
||||
message(STATUS "All required private clang files already exist.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Skip download in offline build mode
|
||||
if(CLICE_OFFLINE_BUILD)
|
||||
message(WARNING "CLICE_OFFLINE_BUILD is enabled, skipping private clang files download")
|
||||
message(WARNING "Build may fail if required private headers are missing")
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(WARNING "Required private clang files incomplete, fetching from llvm-project source...")
|
||||
|
||||
# Get the commit SHA for this LLVM version
|
||||
lookup_commit(${llvm_ver} LLVM_COMMIT)
|
||||
if(LLVM_COMMIT STREQUAL "NOTFOUND")
|
||||
message(WARNING "Failed to lookup commit for LLVM ${llvm_ver}, skipping private clang files download")
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "LLVM ${llvm_ver} corresponds to commit ${LLVM_COMMIT}")
|
||||
|
||||
# Download missing files
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/clang")
|
||||
foreach(FILE ${PRIVATE_CLANG_FILE_LIST})
|
||||
set(FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/clang/${FILE}")
|
||||
if(NOT EXISTS "${FILE_PATH}")
|
||||
message(STATUS "Downloading ${FILE}...")
|
||||
file(DOWNLOAD "https://raw.githubusercontent.com/llvm/llvm-project/${LLVM_COMMIT}/clang/lib/${FILE}"
|
||||
"${FILE_PATH}"
|
||||
STATUS DOWNLOAD_STATUS
|
||||
TLS_VERIFY ON)
|
||||
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
||||
if(NOT STATUS_CODE EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to download private clang file: ${FILE}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Detect system-installed LLVM using llvm-config
|
||||
function(detect_llvm OUTPUT_VAR)
|
||||
find_program(LLVM_CONFIG_EXEC llvm-config)
|
||||
|
||||
if(NOT LLVM_CONFIG_EXEC)
|
||||
set(${OUTPUT_VAR} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Get LLVM version and paths
|
||||
execute_process(
|
||||
COMMAND "${LLVM_CONFIG_EXEC}" --version
|
||||
OUTPUT_VARIABLE LLVM_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(
|
||||
COMMAND "${LLVM_CONFIG_EXEC}" --prefix
|
||||
OUTPUT_VARIABLE LLVM_INSTALL_PATH_DETECTED
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(
|
||||
COMMAND "${LLVM_CONFIG_EXEC}" --cmakedir
|
||||
OUTPUT_VARIABLE LLVM_CMAKE_DIR_DETECTED
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Set cache variables
|
||||
set(LLVM_INSTALL_PATH "${LLVM_INSTALL_PATH_DETECTED}" CACHE PATH "Path to LLVM installation" FORCE)
|
||||
set(LLVM_CMAKE_DIR "${LLVM_CMAKE_DIR_DETECTED}" CACHE PATH "Path to LLVM CMake files" FORCE)
|
||||
set(${OUTPUT_VAR} ${LLVM_VERSION} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Download and install prebuilt LLVM binaries with error checking
|
||||
function(install_prebuilt_llvm llvm_ver)
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.llvm")
|
||||
|
||||
# Determine platform-specific package name
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(LLVM_BUILD_TYPE "debug")
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
set(LLVM_BUILD_TYPE "release")
|
||||
else()
|
||||
set(LLVM_BUILD_TYPE "release-lto")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(LLVM_PACKAGE "x64-windows-msvc-${LLVM_BUILD_TYPE}.7z")
|
||||
elseif(APPLE)
|
||||
set(LLVM_PACKAGE "arm64-macosx-apple-${LLVM_BUILD_TYPE}.tar.xz")
|
||||
elseif(UNIX)
|
||||
set(LLVM_PACKAGE "x86_64-linux-gnu-${LLVM_BUILD_TYPE}.tar.xz")
|
||||
endif()
|
||||
|
||||
if(NOT LLVM_PACKAGE)
|
||||
message(FATAL_ERROR "Unsupported platform or build type for prebuilt LLVM.")
|
||||
endif()
|
||||
|
||||
set(DOWNLOAD_PATH "${CMAKE_CURRENT_BINARY_DIR}/${LLVM_PACKAGE}")
|
||||
|
||||
# Download if file does not exist
|
||||
if(NOT EXISTS "${DOWNLOAD_PATH}")
|
||||
message(STATUS "Downloading prebuilt LLVM package: ${LLVM_PACKAGE}")
|
||||
set(DOWNLOAD_URL "https://github.com/clice-io/llvm-binary/releases/download/${llvm_ver}/${LLVM_PACKAGE}")
|
||||
file(DOWNLOAD "${DOWNLOAD_URL}"
|
||||
"${DOWNLOAD_PATH}"
|
||||
STATUS DOWNLOAD_STATUS
|
||||
SHOW_PROGRESS
|
||||
TLS_VERIFY ON)
|
||||
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
||||
list(GET DOWNLOAD_STATUS 1 ERROR_MESSAGE)
|
||||
|
||||
if(NOT STATUS_CODE EQUAL 0)
|
||||
# Download failed, remove the incomplete file to force a fresh download next time
|
||||
if(EXISTS "${DOWNLOAD_PATH}")
|
||||
file(REMOVE "${DOWNLOAD_PATH}")
|
||||
message(STATUS "Removed incomplete file: ${DOWNLOAD_PATH}")
|
||||
endif()
|
||||
message(FATAL_ERROR "Failed to download prebuilt LLVM package from ${DOWNLOAD_URL}.\nError: ${ERROR_MESSAGE}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Prebuilt LLVM package already exists, skipping download.")
|
||||
endif()
|
||||
|
||||
message(STATUS "Extracting LLVM package: ${LLVM_PACKAGE}")
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" -E tar xvf "${DOWNLOAD_PATH}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.llvm"
|
||||
RESULT_VARIABLE TAR_RESULT
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
if(NOT TAR_RESULT EQUAL "0")
|
||||
message(FATAL_ERROR "Failed to extract archive. The file may be corrupted or the tool is missing.")
|
||||
endif()
|
||||
|
||||
# Set installation paths
|
||||
set(LLVM_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/.llvm" CACHE PATH "Path to LLVM installation" FORCE)
|
||||
set(LLVM_CMAKE_DIR "${LLVM_INSTALL_PATH}/lib/cmake/llvm" CACHE PATH "Path to LLVM CMake files" FORCE)
|
||||
message(STATUS "LLVM installation path set to: ${LLVM_INSTALL_PATH}")
|
||||
endfunction()
|
||||
|
||||
# Main function to set up LLVM for the project
|
||||
function(setup_llvm)
|
||||
# Use existing LLVM installation if path is already set
|
||||
if(DEFINED LLVM_INSTALL_PATH AND NOT LLVM_INSTALL_PATH STREQUAL "")
|
||||
message(STATUS "LLVM_INSTALL_PATH is set to ${LLVM_INSTALL_PATH}, using it directly.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(LLVM_VERSION_OK false)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
# Try to detect system LLVM
|
||||
detect_llvm(LLVM_VERSION)
|
||||
check_llvm_version("${LLVM_VERSION}" LLVM_VERSION_OK)
|
||||
endif()
|
||||
|
||||
# Download prebuilt LLVM if system version is not suitable
|
||||
if(NOT LLVM_VERSION_OK)
|
||||
set(LLVM_VERSION "20.1.5")
|
||||
message(WARNING "System LLVM not found, version mismatch or incompatible build type, downloading prebuilt LLVM...")
|
||||
install_prebuilt_llvm("${LLVM_VERSION}")
|
||||
endif()
|
||||
|
||||
# Fetch required private Clang headers
|
||||
fetch_private_clang_files("${LLVM_VERSION}")
|
||||
endfunction()
|
||||
@@ -1,84 +1,11 @@
|
||||
include_guard()
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/llvm_setup.cmake)
|
||||
|
||||
setup_llvm()
|
||||
|
||||
get_filename_component(LLVM_INSTALL_PATH "${LLVM_INSTALL_PATH}" ABSOLUTE)
|
||||
|
||||
if(NOT EXISTS "${LLVM_INSTALL_PATH}")
|
||||
message(FATAL_ERROR "Error: The specified LLVM_INSTALL_PATH does not exist: ${LLVM_INSTALL_PATH}")
|
||||
endif()
|
||||
|
||||
# set llvm include and lib path
|
||||
add_library(llvm-libs INTERFACE IMPORTED)
|
||||
|
||||
message(STATUS "LLVM include path: ${LLVM_INSTALL_PATH}/include")
|
||||
# add to include directories
|
||||
target_include_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/include")
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_link_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/lib")
|
||||
target_link_libraries(llvm-libs INTERFACE
|
||||
LLVMSupport
|
||||
LLVMFrontendOpenMP
|
||||
LLVMOption
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
clangDependencyScanning
|
||||
clangDriver
|
||||
clangFormat
|
||||
clangFrontend
|
||||
clangIndex
|
||||
clangLex
|
||||
clangSema
|
||||
clangSerialization
|
||||
clangTidy
|
||||
clangTidyUtils
|
||||
# ALL_CLANG_TIDY_CHECKS
|
||||
clangTidyAndroidModule
|
||||
clangTidyAbseilModule
|
||||
clangTidyAlteraModule
|
||||
clangTidyBoostModule
|
||||
clangTidyBugproneModule
|
||||
clangTidyCERTModule
|
||||
clangTidyConcurrencyModule
|
||||
clangTidyCppCoreGuidelinesModule
|
||||
clangTidyDarwinModule
|
||||
clangTidyFuchsiaModule
|
||||
clangTidyGoogleModule
|
||||
clangTidyHICPPModule
|
||||
clangTidyLinuxKernelModule
|
||||
clangTidyLLVMModule
|
||||
clangTidyLLVMLibcModule
|
||||
clangTidyMiscModule
|
||||
clangTidyModernizeModule
|
||||
clangTidyObjCModule
|
||||
clangTidyOpenMPModule
|
||||
clangTidyPerformanceModule
|
||||
clangTidyPortabilityModule
|
||||
clangTidyReadabilityModule
|
||||
clangTidyZirconModule
|
||||
clangTooling
|
||||
clangToolingCore
|
||||
clangToolingInclusions
|
||||
clangToolingInclusionsStdlib
|
||||
clangToolingSyntax
|
||||
)
|
||||
else()
|
||||
file(GLOB LLVM_LIBRARIES CONFIGURE_DEPENDS "${LLVM_INSTALL_PATH}/lib/*${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
target_link_libraries(llvm-libs INTERFACE ${LLVM_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(llvm-libs INTERFACE "CLANG_BUILD_STATIC")
|
||||
target_link_libraries(llvm-libs INTERFACE version ntdll)
|
||||
endif()
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/llvm.cmake)
|
||||
setup_llvm("21.1.4+r1")
|
||||
|
||||
# install dependencies
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_UPDATES_DISCONNECTED ON)
|
||||
|
||||
if(WIN32)
|
||||
set(NULL_DEVICE NUL)
|
||||
@@ -91,6 +18,8 @@ FetchContent_Declare(
|
||||
libuv
|
||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
||||
GIT_TAG v1.x
|
||||
GIT_SHALLOW TRUE
|
||||
|
||||
)
|
||||
|
||||
if(NOT WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
@@ -104,13 +33,16 @@ set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_Declare(
|
||||
spdlog
|
||||
GIT_REPOSITORY https://github.com/gabime/spdlog.git
|
||||
GIT_TAG v1.15.3
|
||||
GIT_TAG v1.15.3
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
# tomlplusplus
|
||||
FetchContent_Declare(
|
||||
tomlplusplus
|
||||
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
|
||||
GIT_TAG v3.4.0
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
# croaring
|
||||
@@ -118,20 +50,32 @@ FetchContent_Declare(
|
||||
croaring
|
||||
GIT_REPOSITORY https://github.com/RoaringBitmap/CRoaring.git
|
||||
GIT_TAG v4.4.2
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
set(ENABLE_ROARING_TESTS OFF CACHE INTERNAL "" FORCE)
|
||||
set(ENABLE_ROARING_MICROBENCHMARKS OFF CACHE INTERNAL "" FORCE)
|
||||
|
||||
# flatbuffers
|
||||
FetchContent_Declare(
|
||||
flatbuffers
|
||||
GIT_REPOSITORY https://github.com/google/flatbuffers.git
|
||||
GIT_TAG v25.9.23
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
set(FLATBUFFERS_BUILD_GRPC OFF CACHE BOOL "" FORCE)
|
||||
set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||
set(FLATBUFFERS_BUILD_FLATHASH OFF CACHE BOOL "" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(libuv spdlog tomlplusplus croaring flatbuffers)
|
||||
# cpptrace
|
||||
FetchContent_Declare(
|
||||
cpptrace
|
||||
GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
|
||||
GIT_TAG v1.0.4
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
set(CPPTRACE_DISABLE_CXX_20_MODULES ON CACHE BOOL "" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(libuv spdlog tomlplusplus croaring flatbuffers cpptrace)
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(uv_a PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
44
cmake/toolchain.cmake
Normal file
44
cmake/toolchain.cmake
Normal file
@@ -0,0 +1,44 @@
|
||||
cmake_minimum_required(VERSION 3.30)
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_C_COMPILER clang-cl CACHE STRING "C compiler")
|
||||
set(CMAKE_CXX_COMPILER clang-cl CACHE STRING "C++ compiler")
|
||||
set(AR_PROGRAM_NAME "llvm-lib")
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL" CACHE STRING "MSVC runtime")
|
||||
|
||||
find_program(LLVM_LLD_LINK_PATH "lld-link")
|
||||
if(LLVM_LLD_LINK_PATH)
|
||||
set(CMAKE_LINKER "${LLVM_LLD_LINK_PATH}" CACHE FILEPATH "Linker")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_C_COMPILER clang CACHE STRING "C compiler")
|
||||
set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ compiler")
|
||||
set(AR_PROGRAM_NAME "llvm-ar")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "Executable linker flags")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "Shared library linker flags")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "Module linker flags")
|
||||
endif()
|
||||
|
||||
find_program(LLVM_AR_PATH ${AR_PROGRAM_NAME})
|
||||
if(LLVM_AR_PATH)
|
||||
set(CMAKE_AR "${LLVM_AR_PATH}" CACHE FILEPATH "Archiver")
|
||||
set(CMAKE_C_COMPILER_AR "${LLVM_AR_PATH}" CACHE FILEPATH "C archiver")
|
||||
set(CMAKE_CXX_COMPILER_AR "${LLVM_AR_PATH}" CACHE FILEPATH "C++ archiver")
|
||||
endif()
|
||||
|
||||
find_program(LLVM_RANLIB_PATH "llvm-ranlib")
|
||||
if(LLVM_RANLIB_PATH)
|
||||
set(CMAKE_RANLIB "${LLVM_RANLIB_PATH}" CACHE FILEPATH "Ranlib")
|
||||
set(CMAKE_C_COMPILER_RANLIB "${LLVM_RANLIB_PATH}" CACHE FILEPATH "C ranlib")
|
||||
set(CMAKE_CXX_COMPILER_RANLIB "${LLVM_RANLIB_PATH}" CACHE FILEPATH "C++ ranlib")
|
||||
endif()
|
||||
|
||||
find_program(LLVM_NM_PATH "llvm-nm")
|
||||
if(LLVM_NM_PATH)
|
||||
set(CMAKE_NM "${LLVM_NM_PATH}" CACHE FILEPATH "Symbol lister")
|
||||
endif()
|
||||
|
||||
find_program(LLVM_RC_PATH "llvm-rc")
|
||||
if(LLVM_RC_PATH)
|
||||
set(CMAKE_RC_COMPILER "${LLVM_RC_PATH}" CACHE FILEPATH "Resource compiler")
|
||||
endif()
|
||||
@@ -1,55 +0,0 @@
|
||||
include_guard()
|
||||
|
||||
# Download content from URL directly into a string.
|
||||
# Usage: download_to_string(URL OUTPUT_VAR RESULT_VAR)
|
||||
# - URL: The URL to download from.
|
||||
# - OUTPUT_VAR: The variable to store the downloaded content.
|
||||
# - RESULT_VAR: The variable to store the status code (0 on success).
|
||||
function(download_to_string URL OUTPUT_VAR RESULT_VAR)
|
||||
file(DOWNLOAD
|
||||
${URL}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/temp_download_file
|
||||
STATUS DOWNLOAD_STATUS
|
||||
TLS_VERIFY ON
|
||||
TIMEOUT 10 # Set a reasonable timeout
|
||||
)
|
||||
|
||||
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
||||
|
||||
if(NOT STATUS_CODE EQUAL 0)
|
||||
list(GET DOWNLOAD_STATUS 1 ERROR_MSG)
|
||||
message(WARNING "Failed to download from ${URL}: ${ERROR_MSG}")
|
||||
set(${RESULT_VAR} ${STATUS_CODE} PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(READ ${CMAKE_CURRENT_BINARY_DIR}/temp_download_file DOWNLOADED_CONTENT)
|
||||
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/temp_download_file)
|
||||
|
||||
set(${OUTPUT_VAR} ${DOWNLOADED_CONTENT} PARENT_SCOPE)
|
||||
set(${RESULT_VAR} 0 PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Parse a nested JSON field from a string.
|
||||
# Usage: parse_json_field_from_string(JSON_STRING PARENT_KEY FIELD_NAME OUTPUT_VAR)
|
||||
# - JSON_STRING: A variable containing the JSON content as a string.
|
||||
# - PARENT_KEY: A key string to get from the JSON content.
|
||||
# - FIELD_NAME: The field name to extract.
|
||||
# - OUTPUT_VAR: The variable to store the extracted value.
|
||||
function(parse_json_field_from_string JSON_CONTENT)
|
||||
# Get the last argument as the output variable name
|
||||
set(ARGS "${ARGN}")
|
||||
list(GET ARGS -1 OUTPUT_VAR)
|
||||
list(REMOVE_AT ARGS -1)
|
||||
|
||||
string(JSON FIELD_VALUE GET "${JSON_CONTENT}" ${ARGS})
|
||||
|
||||
if(NOT FIELD_VALUE)
|
||||
string(JOIN " " FIELD_PATH_STR ${ARGS})
|
||||
message(WARNING "Could not parse field '${FIELD_PATH_STR}' from JSON.")
|
||||
set(${OUTPUT_VAR} "NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(${OUTPUT_VAR} ${FIELD_VALUE} PARENT_SCOPE)
|
||||
endfunction()
|
||||
11
config/clang-tidy-config.h
Normal file
11
config/clang-tidy-config.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/* This generated file is for internal use. Do not include it from headers. */
|
||||
|
||||
#ifdef CLANG_TIDY_CONFIG_H
|
||||
#error clang-tidy-config.h can only be included once
|
||||
#else
|
||||
#define CLANG_TIDY_CONFIG_H
|
||||
|
||||
// Clice currently doesn't support this configuration, and we use the same default value as clangd.
|
||||
#define CLANG_TIDY_ENABLE_STATIC_ANALYZER 0
|
||||
|
||||
#endif
|
||||
@@ -1,6 +0,0 @@
|
||||
xmake,3.0.2
|
||||
cmake,3.31.8
|
||||
python,3.13
|
||||
gcc,14
|
||||
clang,20
|
||||
msvc
|
||||
83
config/llvm-manifest.json
Normal file
83
config/llvm-manifest.json
Normal file
@@ -0,0 +1,83 @@
|
||||
[
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "arm64-macos-clang-debug-asan.tar.xz",
|
||||
"sha256": "7da4b7d63edefecaf11773e7e701c575140d1a07329bbbb038673b6ee4516ff5",
|
||||
"lto": false,
|
||||
"asan": true,
|
||||
"platform": "macosx",
|
||||
"build_type": "Debug"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "arm64-macos-clang-releasedbg-lto.tar.xz",
|
||||
"sha256": "300455b169448f9f01ae95e3bc269f489558a4ca3955e3032171cc75feca0e30",
|
||||
"lto": true,
|
||||
"asan": false,
|
||||
"platform": "macosx",
|
||||
"build_type": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "arm64-macos-clang-releasedbg.tar.xz",
|
||||
"sha256": "9abfc6cd65b957d734ffb97610a634fb4a66d3fbe0fcfb5a1c9124ef693c1495",
|
||||
"lto": false,
|
||||
"asan": false,
|
||||
"platform": "macosx",
|
||||
"build_type": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "x64-linux-gnu-debug-asan.tar.xz",
|
||||
"sha256": "c1ad3ec476911596a842ac67dd9c9c9475ce9f0a77b81101d3c801840292e7bc",
|
||||
"lto": false,
|
||||
"asan": true,
|
||||
"platform": "linux",
|
||||
"build_type": "Debug"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "x64-linux-gnu-releasedbg-lto.tar.xz",
|
||||
"sha256": "8a869c2184d139dbba704e2d712e7a68336458ad2d70622b3eb906c3e3511e54",
|
||||
"lto": true,
|
||||
"asan": false,
|
||||
"platform": "linux",
|
||||
"build_type": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "x64-linux-gnu-releasedbg.tar.xz",
|
||||
"sha256": "552bab86f715d4f2c027f07eaaf5b3d6b8e430af0b74b470142f3f00da4feec6",
|
||||
"lto": false,
|
||||
"asan": false,
|
||||
"platform": "linux",
|
||||
"build_type": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "x64-windows-msvc-debug-asan.tar.xz",
|
||||
"sha256": "093667a493d336c22ff3c604c5f1fea2a7d2c927c1179cec44e9a03726906ac1",
|
||||
"lto": false,
|
||||
"asan": true,
|
||||
"platform": "windows",
|
||||
"build_type": "Debug"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "x64-windows-msvc-releasedbg-lto.tar.xz",
|
||||
"sha256": "010539e85621dc3c6ecf359d899feb4075aeca5d0bba6625cdbec0e570e79129",
|
||||
"lto": true,
|
||||
"asan": false,
|
||||
"platform": "windows",
|
||||
"build_type": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"version": "21.1.4+r1",
|
||||
"filename": "x64-windows-msvc-releasedbg.tar.xz",
|
||||
"sha256": "f473c09fbea10053fac00be409d75dc228d4a38bcbc5e4aeb58b56a4b0dde78e",
|
||||
"lto": false,
|
||||
"asan": false,
|
||||
"platform": "windows",
|
||||
"build_type": "RelWithDebInfo"
|
||||
}
|
||||
]
|
||||
@@ -1,66 +0,0 @@
|
||||
[
|
||||
{
|
||||
"platform": "Windows",
|
||||
"build_type": "Release",
|
||||
"is_lto": false,
|
||||
"filename": "x64-windows-msvc-release.7z",
|
||||
"version": "20.1.5",
|
||||
"sha256": "499b2e1e37c6dcccbc9d538cea5a222b552d599f54bb523adea8594d7837d02b"
|
||||
},
|
||||
{
|
||||
"platform": "Windows",
|
||||
"build_type": "Release",
|
||||
"is_lto": true,
|
||||
"filename": "x64-windows-msvc-release-lto.7z",
|
||||
"version": "20.1.5",
|
||||
"sha256": "0548c0e3f613d1ec853d493870e68c7d424d70442d144fb35b99dc65fc682918"
|
||||
},
|
||||
{
|
||||
"platform": "Linux",
|
||||
"build_type": "Debug",
|
||||
"is_lto": false,
|
||||
"filename": "x86_64-linux-gnu-debug.tar.xz",
|
||||
"version": "20.1.5",
|
||||
"sha256": "c04dddbe1d43d006f1ac52db01ab1776b8686fb8d4a1d13f2e07df37ae1ed47e"
|
||||
},
|
||||
{
|
||||
"platform": "Linux",
|
||||
"build_type": "Release",
|
||||
"is_lto": false,
|
||||
"filename": "x86_64-linux-gnu-release.tar.xz",
|
||||
"version": "20.1.5",
|
||||
"sha256": "5ff442434e9c1fbe67c9c2bd13284ef73590aa984bb74bcdfcec4404e5074b70"
|
||||
},
|
||||
{
|
||||
"platform": "Linux",
|
||||
"build_type": "Release",
|
||||
"is_lto": true,
|
||||
"filename": "x86_64-linux-gnu-release-lto.tar.xz",
|
||||
"version": "20.1.5",
|
||||
"sha256": "37bc9680df5b766de6367c3c690fe8be993e94955341e63fb5ee6a3132080059"
|
||||
},
|
||||
{
|
||||
"platform": "macosx",
|
||||
"build_type": "Debug",
|
||||
"is_lto": false,
|
||||
"filename": "arm64-macosx-apple-debug.tar.xz",
|
||||
"version": "20.1.5",
|
||||
"sha256": "899d15d0678c1099bccb41098355b938d3bb6dd20870763758b70db01b31a709"
|
||||
},
|
||||
{
|
||||
"platform": "macosx",
|
||||
"build_type": "Release",
|
||||
"is_lto": false,
|
||||
"filename": "arm64-macosx-apple-release.tar.xz",
|
||||
"version": "20.1.5",
|
||||
"sha256": "47d89ed747b9946b4677ff902b5889b47d07b5cd92b0daf12db9abc6d284f955"
|
||||
},
|
||||
{
|
||||
"platform": "macosx",
|
||||
"build_type": "Release",
|
||||
"is_lto": true,
|
||||
"filename": "arm64-macosx-apple-release-lto.tar.xz",
|
||||
"version": "20.1.5",
|
||||
"sha256": "57a58adcc0a033acd66dbf8ed1f6bcf4f334074149e37bf803fc6bf022d419d2"
|
||||
}
|
||||
]
|
||||
@@ -1,265 +0,0 @@
|
||||
# build with multi-stage for cache efficiency
|
||||
FROM ubuntu:24.04 AS basic-tools
|
||||
|
||||
# allow build script to bind-mount project source into build container (host path)
|
||||
ARG BUILD_SRC
|
||||
|
||||
# set non-interactive frontend to avoid prompts
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
# ensure user-local bin is on PATH for non-apt installs (xmake, uv, python)
|
||||
ENV PATH="/root/.local/bin:${PATH}"
|
||||
|
||||
# install basic tools
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
# TODO: support more cache for python, xmake installation
|
||||
# TODO: check why cache doesn't work after add-apt-repository, may we change it to cache?
|
||||
bash -eux - <<'BASH'
|
||||
|
||||
set -e
|
||||
apt update
|
||||
# first install minimal apt prerequisites
|
||||
# software-properties-common for add-apt-repository
|
||||
# gnupg for gpg to verify cmake installer
|
||||
# curl, git for downloading sources
|
||||
# xz-utils, unzip for extracting archives
|
||||
# make for xmake installation
|
||||
apt install -y --no-install-recommends \
|
||||
software-properties-common \
|
||||
curl \
|
||||
gnupg \
|
||||
git \
|
||||
xz-utils \
|
||||
unzip \
|
||||
make
|
||||
|
||||
# gcc, llvm PPA
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/ppa
|
||||
apt update
|
||||
BASH
|
||||
|
||||
# Compiler stage
|
||||
FROM basic-tools AS compiler-stage
|
||||
|
||||
# passed from build arg
|
||||
ARG COMPILER
|
||||
|
||||
# copy instead of bind-mount, to avoid docker build cache invalidation
|
||||
COPY config/default-toolchain-version /clice/config/default-toolchain-version
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
bash -eux - <<'BASH'
|
||||
set -e
|
||||
|
||||
# Always install libstdc++ development files, required for both gcc and clang to link against libstdc++
|
||||
GCC_VERSION=$(grep -E '^gcc,' /clice/config/default-toolchain-version | cut -d',' -f2)
|
||||
apt install -y --no-install-recommends "libstdc++-${GCC_VERSION}-dev"
|
||||
|
||||
if [ "$COMPILER" = "gcc" ]; then
|
||||
apt install -y --no-install-recommends "gcc-${GCC_VERSION}" "g++-${GCC_VERSION}"
|
||||
update-alternatives --install /usr/bin/cc cc "/usr/bin/gcc-${GCC_VERSION}" 100
|
||||
update-alternatives --install /usr/bin/gcc gcc "/usr/bin/gcc-${GCC_VERSION}" 100
|
||||
update-alternatives --install /usr/bin/c++ c++ "/usr/bin/g++-${GCC_VERSION}" 100
|
||||
update-alternatives --install /usr/bin/g++ g++ "/usr/bin/g++-${GCC_VERSION}" 100
|
||||
elif [ "$COMPILER" = "clang" ]; then
|
||||
CLANG_VERSION=$(grep -E '^clang,' /clice/config/default-toolchain-version | cut -d',' -f2)
|
||||
# install clang toolchain, libstdc++ is already installed
|
||||
apt install -y --no-install-recommends "clang-${CLANG_VERSION}" "clang-tools-${CLANG_VERSION}" "lld-${CLANG_VERSION}" "libclang-rt-${CLANG_VERSION}-dev"
|
||||
update-alternatives --install /usr/bin/clang clang "/usr/bin/clang-${CLANG_VERSION}" 100
|
||||
update-alternatives --install /usr/bin/clang++ clang++ "/usr/bin/clang++-${CLANG_VERSION}" 100
|
||||
update-alternatives --install /usr/bin/c++ c++ "/usr/bin/clang++-${CLANG_VERSION}" 100
|
||||
update-alternatives --install /usr/bin/cc cc "/usr/bin/clang-${CLANG_VERSION}" 100
|
||||
update-alternatives --install /usr/bin/ld ld "/usr/bin/lld-${CLANG_VERSION}" 100
|
||||
else
|
||||
echo "Error: Unsupported compiler '$COMPILER'. Use 'gcc' or 'clang'." >&2; exit 1
|
||||
fi
|
||||
BASH
|
||||
|
||||
FROM compiler-stage AS build-tool-stage
|
||||
|
||||
ARG XMAKE_CACHE_DIR="/docker-build-cache/xmake"
|
||||
ARG CMAKE_CACHE_DIR="/docker-build-cache/cmake"
|
||||
ARG UV_CACHE_DIR="/var/cache/uv"
|
||||
|
||||
ENV XMAKE_CACHE_DIR=${XMAKE_CACHE_DIR}
|
||||
ENV CMAKE_CACHE_DIR=${CMAKE_CACHE_DIR}
|
||||
ENV UV_CACHE_DIR=${UV_CACHE_DIR}
|
||||
|
||||
COPY ./pyproject.toml /clice/pyproject.toml
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
--mount=type=cache,target=${XMAKE_CACHE_DIR},sharing=locked \
|
||||
--mount=type=cache,target=${CMAKE_CACHE_DIR},sharing=locked \
|
||||
--mount=type=cache,target=${UV_CACHE_DIR},sharing=locked \
|
||||
bash -eux - <<'BASH'
|
||||
|
||||
install_xmake() {
|
||||
set -e
|
||||
|
||||
XMAKE_VERSION=$(grep -E '^xmake,' /clice/config/default-toolchain-version | cut -d',' -f2)
|
||||
XMAKE_BASE_URL="https://github.com/xmake-io/xmake/releases/download/v${XMAKE_VERSION}"
|
||||
XMAKE_FILENAME="xmake-bundle-v${XMAKE_VERSION}.linux.x86_64"
|
||||
XMAKE_CACHED_FILE="${XMAKE_CACHE_DIR}/${XMAKE_FILENAME}"
|
||||
|
||||
if [ ! -f "${XMAKE_CACHED_FILE}" ] ; then
|
||||
rm -f "${XMAKE_CACHE_DIR}/*"
|
||||
curl -fsSL --retry 3 -o "${XMAKE_CACHED_FILE}" "${XMAKE_BASE_URL}/${XMAKE_FILENAME}"
|
||||
fi
|
||||
|
||||
XMAKE_INSTALL_DIR="/usr/bin"
|
||||
XMAKE_INSTALLED_FILE="${XMAKE_INSTALL_DIR}/${XMAKE_FILENAME}"
|
||||
|
||||
cp "${XMAKE_CACHED_FILE}" "${XMAKE_INSTALLED_FILE}"
|
||||
chmod +x "${XMAKE_INSTALLED_FILE}"
|
||||
|
||||
update-alternatives --install /usr/bin/xmake xmake "${XMAKE_INSTALLED_FILE}" 100
|
||||
|
||||
echo "export XMAKE_ROOT=y" >> ~/.bashrc
|
||||
}
|
||||
|
||||
# Attention: DO NOT install cmake via PPA with apt, which would have to install required build-essential compiler tool chain
|
||||
# We SHOULD NOT install another compiler toolchain, which could cause a lot trouble
|
||||
# And we should not install compiler toolchain away from compiler stage
|
||||
# So we install cmake from official installer script, and cache the downloaded files
|
||||
install_cmake() {
|
||||
set -e
|
||||
|
||||
# cached downloads live under /docker-build-cache/cmake (BuildKit cache mount)
|
||||
CMAKE_VERSION=$(grep -E '^cmake,' /clice/config/default-toolchain-version | cut -d',' -f2)
|
||||
ARCH="x86_64"
|
||||
|
||||
BASE_URL="https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}"
|
||||
INSTALLER_FILENAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh"
|
||||
SHA_FILENAME="cmake-${CMAKE_VERSION}-SHA-256.txt"
|
||||
ASC_FILENAME="${SHA_FILENAME}.asc"
|
||||
|
||||
INSTALLER_PATH="${CMAKE_CACHE_DIR}/${INSTALLER_FILENAME}"
|
||||
SHA_PATH="${CMAKE_CACHE_DIR}/${SHA_FILENAME}"
|
||||
ASC_PATH="${CMAKE_CACHE_DIR}/${ASC_FILENAME}"
|
||||
|
||||
verify_cmake_installer() {
|
||||
if ! gpg --verify "${ASC_PATH}" "${SHA_PATH}"; then
|
||||
echo "Signature verification failed for ${SHA_FILENAME}." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local expected_hash
|
||||
expected_hash=$(grep "${INSTALLER_FILENAME}" "${SHA_PATH}" | awk '{print $1}')
|
||||
|
||||
local actual_hash
|
||||
actual_hash=$(sha256sum "${INSTALLER_PATH}" | awk '{print $1}')
|
||||
if [ "${expected_hash}" != "${actual_hash}" ]; then
|
||||
echo "Checksum mismatch for ${INSTALLER_FILENAME}." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Checksum for ${INSTALLER_FILENAME} is valid."
|
||||
return 0
|
||||
}
|
||||
|
||||
gpg --keyserver keys.openpgp.org --recv-keys C6C265324BBEBDC350B513D02D2CEF1034921684
|
||||
|
||||
if [ ! -f "${INSTALLER_PATH}" ] || ! verify_cmake_installer; then
|
||||
rm -f "${CMAKE_CACHE_DIR}/*"
|
||||
|
||||
curl -fsSL --retry 3 -o "${INSTALLER_PATH}" "${BASE_URL}/${INSTALLER_FILENAME}"
|
||||
curl -fsSL --retry 3 -o "${SHA_PATH}" "${BASE_URL}/${SHA_FILENAME}"
|
||||
curl -fsSL --retry 3 -o "${ASC_PATH}" "${BASE_URL}/${ASC_FILENAME}"
|
||||
|
||||
if ! verify_cmake_installer; then
|
||||
echo "Verification of the downloaded installer failed. Cleaning cache." >&2
|
||||
rm -f "${CMAKE_CACHE_DIR}/*"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
sh "${INSTALLER_PATH}" --skip-license --prefix=/usr/local
|
||||
}
|
||||
|
||||
install_python() {
|
||||
set -e
|
||||
PYTHON_VERSION=$(grep -E '^python,' /clice/config/default-toolchain-version | cut -d',' -f2)
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
uv python install "${PYTHON_VERSION}"
|
||||
uv sync
|
||||
}
|
||||
|
||||
do_install() {
|
||||
set -e
|
||||
|
||||
cd /clice
|
||||
|
||||
export PATH="/root/.local/bin:${PATH}"
|
||||
echo "export XMAKE_ROOT=y" >> ~/.bashrc
|
||||
|
||||
install_cmake &
|
||||
install_xmake &
|
||||
install_python &
|
||||
|
||||
for job in $(jobs -p); do
|
||||
wait $job || exit 1
|
||||
done
|
||||
}
|
||||
|
||||
do_install
|
||||
|
||||
BASH
|
||||
|
||||
# download compile dependencies
|
||||
FROM build-tool-stage AS dependency-cache-stage
|
||||
|
||||
# passed from build arg
|
||||
# "lto" or "non_lto"
|
||||
ARG BUILD_SRC
|
||||
# ARG LTO_TYPE=""
|
||||
|
||||
RUN --mount=type=bind,src=./,target=/clice,rw \
|
||||
bash -eux - <<'BASH'
|
||||
|
||||
# cache_xmake_packages() {
|
||||
# set -e
|
||||
|
||||
# export PATH="/root/.local/bin:${PATH}"
|
||||
# export XMAKE_ROOT=y
|
||||
|
||||
# LTO_FLAG=""
|
||||
# if [ "$LTO_TYPE" = "lto" ]; then
|
||||
# LTO_FLAG="--release"
|
||||
# fi
|
||||
|
||||
# xmake f -y -v --mode=release ${LTO_FLAG}
|
||||
# xmake f -y -v --mode=debug ${LTO_FLAG}
|
||||
# }
|
||||
|
||||
do_prepare_dependency() {
|
||||
set -e
|
||||
|
||||
cd /clice
|
||||
|
||||
# cache_xmake_packages &
|
||||
|
||||
for job in $(jobs -p); do
|
||||
wait $job || exit 1
|
||||
done
|
||||
}
|
||||
|
||||
do_prepare_dependency
|
||||
|
||||
BASH
|
||||
|
||||
FROM dependency-cache-stage AS final
|
||||
|
||||
RUN bash -eux - <<'BASH'
|
||||
set -e
|
||||
# clice is mounted here, so remove everything to reduce image size
|
||||
rm -rf /clice
|
||||
|
||||
# disable git exception in cmake build when Fetch-Content
|
||||
git config --global --add safe.directory '*'
|
||||
BASH
|
||||
|
||||
WORKDIR /clice
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Save original working directory and switch to project root
|
||||
ORIG_PWD="$(pwd)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
echo "${SCRIPT_DIR}"
|
||||
cd "${SCRIPT_DIR}/../.."
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
|
||||
trap 'cd "${ORIG_PWD}"' EXIT
|
||||
|
||||
# default configurations
|
||||
COMPILER="clang"
|
||||
DOCKERFILE_PATH="docker/linux/Dockerfile"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [--compiler <gcc|clang>]
|
||||
|
||||
Defaults:
|
||||
--compiler ${COMPILER}
|
||||
EOF
|
||||
}
|
||||
|
||||
# parse command line arguments
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--compiler)
|
||||
COMPILER="$2"; shift 2;;
|
||||
-h|--help)
|
||||
usage; exit 0;;
|
||||
*)
|
||||
echo "Unknown parameter: $1" >&2; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
IMAGE_TAG="linux-${COMPILER}"
|
||||
IMAGE_NAME="clice-io/clice-dev:${IMAGE_TAG}"
|
||||
|
||||
echo "==========================================="
|
||||
echo "Building image: ${IMAGE_NAME}"
|
||||
echo "Compiler: ${COMPILER}"
|
||||
echo "Dockerfile: ${DOCKERFILE_PATH}"
|
||||
echo "==========================================="
|
||||
|
||||
# build the docker image with specified arguments
|
||||
# must run in clice root dir, so that we can mount the project in docker file to acquire essential files
|
||||
docker buildx build --progress=plain -t "${IMAGE_NAME}" \
|
||||
--build-arg COMPILER="${COMPILER}" \
|
||||
--build-arg BUILD_SRC="${PROJECT_ROOT}" \
|
||||
-f "${DOCKERFILE_PATH}" .
|
||||
|
||||
echo "Build complete. Image:${IMAGE_NAME}"
|
||||
@@ -1,87 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Save original working directory and switch to project root
|
||||
ORIG_PWD="$(pwd)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
echo "${SCRIPT_DIR}"
|
||||
cd "${SCRIPT_DIR}/../.."
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
|
||||
trap 'cd "${ORIG_PWD}"' EXIT
|
||||
|
||||
# default configurations
|
||||
COMPILER="clang"
|
||||
RESET="false"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [--compiler <gcc|clang>] [--reset]
|
||||
|
||||
Defaults:
|
||||
--compiler ${COMPILER}
|
||||
--reset (re-create the container)
|
||||
EOF
|
||||
}
|
||||
|
||||
# parse command line arguments
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--compiler)
|
||||
COMPILER="$2"; shift 2;;
|
||||
--reset)
|
||||
RESET="true"; shift 1;;
|
||||
-h|--help)
|
||||
usage; exit 0;;
|
||||
*) echo "Unknown parameter: $1"; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
IMAGE_TAG="linux-${COMPILER}"
|
||||
IMAGE_NAME="clice-io/clice-dev:${IMAGE_TAG}"
|
||||
CONTAINER_NAME="clice-dev-linux-${COMPILER}"
|
||||
|
||||
# If the image doesn't exist, build it automatically by invoking build.sh
|
||||
if ! docker image inspect "${IMAGE_NAME}" >/dev/null 2>&1; then
|
||||
echo "Image ${IMAGE_NAME} not found, invoking build.sh to create it..."
|
||||
./docker/linux/build.sh --compiler "${COMPILER}"
|
||||
fi
|
||||
|
||||
# Handle --reset: remove the existing container if it exists
|
||||
if [ "${RESET}" = "true" ]; then
|
||||
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||
echo "Resetting container: stopping and removing existing container ${CONTAINER_NAME}..."
|
||||
docker stop "${CONTAINER_NAME}" >/dev/null 2>&1 || true
|
||||
docker rm "${CONTAINER_NAME}" >/dev/null 2>&1
|
||||
echo "Container ${CONTAINER_NAME} has been removed."
|
||||
else
|
||||
echo "Container ${CONTAINER_NAME} does not exist, no need to reset."
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONTAINER_WORKDIR="/clice"
|
||||
|
||||
# Check if the container exists
|
||||
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||
echo "==========================================="
|
||||
echo "Attaching to existing container: ${CONTAINER_NAME}"
|
||||
echo "From image: ${IMAGE_NAME}"
|
||||
echo "Project mount: ${PROJECT_ROOT} -> ${CONTAINER_WORKDIR}"
|
||||
echo "==========================================="
|
||||
docker start "${CONTAINER_NAME}" >/dev/null
|
||||
docker exec -it -w "${CONTAINER_WORKDIR}" "${CONTAINER_NAME}" /bin/bash
|
||||
exit 0
|
||||
fi
|
||||
|
||||
DOCKER_RUN_ARGS=(-it -w "${CONTAINER_WORKDIR}")
|
||||
DOCKER_RUN_ARGS+=(--name "${CONTAINER_NAME}")
|
||||
DOCKER_RUN_ARGS+=(--mount "type=bind,src=${PROJECT_ROOT},target=${CONTAINER_WORKDIR}")
|
||||
|
||||
echo "==========================================="
|
||||
echo "Creating and running new container: ${CONTAINER_NAME}"
|
||||
echo "From image: ${IMAGE_NAME}"
|
||||
echo "Project mount: ${PROJECT_ROOT} -> ${CONTAINER_WORKDIR}"
|
||||
echo "==========================================="
|
||||
|
||||
docker run "${DOCKER_RUN_ARGS[@]}" "${IMAGE_NAME}"
|
||||
@@ -6,165 +6,77 @@
|
||||
- Linux
|
||||
- MacOS
|
||||
|
||||
## Prerequisites
|
||||
## Prerequisite
|
||||
|
||||
This section introduces the prerequisites for compiling clice.
|
||||
|
||||
### Toolchain
|
||||
|
||||
- clang >= 19
|
||||
- c++23 compatible standard library
|
||||
- cmake/xmake
|
||||
- clang, lld >= 20
|
||||
- c++23 **compatible** standard library
|
||||
- MSVC STL >= 19.44(VS 2022 17.4)
|
||||
- GCC libstdc++ >= 14
|
||||
- Clang libc++ >= 20
|
||||
|
||||
clice uses C++23 as the language standard. Please ensure you have an available clang 19 or above compiler, as well as a standard library compatible with C++23.
|
||||
clice uses C++23 as its language standard. Please ensure you have a clang 20 (or higher) compiler and a C++23 compatible standard library available. clice depends on lld as its linker. Please ensure your clang toolchain can find it (clang distributions usually bundle lld, or you may need to install the lld-20 package separately).
|
||||
|
||||
> clice can currently only be compiled with clang. In the future, we will improve this to allow compilation with gcc and msvc.
|
||||
> clice is currently only guaranteed to compile with clang (as ensured by CI testing). We do our best to maintain compatibility with gcc and msvc, but we do not add corresponding tests in CI. Contributions are welcome if you encounter any issues.
|
||||
|
||||
### LLVM Libs
|
||||
## CMake
|
||||
|
||||
- 20.1.5 <= llvm libs < 21
|
||||
Use the following commands to build clice
|
||||
|
||||
Due to the complexity of C++ syntax, writing a new parser from scratch is unrealistic. clice calls clang's API to parse C++ source files and obtain AST, which means it needs to link llvm/clang libs. Additionally, since clice uses clang's private headers, these private headers are not available in llvm's binary release, so you cannot directly use the system's llvm package.
|
||||
```shell
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
If you can find the llvm commit corresponding to your system's llvm package, copy the following three files from that commit:
|
||||
Optional build options:
|
||||
|
||||
- `clang/lib/Sema/CoroutineStmtBuilder.h`
|
||||
- `clang/lib/Sema/TypeLocBuilder.h`
|
||||
- `clang/lib/Sema/TreeTransform.h`
|
||||
| Option | Default | Description |
|
||||
| :------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| LLVM_INSTALL_PATH | "" | Build clice using llvm libs from a custom path |
|
||||
| CLICE_ENABLE_TEST | OFF | Whether to build clice's unit tests |
|
||||
| CLICE_USE_LIBCXX | OFF | Whether to build clice with libc++ (adds `-std=libc++`). If enabled, ensure that the llvm libs were also compiled with libc++. |
|
||||
| CLICE_CI_ENVIRONMENT | OFF | Whether to enable the `CLICE_CI_ENVIRONMENT` macro. Some tests only run in a CI environment. |
|
||||
|
||||
Copy them to `LLVM_INSTALL_PATH/include/clang/Sema/`.
|
||||
## XMake
|
||||
|
||||
Besides this method, there are two other ways to obtain the llvm libs required by clice:
|
||||
|
||||
1. Use our precompiled version
|
||||
Use the following commands to build clice
|
||||
|
||||
```bash
|
||||
# .github/workflows/cmake.yml
|
||||
|
||||
# Linux precompiled binary require glibc 2.35 (build on ubuntu 22.04)
|
||||
$ mkdir -p ./.llvm
|
||||
$ curl -L "https://github.com/clice-io/llvm-binary/releases/download/20.1.5/x86_64-linux-gnu-release.tar.xz" | tar -xJ -C ./.llvm
|
||||
|
||||
# MacOS precompiled binary require macos15+
|
||||
$ mkdir -p ./.llvm
|
||||
$ curl -L "https://github.com/clice-io/llvm-binary/releases/download/20.1.5/arm64-macosx-apple-release.tar.xz" | tar -xJ -C ./.llvm
|
||||
|
||||
# Windows precompiled binary only MD runtime support
|
||||
$ curl -O -L "https://github.com/clice-io/llvm-binary/releases/download/20.1.5/x64-windows-msvc-release.7z"
|
||||
$ 7z x x64-windows-msvc-release.7z "-o.llvm"
|
||||
xmake f -c --mode=releasedbg --toolchain=clang
|
||||
xmake build --all
|
||||
```
|
||||
|
||||
Optional build options:
|
||||
|
||||
| Option | Default | Description |
|
||||
| :------------ | :------ | :--------------------------------------------- |
|
||||
| --llvm | "" | Build clice using llvm libs from a custom path |
|
||||
| --enable_test | false | Whether to build clice's unit tests |
|
||||
| --ci | false | Whether to enable `CLICE_CI_ENVIRONMENT` |
|
||||
|
||||
## A Note on LLVM Libs
|
||||
|
||||
Due to the complexity of C++ syntax, writing a new parser from scratch is unrealistic. clice calls clang's APIs to parse C++ source files and obtain the AST, which means it needs to link against llvm/clang libs. Because clice uses clang's private headers, which are not included in the binary releases published by LLVM, you cannot use the system's llvm package directly.
|
||||
|
||||
1. We publish pre-compiled binaries for the LLVM version we use on [clice-llvm](https://github.com/clice-io/clice-llvm/releases), which are used for CI or release builds. By default, cmake and xmake will download and use the llvm libs from here during the build.
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> For debug versions of llvm libs, we enabled address sanitizer during build, and address sanitizer depends on compiler rt, which is very sensitive to compiler versions. So if using debug versions, please ensure your clang's compiler rt version is **strictly consistent** with what we used during build.
|
||||
> For debug builds of llvm libs, we enable address sanitizer. Address sanitizer depends on compiler-rt, which is highly sensitive to the compiler version.
|
||||
>
|
||||
> - Windows currently has no debug build of llvm libs because it doesn't support building clang as a dynamic library. Related progress can be found [here](https://discourse.llvm.org/t/llvm-is-buildable-as-a-windows-dll/87748)
|
||||
> Therefore, if you use a debug build, please ensure your clang's compiler-rt version is **strictly identical** to the one used in our build.
|
||||
>
|
||||
> - Windows does not currently have debug builds for llvm libs, as it does not support building clang as a dynamic library. Related progress is tracked [here](https://github.com/clice-io/clice/issues/42).
|
||||
> - Linux uses clang20
|
||||
> - MacOS uses homebrew llvm@20, definitely don't use apple clang
|
||||
> - MacOS uses homebrew llvm@20. **Do not use apple clang**.
|
||||
>
|
||||
> You can refer to the [cmake](https://github.com/clice-io/clice/blob/main/.github/workflows/cmake.yml) and [xmake](https://github.com/clice-io/clice/blob/main/.github/workflows/xmake.yml) files in our CI as a reference, as they maintain an environment strictly consistent with the pre-compiled llvm libs.
|
||||
|
||||
2. Compile llvm/clang from scratch
|
||||
|
||||
This is the most recommended approach, ensuring environment consistency and avoiding crash issues caused by ABI inconsistencies. We provide a script for building the llvm libs required by clice: [build-llvm-libs.py](https://github.com/clice-io/clice/blob/main/scripts/build-llvm-libs.py).
|
||||
2. Build llvm/clang yourself to match your current environment. If the default pre-compiled binaries (Method 1) fail to run on your system due to ABI or library version (e.g., glibc) incompatibility, or if you need a custom Debug build, we recommend you use this method to compile llvm libs from scratch. We provide a script to build the llvm libs required by clice: [build-llvm-libs.py](https://github.com/clice-io/clice/blob/main/scripts/build-llvm-libs.py).
|
||||
|
||||
```bash
|
||||
$ cd llvm-project
|
||||
$ python3 <clice>/scripts/build-llvm-libs.py debug
|
||||
cd llvm-project
|
||||
python3 <clice>/scripts/build-llvm-libs.py debug
|
||||
```
|
||||
|
||||
You can also refer to llvm's official build tutorial [Building LLVM with CMake](https://llvm.org/docs/CMake.html).
|
||||
|
||||
### GCC Toolchain
|
||||
|
||||
clice requires GCC libstdc++ >= 14. You could use a different GCC toolchain and also link statically against its libstdc++:
|
||||
|
||||
```bash
|
||||
cmake .. -DCMAKE_C_FLAGS="--gcc-toolchain=/usr/local/gcc-14.3.0/" \
|
||||
-DCMAKE_CXX_FLAGS="--gcc-toolchain=/usr/local/gcc-14.3.0/" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++"
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
After handling the prerequisites, you can start building clice. We provide two build methods: cmake/xmake.
|
||||
|
||||
### CMake
|
||||
|
||||
Below are the cmake parameters supported by clice:
|
||||
|
||||
- `LLVM_INSTALL_PATH` specifies the installation path of llvm libs
|
||||
- `CLICE_ENABLE_TEST` whether to build clice's unit tests
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
$ cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_INSTALL_PATH="./.llvm" -DCLICE_ENABLE_TEST=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
$ cmake --build build
|
||||
```
|
||||
|
||||
### Xmake
|
||||
|
||||
Use the following command to build clice:
|
||||
|
||||
```bash
|
||||
$ xmake f -c --dev=true --mode=debug --toolchain=clang --llvm="./.llvm" --enable_test=true
|
||||
$ xmake build --all
|
||||
```
|
||||
|
||||
> --llvm is optional. If not specified, xmake will automatically download our precompiled binary
|
||||
|
||||
## Building Docker Image
|
||||
|
||||
Use the following command to build docker image:
|
||||
|
||||
```bash
|
||||
$ docker build -t clice .
|
||||
```
|
||||
|
||||
Run docker image by running the following command:
|
||||
|
||||
```bash
|
||||
$ docker run --rm -it clice --help
|
||||
OVERVIEW: clice is a new generation of language server for C/C++
|
||||
...
|
||||
```
|
||||
|
||||
The directory structure of the docker image is as follows:
|
||||
|
||||
```
|
||||
/opt/clice
|
||||
├── bin
|
||||
│ ├── clice -> /usr/local/bin/clice
|
||||
├── include
|
||||
├── lib
|
||||
├── LICENSE
|
||||
├── README.md
|
||||
```
|
||||
|
||||
Hint: launch clice in the docker container by running the following command:
|
||||
|
||||
```bash
|
||||
$ docker run --rm -it --entrypoint bash clice
|
||||
```
|
||||
|
||||
## Development Container
|
||||
|
||||
We provide Docker images as a pre-configured environment to streamline the setup process. You can use the following scripts to manage the development container. These scripts can be run from the project root directory.
|
||||
|
||||
```bash
|
||||
# Build the development image
|
||||
./docker/linux/build.sh
|
||||
|
||||
# Run the container with the clang toolchain
|
||||
./docker/linux/run.sh --compiler clang
|
||||
|
||||
# Run the container with the gcc toolchain
|
||||
./docker/linux/run.sh --compiler gcc
|
||||
|
||||
# Reset the container (stops and removes the existing one)
|
||||
./docker/linux/run.sh --reset
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> This feature is currently in a preview stage and only supports Linux. Windows support will be provided in the future, and the functionality may be subject to change.
|
||||
You can also refer to LLVM's official build tutorial: [Building LLVM with CMake](https://llvm.org/docs/CMake.html).
|
||||
|
||||
@@ -58,4 +58,5 @@ struct Widget {
|
||||
|
||||
template <typename T>
|
||||
Widget(T) -> Widget<typename T::value_type>;
|
||||
|
||||
} // namespace foo
|
||||
|
||||
@@ -8,159 +8,74 @@
|
||||
|
||||
## Prerequisite
|
||||
|
||||
本小节介绍编译 clice 的前置依赖。
|
||||
|
||||
### Toolchain
|
||||
|
||||
- clang >= 19
|
||||
- c++23 compitable standard library
|
||||
- cmake/xmake
|
||||
- clang, lld >= 20
|
||||
- c++23 **compatible** standard library
|
||||
- MSVC STL >= 19.44(VS 2022 17.4)
|
||||
- GCC libstdc++ >= 14
|
||||
- Clang libc++ >= 20
|
||||
|
||||
clice 使用 C++23 作为语言标准 ,请确保有可用的 clang 19 以及以上的编译器,以及兼容 C++23 的标准库。
|
||||
clice 使用 C++23 作为语言标准,请确保有可用的 clang 20 以及以上的编译器,以及兼容 C++23 的标准库。clice 依赖 lld 作为链接器。请确保你的 clang 工具链可以找到它(通常 clang 发行版会自带 lld,或者你需要单独安装 lld-20 包)。
|
||||
|
||||
> clice 暂时只能使用 clang 编译,在未来我们会改进这一点,使其能使用 gcc 和 msvc 编译。
|
||||
> clice 目前只保证能使用 clang 编译(CI 测试保证)。对于 gcc 和 msvc 的兼容,我们尽力而为,但不会在 CI 中添加对应的测试。如果遇到任何问题,欢迎贡献。
|
||||
|
||||
### LLVM Libs
|
||||
## CMake
|
||||
|
||||
- 20.1.5 <= llvm libs < 21
|
||||
使用如下的命令构建 clice
|
||||
|
||||
由于 C++ 的语法太过复杂,自己编写一个新的 parser 是不现实的。clice 调用 clang 的 API 来 parse C++ 源文件获取 AST,这意味它需要链接 llvm/clang libs。另外由于 clice 使用了 clang 的私有头文件,这些私有头文件在 llvm 发布的 binary release 中是没有的,所以不能直接使用系统的 llvm package。
|
||||
```shell
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
如果你能找到系统的 llvm package 对应的 llvm commit,将该 commit 下的如下三个文件
|
||||
可选的构建选项:
|
||||
|
||||
- `clang/lib/Sema/CoroutineStmtBuilder.h`
|
||||
- `clang/lib/Sema/TypeLocBuilder.h`
|
||||
- `clang/lib/Sema/TreeTransform.h`
|
||||
| 选项 | 默认值 | 效果 |
|
||||
| -------------------- | ------ | ----------------------------------------------------------------------------------------------------- |
|
||||
| LLVM_INSTALL_PATH | "" | 使用自定义路径的 llvm libs 来构建 clice |
|
||||
| CLICE_ENABLE_TEST | OFF | 是否构建 clice 的单元测试 |
|
||||
| CLICE_USE_LIBCXX | OFF | 是否使用 libc++ 来构建 clice(添加 `-std=libc++`),如果开启,请确保 llvm libs 也是使用 libc++ 编译的 |
|
||||
| CLICE_CI_ENVIRONMENT | OFF | 是否打开 `CLICE_CI_ENVIRONMENT` 这个宏,有些测试在 CI 环境才会执行 |
|
||||
|
||||
拷贝到 `LLVM_INSTALL_PATH/include/clang/Sema/` 中即可。
|
||||
## XMake
|
||||
|
||||
除了这种方法以外,还有两种办法获取 clice 所需的 llvm libs:
|
||||
|
||||
1. 使用我们提供的预编译版本
|
||||
使用如下的命令即可构建 clice
|
||||
|
||||
```bash
|
||||
# .github/workflows/cmake.yml
|
||||
|
||||
# Linux precompiled binary require glibc 2.35 (build on ubuntu 22.04)
|
||||
$ mkdir -p ./.llvm
|
||||
$ curl -L "https://github.com/clice-io/llvm-binary/releases/download/20.1.5/x86_64-linux-gnu-release.tar.xz" | tar -xJ -C ./.llvm
|
||||
|
||||
# MacOS precompiled binary require macos15+
|
||||
$ mkdir -p ./.llvm
|
||||
$ curl -L "https://github.com/clice-io/llvm-binary/releases/download/20.1.5/arm64-macosx-apple-release.tar.xz" | tar -xJ -C ./.llvm
|
||||
|
||||
# Windows precompiled binary only MD runtime support
|
||||
$ curl -O -L "https://github.com/clice-io/llvm-binary/releases/download/20.1.5/x64-windows-msvc-release.7z"
|
||||
$ 7z x x64-windows-msvc-release.7z "-o.llvm"
|
||||
xmake f -c --mode=releasedbg --toolchain=clang
|
||||
xmake build --all
|
||||
```
|
||||
|
||||
可选的构建选项:
|
||||
|
||||
| 选项 | 默认值 | 效果 |
|
||||
| ------------- | ------ | --------------------------------------- |
|
||||
| --llvm | "" | 使用自定义路径的 llvm libs 来构建 clice |
|
||||
| --enable_test | false | 是否构建 clice 的单元测试 |
|
||||
| --ci | false | 是否打开 `CLICE_CI_ENVIRONMENT` |
|
||||
|
||||
|
||||
## A Note on LLVM Libs
|
||||
|
||||
由于 C++ 的语法太过复杂,自己编写一个新的 parser 是不现实的。clice 调用 clang 的 API 来 parse C++ 源文件获取 AST,这意味它需要链接 llvm/clang libs。由于 clice 使用了 clang 的私有头文件,这些私有头文件在 llvm 发布的 binary release 中是没有的,所以不能直接使用系统的 llvm package。
|
||||
|
||||
1. 我们在 [clice-llvm](https://github.com/clice-io/clice-llvm/releases) 上会发布使用的 llvm 版本的预编译二进制,用于 CI 或者 release 构建。在构建时 cmake 和 xmake 默认会从此处下载 llvm libs 然后使用,
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> 对于 debug 版本的 llvm libs,构建的时候我们开启了 address sanitizer,而 address sanitizer 依赖于 compiler rt,它对编译器版本十分敏感。所以如果使用 debug 版本,请确保你的 clang 的 compiler rt 版本和我们构建的时候**严格一致**。
|
||||
>
|
||||
> - Windows 暂时无 debug 构建的 llvm libs,因为它不支持将 clang 构建为动态库,相关的进展可以在 [这里](https://discourse.llvm.org/t/llvm-is-buildable-as-a-windows-dll/87748) 找到
|
||||
> - Windows 暂时没有 debug 构建的 llvm libs,因为它不支持将 clang 构建为动态库,相关的进展在 [这里](https://github.com/clice-io/clice/issues/42) 跟踪
|
||||
> - Linux 使用 clang20
|
||||
> - MacOS 使用 homebrew llvm@20,一定不要使用 apple clang
|
||||
> - MacOS 使用 homebrew llvm@20,**不要使用 apple clang**
|
||||
>
|
||||
> 可以参考 CI 中的 [cmake](https://github.com/clice-io/clice/blob/main/.github/workflows/cmake.yml) 和 [xmake](https://github.com/clice-io/clice/blob/main/.github/workflows/xmake.yml) 文件作为参考,它们与预编译 llvm libs 的环境保持严格一致。
|
||||
|
||||
2. 自己从头编译 llvm/clang
|
||||
|
||||
这是最推荐的方式,可以保证环境一致性,避免因为 ABI 不一致而导致的崩溃问题。我们提供了一个脚本,用于构建 clice 所需要的 llvm libs:[build-llvm-libs.py](https://github.com/clice-io/clice/blob/main/scripts/build-llvm-libs.py)。
|
||||
2. 自己重新一个与当前环境一致的 llvm/clang。如果默认的预编译二进制文件(方法 1)在你的系统上因 ABI 或库版本(如 glibc)不兼容而运行失败,或者你需要一个自定义的 Debug 版本,那么我们推荐你使用此方法从头编译 llvm libs。我们提供了一个脚本,用于构建 clice 所需要的 llvm libs:[build-llvm-libs.py](https://github.com/clice-io/clice/blob/main/scripts/build-llvm-libs.py)。
|
||||
|
||||
```bash
|
||||
$ cd llvm-project
|
||||
$ python3 <clice>/scripts/build-llvm-libs.py debug
|
||||
cd llvm-project
|
||||
python3 <clice>/scripts/build-llvm-libs.py debug
|
||||
```
|
||||
|
||||
也可以参考 llvm 的官方构建教程 [Building LLVM with CMake](https://llvm.org/docs/CMake.html)。
|
||||
|
||||
### GCC Toolchain
|
||||
|
||||
clice 要求 GCC libstdc++ >= 14。以下命令使用不同的 GCC 工具链并静态链接其 libstdc++:
|
||||
|
||||
```bash
|
||||
cmake .. -DCMAKE_C_FLAGS="--gcc-toolchain=/usr/local/gcc-14.3.0/" \
|
||||
-DCMAKE_CXX_FLAGS="--gcc-toolchain=/usr/local/gcc-14.3.0/" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++"
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
在处理好前置依赖之后,可以开始构建 clice 了,我们提供 cmake/xmake 两种构建方式。
|
||||
|
||||
### CMake
|
||||
|
||||
下面是 clice 支持的 cmake 参数
|
||||
|
||||
- `LLVM_INSTALL_PATH` 用于指定 llvm libs 的安装路径
|
||||
- `CLICE_ENABLE_TEST` 是否构建 clice 的单元测试
|
||||
|
||||
例如
|
||||
|
||||
```bach
|
||||
$ cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_INSTALL_PATH="./.llvm" -DCLICE_ENABLE_TEST=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
$ cmake --build build
|
||||
```
|
||||
|
||||
### Xmake
|
||||
|
||||
使用如下的命令即可构建 clice
|
||||
|
||||
```bash
|
||||
$ xmake f -c --dev=true --mode=debug --toolchain=clang --llvm="./.llvm" --enable_test=true
|
||||
$ xmake build --all
|
||||
```
|
||||
|
||||
> --llvm 是可选的,如果不指定的话,xmake 会自动下载我们编译好的预编译二进制
|
||||
|
||||
## Dev Container
|
||||
|
||||
我们提供了 docker 镜像作为预装环境解决方案,可以有效地解决环境配置问题,可通过下列命令使用(不限脚本调用路径,可以直接运行 ./build.sh):
|
||||
|
||||
```bash
|
||||
# construct container
|
||||
docker/linux/build.sh
|
||||
# run clang container
|
||||
docker/linux/run.sh --compiler clang
|
||||
# run gcc container
|
||||
docker/linux/run.sh --compiler gcc
|
||||
# reset container(delete exist container and reset)
|
||||
docker/linux/run.sh --reset
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> 当前该功能仍处于 Preview 阶段,仅支持 Linux,后续会提供 Windows 平台版本,并可能存在功能改动
|
||||
|
||||
## Building Docker Image
|
||||
|
||||
使用以下命令构建 docker 镜像:
|
||||
|
||||
```bash
|
||||
$ docker build -t clice .
|
||||
```
|
||||
|
||||
运行 docker 镜像:
|
||||
|
||||
```bash
|
||||
$ docker run --rm -it clice --help
|
||||
OVERVIEW: clice is a new generation of language server for C/C++
|
||||
...
|
||||
```
|
||||
|
||||
docker 镜像的目录结构如下:
|
||||
|
||||
```
|
||||
/opt/clice
|
||||
├── bin
|
||||
│ ├── clice -> /usr/local/bin/clice
|
||||
├── include
|
||||
├── lib
|
||||
├── LICENSE
|
||||
├── README.md
|
||||
```
|
||||
|
||||
提示:可以使用以下命令进入 clice 容器:
|
||||
|
||||
```bash
|
||||
$ docker run --rm -it --entrypoint bash clice
|
||||
|
||||
3
editors/nvim/README.md
Normal file
3
editors/nvim/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# clice-nvim
|
||||
|
||||
Provide extended functionality for [clice](https://github.com/clice-io/clice)
|
||||
32
editors/nvim/doc/clice.lua
Normal file
32
editors/nvim/doc/clice.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
-- Should be placed under config_dir/lsp/
|
||||
-- Lsp configuration for nvim >= 0.11
|
||||
|
||||
local clice = {
|
||||
filetypes = { 'c', 'cpp' },
|
||||
|
||||
root_markers = {
|
||||
'.git/',
|
||||
'clice.toml',
|
||||
'.clang-tidy',
|
||||
'.clang-format',
|
||||
'compile_commands.json',
|
||||
'compile_flags.txt',
|
||||
'configure.ac', -- AutoTools
|
||||
},
|
||||
|
||||
capabilities = {
|
||||
textDocument = {
|
||||
completion = {
|
||||
editsNearCursor = true,
|
||||
},
|
||||
},
|
||||
offsetEncoding = { 'utf-8' },
|
||||
},
|
||||
|
||||
cmd = {
|
||||
'clice',
|
||||
'--mode=pipe',
|
||||
},
|
||||
}
|
||||
|
||||
return clice
|
||||
3
editors/nvim/plugin/clice-nvim.lua
Normal file
3
editors/nvim/plugin/clice-nvim.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
local augroup = vim.api.nvim_create_augroup('LspClice', { clear = true })
|
||||
|
||||
-- TODO: CallHierarchy, TypeHierarchy, LspDump?, ShowHeaderContext?
|
||||
6
editors/nvim/stylua.toml
Normal file
6
editors/nvim/stylua.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
column_width = 160
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 4
|
||||
quote_style = "AutoPreferSingle"
|
||||
call_parentheses = "None"
|
||||
30
editors/vscode/.eslintrc.json
Normal file
30
editors/vscode/.eslintrc.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"warn",
|
||||
{
|
||||
"selector": "import",
|
||||
"format": [ "camelCase", "PascalCase" ]
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/semi": "warn",
|
||||
"curly": "warn",
|
||||
"eqeqeq": "warn",
|
||||
"no-throw-literal": "warn",
|
||||
"semi": "off"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"out",
|
||||
"dist",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
5
editors/vscode/.vscode-test.mjs
Normal file
5
editors/vscode/.vscode-test.mjs
Normal file
@@ -0,0 +1,5 @@
|
||||
import { defineConfig } from '@vscode/test-cli';
|
||||
|
||||
export default defineConfig({
|
||||
files: 'out/test/**/*.test.js',
|
||||
});
|
||||
5
editors/vscode/.vscode/extensions.json
vendored
Normal file
5
editors/vscode/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher", "ms-vscode.extension-test-runner"]
|
||||
}
|
||||
21
editors/vscode/.vscode/launch.json
vendored
Normal file
21
editors/vscode/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "${defaultBuildTask}"
|
||||
}
|
||||
]
|
||||
}
|
||||
13
editors/vscode/.vscode/settings.json
vendored
Normal file
13
editors/vscode/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.exclude": {
|
||||
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
||||
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
|
||||
},
|
||||
"search.exclude": {
|
||||
"out": true, // set this to false to include "out" folder in search results
|
||||
"dist": true // set this to false to include "dist" folder in search results
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
||||
40
editors/vscode/.vscode/tasks.json
vendored
Normal file
40
editors/vscode/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch",
|
||||
"problemMatcher": "$ts-webpack-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"group": "watchers"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch-tests",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"group": "watchers"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "tasks: watch-tests",
|
||||
"dependsOn": [
|
||||
"npm: watch",
|
||||
"npm: watch-tests"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
15
editors/vscode/.vscodeignore
Normal file
15
editors/vscode/.vscodeignore
Normal file
@@ -0,0 +1,15 @@
|
||||
.github/
|
||||
.vscode/**
|
||||
.vscode-test/**
|
||||
out/**
|
||||
node_modules/**
|
||||
src/**
|
||||
.gitignore
|
||||
.yarnrc
|
||||
webpack.config.js
|
||||
vsc-extension-quickstart.md
|
||||
**/tsconfig.json
|
||||
**/.eslintrc.json
|
||||
**/*.map
|
||||
**/*.ts
|
||||
**/.vscode-test.*
|
||||
201
editors/vscode/LICENSE
Normal file
201
editors/vscode/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
19
editors/vscode/README.md
Normal file
19
editors/vscode/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# vscode-clice
|
||||
|
||||
This is the vscode extension for [clice](https://github.com/clice-project/clice).
|
||||
|
||||
## develop
|
||||
|
||||
- install dependencies
|
||||
|
||||
```shell
|
||||
git clone https://github.com/clice-io/clice.git
|
||||
cd clice/editors/vscode
|
||||
npm install
|
||||
```
|
||||
|
||||
- package
|
||||
|
||||
```shell
|
||||
npm run package
|
||||
```
|
||||
BIN
editors/vscode/clice.png
Normal file
BIN
editors/vscode/clice.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
5182
editors/vscode/package-lock.json
generated
Normal file
5182
editors/vscode/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
174
editors/vscode/package.json
Normal file
174
editors/vscode/package.json
Normal file
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"name": "clice-vscode",
|
||||
"displayName": "clice",
|
||||
"description": "VSCode extension for clice",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/clice-project/clice-vscode"
|
||||
},
|
||||
"version": "0.1.4",
|
||||
"publisher": "ykiko",
|
||||
"icon": "clice.png",
|
||||
"engines": {
|
||||
"vscode": "^1.80.0"
|
||||
},
|
||||
"categories": [
|
||||
"Programming Languages",
|
||||
"Linters",
|
||||
"Formatters"
|
||||
],
|
||||
"keywords": [
|
||||
"C",
|
||||
"C++",
|
||||
"cuda",
|
||||
"clang"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:c",
|
||||
"onLanguage:cpp",
|
||||
"onLanguage:cuda-cpp"
|
||||
],
|
||||
"contributes": {
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "C/C++ Language Client",
|
||||
"properties": {
|
||||
"clice-client.trace.server": {
|
||||
"default": "verbose"
|
||||
},
|
||||
"clice.executable": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "The path of clice executable."
|
||||
},
|
||||
"clice.mode": {
|
||||
"type": "string",
|
||||
"default": "pipe",
|
||||
"enum": [
|
||||
"pipe",
|
||||
"socket"
|
||||
],
|
||||
"description": "How to communicate with clice. pipe or socket. For daily use please use pipe."
|
||||
},
|
||||
"clice.host": {
|
||||
"type": "string",
|
||||
"default": "127.0.0.1",
|
||||
"description": "The host to connect to (default: 127.0.0.1)"
|
||||
},
|
||||
"clice.port": {
|
||||
"type": "number",
|
||||
"default": 50051,
|
||||
"description": "The port to connect to"
|
||||
}
|
||||
}
|
||||
},
|
||||
"commands": [],
|
||||
"semanticTokenTypes": [
|
||||
{
|
||||
"id": "character",
|
||||
"description": "C/C++ character literal (e.g., 'a')",
|
||||
"superType": "string"
|
||||
},
|
||||
{
|
||||
"id": "directive",
|
||||
"description": "C/C++ preprocessor directive (e.g., #include)",
|
||||
"superType": "keyword"
|
||||
},
|
||||
{
|
||||
"id": "header",
|
||||
"description": "C/C++ header name (e.g., <iostream>)",
|
||||
"superType": "string"
|
||||
},
|
||||
{
|
||||
"id": "module",
|
||||
"description": "C++20 module name",
|
||||
"superType": "namespace"
|
||||
},
|
||||
{
|
||||
"id": "macroParameter",
|
||||
"description": "C/C++ macro parameter",
|
||||
"superType": "parameter"
|
||||
},
|
||||
{
|
||||
"id": "union",
|
||||
"description": "C/C++ union type",
|
||||
"superType": "struct"
|
||||
},
|
||||
{
|
||||
"id": "field",
|
||||
"description": "C/C++ field (member variable)",
|
||||
"superType": "variable"
|
||||
},
|
||||
{
|
||||
"id": "label",
|
||||
"description": "C/C++ label (for goto)",
|
||||
"superType": "variable"
|
||||
},
|
||||
{
|
||||
"id": "concept",
|
||||
"description": "C++20 concept",
|
||||
"superType": "type"
|
||||
},
|
||||
{
|
||||
"id": "attribute",
|
||||
"description": "GNU/MSVC/C++11/C23 attribute",
|
||||
"superType": "macro"
|
||||
},
|
||||
{
|
||||
"id": "paren",
|
||||
"description": "Parentheses `()`",
|
||||
"superType": "operator"
|
||||
},
|
||||
{
|
||||
"id": "bracket",
|
||||
"description": "Brackets `[]`",
|
||||
"superType": "operator"
|
||||
},
|
||||
{
|
||||
"id": "brace",
|
||||
"description": "Braces `{}`",
|
||||
"superType": "operator"
|
||||
},
|
||||
{
|
||||
"id": "angle",
|
||||
"description": "Angle brackets `<>`",
|
||||
"superType": "operator"
|
||||
}
|
||||
]
|
||||
},
|
||||
"main": "./dist/extension.js",
|
||||
"scripts": {
|
||||
"compile": "webpack",
|
||||
"watch": "webpack --watch",
|
||||
"vscode:prepublish": "webpack --mode production --devtool hidden-source-map",
|
||||
"package": "vsce package --baseImagesUrl https://raw.githubusercontent.com/clice-project/clice-vscode/main/",
|
||||
"publish": "vsce publish --baseImagesUrl https://raw.githubusercontent.com/clice-project/clice-vscode/main/",
|
||||
"pretest": "npm run compile && npm run lint",
|
||||
"lint": "eslint src --ext ts",
|
||||
"test": "vscode-test",
|
||||
"release:patch": "npm version patch -m \"release: v%s\" && git push --follow-tags",
|
||||
"release:minor": "npm version minor -m \"release: v%s\" && git push --follow-tags"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/decompress": "^4.2.7",
|
||||
"@types/mocha": "^10.0.7",
|
||||
"@types/node": "20.x",
|
||||
"@types/vscode": "^1.80.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
||||
"@typescript-eslint/parser": "^7.11.0",
|
||||
"@vscode/test-cli": "^0.0.12",
|
||||
"@vscode/test-electron": "^2.4.0",
|
||||
"eslint": "^8.57.0",
|
||||
"ts-loader": "^9.5.1",
|
||||
"typescript": "^5.4.5",
|
||||
"webpack": "^5.92.1",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"decompress": "^4.2.1",
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
},
|
||||
"overrides": {
|
||||
"glob": "^11.1.0"
|
||||
}
|
||||
}
|
||||
224
editors/vscode/src/download.ts
Normal file
224
editors/vscode/src/download.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as https from 'https';
|
||||
import * as os from 'os';
|
||||
// @ts-ignore
|
||||
import decompress = require('decompress');
|
||||
|
||||
interface GitHubRelease {
|
||||
tag_name: string;
|
||||
assets: {
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
|
||||
export async function ensureServerBinary(
|
||||
context: vscode.ExtensionContext,
|
||||
channel: vscode.OutputChannel
|
||||
): Promise<string | undefined> {
|
||||
|
||||
const storagePath = context.globalStorageUri.fsPath;
|
||||
const platform = os.platform();
|
||||
const arch = os.arch();
|
||||
|
||||
channel.appendLine(`[Download] Initializing clice downloader...`);
|
||||
channel.appendLine(`[Download] Platform: ${platform}, Arch: ${arch}, Storage: ${storagePath}`);
|
||||
|
||||
let platformKeyword = '';
|
||||
let archKeyword = '';
|
||||
let binaryName = 'clice';
|
||||
|
||||
if (platform === 'win32') {
|
||||
platformKeyword = 'windows';
|
||||
archKeyword = 'x64';
|
||||
binaryName = 'clice.exe';
|
||||
} else if (platform === 'darwin') {
|
||||
platformKeyword = 'macos';
|
||||
archKeyword = arch;
|
||||
} else if (platform === 'linux') {
|
||||
platformKeyword = 'linux';
|
||||
archKeyword = arch === 'x64' ? 'x86_64' : arch;
|
||||
} else {
|
||||
const msg = `Unsupported platform: ${platform}`;
|
||||
channel.appendLine(`[Download] Error: ${msg}`);
|
||||
vscode.window.showErrorMessage(msg);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const executablePath = path.join(storagePath, "bin", binaryName);
|
||||
|
||||
if (fs.existsSync(executablePath)) {
|
||||
channel.appendLine(`[Download] Found existing binary at: ${executablePath}`);
|
||||
// TODO: check tag update
|
||||
return executablePath;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(storagePath)) {
|
||||
channel.appendLine(`[Download] Creating storage directory: ${storagePath}`);
|
||||
fs.mkdirSync(storagePath, { recursive: true });
|
||||
}
|
||||
|
||||
const statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
|
||||
|
||||
try {
|
||||
statusItem.text = "$(sync~spin) Checking clice updates...";
|
||||
statusItem.show();
|
||||
|
||||
channel.appendLine(`[Download] Fetching latest release from GitHub...`);
|
||||
const release = await fetchReleaseInfo(channel);
|
||||
channel.appendLine(`[Download] Latest tag: ${release.tag_name}`);
|
||||
|
||||
const asset = release.assets.find(a => {
|
||||
const name = a.name.toLowerCase();
|
||||
return name.includes(platformKeyword) &&
|
||||
name.includes(archKeyword) &&
|
||||
!name.includes('symbol');
|
||||
});
|
||||
|
||||
if (!asset) {
|
||||
throw new Error(`No compatible asset found for ${platform}-${archKeyword} in release ${release.tag_name}`);
|
||||
}
|
||||
|
||||
channel.appendLine(`[Download] Found asset: ${asset.name}`);
|
||||
channel.appendLine(`[Download] Download URL: ${asset.browser_download_url}`);
|
||||
|
||||
const tempArchiveName = asset.name;
|
||||
const tempArchivePath = path.join(storagePath, tempArchiveName);
|
||||
|
||||
statusItem.text = `$(cloud-download) Downloading clice...`;
|
||||
await downloadFile(asset.browser_download_url, tempArchivePath, channel);
|
||||
|
||||
statusItem.text = `$(file-zip) Extracting...`;
|
||||
channel.appendLine(`[Download] Extracting ${tempArchivePath} to ${storagePath}...`);
|
||||
|
||||
await decompress(tempArchivePath, storagePath);
|
||||
channel.appendLine(`[Download] Extraction complete.`);
|
||||
|
||||
fs.unlinkSync(tempArchivePath);
|
||||
|
||||
if (!fs.existsSync(executablePath)) {
|
||||
throw new Error(`Executable not found at ${executablePath} after extraction.`);
|
||||
}
|
||||
|
||||
if (platform !== 'win32') {
|
||||
channel.appendLine(`[Download] Setting executable permissions (chmod 755)...`);
|
||||
fs.chmodSync(executablePath, '755');
|
||||
}
|
||||
|
||||
channel.appendLine(`[Download] Setup successful. Binary ready at: ${executablePath}`);
|
||||
vscode.window.showInformationMessage(`Clice language server updated to ${release.tag_name}`);
|
||||
return executablePath;
|
||||
|
||||
} catch (error) {
|
||||
channel.appendLine(`[Download] CRITICAL ERROR during setup:`);
|
||||
if (error instanceof Error) {
|
||||
channel.appendLine(`[Download] Message: ${error.message}`);
|
||||
if (error.stack) {
|
||||
channel.appendLine(`[Download] Stack: ${error.stack}`);
|
||||
}
|
||||
} else {
|
||||
channel.appendLine(`[Download] Unknown error: ${JSON.stringify(error)}`);
|
||||
}
|
||||
|
||||
vscode.window.showErrorMessage(`Failed to download clice server. Check "clice" output channel for details.`, "Open Output").then(selection => {
|
||||
if (selection === "Open Output") {
|
||||
channel.show();
|
||||
}
|
||||
});
|
||||
|
||||
return undefined;
|
||||
} finally {
|
||||
statusItem.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function downloadFile(url: string, destPath: string, channel: vscode.OutputChannel, maxRedirects = 5): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (maxRedirects <= 0) {
|
||||
reject(new Error('Too many redirects'));
|
||||
return;
|
||||
}
|
||||
|
||||
const file = fs.createWriteStream(destPath);
|
||||
channel.appendLine(`[Download] Start downloading to ${destPath}`);
|
||||
|
||||
https.get(url, { headers: { 'User-Agent': 'VSCode-Extension' } }, (response) => {
|
||||
if (response.statusCode === 302 || response.statusCode === 301) {
|
||||
channel.appendLine(`[Download] Redirecting to ${response.headers.location}`);
|
||||
file.close();
|
||||
downloadFile(response.headers.location!, destPath, channel, maxRedirects - 1).then(resolve).catch(reject);
|
||||
return;
|
||||
}
|
||||
if (response.statusCode !== 200) {
|
||||
reject(new Error(`Download failed with status code ${response.statusCode}`));
|
||||
return;
|
||||
}
|
||||
|
||||
response.pipe(file);
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
channel.appendLine(`[Download] Download finished.`);
|
||||
resolve();
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
file.close();
|
||||
fs.unlink(destPath, () => { });
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchReleaseInfo(channel: vscode.OutputChannel): Promise<GitHubRelease> {
|
||||
try {
|
||||
channel.appendLine('[Download] Attempting to fetch latest stable release...');
|
||||
const release = await fetchJson<GitHubRelease>('/repos/clice-io/clice/releases/latest');
|
||||
channel.appendLine(`[Download] Found stable release: ${release.tag_name}`);
|
||||
return release;
|
||||
} catch (error: any) {
|
||||
if (error.message && error.message.includes('404')) {
|
||||
channel.appendLine('[Download] Latest stable release not found (404). Checking for pre-releases...');
|
||||
|
||||
const releases = await fetchJson<GitHubRelease[]>('/repos/clice-io/clice/releases?per_page=1');
|
||||
|
||||
if (Array.isArray(releases) && releases.length > 0) {
|
||||
const latestPre = releases[0];
|
||||
channel.appendLine(`[Download] Found pre-release: ${latestPre.tag_name}`);
|
||||
return latestPre;
|
||||
} else {
|
||||
throw new Error('No releases found in repository.');
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function fetchJson<T>(apiPath: string): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
hostname: 'api.github.com',
|
||||
path: apiPath,
|
||||
headers: { 'User-Agent': 'VSCode-Extension' }
|
||||
};
|
||||
|
||||
https.get(options, (res) => {
|
||||
let data = '';
|
||||
if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
|
||||
res.resume();
|
||||
reject(new Error(`GitHub API returned ${res.statusCode} for ${apiPath}`));
|
||||
return;
|
||||
}
|
||||
|
||||
res.on('data', (chunk) => data += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (e) {
|
||||
reject(new Error(`Failed to parse GitHub API response: ${e}`));
|
||||
}
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
93
editors/vscode/src/extension.ts
Normal file
93
editors/vscode/src/extension.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import * as net from 'net';
|
||||
import * as vscode from 'vscode';
|
||||
import { workspace, window, ExtensionContext } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions, StreamInfo } from 'vscode-languageclient/node';
|
||||
import { getSetting } from './setting';
|
||||
import { ensureServerBinary } from './download'
|
||||
|
||||
let client: LanguageClient;
|
||||
|
||||
export async function registerCommands(client: LanguageClient, context: ExtensionContext) {
|
||||
context.subscriptions.push(vscode.commands.registerCommand("clice.restart", async () => {
|
||||
await client.restart();
|
||||
}));
|
||||
}
|
||||
|
||||
export async function activate(context: ExtensionContext) {
|
||||
console.log('Congratulations, your extension "clice" is now active!');
|
||||
|
||||
const channel = window.createOutputChannel('clice');
|
||||
const verboseChannel = window.createOutputChannel('clice-verbose');
|
||||
|
||||
const setting = getSetting();
|
||||
if (!setting) {
|
||||
return;
|
||||
}
|
||||
|
||||
let executable = setting.executable
|
||||
let serverOptions: ServerOptions | (() => Promise<StreamInfo>);
|
||||
|
||||
if (setting.mode === "pipe") {
|
||||
if (!executable || executable === "") {
|
||||
const downloadedPath = await ensureServerBinary(context, channel);
|
||||
if (downloadedPath) {
|
||||
executable = downloadedPath;
|
||||
} else {
|
||||
window.showErrorMessage("Could not find or download clice executable.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let args = ["--mode=pipe"];
|
||||
serverOptions = {
|
||||
run: { command: executable, args: args },
|
||||
debug: { command: executable, args: args }
|
||||
};
|
||||
} else if (setting.mode === "socket") {
|
||||
serverOptions = (): Promise<StreamInfo> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = new net.Socket();
|
||||
client.connect(setting.port, setting.host, () => {
|
||||
resolve({
|
||||
reader: client,
|
||||
writer: client,
|
||||
});
|
||||
});
|
||||
client.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
} else {
|
||||
vscode.window.showErrorMessage("Invalid mode, please set the mode to 'pipe' or 'socket'.");
|
||||
return
|
||||
}
|
||||
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
documentSelector: [{ scheme: 'file', language: 'cpp' }],
|
||||
outputChannel: channel,
|
||||
traceOutputChannel: verboseChannel,
|
||||
synchronize: {
|
||||
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
|
||||
}
|
||||
};
|
||||
|
||||
client = new LanguageClient(
|
||||
'clice',
|
||||
'clice',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
|
||||
await registerCommands(client, context);
|
||||
|
||||
await client.start();
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> | undefined {
|
||||
if (!client) {
|
||||
return undefined;
|
||||
}
|
||||
let ret = client.stop();
|
||||
return ret;
|
||||
}
|
||||
70
editors/vscode/src/feature/header.ts
Normal file
70
editors/vscode/src/feature/header.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { DocumentUri } from 'vscode-languageclient/node';
|
||||
|
||||
let provider: HeaderContextProvider | undefined = undefined;
|
||||
|
||||
export type HeaderContext = {
|
||||
file: string,
|
||||
index: number,
|
||||
include: number
|
||||
};
|
||||
|
||||
export type HeaderContextSwitchParams = {
|
||||
header: DocumentUri,
|
||||
context: HeaderContext,
|
||||
};
|
||||
|
||||
export type IncludeLocation = {
|
||||
line: number,
|
||||
filename: string
|
||||
};
|
||||
|
||||
export class TreeItem extends vscode.TreeItem {
|
||||
children: Array<TreeItem> = []
|
||||
context: HeaderContext | undefined = undefined;
|
||||
};
|
||||
|
||||
export class HeaderContextProvider implements vscode.TreeDataProvider<TreeItem> {
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<TreeItem | undefined | void> = new vscode.EventEmitter<TreeItem | undefined | void>();
|
||||
readonly onDidChangeTreeData: vscode.Event<TreeItem | undefined | void> = this._onDidChangeTreeData.event;
|
||||
|
||||
header: string = ""
|
||||
items: Array<TreeItem> = []
|
||||
|
||||
update(contexts: Array<Array<HeaderContext>>) {
|
||||
/// Create groups
|
||||
this.items = contexts.map((contexts) => {
|
||||
let item = new TreeItem("", vscode.TreeItemCollapsibleState.Expanded);
|
||||
item.children = contexts.map((context) => {
|
||||
const uri = vscode.Uri.file(context.file);
|
||||
let item = new TreeItem(uri, vscode.TreeItemCollapsibleState.None);
|
||||
item.context = context;
|
||||
item.iconPath = vscode.ThemeIcon.File;
|
||||
item.contextValue = "header-context";
|
||||
return item;
|
||||
});
|
||||
return item;
|
||||
});
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
this._onDidChangeTreeData.fire();
|
||||
}
|
||||
|
||||
getTreeItem(element: TreeItem) {
|
||||
return element;
|
||||
}
|
||||
|
||||
getChildren(element?: TreeItem) {
|
||||
return element ? element.children : this.items;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
export function registerHeaderContextView() {
|
||||
provider = new HeaderContextProvider();
|
||||
let treeView = vscode.window.createTreeView("header-contexts", { treeDataProvider: provider });
|
||||
}
|
||||
66
editors/vscode/src/feature/highlight.ts
Normal file
66
editors/vscode/src/feature/highlight.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
const rainbowColors = [
|
||||
"#56B6C2",
|
||||
"#61AFEF",
|
||||
"#C678DD",
|
||||
"#E06C75",
|
||||
"#98C379",
|
||||
"#D19A66",
|
||||
"#E5C07B"
|
||||
];
|
||||
|
||||
const textEditorDecorationTypes = rainbowColors.map((color) => {
|
||||
return vscode.window.createTextEditorDecorationType({
|
||||
color: color
|
||||
});
|
||||
});
|
||||
|
||||
export function highlightDocument(document: vscode.TextDocument, legend: vscode.SemanticTokensLegend, semanticTokens: vscode.SemanticTokens) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor || editor.document !== document) { return; }
|
||||
const angleIndex = legend?.tokenTypes.indexOf('angle');
|
||||
const leftIndex = legend?.tokenModifiers.indexOf('left');
|
||||
const rightIndex = legend?.tokenModifiers.indexOf('right');
|
||||
if (leftIndex === undefined || rightIndex === undefined || angleIndex === undefined) { return; }
|
||||
|
||||
const decorations = new Map<number, vscode.Range[]>();
|
||||
let level = 0;
|
||||
|
||||
let lastLine = 0;
|
||||
let lastStart = 0;
|
||||
|
||||
// [line, startCharacter, length, tokenType, tokenModifiers]
|
||||
for (let i = 0; i < semanticTokens.data.length; i += 5) {
|
||||
const [lineDelta, startDelta, length, tokenType, tokenModifiers] = semanticTokens.data.slice(i, i + 5);
|
||||
|
||||
lastLine += lineDelta;
|
||||
lastStart = lineDelta === 0 ? lastStart + startDelta : startDelta;
|
||||
|
||||
const range = new vscode.Range(lastLine, lastStart, lastLine, lastStart + length);
|
||||
|
||||
if (tokenType === angleIndex) {
|
||||
if (tokenModifiers & (1 << rightIndex)) {
|
||||
level -= 1;
|
||||
}
|
||||
|
||||
if (decorations.has(level % rainbowColors.length)) {
|
||||
decorations.get(level % rainbowColors.length)?.push(range);
|
||||
} else {
|
||||
decorations.set(level % rainbowColors.length, [range]);
|
||||
}
|
||||
|
||||
if (tokenModifiers & (1 << leftIndex)) {
|
||||
level += 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [level, ranges] of decorations) {
|
||||
editor.setDecorations(
|
||||
textEditorDecorationTypes[level],
|
||||
ranges
|
||||
);
|
||||
}
|
||||
}
|
||||
31
editors/vscode/src/setting.ts
Normal file
31
editors/vscode/src/setting.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
interface Setting {
|
||||
executable: string | undefined,
|
||||
mode: string,
|
||||
host: string,
|
||||
port: number,
|
||||
}
|
||||
|
||||
export function getSetting(): Setting | undefined {
|
||||
const setting = vscode.workspace.getConfiguration('clice')
|
||||
const executable = setting.get<string>('executable');
|
||||
const mode = setting.get<string>('mode');
|
||||
|
||||
if (mode !== "pipe" && mode !== "socket") {
|
||||
vscode.window.showErrorMessage(`Unexpected mode: ${mode}`);
|
||||
return undefined
|
||||
}
|
||||
|
||||
const host = setting.get<string>('host')!;
|
||||
const port = setting.get<number>('port')!;
|
||||
|
||||
if (mode === "socket" && (!host || !port)) {
|
||||
vscode.window.showErrorMessage('Socket mode requires both host and port to be configured.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
executable, mode, host, port,
|
||||
}
|
||||
}
|
||||
15
editors/vscode/src/test/extension.test.ts
Normal file
15
editors/vscode/src/test/extension.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as assert from 'assert';
|
||||
|
||||
// You can import and use all API from the 'vscode' module
|
||||
// as well as import your extension to test it
|
||||
import * as vscode from 'vscode';
|
||||
// import * as myExtension from '../../extension';
|
||||
|
||||
suite('Extension Test Suite', () => {
|
||||
vscode.window.showInformationMessage('Start all tests.');
|
||||
|
||||
test('Sample test', () => {
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
||||
});
|
||||
});
|
||||
16
editors/vscode/tsconfig.json
Normal file
16
editors/vscode/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "Node16",
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"ES2022"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"rootDir": "src",
|
||||
"strict": true /* enable all strict type-checking options */
|
||||
/* Additional Checks */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
}
|
||||
}
|
||||
48
editors/vscode/webpack.config.js
Normal file
48
editors/vscode/webpack.config.js
Normal file
@@ -0,0 +1,48 @@
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
|
||||
//@ts-check
|
||||
/** @typedef {import('webpack').Configuration} WebpackConfig **/
|
||||
|
||||
/** @type WebpackConfig */
|
||||
const extensionConfig = {
|
||||
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
||||
|
||||
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
output: {
|
||||
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'extension.js',
|
||||
libraryTarget: 'commonjs2'
|
||||
},
|
||||
externals: {
|
||||
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
||||
// modules added here also need to be added in the .vscodeignore file
|
||||
},
|
||||
resolve: {
|
||||
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
||||
extensions: ['.ts', '.js']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
devtool: 'nosources-source-map',
|
||||
infrastructureLogging: {
|
||||
level: "log", // enables logging required for problem matchers
|
||||
},
|
||||
};
|
||||
module.exports = [ extensionConfig ];
|
||||
1
editors/zed/.gitignore
vendored
Normal file
1
editors/zed/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
329
editors/zed/Cargo.lock
generated
Normal file
329
editors/zed/Cargo.lock
generated
Normal file
@@ -0,0 +1,329 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.143"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e17e880bafaeb362a7b751ec46bdc5b61445a188f80e0606e68167cd540fa3"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.201.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.201.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.201.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "288f992ea30e6b5c531b52cdd5f3be81c148554b09ea416f058d16556ba92c27"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rt",
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e85e72719ffbccf279359ad071497e47eb0675fe22106dea4ed2d8a7fcb60ba4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb8738270f32a2d6739973cbbb7c1b6dd8959ce515578a6e19165853272ee64"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d376d3ae5850526dfd00d937faea0d81a06fa18f7ac1e26f386d760f241a8f4b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.201.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.201.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_clice"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"zed_extension_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zed_extension_api"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "594fd10dd0f2f853eb243e2425e7c95938cef49adb81d9602921d002c5e6d9d9"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wit-bindgen",
|
||||
]
|
||||
13
editors/zed/Cargo.toml
Normal file
13
editors/zed/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "zed_clice"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
path = "src/clice.rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
zed_extension_api = "0.1.0"
|
||||
21
editors/zed/LICENSE
Normal file
21
editors/zed/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 clice-project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
5
editors/zed/README.md
Normal file
5
editors/zed/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# clice-zed
|
||||
|
||||
This is the zed extension for [clice](https://github.com/clice-io/clice).
|
||||
|
||||
Currently, `clice-zed` uses `clice` in environment variables. Support for configuring the clice path in the configuration file may be added in the future.
|
||||
11
editors/zed/extension.toml
Normal file
11
editors/zed/extension.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
id = "clice"
|
||||
name = "clice"
|
||||
version = "0.1.0"
|
||||
schema_version = 1
|
||||
authors = ["clice-io"]
|
||||
description = "C++ support"
|
||||
repository = "https://github.com/clice-io/clice"
|
||||
|
||||
[language_servers.clice]
|
||||
name = "clice"
|
||||
language = "C++"
|
||||
68
editors/zed/src/clice.rs
Normal file
68
editors/zed/src/clice.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use zed_extension_api::{self as zed, LanguageServerId, Result, Worktree};
|
||||
|
||||
struct CliceExtension;
|
||||
|
||||
struct CliceBinary {
|
||||
path: String,
|
||||
resource_dir: String,
|
||||
}
|
||||
|
||||
impl CliceExtension {
|
||||
fn find_clice_binary(&self, worktree: &Worktree) -> Result<CliceBinary> {
|
||||
if let Some(path_str) = worktree.which("clice") {
|
||||
// The std::path module seems to behave unexpectedly in the Zed sandbox,
|
||||
// failing to correctly parse parent directories for full paths on Windows.
|
||||
// To ensure reliability, we revert to manual string manipulation to find the parent directory.
|
||||
let separator_pos = path_str.rfind(|c| c == '\\' || c == '/');
|
||||
|
||||
if let Some(pos) = separator_pos {
|
||||
let parent_dir = &path_str[..pos];
|
||||
// We use std::path::MAIN_SEPARATOR to construct the path in a cross-platform way,
|
||||
// avoiding the hardcoded '\' from the original implementation.
|
||||
let resource_dir = format!("{}{}{}", parent_dir, std::path::MAIN_SEPARATOR, "lib");
|
||||
|
||||
Ok(CliceBinary {
|
||||
path: path_str,
|
||||
resource_dir,
|
||||
})
|
||||
} else {
|
||||
Err(format!(
|
||||
"clice found as `{}`,
|
||||
but a full path is required to find the `lib` directory.",
|
||||
path_str
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(
|
||||
"`clice` not found in your PATH. Please install it and add it to your system's PATH environment variable.".to_string()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl zed::Extension for CliceExtension {
|
||||
fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
// Currently, we only search for the 'clice' binary in the system's PATH.
|
||||
fn language_server_command(
|
||||
&mut self,
|
||||
_language_server_id: &LanguageServerId,
|
||||
worktree: &Worktree,
|
||||
) -> Result<zed::Command> {
|
||||
let binary = self.find_clice_binary(worktree)?;
|
||||
Ok(zed::Command {
|
||||
command: binary.path,
|
||||
args: vec![
|
||||
"--resource-dir".to_string(),
|
||||
binary.resource_dir,
|
||||
"--mode".to_string(),
|
||||
"pipe".to_string(),
|
||||
],
|
||||
env: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
zed::register_extension!(CliceExtension);
|
||||
61
flake.lock
generated
61
flake.lock
generated
@@ -1,61 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1738961098,
|
||||
"narHash": "sha256-yWNBf6VDW38tl179FEuJ0qukthVfB02kv+mRsfUsWC0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a3eaf5e8eca7cab680b964138fb79073704aca75",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
72
flake.nix
72
flake.nix
@@ -1,72 +0,0 @@
|
||||
{
|
||||
description = "Flake for Clice";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
tomlplusplus = pkgs.tomlplusplus.overrideAttrs (
|
||||
oldAttrs: {
|
||||
mesonFlags = oldAttrs.mesonFlags or [] ++ [
|
||||
"-Dbuild_examples=false"
|
||||
"-Dbuild_tests=false"
|
||||
"-Dcompile_library=false"
|
||||
];
|
||||
|
||||
postInstall = oldAttrs.postInstall or "" + ''
|
||||
cat > "$out/share/pkgconfig/toml++.pc" <<EOF
|
||||
Name: toml++
|
||||
Description: Alias for tomlplusplus
|
||||
Version: ${oldAttrs.version}
|
||||
Requires: tomlplusplus
|
||||
EOF
|
||||
'';
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.gcc
|
||||
pkgs.pkg-config
|
||||
pkgs.xmake
|
||||
pkgs.cmake
|
||||
pkgs.ninja
|
||||
pkgs.python3
|
||||
pkgs.gtest
|
||||
pkgs.libuv
|
||||
pkgs.llvmPackages_20.libstdcxxClang
|
||||
# pkgs.llvmPackages_20.libllvm
|
||||
pkgs.llvmPackages_20.bintools
|
||||
pkgs.llvmPackages_20.compiler-rt
|
||||
pkgs.llvmPackages_20.libunwind
|
||||
pkgs.zlib
|
||||
tomlplusplus
|
||||
];
|
||||
|
||||
shellHook =
|
||||
let
|
||||
gcc = pkgs.gcc-unwrapped;
|
||||
gccInclude = "${gcc}/include";
|
||||
gccCxxInclude = "${gccInclude}/c++/${gcc.lib.version}";
|
||||
in
|
||||
''
|
||||
export NIX_CFLAGS_COMPILE+=" -isystem ${gccInclude}"
|
||||
export NIX_CFLAGS_COMPILE+=" -isystem ${gccCxxInclude}"
|
||||
export NIX_CFLAGS_COMPILE+=" -isystem ${gccCxxInclude}/$(gcc -dumpmachine)"
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace clice {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "AST/SourceCode.h"
|
||||
#include "Compiler/CompilationUnit.h"
|
||||
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@@ -45,7 +45,14 @@ public:
|
||||
}
|
||||
|
||||
lookup_result lookup(const clang::DependentTemplateSpecializationType* type) {
|
||||
return lookup(type->getQualifier(), type->getIdentifier());
|
||||
auto& template_name = type->getDependentTemplateName();
|
||||
auto identifier = template_name.getName().getIdentifier();
|
||||
if(identifier) {
|
||||
return lookup(template_name.getQualifier(), identifier);
|
||||
} else {
|
||||
/// FIXME: Operators does't have a name.
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
lookup_result lookup(const clang::DependentScopeDeclRefExpr* expr) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "SourceCode.h"
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "clang/AST/ASTTypeTraits.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/Tooling/Syntax/Tokens.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -57,11 +59,11 @@ public:
|
||||
|
||||
/// Copies are no good - contain pointers to other nodes.
|
||||
SelectionTree(const SelectionTree&) = delete;
|
||||
SelectionTree& operator= (const SelectionTree&) = delete;
|
||||
SelectionTree& operator=(const SelectionTree&) = delete;
|
||||
|
||||
/// Moves are OK though - internal storage is pointer-stable when moved.
|
||||
SelectionTree(SelectionTree&&) = default;
|
||||
SelectionTree& operator= (SelectionTree&&) = default;
|
||||
SelectionTree& operator=(SelectionTree&&) = default;
|
||||
|
||||
// Describes to what extent an AST node is covered by the selection.
|
||||
enum SelectionKind : unsigned char {
|
||||
@@ -129,7 +131,7 @@ public:
|
||||
|
||||
void print(llvm::raw_ostream& os, const Node& node, int indent) const;
|
||||
|
||||
friend llvm::raw_ostream& operator<< (llvm::raw_ostream& os, const SelectionTree& tree) {
|
||||
friend llvm::raw_ostream& operator<<(llvm::raw_ostream& os, const SelectionTree& tree) {
|
||||
tree.print(os, tree.root(), 1);
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utility.h"
|
||||
#include "FilterASTVisitor.h"
|
||||
#include "RelationKind.h"
|
||||
#include "Resolver.h"
|
||||
#include "SymbolKind.h"
|
||||
#include "RelationKind.h"
|
||||
#include "FilterASTVisitor.h"
|
||||
#include "Utility.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -627,7 +627,6 @@ public:
|
||||
}
|
||||
|
||||
case clang::NestedNameSpecifier::TypeSpec:
|
||||
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
case clang::NestedNameSpecifier::Global:
|
||||
case clang::NestedNameSpecifier::Super: {
|
||||
break;
|
||||
@@ -638,7 +637,6 @@ public:
|
||||
}
|
||||
|
||||
bool VisitAttr(clang::Attr* attr) {
|
||||
|
||||
getDerived().handleAttrOccurrence(attr, attr->getRange());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include "clang/Lex/Token.h"
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
|
||||
namespace std {
|
||||
|
||||
@@ -33,6 +34,8 @@ clang::SourceLocation get(clang::SourceRange range) {
|
||||
}
|
||||
}
|
||||
|
||||
class Lexer;
|
||||
|
||||
} // namespace clang
|
||||
|
||||
namespace clice {
|
||||
@@ -44,7 +47,7 @@ struct LocalSourceRange {
|
||||
/// The end position offset to the source file.
|
||||
uint32_t end = static_cast<uint32_t>(-1);
|
||||
|
||||
constexpr bool operator== (const LocalSourceRange& other) const = default;
|
||||
constexpr bool operator==(const LocalSourceRange& other) const = default;
|
||||
|
||||
constexpr auto length() {
|
||||
return end - begin;
|
||||
@@ -63,15 +66,17 @@ struct LocalSourceRange {
|
||||
}
|
||||
};
|
||||
|
||||
using TokenKind = clang::tok::TokenKind;
|
||||
|
||||
struct Token {
|
||||
/// Whether this token is at the start of line.
|
||||
bool is_at_start_of_line = false;
|
||||
|
||||
/// Whether this token is a preprocessor directive.
|
||||
bool is_preprocessor_directive = false;
|
||||
bool is_pp_keyword = false;
|
||||
|
||||
/// The kind of this token.
|
||||
clang::tok::TokenKind kind;
|
||||
TokenKind kind;
|
||||
|
||||
/// The source range of this token.
|
||||
LocalSourceRange range;
|
||||
@@ -80,31 +85,35 @@ struct Token {
|
||||
return range.valid();
|
||||
}
|
||||
|
||||
llvm::StringRef name() {
|
||||
llvm::StringRef name() const {
|
||||
return clang::tok::getTokenName(kind);
|
||||
}
|
||||
|
||||
llvm::StringRef text(llvm::StringRef content) {
|
||||
llvm::StringRef text(llvm::StringRef content) const {
|
||||
assert(range.valid() && "Invalid source range");
|
||||
return content.substr(range.begin, range.end - range.begin);
|
||||
}
|
||||
|
||||
bool is_eof() {
|
||||
bool is_eod() const {
|
||||
return kind == clang::tok::eod;
|
||||
}
|
||||
|
||||
bool is_eof() const {
|
||||
return kind == clang::tok::eof;
|
||||
}
|
||||
|
||||
bool is_identifier() {
|
||||
bool is_identifier() const {
|
||||
return kind == clang::tok::raw_identifier;
|
||||
}
|
||||
|
||||
bool is_directive_hash() {
|
||||
bool is_directive_hash() const {
|
||||
return is_at_start_of_line && kind == clang::tok::hash;
|
||||
}
|
||||
|
||||
/// The tokens after the include diretive are regarded as
|
||||
/// a whole token, whose kind is `header_name`. For example
|
||||
/// `<iostream>` and `"test.h"` are both header name.
|
||||
bool is_header_name() {
|
||||
bool is_header_name() const {
|
||||
return kind == clang::tok::header_name;
|
||||
}
|
||||
};
|
||||
@@ -120,6 +129,10 @@ public:
|
||||
|
||||
Lexer(Lexer&&) = delete;
|
||||
|
||||
Lexer& operator=(const Lexer&) = delete;
|
||||
|
||||
Lexer& operator=(Lexer&&) = delete;
|
||||
|
||||
~Lexer();
|
||||
|
||||
void lex(Token& token);
|
||||
@@ -133,8 +146,21 @@ public:
|
||||
/// Advance the lexer and return the next token.
|
||||
Token advance();
|
||||
|
||||
/// Advance the lexer if the next token kind is the param.
|
||||
std::optional<Token> advance_if(llvm::function_ref<bool(const Token&)> callback);
|
||||
|
||||
std::optional<Token> advance_if(llvm::StringRef spelling) {
|
||||
return advance_if([&](const Token& token) {
|
||||
return token.is_identifier() && token.text(content) == spelling;
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<Token> advance_if(TokenKind kind) {
|
||||
return advance_if([&](const Token& token) { return token.kind == kind; });
|
||||
}
|
||||
|
||||
/// Advance the lexer until meet the specific kind token.
|
||||
Token advance_until(clang::tok::TokenKind kind);
|
||||
Token advance_until(TokenKind kind);
|
||||
|
||||
private:
|
||||
/// If this is set to false, the lexer will emit tok::eod at the end
|
||||
@@ -142,11 +168,13 @@ private:
|
||||
bool ignore_end_of_directive = true;
|
||||
|
||||
/// Whether we are lexing the preprocessor directive.
|
||||
bool parse_preprocessor_directive = false;
|
||||
bool parse_pp_keyword = false;
|
||||
|
||||
/// Whether we are lexing the header name.
|
||||
bool parse_header_name = false;
|
||||
|
||||
bool module_declaration_context = true;
|
||||
|
||||
/// The cache of last token.
|
||||
Token last_token;
|
||||
|
||||
@@ -159,7 +187,7 @@ private:
|
||||
/// The lexed content.
|
||||
llvm::StringRef content;
|
||||
|
||||
void* impl;
|
||||
std::unique_ptr<clang::Lexer> lexer;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Support/Enum.h"
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -15,6 +15,12 @@ bool is_templated(const clang::Decl* decl);
|
||||
/// Check whether the decl is anonymous.
|
||||
bool is_anonymous(const clang::NamedDecl* decl);
|
||||
|
||||
/// Checks whether the location is inside the main file.
|
||||
bool is_inside_main_file(clang::SourceLocation loc, const clang::SourceManager& sm);
|
||||
|
||||
/// Checks whether the decl is an implicit template instantiation.
|
||||
bool is_implicit_template_instantiation(const clang::NamedDecl* decl);
|
||||
|
||||
/// Return the decl where it is instantiated from. If could be a template decl
|
||||
/// or a member of a class template. If the decl is a full specialization, return
|
||||
/// itself.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Lock.h"
|
||||
#include "Event.h"
|
||||
#include "Sleep.h"
|
||||
#include "Gather.h"
|
||||
#include "Network.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Gather.h"
|
||||
#include "Lock.h"
|
||||
#include "Network.h"
|
||||
#include "Sleep.h"
|
||||
#include "ThreadPool.h"
|
||||
#include "libuv.h"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Task.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
|
||||
namespace clice::async {
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
|
||||
#include "libuv.h"
|
||||
#include "Task.h"
|
||||
#include "Awaiter.h"
|
||||
|
||||
#include "Support/JSON.h"
|
||||
#include "Task.h"
|
||||
#include "libuv.h"
|
||||
#include "Support/Enum.h"
|
||||
#include "Support/JSON.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/FunctionExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clice::async {
|
||||
|
||||
@@ -56,9 +55,9 @@ public:
|
||||
|
||||
~handle();
|
||||
|
||||
handle& operator= (const handle&) = delete;
|
||||
handle& operator=(const handle&) = delete;
|
||||
|
||||
handle& operator= (handle&& other) noexcept = delete;
|
||||
handle& operator=(handle&& other) noexcept = delete;
|
||||
|
||||
int value() const {
|
||||
return file;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
|
||||
#include "Task.h"
|
||||
#include "Event.h"
|
||||
#include "Task.h"
|
||||
|
||||
namespace clice::async {
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "libuv.h"
|
||||
|
||||
#include "Task.h"
|
||||
#include "libuv.h"
|
||||
#include "Support/JSON.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/FunctionExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clice::async::net {
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "Awaiter.h"
|
||||
|
||||
namespace clice::async {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <coroutine>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <optional>
|
||||
#include <coroutine>
|
||||
#include <source_location>
|
||||
|
||||
#include "Support/Format.h"
|
||||
@@ -198,8 +198,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct promise_result<void> {
|
||||
// WORKAROUND: GCC bug - full specialization in non-namespace scope not supported
|
||||
// see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282
|
||||
template <std::same_as<void> V>
|
||||
struct promise_result<V> {
|
||||
void return_void() noexcept {}
|
||||
};
|
||||
|
||||
@@ -245,9 +247,9 @@ public:
|
||||
other.core = nullptr;
|
||||
}
|
||||
|
||||
Task& operator= (const Task&) = delete;
|
||||
Task& operator=(const Task&) = delete;
|
||||
|
||||
Task& operator= (Task&& other) noexcept {
|
||||
Task& operator=(Task&& other) noexcept {
|
||||
if(core) {
|
||||
core.destroy();
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <expected>
|
||||
#include <type_traits>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
#include "Support/TypeTraits.h"
|
||||
#include "Support/Logging.h"
|
||||
#include "Support/TypeTraits.h"
|
||||
|
||||
namespace clice::async {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <expected>
|
||||
|
||||
#include "Toolchain.h"
|
||||
#include "Support/Enum.h"
|
||||
#include "Support/Format.h"
|
||||
|
||||
@@ -13,214 +14,112 @@
|
||||
namespace clice {
|
||||
|
||||
struct CommandOptions {
|
||||
/// Ignore unknown commands.
|
||||
/// Ignore unknown commands arguments.
|
||||
bool ignore_unknown = true;
|
||||
|
||||
/// Inject resource directory to the command.
|
||||
bool resource_dir = false;
|
||||
|
||||
/// Query the compiler driver for additional information, such as system includes and target.
|
||||
bool query_toolchain = false;
|
||||
|
||||
/// Suppress the warning log if failed to query driver info.
|
||||
/// Set true in unittests to avoid cluttering test output.
|
||||
bool suppress_logging = false;
|
||||
|
||||
/// The commands that you want to remove from original commands list.
|
||||
llvm::ArrayRef<std::string> remove;
|
||||
|
||||
/// The commands that you want to add to original commands list.
|
||||
llvm::ArrayRef<std::string> append;
|
||||
|
||||
/// Attach resource directory to the command.
|
||||
bool resource_dir = false;
|
||||
|
||||
/// Query the compiler driver for additional information, such as system includes and target.
|
||||
bool query_driver = false;
|
||||
|
||||
/// Suppress the warning log if failed to query driver info.
|
||||
/// Set true in unittests to avoid cluttering test output.
|
||||
bool suppress_logging = false;
|
||||
};
|
||||
|
||||
enum class UpdateKind : std::uint8_t {
|
||||
Unchanged,
|
||||
Inserted,
|
||||
Deleted,
|
||||
};
|
||||
|
||||
struct UpdateInfo {
|
||||
/// The kind of update.
|
||||
UpdateKind kind;
|
||||
|
||||
/// The updated file.
|
||||
std::uint32_t path_id;
|
||||
|
||||
/// The compilation context of this file command, which could
|
||||
/// be used to identity the same file with different compilation
|
||||
/// contexts.
|
||||
const void* context;
|
||||
};
|
||||
|
||||
struct CompilationContext {
|
||||
/// The working directory of compilation.
|
||||
llvm::StringRef directory;
|
||||
|
||||
/// The compilation arguments.
|
||||
std::vector<const char*> arguments;
|
||||
};
|
||||
|
||||
std::string print_argv(llvm::ArrayRef<const char*> args);
|
||||
|
||||
class CompilationDatabase {
|
||||
public:
|
||||
using Self = CompilationDatabase;
|
||||
|
||||
enum class UpdateKind : std::uint8_t {
|
||||
Unchange,
|
||||
Create,
|
||||
Update,
|
||||
Delete,
|
||||
};
|
||||
|
||||
struct CommandInfo {
|
||||
/// TODO: add sysroot or no stdinc command info.
|
||||
llvm::StringRef directory;
|
||||
|
||||
/// The canonical command list.
|
||||
llvm::ArrayRef<const char*> arguments;
|
||||
|
||||
/// The extra command @...
|
||||
llvm::StringRef response_file;
|
||||
|
||||
/// The original index of the response file argument in the command list.
|
||||
std::uint32_t response_file_index = 0;
|
||||
};
|
||||
|
||||
struct DriverInfo {
|
||||
/// The target of this driver.
|
||||
llvm::StringRef target;
|
||||
|
||||
/// The default system includes of this driver.
|
||||
llvm::ArrayRef<const char*> system_includes;
|
||||
};
|
||||
|
||||
struct UpdateInfo {
|
||||
/// The kind of update.
|
||||
UpdateKind kind;
|
||||
|
||||
llvm::StringRef file;
|
||||
};
|
||||
|
||||
struct LookupInfo {
|
||||
llvm::StringRef directory;
|
||||
|
||||
std::vector<const char*> arguments;
|
||||
};
|
||||
|
||||
struct QueryDriverError {
|
||||
struct ErrorKind : refl::Enum<ErrorKind> {
|
||||
enum Kind : std::uint8_t {
|
||||
NotFoundInPATH,
|
||||
FailToCreateTempFile,
|
||||
InvokeDriverFail,
|
||||
OutputFileNotReadable,
|
||||
InvalidOutputFormat,
|
||||
};
|
||||
|
||||
using Enum::Enum;
|
||||
};
|
||||
|
||||
ErrorKind kind;
|
||||
std::string detail;
|
||||
};
|
||||
|
||||
CompilationDatabase();
|
||||
|
||||
CompilationDatabase(const CompilationDatabase&) = delete;
|
||||
|
||||
CompilationDatabase(CompilationDatabase&& other);
|
||||
|
||||
CompilationDatabase& operator= (CompilationDatabase&& other);
|
||||
CompilationDatabase& operator=(const CompilationDatabase&) = delete;
|
||||
|
||||
CompilationDatabase& operator=(CompilationDatabase&& other);
|
||||
|
||||
~CompilationDatabase();
|
||||
|
||||
auto save_string(this Self& self, llvm::StringRef string) -> llvm::StringRef;
|
||||
public:
|
||||
/// Read the compilation database on the give file and return the
|
||||
/// incremental update infos.
|
||||
std::vector<UpdateInfo> load_compile_database(llvm::StringRef file);
|
||||
|
||||
auto save_cstring_list(this Self& self, llvm::ArrayRef<const char*> arguments)
|
||||
-> llvm::ArrayRef<const char*>;
|
||||
/// Lookup the compilation context of specific file. If the context
|
||||
/// param is provided, we will return the compilation context corresponding
|
||||
/// to the handle. Otherwise we just return the first one(if the file have)
|
||||
/// multiple compilation contexts.
|
||||
CompilationContext lookup(llvm::StringRef file,
|
||||
const CommandOptions& options = {},
|
||||
const void* context = nullptr);
|
||||
|
||||
/// TODO: list all compilation context of the file, this is useful to show
|
||||
/// all contexts and let user choose one.
|
||||
/// std::vector<CompilationContext> fetch_all(llvm::StringRef file);
|
||||
|
||||
/// Get an the option for specific argument.
|
||||
static std::optional<std::uint32_t> get_option_id(llvm::StringRef argument);
|
||||
|
||||
/// Query the compiler driver and return its driver info.
|
||||
auto query_driver(this Self& self, llvm::StringRef driver)
|
||||
-> std::expected<DriverInfo, QueryDriverError>;
|
||||
/// FIXME: bad interface design ...
|
||||
std::vector<const char*> files();
|
||||
|
||||
/// Update with arguments.
|
||||
auto update_command(this Self& self,
|
||||
llvm::StringRef directory,
|
||||
llvm::StringRef file,
|
||||
llvm::ArrayRef<const char*> arguments) -> UpdateInfo;
|
||||
/// FIXME: remove this api?
|
||||
auto save_string(llvm::StringRef string) -> llvm::StringRef;
|
||||
|
||||
/// Update with full command.
|
||||
auto update_command(this Self& self,
|
||||
llvm::StringRef directory,
|
||||
llvm::StringRef file,
|
||||
llvm::StringRef command) -> UpdateInfo;
|
||||
#ifdef CLICE_ENABLE_TEST
|
||||
|
||||
void add_command(llvm::StringRef directory,
|
||||
llvm::StringRef file,
|
||||
llvm::ArrayRef<const char*> arguments);
|
||||
|
||||
void add_command(llvm::StringRef directory, llvm::StringRef file, llvm::StringRef command);
|
||||
|
||||
/// FIXME: remove this
|
||||
/// Update commands from json file and return all updated file.
|
||||
auto load_commands(this Self& self, llvm::StringRef json_content, llvm::StringRef workspace)
|
||||
-> std::expected<std::vector<UpdateInfo>, std::string>;
|
||||
|
||||
auto process_command(this Self& self,
|
||||
llvm::StringRef file,
|
||||
const CommandInfo& info,
|
||||
const CommandOptions& options) -> std::vector<const char*>;
|
||||
|
||||
/// Get compile command from database. `file` should has relative path of workspace.
|
||||
auto get_command(this Self& self, llvm::StringRef file, CommandOptions options = {})
|
||||
-> LookupInfo;
|
||||
|
||||
/// Load compile commands from given directories. If no valid commands are found,
|
||||
/// search recursively from the workspace directory.
|
||||
auto load_compile_database(this Self& self,
|
||||
llvm::ArrayRef<std::string> compile_commands_dirs,
|
||||
llvm::StringRef workspace) -> void;
|
||||
|
||||
auto commands_size() {
|
||||
return command_infos.size();
|
||||
}
|
||||
|
||||
auto begin() {
|
||||
return command_infos.begin();
|
||||
}
|
||||
|
||||
auto end() {
|
||||
return command_infos.end();
|
||||
}
|
||||
std::expected<std::vector<UpdateInfo>, std::string> load_commands(llvm::StringRef json_content,
|
||||
llvm::StringRef workspace);
|
||||
#endif
|
||||
|
||||
private:
|
||||
/// If file not found in CDB file, try to guess commands or use the default case.
|
||||
auto guess_or_fallback(this Self& self, llvm::StringRef file) -> LookupInfo;
|
||||
|
||||
private:
|
||||
/// The opaque handle of `ArgumentParser`.
|
||||
void* parser;
|
||||
|
||||
/// The memory pool to hold all cstring and command list.
|
||||
llvm::BumpPtrAllocator allocator;
|
||||
|
||||
/// A cache between input string and its cache cstring
|
||||
/// in the allocator, make sure end with `\0`.
|
||||
llvm::DenseSet<llvm::StringRef> string_cache;
|
||||
|
||||
/// A cache between input command and its cache array
|
||||
/// in the allocator.
|
||||
llvm::DenseSet<llvm::ArrayRef<const char*>> arguments_cache;
|
||||
|
||||
/// The clang options we want to filter in all cases, like -c and -o.
|
||||
llvm::DenseSet<std::uint32_t> filtered_options;
|
||||
|
||||
/// A map between file path and its canonical command list.
|
||||
llvm::DenseMap<const char*, CommandInfo> command_infos;
|
||||
|
||||
/// A map between driver path and its query driver info.
|
||||
llvm::DenseMap<const char*, DriverInfo> driver_infos;
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> self;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <>
|
||||
struct DenseMapInfo<llvm::ArrayRef<const char*>> {
|
||||
using T = llvm::ArrayRef<const char*>;
|
||||
|
||||
inline static T getEmptyKey() {
|
||||
return T(reinterpret_cast<T::const_pointer>(~0), T::size_type(0));
|
||||
}
|
||||
|
||||
inline static T getTombstoneKey() {
|
||||
return T(reinterpret_cast<T::const_pointer>(~1), T::size_type(0));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const T& value) {
|
||||
return llvm::hash_combine_range(value.begin(), value.end());
|
||||
}
|
||||
|
||||
static bool isEqual(const T& lhs, const T& rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
template <>
|
||||
struct std::formatter<clice::CompilationDatabase::QueryDriverError> :
|
||||
std::formatter<std::string_view> {
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const clice::CompilationDatabase::QueryDriverError& e, FormatContext& ctx) const {
|
||||
return std::format_to(ctx.out(), "{} {}", e.kind.name(), e.detail);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "CompilationUnit.h"
|
||||
#include "Module.h"
|
||||
#include "Preamble.h"
|
||||
#include "CompilationUnit.h"
|
||||
#include "Support/FileSystem.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CodeCompleteConsumer;
|
||||
|
||||
}
|
||||
|
||||
namespace clice {
|
||||
@@ -15,11 +17,16 @@ struct CompilationParams {
|
||||
/// The kind of this compilation.
|
||||
CompilationUnit::Kind kind;
|
||||
|
||||
/// Whether to run clang-tidy.
|
||||
bool clang_tidy = false;
|
||||
|
||||
/// Output file path.
|
||||
llvm::SmallString<128> output_file;
|
||||
|
||||
std::string directory;
|
||||
|
||||
bool arguments_from_database = false;
|
||||
|
||||
/// Responsible for storing the arguments.
|
||||
std::vector<const char*> arguments;
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
#include <chrono>
|
||||
|
||||
#include "Directive.h"
|
||||
#include "Compiler/Diagnostic.h"
|
||||
#include "AST/SymbolID.h"
|
||||
#include "AST/SourceCode.h"
|
||||
#include "AST/Resolver.h"
|
||||
#include "AST/SourceCode.h"
|
||||
#include "AST/SymbolID.h"
|
||||
#include "Compiler/Diagnostic.h"
|
||||
|
||||
#include "clang/Tooling/Syntax/Tokens.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "AST/SourceCode.h"
|
||||
#include "Compiler/Tidy.h"
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class DiagnosticConsumer;
|
||||
|
||||
}
|
||||
|
||||
namespace clice {
|
||||
@@ -52,6 +58,11 @@ struct DiagnosticID {
|
||||
bool is_unused() const;
|
||||
};
|
||||
|
||||
class DiagnosticCollector : public clang::DiagnosticConsumer {
|
||||
public:
|
||||
tidy::ClangTidyChecker* checker = nullptr;
|
||||
};
|
||||
|
||||
struct Diagnostic {
|
||||
/// The diagnostic id.
|
||||
DiagnosticID id;
|
||||
@@ -66,7 +77,8 @@ struct Diagnostic {
|
||||
/// The error message of this diagnostic.
|
||||
std::string message;
|
||||
|
||||
static clang::DiagnosticConsumer* create(std::shared_ptr<std::vector<Diagnostic>> diagnostics);
|
||||
static std::unique_ptr<DiagnosticCollector>
|
||||
create(std::shared_ptr<std::vector<Diagnostic>> diagnostics);
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "AST/SourceCode.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <expected>
|
||||
|
||||
#include "Support/Struct.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <expected>
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
|
||||
34
include/Compiler/Scan.h
Normal file
34
include/Compiler/Scan.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "AST/SourceCode.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
struct Inclusion {
|
||||
/// Whether this file is braced angles.
|
||||
bool angled;
|
||||
|
||||
/// The line of this inclusion(zero based).
|
||||
/// std::uint32_t line;
|
||||
|
||||
/// The included file.
|
||||
llvm::StringRef file;
|
||||
};
|
||||
|
||||
struct ScanResult {
|
||||
/// The module file of this file(may be empty).
|
||||
std::vector<Token> module_name;
|
||||
|
||||
/// The includes of file.
|
||||
std::vector<Inclusion> includes;
|
||||
};
|
||||
|
||||
/// Scan the file and return necessary info.
|
||||
ScanResult scan(llvm::StringRef content);
|
||||
|
||||
} // namespace clice
|
||||
@@ -1,10 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CompilerInstance;
|
||||
|
||||
}
|
||||
|
||||
namespace clice::tidy {
|
||||
|
||||
bool is_registered_tidy_check(llvm::StringRef check);
|
||||
std::optional<bool> is_fast_tidy_check(llvm::StringRef check);
|
||||
|
||||
struct TidyParams {};
|
||||
|
||||
class ClangTidyChecker;
|
||||
|
||||
/// Configure to run clang-tidy on the given file.
|
||||
std::unique_ptr<ClangTidyChecker> configure(clang::CompilerInstance& instance,
|
||||
const TidyParams& params);
|
||||
|
||||
} // namespace clice::tidy
|
||||
|
||||
49
include/Compiler/Toolchain.h
Normal file
49
include/Compiler/Toolchain.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clice::toolchain {
|
||||
|
||||
enum class CompilerFamily {
|
||||
Unknown,
|
||||
GCC, // Covers gcc, g++, cc, c++, and versioned/arch variants
|
||||
Clang, // Covers clang, clang++, and versioned variants (excluding clang-cl)
|
||||
MSVC, // Covers cl
|
||||
ClangCL, // Covers clang-cl explicitly
|
||||
NVCC, // Covers nvcc
|
||||
Intel, // Covers icc, icpc, icx, dpcpp
|
||||
Zig, // Covers zig cc / zig c++ (assumed GCC/Clang compatible for query)
|
||||
};
|
||||
|
||||
struct QueryParams {
|
||||
llvm::StringRef file;
|
||||
llvm::StringRef directory;
|
||||
llvm::ArrayRef<const char*> arguments;
|
||||
llvm::function_ref<const char*(const char*)> callback;
|
||||
};
|
||||
|
||||
/// Query the toolchain info and return the full arguments, the returned arguments should be
|
||||
/// converted to `clang::CompilerInvocation::CreateFromArgs` directly.
|
||||
std::vector<const char*> query_toolchain(const QueryParams& params);
|
||||
|
||||
CompilerFamily driver_family(llvm::StringRef driver);
|
||||
|
||||
/// Query g++ or mingw toolchain info. We detect the target and corresponding
|
||||
/// gcc toolchain install path as default behavior.
|
||||
std::vector<const char*> query_gcc_toolchain(const QueryParams& params);
|
||||
|
||||
/// Query clang++ or any clang based toolchain, e.g. zig cc/c++. We query
|
||||
/// the full cc1 command of clang toolchain as default.
|
||||
/// TODO: Is armclang also compatible?
|
||||
std::vector<const char*> query_clang_toolchain(const QueryParams& params);
|
||||
|
||||
/// Query the msvc or clang-cl toolchain, default behavior only adds the
|
||||
/// target and includes info.
|
||||
std::vector<const char*> query_msvc_toolchain(const QueryParams& params);
|
||||
|
||||
/// FIXME: To be implemented
|
||||
std::vector<const char*> query_nvcc_toolchain(const QueryParams& params);
|
||||
|
||||
} // namespace clice::toolchain
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "AST/SourceCode.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "AST/SourceCode.h"
|
||||
#include "Protocol/Feature/Formatting.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clice::feature {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "AST/SymbolKind.h"
|
||||
#include "AST/SourceCode.h"
|
||||
#include "AST/SymbolKind.h"
|
||||
#include "Index/Shared.h"
|
||||
|
||||
namespace clice::config {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "AST/SymbolID.h"
|
||||
#include "AST/SourceCode.h"
|
||||
#include "AST/SymbolID.h"
|
||||
#include "Index/Shared.h"
|
||||
#include "Support/JSON.h"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user