neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

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)