CMakeLists.txt (14368B)
1 # CMAKE REFERENCE 2 # - intro: https://codingnest.com/basic-cmake/ 3 # - best practices (3.0+): https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1 4 # - pitfalls: https://izzys.casa/2019/02/everything-you-never-wanted-to-know-about-cmake/ 5 # - troubleshooting: 6 # - variable_watch https://cmake.org/cmake/help/latest/command/variable_watch.html 7 # - verbose output: cmake --build build --verbose 8 9 # Version should match the tested CMAKE_URL in .github/workflows/build.yml. 10 cmake_minimum_required(VERSION 3.16) 11 12 project(nvim C) 13 14 if(POLICY CMP0135) 15 cmake_policy(SET CMP0135 NEW) 16 endif() 17 18 if(XCODE) 19 message(FATAL_ERROR [[Xcode generator is not supported. Use "Ninja" or "Unix Makefiles" instead]]) 20 endif() 21 22 # Point CMake at any custom modules we may ship 23 list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") 24 25 include(CheckCCompilerFlag) 26 include(CheckCSourceCompiles) 27 include(CheckLibraryExists) 28 include(ExternalProject) 29 include(FindPackageHandleStandardArgs) 30 include(GNUInstallDirs) 31 32 include(Deps) 33 include(Find) 34 include(InstallHelpers) 35 include(PreventInTreeBuilds) 36 include(Util) 37 38 if(NOT PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) 39 # Auto-create a .gitignore in the specified "build" directory. 40 file(GENERATE OUTPUT .gitignore CONTENT "*") 41 endif() 42 43 #------------------------------------------------------------------------------- 44 # User settings 45 #------------------------------------------------------------------------------- 46 47 set(DEPS_IGNORE_SHA FALSE) 48 49 #------------------------------------------------------------------------------- 50 # Variables 51 #------------------------------------------------------------------------------- 52 set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack) 53 set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches) 54 set(VTERM_TEST_FILE ${PROJECT_BINARY_DIR}/test/vterm_test_output) 55 56 file(GLOB DOCFILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt) 57 58 if(NOT CI_BUILD) 59 set(CMAKE_INSTALL_MESSAGE NEVER) 60 endif() 61 62 if(${CMAKE_VERSION} VERSION_LESS 3.20) 63 set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 64 endif() 65 66 if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.26) 67 set(COPY_DIRECTORY copy_directory_if_different) 68 else() 69 set(COPY_DIRECTORY copy_directory) 70 endif() 71 72 # Prefer our bundled versions of dependencies. 73 if(DEFINED ENV{DEPS_BUILD_DIR}) 74 set(DEPS_PREFIX "$ENV{DEPS_BUILD_DIR}/usr" CACHE PATH "Path prefix for finding dependencies") 75 else() 76 set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies") 77 # When running from within CLion or Visual Studio, 78 # build bundled dependencies automatically. 79 if(NOT EXISTS ${DEPS_PREFIX} 80 AND (DEFINED ENV{CLION_IDE} 81 OR DEFINED ENV{VisualStudioEdition})) 82 message(STATUS "Building dependencies...") 83 set(DEPS_BUILD_DIR ${PROJECT_BINARY_DIR}/.deps) 84 file(MAKE_DIRECTORY ${DEPS_BUILD_DIR}) 85 execute_process( 86 COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} 87 -D CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} 88 -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} 89 -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER} 90 -D CMAKE_C_FLAGS=${CMAKE_C_FLAGS} 91 -D CMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} 92 -D CMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} 93 -D CMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} 94 -D CMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} 95 -D CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} 96 ${PROJECT_SOURCE_DIR}/cmake.deps 97 WORKING_DIRECTORY ${DEPS_BUILD_DIR}) 98 execute_process( 99 COMMAND ${CMAKE_COMMAND} --build ${DEPS_BUILD_DIR} 100 --config ${CMAKE_BUILD_TYPE}) 101 set(DEPS_PREFIX ${DEPS_BUILD_DIR}/usr) 102 endif() 103 endif() 104 105 list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX}) 106 107 if(APPLE) 108 # If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET), 109 # fall back to local system version. Needs to be done both here and in cmake.deps. 110 if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) 111 execute_process(COMMAND sw_vers -productVersion 112 OUTPUT_VARIABLE MACOS_VERSION 113 OUTPUT_STRIP_TRAILING_WHITESPACE) 114 set(CMAKE_OSX_DEPLOYMENT_TARGET "${MACOS_VERSION}") 115 endif() 116 message(STATUS "Using deployment target ${CMAKE_OSX_DEPLOYMENT_TARGET}") 117 endif() 118 119 if(WIN32 OR APPLE) 120 # Handle case-insensitive filenames for Windows and Mac. 121 set(CASE_INSENSITIVE_FILENAME TRUE) 122 endif() 123 124 if (MINGW) 125 # Disable LTO by default as it may not compile 126 # See https://github.com/Alexpux/MINGW-packages/issues/3516 127 # and https://github.com/neovim/neovim/pull/8654#issuecomment-402316672 128 option(ENABLE_LTO "enable link time optimization" OFF) 129 else() 130 option(ENABLE_LTO "enable link time optimization" ON) 131 endif() 132 option(ENABLE_LIBINTL "enable libintl" ON) 133 option(ENABLE_UNIBILIUM "enable unibilium" ON) 134 option(ENABLE_WASMTIME "enable wasmtime" OFF) 135 136 message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") 137 138 set_default_buildtype(Debug) 139 get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 140 if(NOT isMultiConfig) 141 # Unlike build dependencies in cmake.deps, we want dev dependencies such as 142 # Uncrustify to always be built with Release. 143 list(APPEND DEPS_CMAKE_ARGS -D CMAKE_BUILD_TYPE=Release) 144 endif() 145 146 # If not in a git repo (e.g., a tarball) these tokens define the complete 147 # version string, else they are combined with the result of `git describe`. 148 set(NVIM_VERSION_MAJOR 0) 149 set(NVIM_VERSION_MINOR 12) 150 set(NVIM_VERSION_PATCH 0) 151 set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers 152 153 # API level 154 set(NVIM_API_LEVEL 14) # Bump this after any API/stdlib change. 155 set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change. 156 set(NVIM_API_PRERELEASE true) 157 158 # We _want_ assertions in RelWithDebInfo build-type. 159 if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG) 160 string(REPLACE "-DNDEBUG" "-DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") 161 string(REPLACE "/DNDEBUG" "/DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") 162 string(REPLACE " " " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Remove duplicate whitespace 163 endif() 164 165 option(ENABLE_ASAN_UBSAN "Enable Clang address & undefined behavior sanitizer for nvim binary." OFF) 166 option(ENABLE_MSAN "Enable Clang memory sanitizer for nvim binary." OFF) 167 # TSAN exists to test Luv threads. 168 option(ENABLE_TSAN "Enable Clang thread sanitizer for nvim binary." OFF) 169 170 if((ENABLE_ASAN_UBSAN AND ENABLE_MSAN) 171 OR (ENABLE_ASAN_UBSAN AND ENABLE_TSAN) 172 OR (ENABLE_MSAN AND ENABLE_TSAN)) 173 message(FATAL_ERROR "Sanitizers cannot be enabled simultaneously") 174 endif() 175 176 # Place targets in bin/ or lib/ for all build configurations 177 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 178 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 179 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 180 foreach(CFGNAME ${CMAKE_CONFIGURATION_TYPES}) 181 string(TOUPPER ${CFGNAME} CFGNAME) 182 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/bin) 183 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib) 184 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib) 185 endforeach() 186 187 if(NOT PREFER_LUA) 188 find_program(LUA_PRG NAMES luajit) 189 endif() 190 find_program(LUA_PRG NAMES lua5.1 lua5.2 lua) 191 mark_as_advanced(LUA_PRG) 192 if(NOT LUA_PRG) 193 message(FATAL_ERROR "Failed to find a Lua 5.1-compatible interpreter") 194 endif() 195 message(STATUS "Using Lua interpreter: ${LUA_PRG}") 196 197 # Some of the code generation still relies on stable table ordering in order to 198 # produce reproducible output - specifically the msgpack'ed data in 199 # funcs_metadata.generated.h and ui_events_metadata.generated.h. This should 200 # ideally be fixed in the generators, but until then as a workaround you may provide 201 # a specific lua implementation that provides the needed stability by setting LUA_GEN_PRG: 202 if(NOT LUA_GEN_PRG) 203 set(LUA_GEN_PRG "${LUA_PRG}" CACHE FILEPATH "Path to the lua used for code generation.") 204 endif() 205 mark_as_advanced(LUA_GEN_PRG) 206 message(STATUS "Using Lua interpreter for code generation: ${LUA_GEN_PRG}") 207 208 option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON) 209 if(COMPILE_LUA AND NOT WIN32) 210 if(PREFER_LUA) 211 foreach(CURRENT_LUAC_PRG luac5.1 luac) 212 find_program(_CHECK_LUAC_PRG ${CURRENT_LUAC_PRG}) 213 if(_CHECK_LUAC_PRG) 214 set(LUAC_PRG "${_CHECK_LUAC_PRG} -s -o - %s" CACHE STRING "Format for compiling to Lua bytecode") 215 break() 216 endif() 217 endforeach() 218 elseif(LUA_PRG MATCHES "luajit") 219 check_lua_module(${LUA_PRG} "jit.bcsave" LUAJIT_HAS_JIT_BCSAVE) 220 if(LUAJIT_HAS_JIT_BCSAVE) 221 set(LUAC_PRG "${LUA_PRG} -b -s %s -" CACHE STRING "Format for compiling to Lua bytecode") 222 endif() 223 endif() 224 endif() 225 mark_as_advanced(LUAC_PRG) 226 if(LUAC_PRG) 227 message(STATUS "Using Lua compiler: ${LUAC_PRG}") 228 endif() 229 230 # Lint 231 option(CI_LINT "Abort if lint programs not found" OFF) 232 if(CI_LINT) 233 set(LINT_REQUIRED "REQUIRED") 234 endif() 235 find_program(SHELLCHECK_PRG shellcheck ${LINT_REQUIRED}) 236 mark_as_advanced(SHELLCHECK_PRG) 237 find_program(STYLUA_PRG stylua ${LINT_REQUIRED}) 238 mark_as_advanced(STYLUA_PRG) 239 find_program(TS_QUERY_LS_PRG ts_query_ls ${LINT_REQUIRED}) 240 mark_as_advanced(TS_QUERY_LS_PRG) 241 242 set(STYLUA_DIRS runtime scripts src test contrib) 243 244 add_glob_target( 245 TARGET lintlua-luacheck 246 COMMAND $<TARGET_FILE:nvim_bin> 247 FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr/share/lua/5.1 luacheck -q 248 GLOB_DIRS runtime scripts src test 249 GLOB_PAT *.lua 250 TOUCH_STRATEGY PER_DIR) 251 add_dependencies(lintlua-luacheck lua_dev_deps) 252 253 add_glob_target( 254 TARGET lintlua-stylua 255 COMMAND ${STYLUA_PRG} 256 FLAGS --color=always --check --respect-ignores 257 GLOB_DIRS ${STYLUA_DIRS} 258 GLOB_PAT *.lua 259 TOUCH_STRATEGY PER_DIR) 260 # Special handling of some files (which are ignored in .styluaignore). 261 # Workaround because stylua doesn't(?) support file-specific settings. 262 add_custom_target(lintlua-stylua2 263 COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml" 264 --color=always --check 265 "${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua" 266 "${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua" 267 "${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua" 268 ) 269 add_dependencies(lintlua-stylua lintlua-stylua2) 270 271 add_custom_target(lintlua) 272 add_dependencies(lintlua lintlua-luacheck lintlua-stylua) 273 274 add_glob_target( 275 TARGET lintsh 276 COMMAND ${SHELLCHECK_PRG} 277 FLAGS -x -a 278 GLOB_DIRS scripts 279 GLOB_PAT *.sh 280 TOUCH_STRATEGY PER_DIR) 281 282 add_custom_target(lintquery-compilation 283 COMMAND ${TS_QUERY_LS_PRG} 284 check ${PROJECT_SOURCE_DIR}/runtime/queries --config 285 '{"parser_install_directories": ["${DEPS_PREFIX}/lib/nvim/parser"]}') 286 287 add_custom_target(lintquery-format 288 COMMAND ${TS_QUERY_LS_PRG} 289 format ${PROJECT_SOURCE_DIR}/runtime/queries --check) 290 291 add_custom_target(lintquery) 292 add_dependencies(lintquery lintquery-compilation lintquery-format) 293 294 add_custom_target(lintcommit 295 COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main) 296 add_dependencies(lintcommit nvim_bin) 297 298 add_custom_target(lint) 299 add_dependencies(lint lintc lintlua lintsh lintquery) 300 301 # Format 302 add_glob_target( 303 TARGET formatlua 304 COMMAND ${STYLUA_PRG} 305 FLAGS --respect-ignores 306 GLOB_DIRS ${STYLUA_DIRS} 307 GLOB_PAT *.lua 308 TOUCH_STRATEGY PER_DIR) 309 # Special handling of some files (which are ignored in .styluaignore). 310 # Workaround because stylua doesn't(?) support file-specific settings. 311 add_custom_target(formatlua2 312 COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml" 313 "${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua" 314 "${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua" 315 "${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua" 316 ) 317 add_dependencies(formatlua formatlua2) 318 319 add_custom_target(formatquery 320 COMMAND ${TS_QUERY_LS_PRG} 321 format ${PROJECT_SOURCE_DIR}/runtime/queries) 322 323 add_custom_target(format) 324 add_dependencies(format formatc formatlua formatquery) 325 326 install_helper( 327 FILES ${CMAKE_SOURCE_DIR}/src/man/nvim.1 328 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) 329 330 add_custom_target(nvim ALL) 331 add_dependencies(nvim nvim_bin nvim_runtime_deps nvim_runtime) 332 333 add_subdirectory(src/nvim) 334 add_subdirectory(src/tee) 335 add_subdirectory(src/xxd) 336 add_subdirectory(cmake.config) 337 add_subdirectory(runtime) 338 add_subdirectory(test) 339 340 add_custom_target(uninstall 341 COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/UninstallHelper.cmake) 342 343 if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) 344 add_subdirectory(cmake.packaging) 345 endif() 346 347 get_externalproject_options(uncrustify ${DEPS_IGNORE_SHA}) 348 ExternalProject_Add(uncrustify 349 DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/uncrustify 350 CMAKE_ARGS ${DEPS_CMAKE_ARGS} 351 -D CMAKE_RUNTIME_OUTPUT_DIRECTORY=${DEPS_BIN_DIR} 352 -D CMAKE_SKIP_RPATH=true 353 EXCLUDE_FROM_ALL TRUE 354 ${EXTERNALPROJECT_OPTIONS}) 355 356 option(USE_BUNDLED_BUSTED "Use bundled busted" ON) 357 if(USE_BUNDLED_BUSTED) 358 get_externalproject_options(lua_dev_deps ${DEPS_IGNORE_SHA}) 359 ExternalProject_Add(lua_dev_deps 360 DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua_dev_deps 361 SOURCE_DIR ${DEPS_SHARE_DIR} 362 CONFIGURE_COMMAND "" 363 BUILD_COMMAND "" 364 INSTALL_COMMAND "" 365 EXCLUDE_FROM_ALL TRUE 366 ${EXTERNALPROJECT_OPTIONS}) 367 else() 368 add_custom_target(lua_dev_deps) 369 endif() 370 371 if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch") 372 set(LUALS_ARCH arm64) 373 else() 374 set(LUALS_ARCH x64) 375 endif() 376 377 set(LUALS_VERSION 3.15.0) 378 set(LUALS "lua-language-server-${LUALS_VERSION}-${CMAKE_SYSTEM_NAME}-${LUALS_ARCH}") 379 set(LUALS_TARBALL ${LUALS}.tar.gz) 380 set(LUALS_URL https://github.com/LuaLS/lua-language-server/releases/download/${LUALS_VERSION}/${LUALS_TARBALL}) 381 382 ExternalProject_Add(download_luals 383 URL ${LUALS_URL} 384 DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/luals 385 SOURCE_DIR ${DEPS_BIN_DIR}/luals 386 CONFIGURE_COMMAND "" 387 BUILD_COMMAND "" 388 INSTALL_COMMAND "" 389 EXCLUDE_FROM_ALL TRUE 390 DOWNLOAD_NO_PROGRESS TRUE 391 CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS}) 392 393 file(GLOB_RECURSE LUAFILES runtime/*.lua) 394 add_target(luals 395 COMMAND ${DEPS_BIN_DIR}/luals/bin/lua-language-server 396 --configpath=${PROJECT_SOURCE_DIR}/.luarc.json 397 --check=${PROJECT_SOURCE_DIR}/runtime 398 --checklevel=Hint 399 DEPENDS ${LUAFILES} 400 CUSTOM_COMMAND_ARGS USES_TERMINAL) 401 402 add_dependencies(luals download_luals)