mirror of
https://github.com/neovim/neovim.git
synced 2026-05-24 05:40:08 +00:00
This feature might be a little silly and niche, but it is very useful
for _my_ workflow (and open source is about mee)
An issue which is never present on high quality RELEASE builds, but
might occur on Debug builds is that the Nvim server crashes
on some error in your unfinished PR code. If you compile your debug
builds with sanitizers enabled, as you should, the ASAN/UBSAN runtime
will print some useful info about your mistake to stderr or a log file,
such as a stack trace. This can be used to jump to the error in the
code.
This allows the nvim server to install a signal hander in the ui client,
which can load this log file in a good safe version of nvim and parse it
using 'errorformat'
This is inspired by the "press ENTER" free workflow of ui2 and applies
it beyond the lifetime cycle of the nvim instance.
example config:
```lua
local asan = vim.env.ASAN_OPTIONS
if asan ~= nil and string.match(asan, "log_path=/tmp/nvim_asan") then
local myname = "/tmp/nvim_asan."..vim.uv.getpid()
local args = {"--embed", "-n", "+set efm=%+A%*[^/]%f:%l:%c", "+silent cfile "..myname, "+silent cfirst", "+silent copen"}
vim.api.nvim__set_restart_on_crash("nvim", args)
end
```
and run your debug nvim like so
ASAN_OPTIONS=handle_abort=1,handle_sigill=1,log_path=/tmp/nvim_asan ./build/bin/nvim
366 lines
13 KiB
CMake
366 lines
13 KiB
CMake
# CMAKE REFERENCE
|
|
# - intro: https://codingnest.com/basic-cmake/
|
|
# - best practices (3.0+): https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
|
|
# - pitfalls: https://izzys.casa/2019/02/everything-you-never-wanted-to-know-about-cmake/
|
|
# - troubleshooting:
|
|
# - variable_watch https://cmake.org/cmake/help/latest/command/variable_watch.html
|
|
# - verbose output: cmake --build build --verbose
|
|
|
|
# Version should match the tested CMAKE_URL in .github/workflows/build.yml.
|
|
cmake_minimum_required(VERSION 3.16)
|
|
|
|
project(nvim C)
|
|
|
|
if(POLICY CMP0135)
|
|
cmake_policy(SET CMP0135 NEW)
|
|
endif()
|
|
|
|
if(XCODE)
|
|
message(FATAL_ERROR [[Xcode generator is not supported. Use "Ninja" or "Unix Makefiles" instead]])
|
|
endif()
|
|
|
|
# Point CMake at any custom modules we may ship
|
|
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
|
|
|
include(CheckCCompilerFlag)
|
|
include(CheckCSourceCompiles)
|
|
include(CheckLibraryExists)
|
|
include(ExternalProject)
|
|
include(FindPackageHandleStandardArgs)
|
|
include(GNUInstallDirs)
|
|
|
|
include(Deps)
|
|
include(Find)
|
|
include(InstallHelpers)
|
|
include(PreventInTreeBuilds)
|
|
include(Util)
|
|
|
|
if(NOT PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
|
# Auto-create a .gitignore in the specified "build" directory.
|
|
file(GENERATE OUTPUT .gitignore CONTENT "*")
|
|
endif()
|
|
|
|
#-------------------------------------------------------------------------------
|
|
# User settings
|
|
#-------------------------------------------------------------------------------
|
|
|
|
if(NOT DEPS_IGNORE_SHA)
|
|
set(DEPS_IGNORE_SHA FALSE)
|
|
endif()
|
|
|
|
#-------------------------------------------------------------------------------
|
|
# Variables
|
|
#-------------------------------------------------------------------------------
|
|
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
|
|
set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
|
|
set(VTERM_TEST_FILE ${PROJECT_BINARY_DIR}/test/vterm_test_output)
|
|
|
|
file(GLOB DOCFILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt)
|
|
|
|
if(NOT CI_BUILD)
|
|
set(CMAKE_INSTALL_MESSAGE NEVER)
|
|
endif()
|
|
|
|
if(${CMAKE_VERSION} VERSION_LESS 3.20)
|
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
endif()
|
|
|
|
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.26)
|
|
set(COPY_DIRECTORY copy_directory_if_different)
|
|
else()
|
|
set(COPY_DIRECTORY copy_directory)
|
|
endif()
|
|
|
|
# Prefer our bundled versions of dependencies.
|
|
if(DEFINED ENV{DEPS_BUILD_DIR})
|
|
set(DEPS_PREFIX "$ENV{DEPS_BUILD_DIR}/usr" CACHE PATH "Path prefix for finding dependencies")
|
|
else()
|
|
set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies")
|
|
# When running from within CLion or Visual Studio,
|
|
# build bundled dependencies automatically.
|
|
if(NOT EXISTS ${DEPS_PREFIX}
|
|
AND (DEFINED ENV{CLION_IDE}
|
|
OR DEFINED ENV{VisualStudioEdition}))
|
|
message(STATUS "Building dependencies...")
|
|
set(DEPS_BUILD_DIR ${PROJECT_BINARY_DIR}/.deps)
|
|
file(MAKE_DIRECTORY ${DEPS_BUILD_DIR})
|
|
execute_process(
|
|
COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR}
|
|
-D CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
|
|
-D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
|
-D CMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
|
-D CMAKE_C_FLAGS=${CMAKE_C_FLAGS}
|
|
-D CMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG}
|
|
-D CMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL}
|
|
-D CMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO}
|
|
-D CMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE}
|
|
-D CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
|
|
${PROJECT_SOURCE_DIR}/cmake.deps
|
|
WORKING_DIRECTORY ${DEPS_BUILD_DIR})
|
|
execute_process(
|
|
COMMAND ${CMAKE_COMMAND} --build ${DEPS_BUILD_DIR}
|
|
--config ${CMAKE_BUILD_TYPE})
|
|
set(DEPS_PREFIX ${DEPS_BUILD_DIR}/usr)
|
|
endif()
|
|
endif()
|
|
|
|
list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX})
|
|
|
|
if(APPLE)
|
|
# If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET),
|
|
# fall back to local system version. Needs to be done both here and in cmake.deps.
|
|
if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
|
execute_process(COMMAND sw_vers -productVersion
|
|
OUTPUT_VARIABLE MACOS_VERSION
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "${MACOS_VERSION}")
|
|
endif()
|
|
message(STATUS "Using deployment target ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
|
endif()
|
|
|
|
if(WIN32 OR APPLE)
|
|
# Handle case-insensitive filenames for Windows and Mac.
|
|
set(CASE_INSENSITIVE_FILENAME TRUE)
|
|
endif()
|
|
|
|
if (MINGW)
|
|
# Disable LTO by default as it may not compile
|
|
# See https://github.com/Alexpux/MINGW-packages/issues/3516
|
|
# and https://github.com/neovim/neovim/pull/8654#issuecomment-402316672
|
|
option(ENABLE_LTO "enable link time optimization" OFF)
|
|
else()
|
|
option(ENABLE_LTO "enable link time optimization" ON)
|
|
endif()
|
|
option(ENABLE_LIBINTL "enable libintl" ON)
|
|
option(ENABLE_UNIBILIUM "enable unibilium" ON)
|
|
option(ENABLE_WASMTIME "enable wasmtime" OFF)
|
|
|
|
message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
|
|
|
|
set_default_buildtype(Debug)
|
|
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
|
if(NOT isMultiConfig)
|
|
# Unlike build dependencies in cmake.deps, we want dev dependencies such as
|
|
# Uncrustify to always be built with Release.
|
|
list(APPEND DEPS_CMAKE_ARGS -D CMAKE_BUILD_TYPE=Release)
|
|
endif()
|
|
|
|
# If not in a git repo (e.g., a tarball) these tokens define the complete
|
|
# version string, else they are combined with the result of `git describe`.
|
|
set(NVIM_VERSION_MAJOR 0)
|
|
set(NVIM_VERSION_MINOR 13)
|
|
set(NVIM_VERSION_PATCH 0)
|
|
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
|
|
|
|
# API level
|
|
set(NVIM_API_LEVEL 15) # Bump this after any API/stdlib change.
|
|
set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
|
|
set(NVIM_API_PRERELEASE true)
|
|
|
|
# We _want_ assertions in RelWithDebInfo build-type.
|
|
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG)
|
|
string(REPLACE "-DNDEBUG" "-DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
|
string(REPLACE "/DNDEBUG" "/DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
|
string(REPLACE " " " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Remove duplicate whitespace
|
|
endif()
|
|
|
|
option(ENABLE_ASAN_UBSAN "Enable Clang address & undefined behavior sanitizer for nvim binary." OFF)
|
|
option(ENABLE_MSAN "Enable Clang memory sanitizer for nvim binary." OFF)
|
|
# TSAN exists to test Luv threads.
|
|
option(ENABLE_TSAN "Enable Clang thread sanitizer for nvim binary." OFF)
|
|
|
|
if((ENABLE_ASAN_UBSAN AND ENABLE_MSAN)
|
|
OR (ENABLE_ASAN_UBSAN AND ENABLE_TSAN)
|
|
OR (ENABLE_MSAN AND ENABLE_TSAN))
|
|
message(FATAL_ERROR "Sanitizers cannot be enabled simultaneously")
|
|
endif()
|
|
|
|
# Place targets in bin/ or lib/ for all build configurations
|
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
|
foreach(CFGNAME ${CMAKE_CONFIGURATION_TYPES})
|
|
string(TOUPPER ${CFGNAME} CFGNAME)
|
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/bin)
|
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib)
|
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib)
|
|
endforeach()
|
|
|
|
if(NOT PREFER_LUA)
|
|
find_program(LUA_PRG NAMES luajit)
|
|
endif()
|
|
find_program(LUA_PRG NAMES lua5.1 lua5.2 lua)
|
|
mark_as_advanced(LUA_PRG)
|
|
if(NOT LUA_PRG)
|
|
message(FATAL_ERROR "Failed to find a Lua 5.1-compatible interpreter")
|
|
endif()
|
|
message(STATUS "Using Lua interpreter: ${LUA_PRG}")
|
|
|
|
# Some of the code generation still relies on stable table ordering in order to
|
|
# produce reproducible output - specifically the msgpack'ed data in
|
|
# funcs_metadata.generated.h and ui_events_metadata.generated.h. This should
|
|
# ideally be fixed in the generators, but until then as a workaround you may provide
|
|
# a specific lua implementation that provides the needed stability by setting LUA_GEN_PRG:
|
|
if(NOT LUA_GEN_PRG)
|
|
set(LUA_GEN_PRG "${LUA_PRG}" CACHE FILEPATH "Path to the lua used for code generation.")
|
|
endif()
|
|
mark_as_advanced(LUA_GEN_PRG)
|
|
message(STATUS "Using Lua interpreter for code generation: ${LUA_GEN_PRG}")
|
|
|
|
option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON)
|
|
|
|
# Lint
|
|
option(CI_LINT "Abort if lint programs not found" OFF)
|
|
if(CI_LINT)
|
|
set(LINT_REQUIRED "REQUIRED")
|
|
endif()
|
|
find_program(SHELLCHECK_PRG shellcheck ${LINT_REQUIRED})
|
|
mark_as_advanced(SHELLCHECK_PRG)
|
|
find_program(STYLUA_PRG stylua ${LINT_REQUIRED})
|
|
mark_as_advanced(STYLUA_PRG)
|
|
find_program(TS_QUERY_LS_PRG ts_query_ls ${LINT_REQUIRED})
|
|
mark_as_advanced(TS_QUERY_LS_PRG)
|
|
|
|
set(STYLUA_DIRS runtime scripts src test contrib)
|
|
|
|
add_glob_target(
|
|
TARGET lintlua-stylua
|
|
COMMAND ${STYLUA_PRG}
|
|
FLAGS --color=always --check --respect-ignores
|
|
GLOB_DIRS ${STYLUA_DIRS}
|
|
GLOB_PAT *.lua
|
|
TOUCH_STRATEGY PER_DIR)
|
|
# Special handling of some files (which are ignored in .styluaignore).
|
|
# Workaround because stylua doesn't(?) support file-specific settings.
|
|
add_custom_target(lintlua-stylua2
|
|
COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml"
|
|
--color=always --check
|
|
"${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua"
|
|
"${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua"
|
|
"${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua"
|
|
)
|
|
add_dependencies(lintlua-stylua lintlua-stylua2)
|
|
|
|
add_custom_target(lintlua)
|
|
add_dependencies(lintlua lintlua-stylua)
|
|
|
|
add_glob_target(
|
|
TARGET lintsh
|
|
COMMAND ${SHELLCHECK_PRG}
|
|
FLAGS -x -a
|
|
GLOB_DIRS scripts
|
|
GLOB_PAT *.sh
|
|
TOUCH_STRATEGY PER_DIR)
|
|
|
|
add_custom_target(lintquery-compilation
|
|
COMMAND ${TS_QUERY_LS_PRG}
|
|
check ${PROJECT_SOURCE_DIR}/runtime/queries --config
|
|
'{"parser_install_directories": ["${DEPS_PREFIX}/lib/nvim/parser"]}')
|
|
|
|
add_custom_target(lintquery-format
|
|
COMMAND ${TS_QUERY_LS_PRG}
|
|
format ${PROJECT_SOURCE_DIR}/runtime/queries --check)
|
|
|
|
add_custom_target(lintquery)
|
|
add_dependencies(lintquery lintquery-compilation lintquery-format)
|
|
|
|
add_custom_target(lintcommit
|
|
COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
|
|
add_dependencies(lintcommit nvim_bin)
|
|
|
|
add_custom_target(linterrcodes
|
|
COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/linterrcodes.lua
|
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
|
add_dependencies(linterrcodes nvim_bin)
|
|
|
|
add_custom_target(lint)
|
|
add_dependencies(lint lintc lintlua lintsh lintquery)
|
|
|
|
# Format
|
|
add_glob_target(
|
|
TARGET formatlua
|
|
COMMAND ${STYLUA_PRG}
|
|
FLAGS --respect-ignores
|
|
GLOB_DIRS ${STYLUA_DIRS}
|
|
GLOB_PAT *.lua
|
|
TOUCH_STRATEGY PER_DIR)
|
|
# Special handling of some files (which are ignored in .styluaignore).
|
|
# Workaround because stylua doesn't(?) support file-specific settings.
|
|
add_custom_target(formatlua2
|
|
COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml"
|
|
"${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua"
|
|
"${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua"
|
|
"${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua"
|
|
)
|
|
add_dependencies(formatlua formatlua2)
|
|
|
|
add_custom_target(formatquery
|
|
COMMAND ${TS_QUERY_LS_PRG}
|
|
format ${PROJECT_SOURCE_DIR}/runtime/queries)
|
|
|
|
add_custom_target(format)
|
|
add_dependencies(format formatc formatlua formatquery)
|
|
|
|
install_helper(
|
|
FILES ${CMAKE_SOURCE_DIR}/src/man/nvim.1
|
|
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
|
|
|
add_custom_target(nvim ALL)
|
|
add_dependencies(nvim nvim_bin nvim_runtime_deps nvim_runtime)
|
|
|
|
add_subdirectory(src/nvim)
|
|
add_subdirectory(src/tee)
|
|
add_subdirectory(src/xxd)
|
|
add_subdirectory(cmake.config)
|
|
add_subdirectory(runtime)
|
|
add_subdirectory(test)
|
|
|
|
add_custom_target(uninstall
|
|
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/UninstallHelper.cmake)
|
|
|
|
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
|
|
add_subdirectory(cmake.packaging)
|
|
endif()
|
|
|
|
get_externalproject_options(uncrustify ${DEPS_IGNORE_SHA})
|
|
ExternalProject_Add(uncrustify
|
|
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/uncrustify
|
|
CMAKE_ARGS ${DEPS_CMAKE_ARGS}
|
|
-D CMAKE_RUNTIME_OUTPUT_DIRECTORY=${DEPS_BIN_DIR}
|
|
-D CMAKE_SKIP_RPATH=true
|
|
EXCLUDE_FROM_ALL TRUE
|
|
${EXTERNALPROJECT_OPTIONS})
|
|
|
|
if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch")
|
|
set(LUALS_ARCH arm64)
|
|
else()
|
|
set(LUALS_ARCH x64)
|
|
endif()
|
|
|
|
set(LUALS_VERSION 3.15.0)
|
|
set(LUALS "lua-language-server-${LUALS_VERSION}-${CMAKE_SYSTEM_NAME}-${LUALS_ARCH}")
|
|
set(LUALS_TARBALL ${LUALS}.tar.gz)
|
|
set(LUALS_URL https://github.com/LuaLS/lua-language-server/releases/download/${LUALS_VERSION}/${LUALS_TARBALL})
|
|
|
|
ExternalProject_Add(download_luals
|
|
URL ${LUALS_URL}
|
|
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/luals
|
|
SOURCE_DIR ${DEPS_BIN_DIR}/luals
|
|
CONFIGURE_COMMAND ""
|
|
BUILD_COMMAND ""
|
|
INSTALL_COMMAND ""
|
|
EXCLUDE_FROM_ALL TRUE
|
|
DOWNLOAD_NO_PROGRESS TRUE
|
|
CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS})
|
|
|
|
file(GLOB_RECURSE LUAFILES runtime/*.lua)
|
|
add_target(luals
|
|
COMMAND ${DEPS_BIN_DIR}/luals/bin/lua-language-server
|
|
--configpath=${PROJECT_SOURCE_DIR}/.luarc.json
|
|
--check=${PROJECT_SOURCE_DIR}/runtime
|
|
--checklevel=Hint
|
|
DEPENDS ${LUAFILES}
|
|
CUSTOM_COMMAND_ARGS USES_TERMINAL)
|
|
|
|
add_dependencies(luals download_luals)
|