FileIndex and MergedIndex for clice (#271)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
# .pre-commit-config.yaml
|
||||
exclude: "\\.patch$"
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
|
||||
271
CMakeLists.txt
271
CMakeLists.txt
@@ -1,236 +1,101 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(CLICE_PROJECT LANGUAGES C CXX)
|
||||
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
include(cmake/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()
|
||||
message(STATUS "Found llvm-libs ${LLVM_INSTALL_PATH}")
|
||||
if (EXISTS "${LLVM_CMAKE_DIR}")
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
|
||||
else()
|
||||
list(APPEND CMAKE_PREFIX_PATH "${LLVM_INSTALL_PATH}")
|
||||
endif()
|
||||
message(STATUS "CMake module path: ${CMAKE_MODULE_PATH}")
|
||||
message(STATUS "CMake prefix path: ${CMAKE_PREFIX_PATH}")
|
||||
include(GNUInstallDirs)
|
||||
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")
|
||||
|
||||
# Make sure all third libraries are affected by ABI related options
|
||||
if(CLICE_USE_LIBCXX)
|
||||
string(APPEND CMAKE_CXX_FLAGS "-stdlib=libc++")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++")
|
||||
string(APPEND CMAKE_SHARED_LINKER_FLAGS "-stdlib=libc++")
|
||||
string(APPEND CMAKE_MODULE_LINKER_FLAGS "-stdlib=libc++")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -stdlib=libc++")
|
||||
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -stdlib=libc++")
|
||||
endif()
|
||||
|
||||
message(STATUS "Installing other dependencies, please wait...")
|
||||
# install dependencies
|
||||
include(FetchContent)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# libuv option
|
||||
set(ASAN ON CACHE BOOL "" FORCE)
|
||||
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")
|
||||
endif()
|
||||
|
||||
message(STATUS "Fetching libuv...")
|
||||
FetchContent_Declare(
|
||||
libuv
|
||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
||||
GIT_TAG v1.x
|
||||
)
|
||||
include("${PROJECT_SOURCE_DIR}/cmake/package.cmake")
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
message(STATUS "Fetching spdlog...")
|
||||
FetchContent_Declare(
|
||||
spdlog
|
||||
GIT_REPOSITORY https://github.com/gabime/spdlog.git
|
||||
GIT_TAG v1.15.3
|
||||
)
|
||||
add_library(clice_options INTERFACE)
|
||||
|
||||
message(STATUS "Fetching tomlplusplus...")
|
||||
FetchContent_Declare(
|
||||
tomlplusplus
|
||||
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(libuv spdlog tomlplusplus)
|
||||
|
||||
message(STATUS "Found tomlplusplus: ${tomlplusplus_SOURCE_DIR}")
|
||||
message(STATUS "Found libuv: ${libuv_SOURCE_DIR}")
|
||||
message(STATUS "Found spdlog: ${spdlog_SOURCE_DIR}")
|
||||
if(CLICE_CI_ENVIRONMENT)
|
||||
target_compile_definitions(clice_options INTERFACE CLICE_CI_ENVIRONMENT)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
||||
target_compile_definitions(uv_a PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
target_link_options(clice_options INTERFACE -fuse-ld=lld-link)
|
||||
else()
|
||||
target_link_options(clice_options INTERFACE -fuse-ld=lld)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_USE_STD_FORMAT=1 SPDLOG_NO_EXCEPTIONS=1)
|
||||
|
||||
if (MSVC)
|
||||
# Remove any RTTI or exception enabling flags from CMAKE_CXX_FLAGS
|
||||
string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# Fix MSVC Non-standard preprocessor caused error C1189
|
||||
# While compiling Command.cpp, MSVC won't expand Options macro correctly
|
||||
# Output: D:\Desktop\code\clice\build\.packages\l\llvm\20.1.5\cc2aa9f1d09a4b71b6fa3bf0011f6387\include\clang/Driver/Options.inc(3590): error C2365: “clang::driver::options::OPT_”: redefinition; previous definition was 'enumerator'
|
||||
set(CLICE_CXX_FLAGS "/GR-;/EHsc-;/Zc:preprocessor;")
|
||||
target_compile_options(clice_options INTERFACE
|
||||
/GR-
|
||||
/EHsc-
|
||||
/Zc:preprocessor
|
||||
)
|
||||
else()
|
||||
set(CLICE_CXX_FLAGS "-fno-rtti;-fno-exceptions;-Wno-deprecated-declarations;-Wno-undefined-inline;")
|
||||
target_compile_options(clice_options INTERFACE
|
||||
-fno-rtti
|
||||
-fno-exceptions
|
||||
-Wno-deprecated-declarations
|
||||
-Wno-undefined-inline
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CLICE_LINKER_FLAGS "")
|
||||
|
||||
# Build-type specific flags
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(STATUS "Debug build: Enabling -g -O0 -fsanitize=address")
|
||||
list(APPEND CLICE_CXX_FLAGS "-g;-O0;-fsanitize=address")
|
||||
list(APPEND CLICE_LINKER_FLAGS "-fsanitize=address")
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
if(NOT MSVC)
|
||||
# MSVC only supports ASAN
|
||||
message(STATUS "RelWithDebInfo build: Enabling -fsanitize=thread")
|
||||
list(APPEND CLICE_CXX_FLAGS "-fsanitize=thread")
|
||||
list(APPEND CLICE_LINKER_FLAGS "-fsanitize=thread")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Release/Default build: Enabling -O3")
|
||||
list(APPEND CLICE_CXX_FLAGS "-O3")
|
||||
endif()
|
||||
|
||||
if(CLICE_CI_ENVIRONMENT)
|
||||
list(APPEND CLICE_CXX_FLAGS "-DCLICE_CI_ENVIRONMENT")
|
||||
endif()
|
||||
|
||||
|
||||
# Linker flags for LLD
|
||||
if(WIN32)
|
||||
list(APPEND CLICE_LINKER_FLAGS "-fuse-ld=lld-link")
|
||||
else()
|
||||
list(APPEND CLICE_LINKER_FLAGS "-fuse-ld=lld")
|
||||
endif()
|
||||
|
||||
# build clice core part as library
|
||||
file(GLOB_RECURSE CLICE_SOURCES CONFIGURE_DEPENDS
|
||||
"${CMAKE_SOURCE_DIR}/src/AST/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/Async/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/Basic/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/Compiler/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/Index/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/Feature/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/Server/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/Support/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/AST/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Async/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Basic/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Compiler/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Index/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Feature/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Server/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/Support/*.cpp"
|
||||
)
|
||||
add_library(clice-core STATIC "${CLICE_SOURCES}")
|
||||
|
||||
# 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(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
# private files are downloaded here
|
||||
message(STATUS "Fetched private headers to include: ${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
target_include_directories(llvm-libs INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(llvm-libs INTERFACE "CLANG_BUILD_STATIC")
|
||||
target_link_libraries(llvm-libs INTERFACE version ntdll)
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
target_compile_options(clice-core PUBLIC ${CLICE_CXX_FLAGS})
|
||||
target_link_options(clice-core PUBLIC ${CLICE_LINKER_FLAGS})
|
||||
|
||||
target_include_directories(clice-core PUBLIC "${CMAKE_SOURCE_DIR}/include")
|
||||
target_link_libraries(clice-core PUBLIC uv_a spdlog::spdlog tomlplusplus::tomlplusplus llvm-libs)
|
||||
target_compile_definitions(clice-core PUBLIC TOML_EXCEPTIONS=0)
|
||||
|
||||
# clice executable
|
||||
add_executable(clice "${CMAKE_SOURCE_DIR}/src/Driver/clice.cc")
|
||||
target_link_libraries(clice PRIVATE clice-core)
|
||||
target_compile_options(clice PUBLIC ${CLICE_CXX_FLAGS})
|
||||
target_link_options(clice PUBLIC ${CLICE_LINKER_FLAGS})
|
||||
# install clice executable
|
||||
install(TARGETS clice RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# copy resource dir
|
||||
message(STATUS "Copying resource directory")
|
||||
file(COPY
|
||||
${LLVM_INSTALL_PATH}/lib/clang/20/
|
||||
DESTINATION ${PROJECT_BINARY_DIR}/lib/clang/20
|
||||
target_include_directories(clice-core PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
target_link_libraries(clice-core PUBLIC
|
||||
clice_options
|
||||
uv_a
|
||||
spdlog::spdlog
|
||||
tomlplusplus::tomlplusplus
|
||||
roaring::roaring
|
||||
llvm-libs
|
||||
)
|
||||
|
||||
# clice tests
|
||||
if(CLICE_ENABLE_TEST)
|
||||
file(GLOB_RECURSE CLICE_TEST_SOURCES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/tests/unit/*/*.cpp")
|
||||
add_executable(unit_tests "${CLICE_TEST_SOURCES}" "${CMAKE_SOURCE_DIR}/src/Driver/unit_tests.cc")
|
||||
target_include_directories(unit_tests PUBLIC "${CMAKE_SOURCE_DIR}")
|
||||
add_executable(clice "${PROJECT_SOURCE_DIR}/bin/clice.cc")
|
||||
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"
|
||||
)
|
||||
install(DIRECTORY "${LLVM_INSTALL_PATH}/lib/clang/20/"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/clang/20"
|
||||
)
|
||||
|
||||
if(CLICE_ENABLE_TEST)
|
||||
file(GLOB_RECURSE CLICE_TEST_SOURCES CONFIGURE_DEPENDS
|
||||
"${PROJECT_SOURCE_DIR}/tests/unit/*/*.cpp")
|
||||
add_executable(unit_tests
|
||||
"${CLICE_TEST_SOURCES}"
|
||||
"${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_compile_options(unit_tests PUBLIC ${CLICE_CXX_FLAGS})
|
||||
target_link_options(unit_tests PUBLIC ${CLICE_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
30
cmake/croaring-fix.patch
Normal file
30
cmake/croaring-fix.patch
Normal file
@@ -0,0 +1,30 @@
|
||||
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
|
||||
index addff26d..72d4b2f8 100644
|
||||
--- a/src/CMakeLists.txt
|
||||
+++ b/src/CMakeLists.txt
|
||||
@@ -90,7 +90,7 @@ foreach(tree_type BUILD INSTALL)
|
||||
"${build_location}/roaring-config-version.cmake"
|
||||
VERSION ${ROARING_LIB_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
- configure_package_config_file("${CMAKE_SOURCE_DIR}/cmake/config.cmake.in"
|
||||
+ configure_package_config_file("${PROJECT_SOURCE_DIR}/cmake/config.cmake.in"
|
||||
"${build_location}/roaring-config.cmake"
|
||||
INSTALL_DESTINATION "${install_location}")
|
||||
|
||||
diff --git a/tools/cmake/FindOptions.cmake b/tools/cmake/FindOptions.cmake
|
||||
index 69b40ed8..55cbece4 100644
|
||||
--- a/tools/cmake/FindOptions.cmake
|
||||
+++ b/tools/cmake/FindOptions.cmake
|
||||
@@ -38,10 +38,11 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXXSTD_FLAGS} ${OPT_FLAGS} ${INCLUDE_F
|
||||
|
||||
if(MSVC)
|
||||
add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /wd4267 /wd4244 /wd4113 /nologo")
|
||||
-endif()
|
||||
if(MSVC_VERSION GREATER 1910)
|
||||
add_definitions("/permissive-")
|
||||
endif()
|
||||
+endif()
|
||||
+
|
||||
if(ROARING_LINK_STATIC)
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-static")
|
||||
142
cmake/package.cmake
Normal file
142
cmake/package.cmake
Normal file
@@ -0,0 +1,142 @@
|
||||
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()
|
||||
|
||||
# install dependencies
|
||||
include(FetchContent)
|
||||
|
||||
if(WIN32)
|
||||
set(NULL_DEVICE NUL)
|
||||
else()
|
||||
set(NULL_DEVICE /dev/null)
|
||||
endif()
|
||||
|
||||
# libuv
|
||||
FetchContent_Declare(
|
||||
libuv
|
||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
||||
GIT_TAG v1.x
|
||||
)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(ASAN ON CACHE BOOL "Enable AddressSanitizer for libuv" FORCE)
|
||||
endif()
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build dependencies as static libs")
|
||||
|
||||
# spdlog
|
||||
FetchContent_Declare(
|
||||
spdlog
|
||||
GIT_REPOSITORY https://github.com/gabime/spdlog.git
|
||||
GIT_TAG v1.15.3
|
||||
)
|
||||
|
||||
# tomlplusplus
|
||||
FetchContent_Declare(
|
||||
tomlplusplus
|
||||
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
|
||||
)
|
||||
|
||||
# croaring
|
||||
FetchContent_Declare(
|
||||
croaring
|
||||
GIT_REPOSITORY https://github.com/RoaringBitmap/CRoaring.git
|
||||
GIT_TAG v4.4.0
|
||||
# Workaround for https://github.com/RoaringBitmap/CRoaring/pull/750
|
||||
PATCH_COMMAND git apply --reverse --check ${PROJECT_SOURCE_DIR}/cmake/croaring-fix.patch 2> ${NULL_DEVICE}
|
||||
|| git apply ${PROJECT_SOURCE_DIR}/cmake/croaring-fix.patch
|
||||
)
|
||||
set(ENABLE_ROARING_TESTS OFF CACHE INTERNAL "")
|
||||
|
||||
set(CMAKE_MODULE_PATH "")
|
||||
FetchContent_MakeAvailable(libuv spdlog tomlplusplus croaring)
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(uv_a PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND TARGET uv_a)
|
||||
target_compile_options(uv_a PRIVATE
|
||||
"-Wno-unused-function"
|
||||
"-Wno-unused-variable"
|
||||
"-Wno-unused-but-set-variable"
|
||||
"-Wno-deprecated-declarations"
|
||||
"-Wno-missing-braces"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_USE_STD_FORMAT=1 SPDLOG_NO_EXCEPTIONS=1)
|
||||
@@ -75,8 +75,10 @@ public:
|
||||
}
|
||||
|
||||
void handleAttrOccurrence(const clang::Attr* attr, clang::SourceRange range) {
|
||||
assert(attr && "Invalid attribute");
|
||||
assert(range.isValid() && "Invalid range");
|
||||
if(!attr || range.isInvalid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr(!std::same_as<decltype(&SemanticVisitor::handleAttrOccurrence),
|
||||
decltype(&Derived::handleAttrOccurrence)>) {
|
||||
getDerived().handleAttrOccurrence(attr, range);
|
||||
@@ -633,6 +635,7 @@ public:
|
||||
}
|
||||
|
||||
bool VisitAttr(clang::Attr* attr) {
|
||||
|
||||
getDerived().handleAttrOccurrence(attr, attr->getRange());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Shared.h"
|
||||
#include "Feature/SemanticToken.h"
|
||||
#include "Feature/FoldingRange.h"
|
||||
#include "Feature/DocumentLink.h"
|
||||
#include "Feature/DocumentSymbol.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
class FeatureIndex {
|
||||
public:
|
||||
FeatureIndex(char* base, std::size_t size) : base(base), size(size) {}
|
||||
|
||||
/// The path of source file.
|
||||
llvm::StringRef path();
|
||||
|
||||
/// The content of source file.
|
||||
llvm::StringRef content();
|
||||
|
||||
feature::SemanticTokens semanticTokens() const;
|
||||
|
||||
feature::FoldingRanges foldingRanges() const;
|
||||
|
||||
feature::DocumentLinks documentLinks() const;
|
||||
|
||||
feature::DocumentSymbols documentSymbols() const;
|
||||
|
||||
static Shared<std::vector<char>> build(CompilationUnit& unit);
|
||||
|
||||
public:
|
||||
char* base;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
#include "TUIndex.h"
|
||||
#include "RawIndex.h"
|
||||
#include "HeaderIndex.h"
|
||||
#include "IncludeGraph.h"
|
||||
|
||||
namespace clice::index::memory {
|
||||
|
||||
struct Indices {
|
||||
std::unique_ptr<TUIndex> tu_index;
|
||||
llvm::DenseMap<clang::FileID, std::unique_ptr<RawIndex>> header_indices;
|
||||
};
|
||||
|
||||
Indices index(CompilationUnit& unit);
|
||||
|
||||
} // namespace clice::index::memory
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
/// When serialize index to binary, we will transform all pointer to offset
|
||||
/// to base address. And data only will be deserialized when it is accessed.
|
||||
struct Relative {
|
||||
const void* base = nullptr;
|
||||
const void* data = nullptr;
|
||||
|
||||
bool operator== (const Relative& other) const = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LazyArray : Relative {
|
||||
public:
|
||||
LazyArray(const void* base, const void* data, std::uint32_t size, std::uint32_t stride) :
|
||||
Relative{base, data}, size(size), stride(stride) {}
|
||||
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = T;
|
||||
|
||||
class Iterator : Relative {
|
||||
public:
|
||||
Iterator(const void* base, const void* data, std::size_t stride) :
|
||||
Relative{base, data}, stride(stride) {}
|
||||
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = T;
|
||||
|
||||
Iterator() = default;
|
||||
|
||||
Iterator(const Iterator&) = default;
|
||||
|
||||
decltype(auto) operator* () const {
|
||||
if constexpr(std::derived_from<T, Relative>) {
|
||||
return T{base, data};
|
||||
} else {
|
||||
return *static_cast<const T*>(data);
|
||||
}
|
||||
}
|
||||
|
||||
Iterator& operator++ () {
|
||||
data = static_cast<const char*>(data) + stride;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++ (int) {
|
||||
++*this;
|
||||
}
|
||||
|
||||
bool operator== (const Iterator& other) const = default;
|
||||
|
||||
private:
|
||||
std::uint32_t stride;
|
||||
};
|
||||
|
||||
Iterator begin() const {
|
||||
return Iterator(base, data, stride);
|
||||
}
|
||||
|
||||
Iterator end() const {
|
||||
return Iterator(base, static_cast<const char*>(data) + size * stride, stride);
|
||||
}
|
||||
|
||||
uint32_t length() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
decltype(auto) operator[] (uint32_t index) const {
|
||||
const void* data = static_cast<const char*>(this->data) + index * stride;
|
||||
if constexpr(std::derived_from<T, Relative>) {
|
||||
return T{base, data};
|
||||
} else {
|
||||
return *static_cast<const T*>(data);
|
||||
}
|
||||
}
|
||||
|
||||
bool operator== (const LazyArray& other) const = default;
|
||||
|
||||
private:
|
||||
std::uint32_t size;
|
||||
std::uint32_t stride;
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
138
include/Index/MergedIndex.h
Normal file
138
include/Index/MergedIndex.h
Normal file
@@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
|
||||
#include "TUIndex.h"
|
||||
|
||||
#define ROARING_EXCEPTIONS 0
|
||||
#define ROARING_TERMINATE(message) std::abort()
|
||||
#include "roaring/roaring.hh"
|
||||
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
/// struct CompilationContext {
|
||||
/// /// The target of this compilation.
|
||||
/// llvm::StringRef target;
|
||||
///
|
||||
/// /// The canonical compilation command.
|
||||
/// llvm::StringRef command;
|
||||
///
|
||||
/// /// A version field for verification.
|
||||
/// std::uint32_t version;
|
||||
/// };
|
||||
///
|
||||
/// struct HeaderContext : CompilationContext {
|
||||
/// /// The include location in the include graph.
|
||||
/// std::uint32_t include;
|
||||
///
|
||||
/// /// The path of the file includes this header.
|
||||
/// llvm::StringRef path;
|
||||
/// };
|
||||
|
||||
struct HeaderContexts {
|
||||
std::uint32_t version = 0;
|
||||
|
||||
using Context = std::pair<std::uint32_t, std::uint32_t>;
|
||||
|
||||
/// A array of include location and its context id.
|
||||
llvm::SmallVector<Context> includes;
|
||||
};
|
||||
|
||||
struct MergedIndex {
|
||||
/// For each merged index, we will give it a canonical id.
|
||||
/// The max canonical id.
|
||||
std::uint32_t max_canonical_id = 0;
|
||||
|
||||
/// We use the value of SHA256 to judge whether two indices are same.
|
||||
/// Index with same content will be given same canonical id.
|
||||
llvm::DenseMap<llvm::StringRef, std::uint32_t> canonical_cache;
|
||||
|
||||
/// The allocator for storing sha256 hash.
|
||||
llvm::BumpPtrAllocator allocator;
|
||||
|
||||
/// The reference count of each canonical id.
|
||||
std::vector<std::uint32_t> canonical_ref_counts;
|
||||
|
||||
/// The canonical id set of removed index.
|
||||
roaring::Roaring removed;
|
||||
|
||||
/// A map between source file path and its header contexts.
|
||||
llvm::StringMap<HeaderContexts> contexts;
|
||||
|
||||
/// All merged symbol relations.
|
||||
llvm::DenseMap<SymbolHash, llvm::DenseMap<Relation, roaring::Roaring>> relations;
|
||||
|
||||
/// All merged symbol occurrences.
|
||||
llvm::DenseMap<Occurrence, roaring::Roaring> occurrences;
|
||||
|
||||
void remove(llvm::StringRef path);
|
||||
|
||||
void merge(llvm::StringRef path, std::uint32_t include, FileIndex& index);
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <typename... Ts>
|
||||
unsigned dense_hash(const Ts&... ts) {
|
||||
return llvm::DenseMapInfo<std::tuple<Ts...>>::getHashValue(std::tuple{ts...});
|
||||
}
|
||||
|
||||
template <>
|
||||
struct DenseMapInfo<clice::index::Occurrence> {
|
||||
using R = clice::LocalSourceRange;
|
||||
using V = clice::index::Occurrence;
|
||||
|
||||
inline static V getEmptyKey() {
|
||||
return V(R(-1, 0), 0);
|
||||
}
|
||||
|
||||
inline static V getTombstoneKey() {
|
||||
return V(R(-2, 0), 0);
|
||||
}
|
||||
|
||||
static auto getHashValue(const V& v) {
|
||||
return dense_hash(v.range.begin, v.range.end, v.target);
|
||||
}
|
||||
|
||||
static bool isEqual(const V& lhs, const V& rhs) {
|
||||
return lhs.range == rhs.range && lhs.target == rhs.target;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DenseMapInfo<clice::index::Relation> {
|
||||
using R = clice::index::Relation;
|
||||
|
||||
inline static R getEmptyKey() {
|
||||
return R{
|
||||
.kind = clice::RelationKind(),
|
||||
.range = clice::LocalSourceRange(-1, 0),
|
||||
.target_symbol = 0,
|
||||
};
|
||||
}
|
||||
|
||||
inline static R getTombstoneKey() {
|
||||
return R{
|
||||
.kind = clice::RelationKind(),
|
||||
.range = clice::LocalSourceRange(-2, 0),
|
||||
.target_symbol = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Contextual doen't take part in hashing and equality.
|
||||
static auto getHashValue(const R& relation) {
|
||||
return dense_hash(relation.kind.value(),
|
||||
relation.range.begin,
|
||||
relation.range.end,
|
||||
relation.target_symbol);
|
||||
}
|
||||
|
||||
static bool isEqual(const R& lhs, const R& rhs) {
|
||||
return lhs.kind == rhs.kind && lhs.range == rhs.range &&
|
||||
lhs.target_symbol == rhs.target_symbol;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
@@ -1,85 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Shared.h"
|
||||
#include "LazyArray.h"
|
||||
#include "AST/SymbolID.h"
|
||||
#include "AST/SourceCode.h"
|
||||
#include "AST/SymbolKind.h"
|
||||
#include "AST/RelationKind.h"
|
||||
#include "Support/JSON.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
struct Symbol;
|
||||
|
||||
struct Relation : Relative {
|
||||
/// Return the relation kind.
|
||||
RelationKind kind() const;
|
||||
|
||||
/// Return the range of relation.
|
||||
LocalSourceRange range() const;
|
||||
|
||||
/// Return the definition range.
|
||||
LocalSourceRange sourceRange() const;
|
||||
|
||||
/// The target symbol.
|
||||
Symbol target() const;
|
||||
};
|
||||
|
||||
struct Symbol : Relative {
|
||||
/// Return the symbol id.
|
||||
SymbolID id() const;
|
||||
|
||||
/// Return the hash value of symbol id.
|
||||
std::uint64_t hash() const;
|
||||
|
||||
/// Return the symbol name.
|
||||
llvm::StringRef name() const;
|
||||
|
||||
/// Return the symbol kind.
|
||||
SymbolKind kind() const;
|
||||
|
||||
/// Return all relations of this symbol.
|
||||
LazyArray<Relation> relations() const;
|
||||
};
|
||||
|
||||
struct Occurrence : Relative {
|
||||
/// The source range of occurrence.
|
||||
LocalSourceRange range() const;
|
||||
|
||||
/// The target symbol of occurrence.
|
||||
Symbol symbol() const;
|
||||
};
|
||||
|
||||
class SymbolIndex {
|
||||
public:
|
||||
SymbolIndex(const char* data, std::uint32_t size) : data(data), size(size) {}
|
||||
|
||||
/// The path of source file.
|
||||
llvm::StringRef path() const;
|
||||
|
||||
/// The content of source file.
|
||||
llvm::StringRef content() const;
|
||||
|
||||
/// All symbols in the index.
|
||||
LazyArray<Symbol> symbols() const;
|
||||
|
||||
/// All occurrences in the index.
|
||||
LazyArray<Occurrence> occurrences() const;
|
||||
|
||||
/// Locate the symbols with given offset.
|
||||
std::vector<Symbol> locateSymbol(uint32_t offset) const;
|
||||
|
||||
/// Locate the symbol with given symbol id.
|
||||
std::optional<Symbol> locateSymbol(const SymbolID& id) const;
|
||||
|
||||
static Shared<std::vector<char>> build(CompilationUnit& unit);
|
||||
|
||||
json::Value toJSON(bool line = true);
|
||||
|
||||
private:
|
||||
const char* data;
|
||||
std::uint32_t size;
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
@@ -1,19 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "RawIndex.h"
|
||||
#include "IncludeGraph.h"
|
||||
#include "AST/SourceCode.h"
|
||||
#include "AST/RelationKind.h"
|
||||
|
||||
namespace clice::index::memory {
|
||||
namespace clice::index {
|
||||
|
||||
class TUIndex : public RawIndex {
|
||||
public:
|
||||
using Range = LocalSourceRange;
|
||||
using SymbolHash = std::uint64_t;
|
||||
|
||||
public:
|
||||
/// The time of building this index.
|
||||
std::int64_t time;
|
||||
struct Relation {
|
||||
RelationKind kind;
|
||||
|
||||
/// The include graph of this index.
|
||||
IncludeGraph graph;
|
||||
char padding[4] = {0, 0, 0, 0};
|
||||
|
||||
LocalSourceRange range;
|
||||
|
||||
union {
|
||||
LocalSourceRange definition_range;
|
||||
|
||||
SymbolHash target_symbol;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace clice::index::memory
|
||||
struct Occurrence {
|
||||
/// range of this occurrence.
|
||||
Range range;
|
||||
|
||||
///
|
||||
SymbolHash target;
|
||||
};
|
||||
|
||||
struct FileIndex {
|
||||
llvm::DenseMap<SymbolHash, std::vector<Relation>> relations;
|
||||
|
||||
std::vector<Occurrence> occurrences;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
std::string name;
|
||||
|
||||
/// ...
|
||||
};
|
||||
|
||||
struct TUIndex {
|
||||
IncludeGraph graph;
|
||||
|
||||
llvm::DenseMap<SymbolHash, Symbol> symbols;
|
||||
|
||||
llvm::DenseMap<clang::FileID, FileIndex> file_indices;
|
||||
|
||||
static TUIndex build(CompilationUnit& unit);
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
|
||||
@@ -13,65 +13,6 @@ namespace clice {
|
||||
|
||||
class CompilationUnit;
|
||||
|
||||
class Indexer {
|
||||
public:
|
||||
/// Index an opened file, its AST is already builtin
|
||||
/// and PCH is used for it.
|
||||
async::Task<> index(CompilationUnit& unit);
|
||||
|
||||
/// Index an static file.
|
||||
async::Task<> index(llvm::StringRef file);
|
||||
|
||||
using Path = std::string;
|
||||
using PathID = std::uint32_t;
|
||||
using SymbolID = std::uint64_t;
|
||||
|
||||
public:
|
||||
Indexer(CompilationDatabase& database) : database(database) {}
|
||||
|
||||
PathID getPath(llvm::StringRef path) {
|
||||
auto it = paths.find(path);
|
||||
if(it != paths.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto id = path_storage.size();
|
||||
path_storage.emplace_back(path);
|
||||
paths.try_emplace(path, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
private:
|
||||
struct HeaderIndices {
|
||||
using RawIndex = std::pair<std::uint32_t, std::unique_ptr<index::memory::RawIndex>>;
|
||||
|
||||
/// The merged index.
|
||||
std::unique_ptr<index::memory::HeaderIndex> merged;
|
||||
|
||||
llvm::DenseMap<PathID, std::vector<RawIndex>> unmergeds;
|
||||
};
|
||||
|
||||
CompilationDatabase& database;
|
||||
|
||||
/// All paths of indices.
|
||||
std::vector<Path> path_storage;
|
||||
|
||||
/// A map between path and its id.
|
||||
llvm::StringMap<PathID> paths;
|
||||
|
||||
/// A map between symbol id and files that contains it.
|
||||
llvm::DenseMap<SymbolID, llvm::DenseSet<PathID>> symbol_indices;
|
||||
|
||||
/// A map between source file path and its static indices.
|
||||
llvm::DenseMap<PathID, Path> static_indices;
|
||||
|
||||
std::uint32_t unmerged_count = 0;
|
||||
|
||||
/// In-memory header indices.
|
||||
llvm::DenseMap<PathID, std::unique_ptr<HeaderIndices>> dynamic_header_indices;
|
||||
|
||||
/// In-memory translation unit indices.
|
||||
llvm::DenseMap<PathID, std::unique_ptr<index::memory::TUIndex>> dynamic_tu_indices;
|
||||
};
|
||||
class Indexer {};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#include "Compiler/CompilationUnit.h"
|
||||
#include "Support/Binary.h"
|
||||
#include "Index/FeatureIndex.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
namespace memory {
|
||||
|
||||
struct FeatureIndex {
|
||||
/// The path of source file.
|
||||
std::string path;
|
||||
|
||||
/// The content of source file.
|
||||
std::string content;
|
||||
|
||||
/// The index of semantic tokens.
|
||||
feature::SemanticTokens tokens;
|
||||
|
||||
/// The index of folding ranges.
|
||||
feature::FoldingRanges foldings;
|
||||
|
||||
/// The index of document links.
|
||||
feature::DocumentLinks links;
|
||||
|
||||
/// The index of document symbols.
|
||||
feature::DocumentSymbols symbols;
|
||||
};
|
||||
|
||||
} // namespace memory
|
||||
|
||||
llvm::StringRef FeatureIndex::path() {
|
||||
binary::Proxy<memory::FeatureIndex> index{base, base};
|
||||
return index.get<"path">().as_string();
|
||||
}
|
||||
|
||||
llvm::StringRef FeatureIndex::content() {
|
||||
binary::Proxy<memory::FeatureIndex> index{base, base};
|
||||
return index.get<"content">().as_string();
|
||||
}
|
||||
|
||||
feature::SemanticTokens FeatureIndex::semanticTokens() const {
|
||||
binary::Proxy<memory::FeatureIndex> index{base, base};
|
||||
return binary::deserialize(index.get<"tokens">());
|
||||
}
|
||||
|
||||
feature::FoldingRanges FeatureIndex::foldingRanges() const {
|
||||
binary::Proxy<memory::FeatureIndex> index{base, base};
|
||||
return binary::deserialize(index.get<"foldings">());
|
||||
}
|
||||
|
||||
feature::DocumentLinks FeatureIndex::documentLinks() const {
|
||||
binary::Proxy<memory::FeatureIndex> index{base, base};
|
||||
return binary::deserialize(index.get<"links">());
|
||||
}
|
||||
|
||||
feature::DocumentSymbols FeatureIndex::documentSymbols() const {
|
||||
binary::Proxy<memory::FeatureIndex> index{base, base};
|
||||
return binary::deserialize(index.get<"symbols">());
|
||||
}
|
||||
|
||||
Shared<std::vector<char>> FeatureIndex::build(CompilationUnit& unit) {
|
||||
Shared<memory::FeatureIndex> indices;
|
||||
|
||||
for(auto&& [fid, result]: feature::index_semantic_token(unit)) {
|
||||
indices[fid].tokens = std::move(result);
|
||||
}
|
||||
|
||||
for(auto&& [fid, result]: feature::index_folding_range(unit)) {
|
||||
indices[fid].foldings = std::move(result);
|
||||
}
|
||||
|
||||
for(auto&& [fid, result]: feature::index_document_link(unit)) {
|
||||
indices[fid].links = std::move(result);
|
||||
}
|
||||
|
||||
for(auto&& [fid, result]: feature::index_document_symbol(unit)) {
|
||||
indices[fid].symbols = std::move(result);
|
||||
}
|
||||
|
||||
Shared<std::vector<char>> result;
|
||||
|
||||
for(auto&& [fid, index]: indices) {
|
||||
index.path = unit.file_path(fid);
|
||||
index.content = unit.file_content(fid);
|
||||
auto [buffer, _] = binary::serialize(index);
|
||||
result.try_emplace(fid, std::move(buffer));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace clice::index
|
||||
@@ -1,145 +0,0 @@
|
||||
#include "AST/Semantic.h"
|
||||
#include "Index/Index.h"
|
||||
#include "Index/IncludeGraph.h"
|
||||
#include "Support/Format.h"
|
||||
|
||||
namespace clice::index::memory {
|
||||
|
||||
namespace {
|
||||
|
||||
class IndexBuilder : public Indices, public SemanticVisitor<IndexBuilder> {
|
||||
public:
|
||||
IndexBuilder(CompilationUnit& unit) : SemanticVisitor(unit, false) {
|
||||
tu_index = std::make_unique<TUIndex>();
|
||||
tu_index->path = unit.file_path(unit.interested_file());
|
||||
tu_index->content = unit.file_content(unit.interested_file());
|
||||
tu_index->graph = IncludeGraph::from(unit);
|
||||
}
|
||||
|
||||
RawIndex& getIndex(clang::FileID fid) {
|
||||
if(fid == unit.interested_file()) {
|
||||
return *tu_index;
|
||||
}
|
||||
|
||||
if(auto it = header_indices.find(fid); it != header_indices.end()) {
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
auto [it, _] = header_indices.try_emplace(fid, new RawIndex());
|
||||
auto& index = *it->second;
|
||||
index.path = unit.file_path(fid);
|
||||
index.content = unit.file_content(fid);
|
||||
return index;
|
||||
}
|
||||
|
||||
void handleDeclOccurrence(const clang::NamedDecl* decl,
|
||||
RelationKind kind,
|
||||
clang::SourceLocation location) {
|
||||
assert(decl && "Invalid decl");
|
||||
decl = ast::normalize(decl);
|
||||
|
||||
if(location.isMacroID()) {
|
||||
auto spelling = unit.spelling_location(location);
|
||||
auto expansion = unit.expansion_location(location);
|
||||
|
||||
/// FIXME: For location from macro, we only handle the case that the
|
||||
/// spelling and expansion are in the same file currently.
|
||||
if(unit.file_id(spelling) != unit.file_id(expansion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/// For occurrence, we always use spelling location.
|
||||
location = spelling;
|
||||
}
|
||||
|
||||
auto [fid, range] = unit.decompose_range(location);
|
||||
auto& index = getIndex(fid);
|
||||
auto symbol_id = unit.getSymbolID(decl);
|
||||
auto& symbol = index.get_symbol(symbol_id.hash);
|
||||
symbol.kind = SymbolKind::from(decl);
|
||||
index.add_occurrence(range, symbol_id.hash);
|
||||
}
|
||||
|
||||
void handleMacroOccurrence(const clang::MacroInfo* def,
|
||||
RelationKind kind,
|
||||
clang::SourceLocation location) {
|
||||
/// FIXME: Figure out when location is MacroID.
|
||||
if(location.isMacroID()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto [fid, range] = unit.decompose_range(location);
|
||||
auto& index = getIndex(fid);
|
||||
auto symbol_id = unit.getSymbolID(def);
|
||||
auto& symbol = index.get_symbol(symbol_id.hash);
|
||||
symbol.kind = SymbolKind::Macro;
|
||||
symbol.name = unit.token_spelling(def->getDefinitionLoc());
|
||||
index.add_occurrence(range, symbol_id.hash);
|
||||
|
||||
if(kind & RelationKind::Definition) {
|
||||
auto begin = def->getDefinitionLoc();
|
||||
auto end = def->getDefinitionEndLoc();
|
||||
assert(begin.isFileID() && end.isFileID() && "Invalid location");
|
||||
auto [fid2, definition_range] = unit.decompose_range(clang::SourceRange(begin, end));
|
||||
assert(fid == fid2 && "Invalid macro definition location");
|
||||
/// definitionLoc = builder.getLocation(range);
|
||||
|
||||
index.add_relation(symbol,
|
||||
Relation{
|
||||
.kind = RelationKind::Definition,
|
||||
.range = range,
|
||||
.definition_range = definition_range,
|
||||
});
|
||||
} else {
|
||||
index.add_relation(symbol,
|
||||
Relation{
|
||||
.kind = RelationKind::Reference,
|
||||
.range = range,
|
||||
.target_symbol = 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void handleRelation(const clang::NamedDecl* decl,
|
||||
RelationKind kind,
|
||||
const clang::NamedDecl* target,
|
||||
clang::SourceRange range) {
|
||||
auto [fid, relationRange] = unit.decompose_expansion_range(range);
|
||||
|
||||
Relation relation{.kind = kind};
|
||||
|
||||
if(kind.isDeclOrDef()) {
|
||||
auto [fid2, definitionRange] = unit.decompose_expansion_range(decl->getSourceRange());
|
||||
assert(fid == fid2 && "Invalid definition location");
|
||||
relation.range = relationRange;
|
||||
relation.definition_range = definitionRange;
|
||||
} else if(kind.isReference()) {
|
||||
relation.range = relationRange;
|
||||
relation.target_symbol = 0;
|
||||
} else if(kind.isBetweenSymbol()) {
|
||||
auto symbol_id = unit.getSymbolID(ast::normalize(target));
|
||||
relation.target_symbol = symbol_id.hash;
|
||||
} else if(kind.isCall()) {
|
||||
auto symbol_id = unit.getSymbolID(ast::normalize(target));
|
||||
relation.range = relationRange;
|
||||
relation.target_symbol = symbol_id.hash;
|
||||
} else {
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
auto& index = getIndex(fid);
|
||||
auto symbol_id = unit.getSymbolID(ast::normalize(decl));
|
||||
auto& symbol = index.get_symbol(symbol_id.hash);
|
||||
index.add_relation(symbol, relation);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Indices index(CompilationUnit& unit) {
|
||||
IndexBuilder builder(unit);
|
||||
builder.run();
|
||||
return std::move(builder);
|
||||
}
|
||||
|
||||
} // namespace clice::index::memory
|
||||
89
src/Index/MergedIndex.cpp
Normal file
89
src/Index/MergedIndex.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "Index/MergedIndex.h"
|
||||
#include "llvm/Support/SHA256.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
namespace {
|
||||
|
||||
auto sha256_hash(FileIndex& index) {
|
||||
llvm::SHA256 hasher;
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
|
||||
if(!index.occurrences.empty()) {
|
||||
static_assert(sizeof(Occurrence) == sizeof(Range) + sizeof(SymbolHash));
|
||||
static_assert(sizeof(Occurrence) % 8 == 0);
|
||||
auto data = reinterpret_cast<u8*>(index.occurrences.data());
|
||||
auto size = index.occurrences.size() * sizeof(Occurrence);
|
||||
hasher.update(llvm::ArrayRef(data, size));
|
||||
}
|
||||
|
||||
for(auto& [symbol_id, relations]: index.relations) {
|
||||
hasher.update(std::bit_cast<std::array<u8, sizeof(symbol_id)>>(symbol_id));
|
||||
static_assert(sizeof(Relation) ==
|
||||
sizeof(RelationKind) + 4 + sizeof(Range) + sizeof(SymbolHash));
|
||||
static_assert(sizeof(Relation) % 8 == 0);
|
||||
|
||||
if(!relations.empty()) {
|
||||
auto data = reinterpret_cast<u8*>(relations.data());
|
||||
auto size = relations.size() * sizeof(Relation);
|
||||
hasher.update(llvm::ArrayRef(data, size));
|
||||
}
|
||||
}
|
||||
|
||||
return hasher.final();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void MergedIndex::remove(llvm::StringRef path) {
|
||||
auto& includes = contexts[path].includes;
|
||||
|
||||
for(auto& [_, canonical_id]: includes) {
|
||||
auto& ref_counts = canonical_ref_counts[canonical_id];
|
||||
ref_counts -= 1;
|
||||
|
||||
if(ref_counts == 0) {
|
||||
removed.add(canonical_id);
|
||||
}
|
||||
}
|
||||
|
||||
includes.clear();
|
||||
}
|
||||
|
||||
void MergedIndex::merge(llvm::StringRef path, std::uint32_t include, FileIndex& index) {
|
||||
auto& context = contexts[path];
|
||||
|
||||
auto hash = sha256_hash(index);
|
||||
auto hash_key = llvm::StringRef(reinterpret_cast<char*>(hash.data()), hash.size());
|
||||
auto [it, success] = canonical_cache.try_emplace(hash_key, max_canonical_id);
|
||||
|
||||
auto canonical_id = it->second;
|
||||
context.includes.emplace_back(include, canonical_id);
|
||||
|
||||
if(!success) {
|
||||
canonical_ref_counts[canonical_id] += 1;
|
||||
removed.remove(canonical_id);
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = allocator.Allocate<char>(32);
|
||||
std::ranges::copy(hash, data);
|
||||
it->first = llvm::StringRef(data, hash.size());
|
||||
|
||||
for(auto& occurrence: index.occurrences) {
|
||||
this->occurrences[occurrence].add(canonical_id);
|
||||
}
|
||||
|
||||
for(auto& [symbol_id, relations]: index.relations) {
|
||||
auto& target = this->relations[symbol_id];
|
||||
for(auto& relation: relations) {
|
||||
target[relation].add(canonical_id);
|
||||
}
|
||||
}
|
||||
|
||||
canonical_ref_counts.emplace_back(1);
|
||||
max_canonical_id += 1;
|
||||
}
|
||||
|
||||
} // namespace clice::index
|
||||
119
src/Index/TUIndex.cpp
Normal file
119
src/Index/TUIndex.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "AST/Semantic.h"
|
||||
#include "Index/TUIndex.h"
|
||||
#include "Support/Compare.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
namespace {
|
||||
|
||||
class Builder : public SemanticVisitor<Builder> {
|
||||
public:
|
||||
Builder(TUIndex& result, CompilationUnit& unit) :
|
||||
SemanticVisitor<Builder>(unit, false), result(result) {
|
||||
result.graph = IncludeGraph::from(unit);
|
||||
}
|
||||
|
||||
void handleDeclOccurrence(const clang::NamedDecl* decl,
|
||||
RelationKind kind,
|
||||
clang::SourceLocation location) {
|
||||
assert(decl && "Invalid decl");
|
||||
decl = ast::normalize(decl);
|
||||
|
||||
if(location.isMacroID()) {
|
||||
auto spelling = unit.spelling_location(location);
|
||||
auto expansion = unit.expansion_location(location);
|
||||
|
||||
/// FIXME: For location from macro, we only handle the case that the
|
||||
/// spelling and expansion are in the same file currently.
|
||||
if(unit.file_id(spelling) != unit.file_id(expansion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/// For occurrence, we always use spelling location.
|
||||
location = spelling;
|
||||
}
|
||||
|
||||
auto [fid, range] = unit.decompose_range(location);
|
||||
auto& index = result.file_indices[fid];
|
||||
|
||||
auto symbol_id = unit.getSymbolID(decl);
|
||||
index.occurrences.emplace_back(range, symbol_id.hash);
|
||||
}
|
||||
|
||||
void handleMacroOccurrence(const clang::MacroInfo* def,
|
||||
RelationKind kind,
|
||||
clang::SourceLocation location) {
|
||||
/// FIXME: Figure out when location is MacroID.
|
||||
if(location.isMacroID()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto [fid, range] = unit.decompose_range(location);
|
||||
auto& index = result.file_indices[fid];
|
||||
|
||||
auto symbol_id = unit.getSymbolID(def);
|
||||
index.occurrences.emplace_back(range, symbol_id.hash);
|
||||
|
||||
Relation relation{
|
||||
.kind = RelationKind::Definition,
|
||||
.range = range,
|
||||
.target_symbol = 0,
|
||||
};
|
||||
|
||||
index.relations[symbol_id.hash].emplace_back(relation);
|
||||
}
|
||||
|
||||
void handleRelation(const clang::NamedDecl* decl,
|
||||
RelationKind kind,
|
||||
const clang::NamedDecl* target,
|
||||
clang::SourceRange range) {
|
||||
auto [fid, relationRange] = unit.decompose_expansion_range(range);
|
||||
|
||||
Relation relation{.kind = kind};
|
||||
|
||||
if(kind.isDeclOrDef()) {
|
||||
auto [fid2, definitionRange] = unit.decompose_expansion_range(decl->getSourceRange());
|
||||
assert(fid == fid2 && "Invalid definition location");
|
||||
relation.range = relationRange;
|
||||
relation.definition_range = definitionRange;
|
||||
} else if(kind.isReference()) {
|
||||
relation.range = relationRange;
|
||||
relation.target_symbol = 0;
|
||||
} else if(kind.isBetweenSymbol()) {
|
||||
auto symbol_id = unit.getSymbolID(ast::normalize(target));
|
||||
relation.target_symbol = symbol_id.hash;
|
||||
} else if(kind.isCall()) {
|
||||
auto symbol_id = unit.getSymbolID(ast::normalize(target));
|
||||
relation.range = relationRange;
|
||||
relation.target_symbol = symbol_id.hash;
|
||||
} else {
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
auto& index = result.file_indices[fid];
|
||||
auto symbol_id = unit.getSymbolID(ast::normalize(decl));
|
||||
index.relations[symbol_id.hash].emplace_back(relation);
|
||||
}
|
||||
|
||||
void build() {
|
||||
run();
|
||||
|
||||
for(auto& [fid, index]: result.file_indices) {
|
||||
std::ranges::sort(index.occurrences, refl::less);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TUIndex& result;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TUIndex TUIndex::build(CompilationUnit& unit) {
|
||||
TUIndex index;
|
||||
Builder builder(index, unit);
|
||||
builder.build();
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace clice::index
|
||||
@@ -4,60 +4,4 @@
|
||||
#include "Server/Indexer.h"
|
||||
#include "Support/Logging.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
async::Task<> Indexer::index(CompilationUnit& unit) {
|
||||
auto [tu_index, header_indices] =
|
||||
co_await async::submit([&] { return index::memory::index(unit); });
|
||||
|
||||
auto tu_id = getPath(tu_index->path);
|
||||
|
||||
llvm::DenseSet<PathID> visited_headers;
|
||||
|
||||
for(auto& [fid, index]: header_indices) {
|
||||
auto id = getPath(index->path);
|
||||
auto it = dynamic_header_indices.find(id);
|
||||
|
||||
/// FIXME: If the value less than 0, it represents the file is from
|
||||
/// PCH or module. How to handle such file?
|
||||
if(fid < clang::FileID::getSentinel()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto include = tu_index->graph.getInclude(fid);
|
||||
|
||||
if(it != dynamic_header_indices.end()) {
|
||||
auto& indices = it->second;
|
||||
|
||||
if(!visited_headers.contains(id)) {
|
||||
indices->unmergeds[tu_id].clear();
|
||||
visited_headers.insert(id);
|
||||
}
|
||||
|
||||
indices->unmergeds[tu_id].emplace_back(include, std::move(index));
|
||||
} else {
|
||||
auto [it, _] = dynamic_header_indices.try_emplace(id, new HeaderIndices());
|
||||
it->second->unmergeds[tu_id].emplace_back(include, std::move(index));
|
||||
visited_headers.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
dynamic_tu_indices[tu_id] = std::move(tu_index);
|
||||
}
|
||||
|
||||
async::Task<> Indexer::index(llvm::StringRef file) {
|
||||
CompilationParams params;
|
||||
params.kind = CompilationUnit::Indexing;
|
||||
params.arguments = database.get_command(file).arguments;
|
||||
|
||||
auto AST = co_await async::submit([&] { return compile(params); });
|
||||
|
||||
if(!AST) {
|
||||
logging::info("Fail to index background file {}", file);
|
||||
co_return;
|
||||
}
|
||||
|
||||
co_await index(*AST);
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
namespace clice {} // namespace clice
|
||||
|
||||
67
tests/unit/Index/MergedIndex.cpp
Normal file
67
tests/unit/Index/MergedIndex.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "Test/Tester.h"
|
||||
#include "Index/MergedIndex.h"
|
||||
|
||||
namespace clice::testing {
|
||||
|
||||
namespace {
|
||||
|
||||
suite<"MergedIndex"> suite = [] {
|
||||
Tester tester;
|
||||
index::TUIndex tu_index;
|
||||
|
||||
auto build_index = [&](llvm::StringRef code,
|
||||
std::source_location location = std::source_location::current()) {
|
||||
tester.clear();
|
||||
tester.add_main("main.cpp", code);
|
||||
fatal / expect(tester.compile(), location);
|
||||
|
||||
tu_index = index::TUIndex::build(*tester.unit);
|
||||
};
|
||||
|
||||
auto expect_select = [&](llvm::StringRef pos,
|
||||
llvm::StringRef expect_range,
|
||||
llvm::StringRef file = "",
|
||||
std::source_location location = std::source_location::current()) {
|
||||
auto offset = tester.point(pos, file);
|
||||
auto range = tester.range(expect_range, file);
|
||||
|
||||
auto fid = file.empty() ? tester.unit->interested_file() : tester.unit->file_id(file);
|
||||
auto& index = tu_index.file_indices[fid];
|
||||
|
||||
auto it = std::ranges::lower_bound(
|
||||
index.occurrences,
|
||||
offset,
|
||||
{},
|
||||
[](index::Occurrence& occurrence) { return occurrence.range.end; });
|
||||
|
||||
auto err =
|
||||
std::format("Fail to find symbol for offser: {} range: range: {}", offset, dump(range));
|
||||
|
||||
fatal / expect(it != index.occurrences.end(), location) << err;
|
||||
|
||||
/// FIXME: Make eq pretty print reflectable struct.
|
||||
expect(eq(dump(it->range), dump(range)), location);
|
||||
};
|
||||
|
||||
test("Assert") = [&] {
|
||||
build_index(R"(
|
||||
#include <iostream>
|
||||
)");
|
||||
|
||||
std::println("{}", tu_index.file_indices.size());
|
||||
|
||||
index::MergedIndex merged;
|
||||
|
||||
for(auto& [fid, index]: tu_index.file_indices) {
|
||||
auto path = tester.unit->file_path(fid);
|
||||
|
||||
if(path.ends_with("stddef.h")) {
|
||||
merged.merge(path, tu_index.graph.getInclude(fid), index);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace clice::testing
|
||||
68
tests/unit/Index/TUIndex.cpp
Normal file
68
tests/unit/Index/TUIndex.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "Test/Tester.h"
|
||||
#include "Index/TUIndex.h"
|
||||
|
||||
namespace clice::testing {
|
||||
|
||||
namespace {
|
||||
|
||||
suite<"TUIndex"> suite = [] {
|
||||
Tester tester;
|
||||
index::TUIndex tu_index;
|
||||
|
||||
auto build_index = [&](llvm::StringRef code,
|
||||
std::source_location location = std::source_location::current()) {
|
||||
tester.clear();
|
||||
tester.add_main("main.cpp", code);
|
||||
fatal / expect(tester.compile(), location);
|
||||
|
||||
tu_index = index::TUIndex::build(*tester.unit);
|
||||
};
|
||||
|
||||
auto expect_select = [&](llvm::StringRef pos,
|
||||
llvm::StringRef expect_range,
|
||||
llvm::StringRef file = "",
|
||||
std::source_location location = std::source_location::current()) {
|
||||
auto offset = tester.point(pos, file);
|
||||
auto range = tester.range(expect_range, file);
|
||||
|
||||
auto fid = file.empty() ? tester.unit->interested_file() : tester.unit->file_id(file);
|
||||
auto& index = tu_index.file_indices[fid];
|
||||
|
||||
auto it = std::ranges::lower_bound(
|
||||
index.occurrences,
|
||||
offset,
|
||||
{},
|
||||
[](index::Occurrence& occurrence) { return occurrence.range.end; });
|
||||
|
||||
auto err =
|
||||
std::format("Fail to find symbol for offser: {} range: range: {}", offset, dump(range));
|
||||
|
||||
fatal / expect(it != index.occurrences.end(), location) << err;
|
||||
|
||||
/// FIXME: Make eq pretty print reflectable struct.
|
||||
expect(eq(dump(it->range), dump(range)), location);
|
||||
};
|
||||
|
||||
test("Basic") = [&] {
|
||||
build_index(R"(
|
||||
int @1[f$(1)oo]();
|
||||
|
||||
int @2[b$(2)ar]() {
|
||||
return @3[fo$(3)o]() + 1;
|
||||
}
|
||||
)");
|
||||
|
||||
expect(eq(tu_index.file_indices.size(), 1));
|
||||
auto& index = tu_index.file_indices.begin()->second;
|
||||
expect(eq(index.relations.size(), 2));
|
||||
expect(eq(index.occurrences.size(), 3));
|
||||
|
||||
expect_select("1", "1");
|
||||
expect_select("2", "2");
|
||||
expect_select("3", "3");
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace clice::testing
|
||||
10
xmake.lua
10
xmake.lua
@@ -16,7 +16,7 @@ if has_config("dev") then
|
||||
if is_plat("windows") then
|
||||
set_runtimes("MD")
|
||||
if is_mode("debug") then
|
||||
print("Clice does not support build in debug mode with pre-compiled llvm binary on windows.\n"
|
||||
print("clice does not support build in debug mode with pre-compiled llvm binary on windows.\n"
|
||||
.."See https://github.com/clice-io/clice/issues/42 for more information.")
|
||||
os.raise()
|
||||
end
|
||||
@@ -41,7 +41,7 @@ if has_config("release") then
|
||||
end
|
||||
|
||||
add_defines("TOML_EXCEPTIONS=0")
|
||||
add_requires(libuv_require, "spdlog[header_only=n,std_format,noexcept]" ,"toml++")
|
||||
add_requires(libuv_require, "spdlog[header_only=n,std_format,noexcept]" ,"toml++", "croaring")
|
||||
add_requires("clice-llvm", {alias = "llvm"})
|
||||
|
||||
add_rules("mode.release", "mode.debug", "mode.releasedbg")
|
||||
@@ -53,7 +53,7 @@ target("clice-core")
|
||||
add_files("src/**.cpp|Driver/*.cpp")
|
||||
add_includedirs("include", {public = true})
|
||||
|
||||
add_packages("libuv", "spdlog", "toml++", {public = true})
|
||||
add_packages("libuv", "spdlog", "toml++", "croaring", {public = true})
|
||||
|
||||
if is_mode("debug") then
|
||||
add_packages("llvm", {
|
||||
@@ -116,7 +116,7 @@ target("clice-core")
|
||||
|
||||
target("clice")
|
||||
set_kind("binary")
|
||||
add_files("src/Driver/clice.cc")
|
||||
add_files("bin/clice.cc")
|
||||
|
||||
add_deps("clice-core")
|
||||
|
||||
@@ -136,7 +136,7 @@ target("clice")
|
||||
target("unit_tests")
|
||||
set_default(false)
|
||||
set_kind("binary")
|
||||
add_files("src/Driver/unit_tests.cc", "tests/unit/**.cpp")
|
||||
add_files("bin/unit_tests.cc", "tests/unit/**.cpp")
|
||||
add_includedirs(".", {public = true})
|
||||
|
||||
add_deps("clice-core")
|
||||
|
||||
Reference in New Issue
Block a user