diff --git a/CMakeLists.txt b/CMakeLists.txt index f95f61715..52e26ebc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,14 @@ project(ccls LANGUAGES CXX) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) include(DefaultCMakeBuildType) -include(DownloadAndExtractLLVM) -set(CLANG_VERSION 6.0.0 CACHE STRING "Downloaded Clang version (6.0.0)") -option(SYSTEM_CLANG "Use system Clang instead of downloading Clang" OFF) +# Required libclang version +set(LIBCLANG_VERSION 6.0.0 CACHE STRING "libclang version") +set(LIBCLANG_DOWNLOAD_LOCATION ${CMAKE_BINARY_DIR} + CACHE STRING "Downloaded libclang location") +option(SYSTEM_LIBCLANG "Use system installation of libclang instead of \ + downloading libclang" OFF) option(ASAN "Compile with address sanitizers" OFF) -option(CLANG_CXX "Build with Clang C++ api required by some ccls \ -features (warning: not available in LLVM Windows downloads)" OFF) # Sources for the executable are specified at end of CMakeLists.txt add_executable(ccls "") @@ -63,13 +64,6 @@ else() $<$:-fno-limit-debug-info>) endif() - if(CLANG_CXX) - # -Wno-comment: include/clang/Format/Format.h error: multi-line comment - # -fno-rtti: # Without -fno-rtti, some Clang C++ functions may report - # `undefined references to typeinfo` - target_compile_options(ccls PRIVATE -Wno-comment -fno-rtti) - endif() - if(ASAN) target_compile_options(ccls PRIVATE -fsanitize=address,undefined) # target_link_libraries also takes linker flags @@ -77,18 +71,23 @@ else() endif() endif() -### Download Clang if required +### Download libclang if required -if(NOT SYSTEM_CLANG) - download_and_extract_llvm(${CLANG_VERSION}) +if(NOT SYSTEM_LIBCLANG) + message(STATUS "Using downloaded libclang") + + include(DownloadAndExtractClang) + download_and_extract_clang(${LIBCLANG_VERSION} ${LIBCLANG_DOWNLOAD_LOCATION}) # Used by FindClang set(CLANG_ROOT ${DOWNLOADED_CLANG_DIR}) +else() + message(STATUS "Using system libclang") endif() ### Libraries # See cmake/FindClang.cmake -find_package(Clang REQUIRED) +find_package(Clang ${CLANG_VERSION} REQUIRED) target_link_libraries(ccls PRIVATE Clang::Clang) # Enable threading support @@ -96,7 +95,9 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries(ccls PRIVATE Threads::Threads) -if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") +if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) + target_link_libraries(ccls PRIVATE -lc++experimental) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows) else() target_link_libraries(ccls PRIVATE -lstdc++fs) endif() @@ -117,12 +118,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows) target_link_libraries(ccls PRIVATE Psapi) endif() -if(CLANG_CXX) - # Clang C++ api uses ncurses - find_package(Curses REQUIRED) - target_link_libraries(ccls PRIVATE ${CURSES_LIBRARIES}) -endif() - ### Definitions target_compile_definitions(ccls PRIVATE @@ -131,10 +126,6 @@ target_compile_definitions(ccls PRIVATE LOGURU_THREADNAME_WIDTH=13 DEFAULT_RESOURCE_DIRECTORY="${Clang_RESOURCE_DIR}") -if(CLANG_CXX) - target_compile_definitions(ccls PRIVATE USE_CLANG_CXX=1 LOGURU_RTTI=0) -endif() - ### Includes target_include_directories(ccls PRIVATE @@ -150,9 +141,8 @@ target_include_directories(ccls PRIVATE install(TARGETS ccls RUNTIME DESTINATION bin) -# We don't need to install libclang on Windows if we are using downloaded LLVM -# since libclang is distributed as a static library on Windows -if(NOT SYSTEM_CLANG AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL Windows) +# TODO: install libclang.dll on Windows as well +if(NOT SYSTEM_LIBCLANG AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL Windows) if(${CMAKE_SYSTEM_NAME} MATCHES Linux|FreeBSD) set_property(TARGET ccls APPEND PROPERTY @@ -167,6 +157,44 @@ if(NOT SYSTEM_CLANG AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL Windows) install(FILES ${LIBCLANG_PLUS_SYMLINKS} DESTINATION lib) endif() +# Allow running from build Windows by copying libclang.dll to build directory +if(NOT SYSTEM_LIBCLANG AND ${CMAKE_SYSTEM_NAME} STREQUAL Windows) + add_custom_command(TARGET ccls + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${DOWNLOADED_CLANG_DIR}/bin/libclang.dll + $ + COMMENT "Copying libclang.dll to build directory ...") +endif() + +### Tools + +# We use glob here since source files are already manually added with +# target_sources further down +file(GLOB SOURCES src/*.cc src/*.h src/serializers/*.cc src/serializers/*.h + src/messages/*.h src/messages/*.cc) + +if(Clang_FORMAT AND ${Clang_VERSION} STREQUAL 6.0.0) + add_custom_target(format + COMMAND ${Clang_FORMAT} -i ${SOURCES} + # .clang-format is located in the ccls root project dir + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Running clang-format ...") +else() + # Set error message depending on which condition was false + if (NOT Clang_FORMAT) + set(Clang_FORMAT_ERROR "Error: clang-format executable not found") + elseif(NOT ${Clang_VERSION} STREQUAL 6.0.0) + set(Clang_FORMAT_ERROR "Error: clang-format version does not match \ +6.0.0. Due to differences in clang-format output between versions we only \ +support clang-format 6.0.0") + endif() + + add_custom_target(format + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold + ${Clang_FORMAT_ERROR}) +endif() + ### Sources target_sources(ccls PRIVATE third_party/siphash.cc) diff --git a/cmake/DownloadAndExtract7zip.cmake b/cmake/DownloadAndExtract7zip.cmake index f3257e6b0..72bc879d5 100644 --- a/cmake/DownloadAndExtract7zip.cmake +++ b/cmake/DownloadAndExtract7zip.cmake @@ -1,51 +1,52 @@ # Downloads and extracts the 7-Zip MSI installer from https://www.7-zip.org/. # # Returns the extracted 7-Zip directory in DOWNLOADED_7ZIP_DIR -# -# Downloads 7-Zip to extract LLVM if it isn't available in the PATH -function(download_and_extract_7zip) +function(download_and_extract_7zip 7ZIP_DOWNLOAD_LOCATION) set(7ZIP_VERSION 1801) set(7ZIP_EXT .msi) set(7ZIP_NAME 7z${7ZIP_VERSION}-x64) set(7ZIP_FULL_NAME ${7ZIP_NAME}${7ZIP_EXT}) -set(7ZIP_FILE ${CMAKE_BINARY_DIR}/${7ZIP_FULL_NAME}) -set(7ZIP_EXTRACT_DIR ${CMAKE_BINARY_DIR}/${7ZIP_NAME}) +set(7ZIP_FILE ${7ZIP_DOWNLOAD_LOCATION}/${7ZIP_FULL_NAME}) +set(7ZIP_EXTRACT_DIR ${7ZIP_DOWNLOAD_LOCATION}/${7ZIP_NAME}) set(7ZIP_URL https://www.7-zip.org/a/${7ZIP_FULL_NAME}) -# msiexec requires Windows path separators (\) -file(TO_NATIVE_PATH ${7ZIP_FILE} 7ZIP_FILE) -file(TO_NATIVE_PATH ${7ZIP_EXTRACT_DIR} 7ZIP_EXTRACT_DIR) - -if(NOT EXISTS ${7ZIP_FILE}) - message(STATUS "Downloading 7-Zip ${7ZIP_VERSION} (${7ZIP_URL}) ...") - file(DOWNLOAD ${7ZIP_URL} ${7ZIP_FILE}) +# Exit if 7-Zip is already downloaded and extracted +find_program(7ZIP_EXECUTABLE 7z NO_DEFAULT_PATH + PATHS ${7ZIP_EXTRACT_DIR}/Files/7-Zip) +if(7ZIP_EXECUTABLE) + message(STATUS "7-Zip already downloaded") + return() endif() -if(NOT EXISTS ${7ZIP_EXTRACT_DIR}) +message(STATUS "Downloading 7-Zip ${7ZIP_VERSION} (${7ZIP_URL}) ...") +file(DOWNLOAD ${7ZIP_URL} ${7ZIP_FILE}) - find_program(MSIEXEC_EXECUTABLE msiexec) - if(NOT MSIEXEC_EXECUTABLE) - message(FATAL_ERROR "Unable to find msiexec (required to extract 7-Zip msi \ +find_program(MSIEXEC_EXECUTABLE msiexec) +if(NOT MSIEXEC_EXECUTABLE) + message(FATAL_ERROR "Unable to find msiexec (required to extract 7-Zip msi \ installer). Install 7-Zip yourself and make sure it is available in the path") - endif() +endif() - message(STATUS "Extracting downloaded 7-Zip ...") +message(STATUS "Extracting downloaded 7-Zip ...") - # msiexec with /a option allows extraction of msi installers without requiring - # admin privileges. We use this to extract the 7-Zip installer without - # requiring any actions from the user - execute_process(COMMAND ${MSIEXEC_EXECUTABLE} /a ${7ZIP_FILE} /qn - TARGETDIR=${7ZIP_EXTRACT_DIR} - OUTPUT_QUIET) -endif() +# msiexec requires Windows path separators (\) +file(TO_NATIVE_PATH ${7ZIP_FILE} 7ZIP_FILE) +file(TO_NATIVE_PATH ${7ZIP_EXTRACT_DIR} 7ZIP_EXTRACT_DIR) + +# msiexec with /a option allows extraction of msi installers without requiring +# admin privileges. We use this to extract the 7-Zip installer without +# requiring any actions from the user +execute_process(COMMAND ${MSIEXEC_EXECUTABLE} /a ${7ZIP_FILE} /qn + TARGETDIR=${7ZIP_EXTRACT_DIR} + WORKING_DIRECTORY ${7ZIP_DOWNLOAD_LOCATION} + OUTPUT_QUIET) # Convert back to CMake separators (/) before returning file(TO_CMAKE_PATH ${7ZIP_EXTRACT_DIR} 7ZIP_EXTRACT_DIR) -# Actual directory is nested inside the extract directory. We return the nested -# directory instead of the extract directory +# Actual 7-Zip directory is nested inside the extract directory. set(DOWNLOADED_7ZIP_DIR ${7ZIP_EXTRACT_DIR}/Files/7-Zip PARENT_SCOPE) endfunction() \ No newline at end of file diff --git a/cmake/DownloadAndExtractClang.cmake b/cmake/DownloadAndExtractClang.cmake new file mode 100644 index 000000000..ee5feaa71 --- /dev/null +++ b/cmake/DownloadAndExtractClang.cmake @@ -0,0 +1,124 @@ +# Downloads and extracts the Clang archive for the current system from +# https://releases.llvm.org +# +# Returns the extracted Clang archive directory in DOWNLOADED_CLANG_DIR +# +# Downloads 7-Zip to extract Clang if it isn't available in the PATH +function(download_and_extract_clang CLANG_VERSION CLANG_DOWNLOAD_LOCATION) + +set(CLANG_ARCHIVE_EXT .tar.xz) + +if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) + + set(CLANG_ARCHIVE_NAME + clang+llvm-${CLANG_VERSION}-x86_64-linux-gnu-ubuntu-14.04) + +elseif(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) + + set(CLANG_ARCHIVE_NAME clang+llvm-${CLANG_VERSION}-x86_64-apple-darwin) + +elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows) + + set(CLANG_ARCHIVE_NAME LLVM-${CLANG_VERSION}-win64) + set(CLANG_ARCHIVE_EXT .exe) + +elseif(${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD) + + if(${CLANG_VERSION} STREQUAL 6.0.0) + set(CLANG_ARCHIVE_NAME clang+llvm-${CLANG_VERSION}-amd64-unknown-freebsd-10) + else() + set(CLANG_ARCHIVE_NAME clang+llvm-${CLANG_VERSION}-amd64-unknown-freebsd10) + endif() + +endif() + +set(CLANG_ARCHIVE_FULL_NAME ${CLANG_ARCHIVE_NAME}${CLANG_ARCHIVE_EXT}) +set(CLANG_ARCHIVE_FILE ${CLANG_DOWNLOAD_LOCATION}/${CLANG_ARCHIVE_FULL_NAME}) +set(CLANG_ARCHIVE_EXTRACT_DIR ${CLANG_DOWNLOAD_LOCATION}/${CLANG_ARCHIVE_NAME}) +set(CLANG_ARCHIVE_URL + https://releases.llvm.org/${CLANG_VERSION}/${CLANG_ARCHIVE_FULL_NAME}) +set(CLANG_ARCHIVE_HASH_FILE + ${CMAKE_SOURCE_DIR}/clang_archive_hashes/${CLANG_ARCHIVE_FULL_NAME}.SHA256) + +# Exit if Clang is already downloaded and extracted +set(CLANG_ROOT ${CLANG_ARCHIVE_EXTRACT_DIR}) +find_package(Clang ${CLANG_VERSION} QUIET) +if(Clang_FOUND) + message(STATUS "Clang already downloaded") + set(DOWNLOADED_CLANG_DIR ${CLANG_ARCHIVE_EXTRACT_DIR} PARENT_SCOPE) + return() +endif() + +if(NOT CLANG_ARCHIVE_NAME) + message(FATAL_ERROR "No Clang archive url specified for current platform \ +(${CMAKE_SYSTEM_NAME}). Please file an issue to get it added.") +endif() + +if(NOT EXISTS ${CLANG_ARCHIVE_HASH_FILE}) + message(FATAL_ERROR "No SHA256 hash available for the current platform \ +(${CMAKE_SYSTEM_NAME}) + clang version (${CLANG_VERSION}) combination. Please \ +file an issue to get it added.") +endif() + +# Download Clang archive +message(STATUS "Downloading Clang ${CLANG_VERSION} (${CLANG_ARCHIVE_URL}) ...") +file(DOWNLOAD ${CLANG_ARCHIVE_URL} ${CLANG_ARCHIVE_FILE} + STATUS CLANG_ARCHIVE_DOWNLOAD_RESULT) + +# Abort if download failed +list(GET ${CLANG_ARCHIVE_DOWNLOAD_RESULT} 0 ERROR_CODE) +if(${ERROR_CODE}) + list(GET ${CLANG_ARCHIVE_DOWNLOAD_RESULT} 1 ERROR_STRING) + message(FATAL_ERROR ${ERROR_STRING}) +endif() + +# Retrieve expected hash from file and strip newline +file(READ ${CLANG_ARCHIVE_HASH_FILE} CLANG_ARCHIVE_EXPECTED_HASH) +string(STRIP ${CLANG_ARCHIVE_EXPECTED_HASH} CLANG_ARCHIVE_EXPECTED_HASH) +# Calculate actual hash +file(SHA256 ${CLANG_ARCHIVE_FILE} CLANG_ARCHIVE_HASH) +# Abort if hashes do not match +if(NOT ${CLANG_ARCHIVE_EXPECTED_HASH} STREQUAL ${CLANG_ARCHIVE_HASH}) + message(FATAL_ERROR "SHA256 hash of downloaded Clang does not match \ +expected hash. Remove the build directory and try running CMake again. If this \ +keeps happening, file an issue to report the problem.") +endif() + +if(${CLANG_ARCHIVE_EXT} STREQUAL .exe) + # Download and extract 7-zip if not found in PATH + find_program(7ZIP_EXECUTABLE 7z) + if(NOT 7ZIP_EXECUTABLE) + message(STATUS "7-Zip not found in PATH") + + include(DownloadAndExtract7zip) + download_and_extract_7zip(${CLANG_DOWNLOAD_LOCATION}) + find_program(7ZIP_EXECUTABLE 7z NO_DEFAULT_PATH + PATHS ${DOWNLOADED_7ZIP_DIR}) + else() + message(STATUS "7-Zip found in PATH") + endif() + + message(STATUS "Extracting downloaded Clang with 7-Zip ...") + + # Avoid running the Clang installer by extracting the exe with 7-Zip + execute_process(COMMAND ${7ZIP_EXECUTABLE} x + -o${CLANG_ARCHIVE_EXTRACT_DIR} + -xr!$PLUGINSDIR ${CLANG_ARCHIVE_FILE} + WORKING_DIRECTORY ${CLANG_DOWNLOAD_LOCATION} + OUTPUT_QUIET) + +elseif(${CLANG_ARCHIVE_EXT} STREQUAL .tar.xz) + message(STATUS "Extracting downloaded Clang with CMake built-in tar ...") + + # CMake has builtin support for tar via the -E flag + execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xf ${CLANG_ARCHIVE_FILE} + # Specify working directory to allow running cmake from + # everywhere + # (example: cmake -H"$HOME/ccls" -B"$home/ccls/build") + WORKING_DIRECTORY ${CLANG_DOWNLOAD_LOCATION} + OUTPUT_QUIET) +endif() + +set(DOWNLOADED_CLANG_DIR ${CLANG_ARCHIVE_EXTRACT_DIR} PARENT_SCOPE) + +endfunction() diff --git a/cmake/DownloadAndExtractLLVM.cmake b/cmake/DownloadAndExtractLLVM.cmake deleted file mode 100644 index 4a122e355..000000000 --- a/cmake/DownloadAndExtractLLVM.cmake +++ /dev/null @@ -1,112 +0,0 @@ -# Downloads and extracts the LLVM archive for the current system from -# https://releases.llvm.org -# -# Returns the extracted LLVM archive directory in DOWNLOADED_CLANG_DIR -# -# Downloads 7-Zip to extract LLVM if it isn't available in the PATH -function(download_and_extract_llvm CLANG_VERSION) - -include(DownloadAndExtract7zip) - -set(CLANG_ARCHIVE_EXT .tar.xz) - -if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) - - set(CLANG_ARCHIVE_NAME - clang+llvm-${CLANG_VERSION}-x86_64-linux-gnu-ubuntu-14.04) - -elseif(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) - - set(CLANG_ARCHIVE_NAME clang+llvm-${CLANG_VERSION}-x86_64-apple-darwin) - -elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows) - - set(CLANG_ARCHIVE_NAME LLVM-${CLANG_VERSION}-win64) - set(CLANG_ARCHIVE_EXT .exe) - -elseif(${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD) - - if(${CLANG_VERSION} STREQUAL 6.0.0) - set(CLANG_ARCHIVE_NAME clang+llvm-${CLANG_VERSION}-amd64-unknown-freebsd-10) - else() - set(CLANG_ARCHIVE_NAME clang+llvm-${CLANG_VERSION}-amd64-unknown-freebsd10) - endif() -endif() - -if(NOT CLANG_ARCHIVE_NAME) - message(FATAL_ERROR "No LLVM archive url specified for current platform \ -(${CMAKE_SYSTEM_NAME}). Please file an issue to get it added.") -endif() - -set(CLANG_ARCHIVE_FULL_NAME ${CLANG_ARCHIVE_NAME}${CLANG_ARCHIVE_EXT}) -set(CLANG_ARCHIVE_FILE ${CMAKE_BINARY_DIR}/${CLANG_ARCHIVE_FULL_NAME}) -set(CLANG_ARCHIVE_EXTRACT_DIR ${CMAKE_BINARY_DIR}/${CLANG_ARCHIVE_NAME}) -set(CLANG_ARCHIVE_URL - https://releases.llvm.org/${CLANG_VERSION}/${CLANG_ARCHIVE_FULL_NAME}) -set(CLANG_ARCHIVE_HASH_FILE - ${CMAKE_SOURCE_DIR}/clang_archive_hashes/${CLANG_ARCHIVE_FULL_NAME}.SHA256) - -if(NOT EXISTS ${CLANG_ARCHIVE_HASH_FILE}) - message(FATAL_ERROR "No SHA256 hash available for the current platform \ -(${CMAKE_SYSTEM_NAME}) + clang version (${CLANG_VERSION}) combination. Please \ -file an issue to get it added.") -endif() - -file(READ ${CLANG_ARCHIVE_HASH_FILE} CLANG_ARCHIVE_EXPECTED_HASH) -# Strip newline -string(STRIP ${CLANG_ARCHIVE_EXPECTED_HASH} CLANG_ARCHIVE_EXPECTED_HASH) - -if(NOT EXISTS ${CLANG_ARCHIVE_FILE}) - message(STATUS "Downloading LLVM ${CLANG_VERSION} (${CLANG_ARCHIVE_URL}) ...") - file(DOWNLOAD ${CLANG_ARCHIVE_URL} ${CLANG_ARCHIVE_FILE} - STATUS CLANG_ARCHIVE_DOWNLOAD_RESULT) - - list(GET ${CLANG_ARCHIVE_DOWNLOAD_RESULT} 0 ERROR_CODE) - if(${ERROR_CODE}) - list(GET ${CLANG_ARCHIVE_DOWNLOAD_RESULT} 1 ERROR_STRING) - message(FATAL_ERROR ${ERROR_STRING}) - endif() -endif() - -file(SHA256 ${CLANG_ARCHIVE_FILE} CLANG_ARCHIVE_HASH) -if(NOT ${CLANG_ARCHIVE_EXPECTED_HASH} STREQUAL ${CLANG_ARCHIVE_HASH}) - message(FATAL_ERROR "SHA256 hash of downloaded LLVM does not match \ -expected hash. Remove the build directory and try running CMake again. If this \ -keeps happening, file an issue to report the problem.") -endif() - -if(NOT EXISTS ${CLANG_ARCHIVE_EXTRACT_DIR}) - if(${CLANG_ARCHIVE_EXT} STREQUAL .exe) - find_program(7ZIP_EXECUTABLE 7z) - - if(NOT 7ZIP_EXECUTABLE) - message(STATUS "7-Zip not found in PATH") - download_and_extract_7zip() - find_program(7ZIP_EXECUTABLE 7z NO_DEFAULT_PATH - PATHS ${DOWNLOADED_7ZIP_DIR}) - else() - message(STATUS "7-Zip found in PATH") - endif() - - message(STATUS "Extracting downloaded LLVM with 7-Zip ...") - - # Avoid running the LLVM installer by extracting the exe with 7-Zip - execute_process(COMMAND ${7ZIP_EXECUTABLE} x - -o${CLANG_ARCHIVE_EXTRACT_DIR} - -xr!$PLUGINSDIR ${CLANG_ARCHIVE_FILE} - OUTPUT_QUIET) - elseif(${CLANG_ARCHIVE_EXT} STREQUAL .tar.xz) - message(STATUS "Extracting downloaded LLVM with CMake built-in tar ...") - # CMake has builtin support for tar via the -E flag - execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xf ${CLANG_ARCHIVE_FILE} - # Extract to here to allow running cmake from everywhere - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - OUTPUT_QUIET) - endif() -endif() - -# CMake functions have no return values so we just lift our return variable to -# the parent scope -set(DOWNLOADED_CLANG_DIR ${CLANG_ARCHIVE_EXTRACT_DIR} PARENT_SCOPE) - -endfunction() diff --git a/cmake/FindClang.cmake b/cmake/FindClang.cmake index c8e0d2473..f21fb57b8 100644 --- a/cmake/FindClang.cmake +++ b/cmake/FindClang.cmake @@ -2,12 +2,13 @@ # FindClang # --------- # -# Find Clang and LLVM libraries required by cquery +# Find Clang and LLVM libraries required by ccls # # Results are reported in the following variables:: # # Clang_FOUND - True if headers and requested libraries were found # Clang_EXECUTABLE - Clang executable +# Clang_FORMAT - Clang-format executable # Clang_RESOURCE_DIR - Clang resource directory # Clang_VERSION - Clang version as reported by Clang executable # @@ -32,8 +33,8 @@ macro(_Clang_find_library VAR NAME) # Windows needs lib prefix - if (CLANG_ROOT) - find_library(${VAR} NAMES ${NAME} lib${NAME} + if (CLANG_ROOT) + find_library(${VAR} NAMES ${NAME} lib${NAME} NO_DEFAULT_PATH PATHS ${CLANG_ROOT} PATH_SUFFIXES lib) else() find_library(${VAR} NAMES ${NAME} lib${NAME}) @@ -42,7 +43,7 @@ endmacro() macro(_Clang_find_path VAR INCLUDE_FILE) if (CLANG_ROOT) - find_path(${VAR} ${INCLUDE_FILE} + find_path(${VAR} ${INCLUDE_FILE} NO_DEFAULT_PATH PATHS ${CLANG_ROOT} PATH_SUFFIXES include) else() find_path(${VAR} ${INCLUDE_FILE}) @@ -51,7 +52,7 @@ endmacro() macro(_Clang_find_program VAR NAME) if (CLANG_ROOT) - find_program(${VAR} ${NAME} + find_program(${VAR} ${NAME} NO_DEFAULT_PATH PATHS ${CLANG_ROOT} PATH_SUFFIXES bin) else() find_program(${VAR} ${NAME}) @@ -73,14 +74,14 @@ endmacro() ### Start -set(_Clang_REQUIRED_VARS Clang_LIBRARY Clang_INCLUDE_DIR Clang_EXECUTABLE +set(_Clang_REQUIRED_VARS Clang_LIBRARY Clang_INCLUDE_DIR Clang_EXECUTABLE Clang_RESOURCE_DIR Clang_VERSION) _Clang_find_library(Clang_LIBRARY clang) _Clang_find_path(Clang_INCLUDE_DIR clang-c/Index.h) if(CLANG_CXX) - # The order is derived by topological sorting LINK_LIBS in + # The order is derived by topological sorting LINK_LIBS in # clang/lib/*/CMakeLists.txt _Clang_find_and_add_cxx_lib(clangFormat clang/Format/Format.h) _Clang_find_and_add_cxx_lib(clangToolingCore clang/Tooling/Core/Diagnostic.h) @@ -96,16 +97,24 @@ if(CLANG_CXX) _Clang_find_and_add_cxx_lib(LLVMDemangle llvm/Demangle/Demangle.h) endif() +_Clang_find_program(Clang_FORMAT clang-format) _Clang_find_program(Clang_EXECUTABLE clang) if(Clang_EXECUTABLE) # Find Clang resource directory with Clang executable - execute_process(COMMAND ${Clang_EXECUTABLE} -print-resource-dir + execute_process(COMMAND ${Clang_EXECUTABLE} -print-resource-dir + RESULT_VARIABLE _Clang_FIND_RESOURCE_DIR_RESULT OUTPUT_VARIABLE Clang_RESOURCE_DIR + ERROR_VARIABLE _Clang_FIND_RESOURCE_DIR_ERROR OUTPUT_STRIP_TRAILING_WHITESPACE) + if(_Clang_FIND_RESOURCE_DIR_RESULT) + message(FATAL_ERROR "Error retrieving Clang resource directory with Clang \ +executable. Output:\n ${_Clang_FIND_RESOURCE_DIR_ERROR}") + endif() + # Find Clang version set(_Clang_VERSION_REGEX "([0-9]+)\\.([0-9]+)\\.([0-9]+)") - execute_process(COMMAND ${Clang_EXECUTABLE} --version + execute_process(COMMAND ${Clang_EXECUTABLE} --version OUTPUT_VARIABLE Clang_VERSION) string(REGEX MATCH ${_Clang_VERSION_REGEX} Clang_VERSION ${Clang_VERSION}) endif() @@ -122,8 +131,8 @@ if(Clang_FOUND AND NOT TARGET Clang::Clang) set(_Clang_INCLUDE_DIRS ${Clang_INCLUDE_DIR} ${_Clang_CXX_INCLUDE_DIRS}) add_library(Clang::Clang INTERFACE IMPORTED) - set_property(TARGET Clang::Clang PROPERTY + set_property(TARGET Clang::Clang PROPERTY INTERFACE_LINK_LIBRARIES ${_Clang_LIBRARIES}) - set_property(TARGET Clang::Clang PROPERTY - INTERFACE_INCLUDE_DIRECTORIES ${_Clang_INCLUDE_DIRS}) + set_property(TARGET Clang::Clang PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${_Clang_INCLUDE_DIRS}) endif()