CMakeLists.txt 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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. # Version should match the tested CMAKE_URL in .github/workflows/build.yml.
  6. cmake_minimum_required(VERSION 3.10)
  7. # Can be removed once minimum version is at least 3.15
  8. if(POLICY CMP0092)
  9. cmake_policy(SET CMP0092 NEW)
  10. endif()
  11. project(nvim C)
  12. if(POLICY CMP0075)
  13. cmake_policy(SET CMP0075 NEW)
  14. endif()
  15. # Point CMake at any custom modules we may ship
  16. list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
  17. include(CheckCCompilerFlag)
  18. include(CheckCSourceCompiles)
  19. include(FindPackageHandleStandardArgs)
  20. include(InstallHelpers)
  21. include(LuaHelpers)
  22. include(PreventInTreeBuilds)
  23. include(Util)
  24. set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
  25. find_program(CCACHE_PRG ccache)
  26. if(CCACHE_PRG)
  27. set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env CCACHE_SLOPPINESS=pch_defines,time_macros ${CCACHE_PRG})
  28. endif()
  29. if(NOT CI_BUILD)
  30. set(CMAKE_INSTALL_MESSAGE NEVER)
  31. endif()
  32. # Prefer our bundled versions of dependencies.
  33. if(DEFINED ENV{DEPS_BUILD_DIR})
  34. set(DEPS_PREFIX "$ENV{DEPS_BUILD_DIR}/usr" CACHE PATH "Path prefix for finding dependencies")
  35. else()
  36. set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies")
  37. # When running from within CLion or Visual Studio,
  38. # build bundled dependencies automatically.
  39. if(NOT EXISTS ${DEPS_PREFIX}
  40. AND (DEFINED ENV{CLION_IDE}
  41. OR DEFINED ENV{VisualStudioEdition}))
  42. message(STATUS "Building dependencies...")
  43. set(DEPS_BUILD_DIR ${PROJECT_BINARY_DIR}/.deps)
  44. file(MAKE_DIRECTORY ${DEPS_BUILD_DIR})
  45. execute_process(
  46. COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR}
  47. -D CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
  48. -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
  49. -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER}
  50. -D CMAKE_C_FLAGS=${CMAKE_C_FLAGS}
  51. -D CMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG}
  52. -D CMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL}
  53. -D CMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO}
  54. -D CMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE}
  55. -D CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
  56. ${PROJECT_SOURCE_DIR}/cmake.deps
  57. WORKING_DIRECTORY ${DEPS_BUILD_DIR})
  58. execute_process(
  59. COMMAND ${CMAKE_COMMAND} --build ${DEPS_BUILD_DIR}
  60. --config ${CMAKE_BUILD_TYPE})
  61. set(DEPS_PREFIX ${DEPS_BUILD_DIR}/usr)
  62. endif()
  63. endif()
  64. list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX})
  65. if(APPLE)
  66. # If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET),
  67. # fall back to local system version. Needs to be done both here and in cmake.deps.
  68. if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
  69. execute_process(COMMAND sw_vers -productVersion
  70. OUTPUT_VARIABLE MACOS_VERSION
  71. OUTPUT_STRIP_TRAILING_WHITESPACE)
  72. set(CMAKE_OSX_DEPLOYMENT_TARGET "${MACOS_VERSION}")
  73. endif()
  74. message(STATUS "Using deployment target ${CMAKE_OSX_DEPLOYMENT_TARGET}")
  75. endif()
  76. if(WIN32 OR APPLE)
  77. # Ignore case when comparing filenames on Windows and Mac.
  78. set(CASE_INSENSITIVE_FILENAME TRUE)
  79. # Enable fixing case-insensitive filenames for Windows and Mac.
  80. set(USE_FNAME_CASE TRUE)
  81. endif()
  82. if (MINGW)
  83. # Disable LTO by default as it may not compile
  84. # See https://github.com/Alexpux/MINGW-packages/issues/3516
  85. # and https://github.com/neovim/neovim/pull/8654#issuecomment-402316672
  86. option(ENABLE_LTO "enable link time optimization" OFF)
  87. else()
  88. option(ENABLE_LTO "enable link time optimization" ON)
  89. endif()
  90. option(ENABLE_LIBINTL "enable libintl" ON)
  91. message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
  92. set_default_buildtype()
  93. # If not in a git repo (e.g., a tarball) these tokens define the complete
  94. # version string, else they are combined with the result of `git describe`.
  95. set(NVIM_VERSION_MAJOR 0)
  96. set(NVIM_VERSION_MINOR 9)
  97. set(NVIM_VERSION_PATCH 6)
  98. set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
  99. # API level
  100. set(NVIM_API_LEVEL 11) # Bump this after any API change.
  101. set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
  102. set(NVIM_API_PRERELEASE false)
  103. # Build-type: RelWithDebInfo
  104. # /Og means something different in MSVC
  105. if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
  106. set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -Og -g")
  107. endif()
  108. # We _want_ assertions in RelWithDebInfo build-type.
  109. if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG)
  110. string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
  111. string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
  112. string(REPLACE " " " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Remove duplicate whitespace
  113. endif()
  114. option(ENABLE_ASAN_UBSAN "Enable Clang address & undefined behavior sanitizer for nvim binary." OFF)
  115. option(LOG_DEBUG "Enable debug log messages even in a release build" OFF)
  116. option(ENABLE_MSAN "Enable Clang memory sanitizer for nvim binary." OFF)
  117. option(ENABLE_TSAN "Enable Clang thread sanitizer for nvim binary." OFF)
  118. if((ENABLE_ASAN_UBSAN AND ENABLE_MSAN)
  119. OR (ENABLE_ASAN_UBSAN AND ENABLE_TSAN)
  120. OR (ENABLE_MSAN AND ENABLE_TSAN))
  121. message(FATAL_ERROR "Sanitizers cannot be enabled simultaneously")
  122. endif()
  123. # Place targets in bin/ or lib/ for all build configurations
  124. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
  125. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  126. set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  127. foreach(CFGNAME ${CMAKE_CONFIGURATION_TYPES})
  128. string(TOUPPER ${CFGNAME} CFGNAME)
  129. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/bin)
  130. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib)
  131. set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CFGNAME} ${CMAKE_BINARY_DIR}/lib)
  132. endforeach()
  133. set(LUA_DEPENDENCIES lpeg mpack bit)
  134. if(NOT LUA_PRG)
  135. foreach(CURRENT_LUA_PRG luajit lua5.1 lua5.2 lua)
  136. unset(_CHECK_LUA_PRG CACHE)
  137. unset(LUA_PRG_WORKS)
  138. find_program(_CHECK_LUA_PRG ${CURRENT_LUA_PRG})
  139. if(_CHECK_LUA_PRG)
  140. check_lua_deps(${_CHECK_LUA_PRG} "${LUA_DEPENDENCIES}" LUA_PRG_WORKS)
  141. if(LUA_PRG_WORKS)
  142. set(LUA_PRG "${_CHECK_LUA_PRG}" CACHE FILEPATH "Path to a program.")
  143. break()
  144. endif()
  145. endif()
  146. endforeach()
  147. unset(_CHECK_LUA_PRG CACHE)
  148. else()
  149. check_lua_deps(${LUA_PRG} "${LUA_DEPENDENCIES}" LUA_PRG_WORKS)
  150. endif()
  151. if(NOT LUA_PRG_WORKS)
  152. message(FATAL_ERROR "Failed to find a Lua 5.1-compatible interpreter")
  153. endif()
  154. message(STATUS "Using Lua interpreter: ${LUA_PRG}")
  155. # Some of the code generation still relies on stable table ordering in order to
  156. # produce reproducible output - specifically the msgpack'ed data in
  157. # funcs_metadata.generated.h and ui_events_metadata.generated.h. This should
  158. # ideally be fixed in the generators, but until then as a workaround you may provide
  159. # a specific lua implementation that provides the needed stability by setting LUA_GEN_PRG:
  160. if(NOT LUA_GEN_PRG)
  161. set(LUA_GEN_PRG "${LUA_PRG}" CACHE FILEPATH "Path to the lua used for code generation.")
  162. endif()
  163. message(STATUS "Using Lua interpreter for code generation: ${LUA_GEN_PRG}")
  164. option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON)
  165. if(COMPILE_LUA AND NOT WIN32)
  166. if(PREFER_LUA)
  167. foreach(CURRENT_LUAC_PRG luac5.1 luac)
  168. find_program(_CHECK_LUAC_PRG ${CURRENT_LUAC_PRG})
  169. if(_CHECK_LUAC_PRG)
  170. set(LUAC_PRG "${_CHECK_LUAC_PRG} -s -o - %s" CACHE STRING "Format for compiling to Lua bytecode")
  171. break()
  172. endif()
  173. endforeach()
  174. elseif(LUA_PRG MATCHES "luajit")
  175. check_lua_module(${LUA_PRG} "jit.bcsave" LUAJIT_HAS_JIT_BCSAVE)
  176. if(LUAJIT_HAS_JIT_BCSAVE)
  177. set(LUAC_PRG "${LUA_PRG} -b -s %s -" CACHE STRING "Format for compiling to Lua bytecode")
  178. endif()
  179. endif()
  180. endif()
  181. if(LUAC_PRG)
  182. message(STATUS "Using Lua compiler: ${LUAC_PRG}")
  183. endif()
  184. #
  185. # Lint
  186. #
  187. find_program(LUACHECK_PRG luacheck)
  188. find_program(SHELLCHECK_PRG shellcheck)
  189. find_program(STYLUA_PRG stylua)
  190. find_program(UNCRUSTIFY_PRG uncrustify)
  191. add_glob_target(
  192. REQUIRED
  193. TARGET lintlua-luacheck
  194. COMMAND ${LUACHECK_PRG}
  195. FLAGS -q
  196. GLOB_DIRS runtime/ scripts/ src/ test/
  197. GLOB_PAT *.lua
  198. TOUCH_STRATEGY SINGLE)
  199. add_glob_target(
  200. TARGET lintlua-stylua
  201. COMMAND ${STYLUA_PRG}
  202. FLAGS --color=always --check
  203. GLOB_DIRS runtime/
  204. GLOB_PAT *.lua
  205. EXCLUDE
  206. /runtime/lua/vim/re.lua
  207. TOUCH_STRATEGY SINGLE)
  208. add_custom_target(lintlua)
  209. add_dependencies(lintlua lintlua-luacheck lintlua-stylua)
  210. add_glob_target(
  211. TARGET lintsh
  212. COMMAND ${SHELLCHECK_PRG}
  213. FLAGS -x -a
  214. GLOB_DIRS scripts
  215. GLOB_PAT *.sh
  216. EXCLUDE
  217. scripts/pvscheck.sh
  218. TOUCH_STRATEGY SINGLE)
  219. add_custom_target(lintcommit
  220. COMMAND ${PROJECT_BINARY_DIR}/bin/nvim -u NONE -es -c [[lua require('scripts.lintcommit').main({trace=false})]]
  221. WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
  222. VERBATIM)
  223. add_dependencies(lintcommit nvim)
  224. add_custom_target(lint)
  225. add_dependencies(lint clang-tidy lintc lintlua lintsh lintcommit)
  226. #
  227. # Format
  228. #
  229. add_custom_target(formatlua
  230. COMMAND ${CMAKE_COMMAND}
  231. -D FORMAT_PRG=${STYLUA_PRG}
  232. -D LANG=lua
  233. -P ${PROJECT_SOURCE_DIR}/cmake/Format.cmake
  234. WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
  235. add_custom_target(format)
  236. add_dependencies(format formatc formatlua)
  237. install_helper(
  238. FILES ${CMAKE_SOURCE_DIR}/src/man/nvim.1
  239. DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
  240. if(EXISTS "${DEPS_PREFIX}/share/nvim-qt")
  241. option(USE_BUNDLED_NVIMQT "Bundle neovim-qt" ON)
  242. else()
  243. option(USE_BUNDLED_NVIMQT "Bundle neovim-qt" OFF)
  244. endif()
  245. add_subdirectory(src/nvim)
  246. add_subdirectory(cmake.config)
  247. add_subdirectory(runtime)
  248. add_subdirectory(test)
  249. if(WIN32 AND USE_BUNDLED_NVIMQT)
  250. install_helper(
  251. FILES ${DEPS_PREFIX}/share/nvim-qt/runtime/plugin/nvim_gui_shim.vim
  252. DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim-qt/runtime/plugin)
  253. endif()
  254. add_custom_target(uninstall
  255. COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/UninstallHelper.cmake)
  256. if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
  257. add_subdirectory(cmake.packaging)
  258. endif()