CMakeLists.txt 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. # Version should match the tested CMAKE_URL in .github/workflows/build.yml.
  9. cmake_minimum_required(VERSION 3.16)
  10. project(nvim C)
  11. if(POLICY CMP0135)
  12. cmake_policy(SET CMP0135 NEW)
  13. endif()
  14. if(XCODE)
  15. message(FATAL_ERROR [[Xcode generator is not supported. Use "Ninja" or "Unix Makefiles" instead]])
  16. endif()
  17. # Point CMake at any custom modules we may ship
  18. list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
  19. include(CheckCCompilerFlag)
  20. include(CheckCSourceCompiles)
  21. include(CheckLibraryExists)
  22. include(ExternalProject)
  23. include(FindPackageHandleStandardArgs)
  24. include(GNUInstallDirs)
  25. include(Deps)
  26. include(Find)
  27. include(InstallHelpers)
  28. include(PreventInTreeBuilds)
  29. include(Util)
  30. #-------------------------------------------------------------------------------
  31. # User settings
  32. #-------------------------------------------------------------------------------
  33. set(DEPS_IGNORE_SHA FALSE)
  34. #-------------------------------------------------------------------------------
  35. # Variables
  36. #-------------------------------------------------------------------------------
  37. set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
  38. set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
  39. set(VTERM_TEST_FILE ${PROJECT_BINARY_DIR}/test/vterm_test_output)
  40. file(GLOB DOCFILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt)
  41. if(NOT CI_BUILD)
  42. set(CMAKE_INSTALL_MESSAGE NEVER)
  43. endif()
  44. if(${CMAKE_VERSION} VERSION_LESS 3.20)
  45. set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
  46. endif()
  47. if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.26)
  48. set(COPY_DIRECTORY copy_directory_if_different)
  49. else()
  50. set(COPY_DIRECTORY copy_directory)
  51. endif()
  52. # Prefer our bundled versions of dependencies.
  53. if(DEFINED ENV{DEPS_BUILD_DIR})
  54. set(DEPS_PREFIX "$ENV{DEPS_BUILD_DIR}/usr" CACHE PATH "Path prefix for finding dependencies")
  55. else()
  56. set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies")
  57. # When running from within CLion or Visual Studio,
  58. # build bundled dependencies automatically.
  59. if(NOT EXISTS ${DEPS_PREFIX}
  60. AND (DEFINED ENV{CLION_IDE}
  61. OR DEFINED ENV{VisualStudioEdition}))
  62. message(STATUS "Building dependencies...")
  63. set(DEPS_BUILD_DIR ${PROJECT_BINARY_DIR}/.deps)
  64. file(MAKE_DIRECTORY ${DEPS_BUILD_DIR})
  65. execute_process(
  66. COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR}
  67. -D CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
  68. -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
  69. -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER}
  70. -D CMAKE_C_FLAGS=${CMAKE_C_FLAGS}
  71. -D CMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG}
  72. -D CMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL}
  73. -D CMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO}
  74. -D CMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE}
  75. -D CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
  76. ${PROJECT_SOURCE_DIR}/cmake.deps
  77. WORKING_DIRECTORY ${DEPS_BUILD_DIR})
  78. execute_process(
  79. COMMAND ${CMAKE_COMMAND} --build ${DEPS_BUILD_DIR}
  80. --config ${CMAKE_BUILD_TYPE})
  81. set(DEPS_PREFIX ${DEPS_BUILD_DIR}/usr)
  82. endif()
  83. endif()
  84. list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX})
  85. if(APPLE)
  86. # If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET),
  87. # fall back to local system version. Needs to be done both here and in cmake.deps.
  88. if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
  89. execute_process(COMMAND sw_vers -productVersion
  90. OUTPUT_VARIABLE MACOS_VERSION
  91. OUTPUT_STRIP_TRAILING_WHITESPACE)
  92. set(CMAKE_OSX_DEPLOYMENT_TARGET "${MACOS_VERSION}")
  93. endif()
  94. message(STATUS "Using deployment target ${CMAKE_OSX_DEPLOYMENT_TARGET}")
  95. endif()
  96. if(WIN32 OR APPLE)
  97. # Handle case-insensitive filenames for Windows and Mac.
  98. set(CASE_INSENSITIVE_FILENAME TRUE)
  99. endif()
  100. if (MINGW)
  101. # Disable LTO by default as it may not compile
  102. # See https://github.com/Alexpux/MINGW-packages/issues/3516
  103. # and https://github.com/neovim/neovim/pull/8654#issuecomment-402316672
  104. option(ENABLE_LTO "enable link time optimization" OFF)
  105. else()
  106. option(ENABLE_LTO "enable link time optimization" ON)
  107. endif()
  108. option(ENABLE_LIBINTL "enable libintl" ON)
  109. option(ENABLE_WASMTIME "enable wasmtime" OFF)
  110. message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
  111. set_default_buildtype(Debug)
  112. get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
  113. if(NOT isMultiConfig)
  114. # Unlike build dependencies in cmake.deps, we want dev dependencies such as
  115. # Uncrustify to always be built with Release.
  116. list(APPEND DEPS_CMAKE_ARGS -D CMAKE_BUILD_TYPE=Release)
  117. endif()
  118. # If not in a git repo (e.g., a tarball) these tokens define the complete
  119. # version string, else they are combined with the result of `git describe`.
  120. set(NVIM_VERSION_MAJOR 0)
  121. set(NVIM_VERSION_MINOR 11)
  122. set(NVIM_VERSION_PATCH 0)
  123. set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
  124. # API level
  125. set(NVIM_API_LEVEL 13) # Bump this after any API/stdlib change.
  126. set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
  127. set(NVIM_API_PRERELEASE true)
  128. # Build-type: RelWithDebInfo
  129. # /Og means something different in MSVC
  130. if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
  131. set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -Og -g")
  132. endif()
  133. # We _want_ assertions in RelWithDebInfo build-type.
  134. if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG)
  135. string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
  136. string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
  137. string(REPLACE " " " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Remove duplicate whitespace
  138. endif()
  139. option(ENABLE_ASAN_UBSAN "Enable Clang address & undefined behavior sanitizer for nvim binary." OFF)
  140. option(ENABLE_MSAN "Enable Clang memory sanitizer for nvim binary." OFF)
  141. # TSAN exists to test Luv threads.
  142. option(ENABLE_TSAN "Enable Clang thread sanitizer for nvim binary." OFF)
  143. if((ENABLE_ASAN_UBSAN AND ENABLE_MSAN)
  144. OR (ENABLE_ASAN_UBSAN AND ENABLE_TSAN)
  145. OR (ENABLE_MSAN AND ENABLE_TSAN))
  146. message(FATAL_ERROR "Sanitizers cannot be enabled simultaneously")
  147. endif()
  148. # Place targets in bin/ or lib/ for all build configurations
  149. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
  150. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  151. set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  152. foreach(CFGNAME ${CMAKE_CONFIGURATION_TYPES})
  153. string(TOUPPER ${CFGNAME} CFGNAME)
  154. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/bin)
  155. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib)
  156. set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib)
  157. endforeach()
  158. if(NOT PREFER_LUA)
  159. find_program(LUA_PRG NAMES luajit)
  160. endif()
  161. find_program(LUA_PRG NAMES lua5.1 lua5.2 lua)
  162. if(NOT LUA_PRG)
  163. message(FATAL_ERROR "Failed to find a Lua 5.1-compatible interpreter")
  164. endif()
  165. message(STATUS "Using Lua interpreter: ${LUA_PRG}")
  166. # Some of the code generation still relies on stable table ordering in order to
  167. # produce reproducible output - specifically the msgpack'ed data in
  168. # funcs_metadata.generated.h and ui_events_metadata.generated.h. This should
  169. # ideally be fixed in the generators, but until then as a workaround you may provide
  170. # a specific lua implementation that provides the needed stability by setting LUA_GEN_PRG:
  171. if(NOT LUA_GEN_PRG)
  172. set(LUA_GEN_PRG "${LUA_PRG}" CACHE FILEPATH "Path to the lua used for code generation.")
  173. endif()
  174. message(STATUS "Using Lua interpreter for code generation: ${LUA_GEN_PRG}")
  175. option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON)
  176. if(COMPILE_LUA AND NOT WIN32)
  177. if(PREFER_LUA)
  178. foreach(CURRENT_LUAC_PRG luac5.1 luac)
  179. find_program(_CHECK_LUAC_PRG ${CURRENT_LUAC_PRG})
  180. if(_CHECK_LUAC_PRG)
  181. set(LUAC_PRG "${_CHECK_LUAC_PRG} -s -o - %s" CACHE STRING "Format for compiling to Lua bytecode")
  182. break()
  183. endif()
  184. endforeach()
  185. elseif(LUA_PRG MATCHES "luajit")
  186. check_lua_module(${LUA_PRG} "jit.bcsave" LUAJIT_HAS_JIT_BCSAVE)
  187. if(LUAJIT_HAS_JIT_BCSAVE)
  188. set(LUAC_PRG "${LUA_PRG} -b -s %s -" CACHE STRING "Format for compiling to Lua bytecode")
  189. endif()
  190. endif()
  191. endif()
  192. if(LUAC_PRG)
  193. message(STATUS "Using Lua compiler: ${LUAC_PRG}")
  194. endif()
  195. # Lint
  196. option(CI_LINT "Abort if lint programs not found" OFF)
  197. if(CI_LINT)
  198. set(LINT_REQUIRED "REQUIRED")
  199. endif()
  200. find_program(SHELLCHECK_PRG shellcheck ${LINT_REQUIRED})
  201. find_program(STYLUA_PRG stylua ${LINT_REQUIRED})
  202. set(STYLUA_DIRS runtime scripts src test contrib)
  203. add_glob_target(
  204. TARGET lintlua-luacheck
  205. COMMAND $<TARGET_FILE:nvim_bin>
  206. FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr luacheck -q
  207. GLOB_DIRS runtime scripts src test
  208. GLOB_PAT *.lua
  209. TOUCH_STRATEGY PER_DIR)
  210. add_dependencies(lintlua-luacheck lua_dev_deps)
  211. add_glob_target(
  212. TARGET lintlua-stylua
  213. COMMAND ${STYLUA_PRG}
  214. FLAGS --color=always --check --respect-ignores
  215. GLOB_DIRS ${STYLUA_DIRS}
  216. GLOB_PAT *.lua
  217. TOUCH_STRATEGY PER_DIR)
  218. add_custom_target(lintlua)
  219. add_dependencies(lintlua lintlua-luacheck lintlua-stylua)
  220. add_glob_target(
  221. TARGET lintsh
  222. COMMAND ${SHELLCHECK_PRG}
  223. FLAGS -x -a
  224. GLOB_DIRS scripts
  225. GLOB_PAT *.sh
  226. TOUCH_STRATEGY PER_DIR)
  227. add_custom_target(lintcommit
  228. COMMAND $<TARGET_FILE:nvim_bin> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
  229. add_dependencies(lintcommit nvim_bin)
  230. add_custom_target(lint)
  231. add_dependencies(lint lintc lintlua lintsh lintcommit)
  232. # Format
  233. add_glob_target(
  234. TARGET formatlua
  235. COMMAND ${STYLUA_PRG}
  236. FLAGS --respect-ignores
  237. GLOB_DIRS ${STYLUA_DIRS}
  238. GLOB_PAT *.lua
  239. TOUCH_STRATEGY PER_DIR)
  240. add_custom_target(format)
  241. add_dependencies(format formatc formatlua)
  242. install_helper(
  243. FILES ${CMAKE_SOURCE_DIR}/src/man/nvim.1
  244. DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
  245. add_custom_target(nvim ALL)
  246. add_dependencies(nvim nvim_bin nvim_runtime_deps nvim_runtime)
  247. add_subdirectory(src/nvim)
  248. add_subdirectory(cmake.config)
  249. add_subdirectory(runtime)
  250. add_subdirectory(test)
  251. add_custom_target(uninstall
  252. COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/UninstallHelper.cmake)
  253. if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
  254. add_subdirectory(cmake.packaging)
  255. endif()
  256. get_externalproject_options(uncrustify ${DEPS_IGNORE_SHA})
  257. ExternalProject_Add(uncrustify
  258. DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/uncrustify
  259. CMAKE_ARGS ${DEPS_CMAKE_ARGS}
  260. -D CMAKE_RUNTIME_OUTPUT_DIRECTORY=${DEPS_BIN_DIR}
  261. EXCLUDE_FROM_ALL TRUE
  262. ${EXTERNALPROJECT_OPTIONS})
  263. option(USE_BUNDLED_BUSTED "Use bundled busted" ON)
  264. if(USE_BUNDLED_BUSTED)
  265. get_externalproject_options(lua_dev_deps ${DEPS_IGNORE_SHA})
  266. ExternalProject_Add(lua_dev_deps
  267. DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua_dev_deps
  268. SOURCE_DIR ${DEPS_SHARE_DIR}
  269. CONFIGURE_COMMAND ""
  270. BUILD_COMMAND ""
  271. INSTALL_COMMAND ""
  272. EXCLUDE_FROM_ALL TRUE
  273. ${EXTERNALPROJECT_OPTIONS})
  274. else()
  275. add_custom_target(lua_dev_deps)
  276. endif()