add_library(main_lib INTERFACE) add_executable(nvim main.c) set_target_properties(nvim PROPERTIES EXPORT_COMPILE_COMMANDS ON ENABLE_EXPORTS TRUE) #------------------------------------------------------------------------------- # Dependencies #------------------------------------------------------------------------------- add_library(libuv INTERFACE) find_package(libuv CONFIG QUIET) if(TARGET libuv::uv_a) target_link_libraries(libuv INTERFACE libuv::uv_a) mark_as_advanced(libuv_DIR) else() # Fall back to find module for libuv versions older than v1.45.0 which don't # provide a config file find_package(Libuv 1.28.0 REQUIRED MODULE) target_include_directories(libuv SYSTEM BEFORE INTERFACE ${LIBUV_INCLUDE_DIR}) target_link_libraries(libuv INTERFACE ${LIBUV_LIBRARIES}) endif() add_library(nlua0 MODULE) if(WIN32) target_compile_definitions(nlua0 PUBLIC LUA_BUILD_AS_DLL LUA_LIB) set_target_properties(nlua0 PROPERTIES ENABLE_EXPORTS TRUE) elseif(APPLE) set_target_properties(nlua0 PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") endif() find_package(Luv 1.43.0 REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUV_INCLUDE_DIR}) target_link_libraries(main_lib INTERFACE ${LUV_LIBRARY}) find_package(Iconv REQUIRED) find_package(Lpeg REQUIRED) find_package(Libtermkey 0.22 REQUIRED) find_package(Libvterm 0.3.3 REQUIRED) find_package(Msgpack 1.0.0 REQUIRED) find_package(Treesitter 0.20.8 REQUIRED) find_package(Unibilium 2.0 REQUIRED) target_link_libraries(main_lib INTERFACE iconv libtermkey libvterm msgpack treesitter unibilium lpeg) target_link_libraries(nlua0 PUBLIC lpeg) # Libintl (not Intl) selects our FindLibintl.cmake script. #8464 find_package(Libintl REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBINTL_INCLUDE_DIR}) if (LIBINTL_LIBRARY) target_link_libraries(main_lib INTERFACE ${LIBINTL_LIBRARY}) endif() # The unit test lib requires LuaJIT; it will be skipped if LuaJIT is missing. option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF) if(PREFER_LUA) find_package(Lua 5.1 EXACT REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUA_INCLUDE_DIR}) target_include_directories(nlua0 SYSTEM BEFORE PUBLIC ${LUA_INCLUDE_DIR}) target_link_libraries(main_lib INTERFACE ${LUA_LIBRARIES}) # Passive (not REQUIRED): if LUAJIT_FOUND is not set, fixtures for unittests is skipped. find_package(Luajit) else() find_package(Luajit REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUAJIT_INCLUDE_DIR}) target_link_libraries(main_lib INTERFACE ${LUAJIT_LIBRARY}) target_include_directories(nlua0 SYSTEM BEFORE PUBLIC ${LUAJIT_INCLUDE_DIR}) if(WIN32) target_link_libraries(nlua0 PUBLIC ${LUAJIT_LIBRARY}) endif() endif() #------------------------------------------------------------------------------- # Compiler and linker options #------------------------------------------------------------------------------- if(NOT MSVC) target_compile_options(main_lib INTERFACE -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wvla -Wdouble-promotion -Wmissing-noreturn -Wmissing-format-attribute -Wmissing-prototypes -fsigned-char) # For O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW flags on older systems # (pre POSIX.1-2008: glibc 2.11 and earlier). #4042 # For ptsname(). #6743 target_compile_definitions(main_lib INTERFACE _GNU_SOURCE) endif() # -fstack-protector breaks Mingw-w64 builds if(NOT MINGW) check_c_compiler_flag(-fstack-protector-strong HAS_FSTACK_PROTECTOR_STRONG_FLAG) if(HAS_FSTACK_PROTECTOR_STRONG_FLAG) target_compile_options(main_lib INTERFACE -fstack-protector-strong) target_link_libraries(main_lib INTERFACE -fstack-protector-strong) else() check_c_compiler_flag(-fstack-protector HAS_FSTACK_PROTECTOR_FLAG) if(HAS_FSTACK_PROTECTOR_FLAG) target_compile_options(main_lib INTERFACE -fstack-protector --param ssp-buffer-size=4) target_link_libraries(main_lib INTERFACE -fstack-protector --param ssp-buffer-size=4) endif() endif() endif() # Compiler specific options if(MSVC) target_compile_options(main_lib INTERFACE -W3) # Disable warnings that give too many false positives. target_compile_options(main_lib INTERFACE -wd4311 -wd4146 -wd4003 -wd4715) target_compile_definitions(main_lib INTERFACE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE) target_sources(main_lib INTERFACE ${CMAKE_CURRENT_LIST_DIR}/os/nvim.manifest) elseif(MINGW) # Use POSIX compatible stdio in Mingw target_compile_definitions(main_lib INTERFACE __USE_MINGW_ANSI_STDIO) # Enable wmain target_link_libraries(nvim PRIVATE -municode) elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") target_compile_options(main_lib INTERFACE -fno-common $<$:-Wno-unused-result> $<$:-Wno-unused-result> $<$:-Wno-unused-result>) elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") # On FreeBSD 64 math.h uses unguarded C11 extension, which taints clang # 3.4.1 used there. if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") target_compile_options(main_lib INTERFACE -Wno-c11-extensions) endif() # workaround for clang-11 on macOS, supported on later versions if(NOT APPLE) target_link_libraries(nvim PRIVATE -Wl,--no-undefined) endif() endif() # Platform specific options if(UNIX) target_link_libraries(main_lib INTERFACE m) if (NOT CMAKE_SYSTEM_NAME STREQUAL "SunOS") target_link_libraries(main_lib INTERFACE util) endif() endif() if(CMAKE_SYSTEM_NAME MATCHES "Windows") target_compile_definitions(main_lib INTERFACE _WIN32_WINNT=0x0602 MSWIN) target_link_libraries(main_lib INTERFACE netapi32) elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") target_link_libraries(nvim PRIVATE "-framework CoreServices") # Actually export symbols - symbols may not be visible even though # ENABLE_EXPORTS is set to true. See # https://github.com/neovim/neovim/issues/25295 set_target_properties(nvim PROPERTIES LINK_FLAGS "-Wl,-export_dynamic") elseif(CMAKE_SYSTEM_NAME MATCHES "OpenBSD") target_link_libraries(main_lib INTERFACE pthread c++abi) elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS") target_link_libraries(nvim PRIVATE -lsocket) endif() check_c_compiler_flag(-Wimplicit-fallthrough HAVE_WIMPLICIT_FALLTHROUGH_FLAG) if(HAVE_WIMPLICIT_FALLTHROUGH_FLAG) target_compile_options(main_lib INTERFACE -Wimplicit-fallthrough) endif() check_c_compiler_flag(-fdiagnostics-color=auto HAS_DIAG_COLOR_FLAG) if(HAS_DIAG_COLOR_FLAG) if(CMAKE_GENERATOR MATCHES "Ninja") target_compile_options(main_lib INTERFACE -fdiagnostics-color=always) else() target_compile_options(main_lib INTERFACE -fdiagnostics-color=auto) endif() endif() target_compile_definitions(main_lib INTERFACE INCLUDE_GENERATED_DECLARATIONS) # Remove --sort-common from linker flags, as this seems to cause bugs (see #2641, #3374). # TODO: Figure out the root cause. if(CMAKE_EXE_LINKER_FLAGS MATCHES "--sort-common" OR CMAKE_SHARED_LINKER_FLAGS MATCHES "--sort-common" OR CMAKE_MODULE_LINKER_FLAGS MATCHES "--sort-common") message(STATUS "Removing --sort-common from linker flags") string(REGEX REPLACE ",--sort-common(=[^,]+)?" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") string(REGEX REPLACE ",--sort-common(=[^,]+)?" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") string(REGEX REPLACE ",--sort-common(=[^,]+)?" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") # If no linker flags remain for a -Wl argument, remove it. # '-Wl$' will match LDFLAGS="-Wl,--sort-common", # '-Wl ' will match LDFLAGS="-Wl,--sort-common -Wl,..." string(REGEX REPLACE "-Wl($| )" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") string(REGEX REPLACE "-Wl($| )" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") string(REGEX REPLACE "-Wl($| )" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") endif() #------------------------------------------------------------------------------- # Cmake options #------------------------------------------------------------------------------- if(ENABLE_ASAN_UBSAN) message(STATUS "Enabling address sanitizer and undefined behavior sanitizer for nvim.") if(NOT MSVC) if(CI_BUILD) # Try to recover from all sanitize issues so we get reports about all failures target_compile_options(nvim PRIVATE -fsanitize-recover=all) else() target_compile_options(nvim PRIVATE -fno-sanitize-recover=all) endif() target_compile_options(nvim PRIVATE -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=undefined) endif() target_compile_options(nvim PRIVATE -fsanitize=address) target_link_libraries(nvim PRIVATE -fsanitize=address -fsanitize=undefined) target_compile_definitions(nvim PRIVATE ENABLE_ASAN_UBSAN) elseif(ENABLE_MSAN) message(STATUS "Enabling memory sanitizer for nvim.") target_compile_options(nvim PRIVATE -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -fno-optimize-sibling-calls) target_link_libraries(nvim PRIVATE -fsanitize=memory -fsanitize-memory-track-origins) elseif(ENABLE_TSAN) message(STATUS "Enabling thread sanitizer for nvim.") target_compile_options(nvim PRIVATE -fsanitize=thread -fPIE) target_link_libraries(nvim PRIVATE -fsanitize=thread) endif() option(CI_BUILD "CI, extra flags will be set" OFF) if(CI_BUILD) message(STATUS "CI build enabled") if(MSVC) target_compile_options(main_lib INTERFACE -WX) else() target_compile_options(main_lib INTERFACE -Werror) endif() endif() option(ENABLE_IWYU "Run include-what-you-use with the compiler." OFF) if(ENABLE_IWYU) find_program(IWYU_PRG NAMES include-what-you-use iwyu) if(NOT IWYU_PRG) message(FATAL_ERROR "ENABLE_IWYU is ON but include-what-you-use is not found!") endif() set(iwyu_flags "${IWYU_PRG};") string(APPEND iwyu_flags "-Xiwyu;--no_default_mappings;") string(APPEND iwyu_flags "-Xiwyu;--no_fwd_decls;") string(APPEND iwyu_flags "-Xiwyu;--mapping_file=${PROJECT_SOURCE_DIR}/cmake.config/iwyu/mapping.imp") set_target_properties(nvim PROPERTIES C_INCLUDE_WHAT_YOU_USE "${iwyu_flags}") target_compile_definitions(main_lib INTERFACE EXITFREE) endif() option(ENABLE_COMPILER_SUGGESTIONS "Enable -Wsuggest compiler warnings" OFF) if(ENABLE_COMPILER_SUGGESTIONS) # Clang doesn't have -Wsuggest-attribute so check for each one. check_c_compiler_flag(-Wsuggest-attribute=pure HAVE_WSUGGEST_ATTRIBUTE_PURE) if(HAVE_WSUGGEST_ATTRIBUTE_PURE) target_compile_options(main_lib INTERFACE -Wsuggest-attribute=pure) endif() check_c_compiler_flag(-Wsuggest-attribute=const HAVE_WSUGGEST_ATTRIBUTE_CONST) if(HAVE_WSUGGEST_ATTRIBUTE_CONST) target_compile_options(main_lib INTERFACE -Wsuggest-attribute=const) endif() check_c_compiler_flag(-Wsuggest-attribute=malloc HAVE_WSUGGEST_ATTRIBUTE_MALLOC) if(HAVE_WSUGGEST_ATTRIBUTE_MALLOC) target_compile_options(main_lib INTERFACE -Wsuggest-attribute=malloc) endif() check_c_compiler_flag(-Wsuggest-attribute=cold HAVE_WSUGGEST_ATTRIBUTE_COLD) if(HAVE_WSUGGEST_ATTRIBUTE_COLD) target_compile_options(main_lib INTERFACE -Wsuggest-attribute=cold) endif() endif() option(ENABLE_GCOV "Enable gcov support" OFF) if(ENABLE_GCOV) if(ENABLE_TSAN) # GCOV and TSAN results in false data race reports message(FATAL_ERROR "ENABLE_GCOV cannot be used with ENABLE_TSAN") endif() message(STATUS "Enabling gcov support") target_compile_options(main_lib INTERFACE --coverage) target_link_libraries(main_lib INTERFACE --coverage) target_compile_definitions(main_lib INTERFACE USE_GCOV) endif() #------------------------------------------------------------------------------- # Variables #------------------------------------------------------------------------------- set(GENERATOR_DIR ${CMAKE_CURRENT_LIST_DIR}/generators) set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto) set(BINARY_LIB_DIR ${PROJECT_BINARY_DIR}/lib/nvim/) set(API_DISPATCH_GENERATOR ${GENERATOR_DIR}/gen_api_dispatch.lua) set(API_UI_EVENTS_GENERATOR ${GENERATOR_DIR}/gen_api_ui_events.lua) set(GENERATOR_PRELOAD ${GENERATOR_DIR}/preload.lua) set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua) set(GENERATOR_HASHY ${GENERATOR_DIR}/hashy.lua) set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack) set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack) set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.c) set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua) set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include) set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.generated.h) set(GENERATED_FUNCS_METADATA ${GENERATED_DIR}/api/private/funcs_metadata.generated.h) set(GENERATED_UI_EVENTS_CALL ${GENERATED_DIR}/ui_events_call.generated.h) set(GENERATED_UI_EVENTS_REMOTE ${GENERATED_DIR}/ui_events_remote.generated.h) set(GENERATED_UI_EVENTS_CLIENT ${GENERATED_DIR}/ui_events_client.generated.h) set(GENERATED_UI_EVENTS_METADATA ${GENERATED_DIR}/api/private/ui_events_metadata.generated.h) set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h) set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h) set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.generated.h) set(GENERATED_KEYSETS_DEFS ${GENERATED_DIR}/keysets_defs.generated.h) set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h) set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h) set(GENERATED_OPTIONS ${GENERATED_DIR}/options.generated.h) set(EX_CMDS_GENERATOR ${GENERATOR_DIR}/gen_ex_cmds.lua) set(FUNCS_GENERATOR ${GENERATOR_DIR}/gen_eval.lua) set(EVENTS_GENERATOR ${GENERATOR_DIR}/gen_events.lua) set(OPTIONS_GENERATOR ${GENERATOR_DIR}/gen_options.lua) set(UNICODE_TABLES_GENERATOR ${GENERATOR_DIR}/gen_unicode_tables.lua) set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/src/unicode) set(GENERATED_UNICODE_TABLES ${GENERATED_DIR}/unicode_tables.generated.h) set(VIM_MODULE_FILE ${GENERATED_DIR}/lua/vim_module.generated.h) set(NVIM_RUNTIME_DIR ${PROJECT_SOURCE_DIR}/runtime) set(LUA_EDITOR_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/_editor.lua) set(LUA_SHARED_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/shared.lua) set(LUA_LOADER_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/loader.lua) set(LUA_INSPECT_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/inspect.lua) set(LUA_FS_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/fs.lua) set(LUA_F_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/F.lua) set(LUA_DEFAULTS_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/_defaults.lua) set(LUA_OPTIONS_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/_options.lua) set(LUA_FILETYPE_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/filetype.lua) set(LUA_INIT_PACKAGES_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/_init_packages.lua) set(LUA_KEYMAP_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/keymap.lua) set(CHAR_BLOB_GENERATOR ${GENERATOR_DIR}/gen_char_blob.lua) set(LUAJIT_RUNTIME_DIR ${DEPS_PREFIX}/share/luajit-2.1/jit) glob_wrapper(UNICODE_FILES ${UNICODE_DIR}/*.txt) glob_wrapper(API_HEADERS api/*.h) list(REMOVE_ITEM API_HEADERS ${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h) glob_wrapper(MSGPACK_RPC_HEADERS msgpack_rpc/*.h) target_include_directories(main_lib INTERFACE ${GENERATED_DIR}) target_include_directories(main_lib INTERFACE ${CACHED_GENERATED_DIR}) target_include_directories(main_lib INTERFACE ${GENERATED_INCLUDES_DIR}) target_include_directories(main_lib INTERFACE "${PROJECT_BINARY_DIR}/cmake.config") target_include_directories(main_lib INTERFACE "${PROJECT_SOURCE_DIR}/src") target_include_directories(nlua0 PUBLIC "${PROJECT_SOURCE_DIR}/src") target_include_directories(nlua0 PUBLIC "${PROJECT_BINARY_DIR}/cmake.config") target_include_directories(nlua0 PUBLIC ${GENERATED_INCLUDES_DIR}) file(MAKE_DIRECTORY ${TOUCHES_DIR}) file(MAKE_DIRECTORY ${GENERATED_DIR}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}) glob_wrapper(NVIM_SOURCES *.c) glob_wrapper(NVIM_HEADERS *.h) glob_wrapper(EXTERNAL_SOURCES ../xdiff/*.c ../mpack/*.c ../cjson/*.c ../klib/*.c) glob_wrapper(EXTERNAL_HEADERS ../xdiff/*.h ../mpack/*.h ../cjson/*.h ../klib/*.h) glob_wrapper(NLUA0_SOURCES ../mpack/*.c) if(PREFER_LUA) # luajit not used, use a vendored copy of the bit module list(APPEND EXTERNAL_SOURCES ${PROJECT_SOURCE_DIR}/src/bit.c) list(APPEND NLUA0_SOURCES ${PROJECT_SOURCE_DIR}/src/bit.c) target_compile_definitions(main_lib INTERFACE NVIM_VENDOR_BIT) endif() list(APPEND NLUA0_SOURCES ${PROJECT_SOURCE_DIR}/src/nlua0.c) foreach(subdir os api api/private msgpack_rpc tui event eval lua viml viml/parser ) file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir}) glob_wrapper(sources ${subdir}/*.c) glob_wrapper(headers ${subdir}/*.h) list(APPEND NVIM_SOURCES ${sources}) list(APPEND NVIM_HEADERS ${headers}) endforeach() # Sort file lists to ensure generated files are created in the same order from # build to build. list(SORT NVIM_SOURCES) list(SORT NVIM_HEADERS) list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS}) foreach(sfile ${NVIM_SOURCES}) get_filename_component(f ${sfile} NAME) if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$") list(APPEND to_remove ${sfile}) endif() if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$") list(APPEND to_remove ${sfile}) endif() if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$") list(APPEND to_remove ${sfile}) endif() if(NOT WIN32 AND ${f} MATCHES "^(os_win_console.c)$") list(APPEND to_remove ${sfile}) endif() endforeach() list(REMOVE_ITEM NVIM_SOURCES ${to_remove}) # xdiff, mpack, lua-cjson: inlined external project, we don't maintain it. #9306 if(MSVC) set_source_files_properties( ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -wd4090 -wd4244 -wd4267") else() set_source_files_properties( ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion -Wno-missing-noreturn -Wno-missing-format-attribute -Wno-double-promotion -Wno-strict-prototypes -Wno-misleading-indentation") endif() # Log level (NVIM_LOG_DEBUG in log.h) if(CI_BUILD) # Don't debug log on CI, it gets too verbose in the main build log. # TODO(bfredl): debug log level also exposes some errors with EXITFREE in ASAN build. else() # Minimize logging for release-type builds. target_compile_definitions(nvim PRIVATE $<$:NVIM_LOG_DEBUG>) endif() if(ENABLE_ASAN_UBSAN OR ENABLE_MSAN OR ENABLE_TSAN) target_compile_definitions(main_lib INTERFACE EXITFREE) endif() #------------------------------------------------------------------------------- # Header generation #------------------------------------------------------------------------------- get_target_property(prop main_lib INTERFACE_COMPILE_DEFINITIONS) foreach(gen_cdef DO_NOT_DEFINE_EMPTY_ATTRIBUTES ${prop}) if(NOT ${gen_cdef} MATCHES "INCLUDE_GENERATED_DECLARATIONS") list(APPEND gen_cflags "-D${gen_cdef}") endif() endforeach() get_directory_property(targets BUILDSYSTEM_TARGETS) foreach(target ${targets}) get_target_property(prop ${target} INTERFACE_INCLUDE_DIRECTORIES) foreach(gen_include ${prop}) list(APPEND gen_cflags "-I${gen_include}") endforeach() endforeach() if(APPLE AND CMAKE_OSX_SYSROOT) list(APPEND gen_cflags "-isysroot" "${CMAKE_OSX_SYSROOT}") endif() if(MSVC) list(APPEND gen_cflags -wd4003) endif() list(APPEND gen_cflags -O2) set(NVIM_VERSION_GIT_H ${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef_git.h) add_custom_target(update_version_stamp COMMAND ${CMAKE_COMMAND} -D NVIM_VERSION_MAJOR=${NVIM_VERSION_MAJOR} -D NVIM_VERSION_MINOR=${NVIM_VERSION_MINOR} -D NVIM_VERSION_PATCH=${NVIM_VERSION_PATCH} -D NVIM_VERSION_PRERELEASE=${NVIM_VERSION_PRERELEASE} -D OUTPUT=${NVIM_VERSION_GIT_H} -D NVIM_SOURCE_DIR=${CMAKE_SOURCE_DIR} -P ${PROJECT_SOURCE_DIR}/cmake/GenerateVersion.cmake BYPRODUCTS ${NVIM_VERSION_GIT_H}) set(NVIM_VERSION_DEF_H ${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef.h) add_custom_command( OUTPUT "${NVIM_VERSION_DEF_H}" COMMAND "${CMAKE_COMMAND}" -E copy "${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef-$.h" "${NVIM_VERSION_DEF_H}" DEPENDS "${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef-$.h") set(LUA_GEN ${LUA_GEN_PRG} ${GENERATOR_PRELOAD} ${PROJECT_SOURCE_DIR} $) set(LUA_GEN_DEPS ${GENERATOR_PRELOAD} $) # NVIM_GENERATED_FOR_HEADERS: generated headers to be included in headers # NVIM_GENERATED_FOR_SOURCES: generated headers to be included in sources # NVIM_GENERATED_SOURCES: generated source files # These lists must be mutually exclusive. foreach(sfile ${NVIM_SOURCES} ${GENERATED_API_DISPATCH} "${GENERATED_UI_EVENTS_CALL}" "${GENERATED_UI_EVENTS_REMOTE}" "${GENERATED_UI_EVENTS_CLIENT}" ) get_filename_component(full_d ${sfile} DIRECTORY) file(RELATIVE_PATH d "${CMAKE_CURRENT_LIST_DIR}" "${full_d}") if(${d} MATCHES "^[.][.]|auto/") file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}") endif() get_filename_component(f ${sfile} NAME) get_filename_component(r ${sfile} NAME_WE) if(NOT ${d} EQUAL ".") set(f "${d}/${f}") set(r "${d}/${r}") endif() set(gf_c_h "${GENERATED_DIR}/${r}.c.generated.h") set(gf_h_h "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h") set(gf_i "${GENERATED_DIR}/${r}.i") if(MSVC) set(PREPROC_OUTPUT /P /Fi${gf_i} /nologo) else() set(PREPROC_OUTPUT -E -o ${gf_i}) endif() set(depends "${HEADER_GENERATOR}" "${sfile}" "${LUA_GEN_DEPS}") if("${f}" STREQUAL "version.c") # Ensure auto/versiondef_git.h exists after "make clean". list(APPEND depends update_version_stamp "${NVIM_VERSION_GIT_H}" "${NVIM_VERSION_DEF_H}") endif() add_custom_command( OUTPUT "${gf_c_h}" "${gf_h_h}" COMMAND ${CMAKE_C_COMPILER} ${sfile} ${PREPROC_OUTPUT} ${gen_cflags} COMMAND ${LUA_GEN} "${HEADER_GENERATOR}" "${sfile}" "${gf_c_h}" "${gf_h_h}" "${gf_i}" DEPENDS ${depends}) list(APPEND NVIM_GENERATED_FOR_SOURCES "${gf_c_h}") list(APPEND NVIM_GENERATED_FOR_HEADERS "${gf_h_h}") if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$") list(APPEND API_HEADERS ${gf_h_h}) endif() endforeach() add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES} COMMAND ${LUA_PRG} ${UNICODE_TABLES_GENERATOR} ${UNICODE_DIR} ${GENERATED_UNICODE_TABLES} DEPENDS ${UNICODE_TABLES_GENERATOR} ${UNICODE_FILES} ) add_custom_command( OUTPUT ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA} ${API_METADATA} ${LUA_API_C_BINDINGS} ${GENERATED_KEYSETS_DEFS} COMMAND ${LUA_GEN} ${API_DISPATCH_GENERATOR} ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA} ${API_METADATA} ${LUA_API_C_BINDINGS} ${GENERATED_KEYSETS_DEFS} ${API_HEADERS} DEPENDS ${LUA_GEN_DEPS} ${API_HEADERS} ${MSGPACK_RPC_HEADERS} ${API_DISPATCH_GENERATOR} ${GENERATOR_C_GRAMMAR} ${CMAKE_CURRENT_LIST_DIR}/api/dispatch_deprecated.lua ) add_custom_command( OUTPUT ${VIM_MODULE_FILE} COMMAND ${CMAKE_COMMAND} -E env "LUAC_PRG=${LUAC_PRG}" ${LUA_PRG} ${CHAR_BLOB_GENERATOR} -c ${VIM_MODULE_FILE} # NB: vim._init_packages and vim.inspect must be be first and second ones # respectively, otherwise --luamod-dev won't work properly. ${LUA_INIT_PACKAGES_MODULE_SOURCE} "vim._init_packages" ${LUA_INSPECT_MODULE_SOURCE} "vim.inspect" ${LUA_EDITOR_MODULE_SOURCE} "vim._editor" ${LUA_FILETYPE_MODULE_SOURCE} "vim.filetype" ${LUA_FS_MODULE_SOURCE} "vim.fs" ${LUA_F_MODULE_SOURCE} "vim.F" ${LUA_KEYMAP_MODULE_SOURCE} "vim.keymap" ${LUA_LOADER_MODULE_SOURCE} "vim.loader" ${LUA_DEFAULTS_MODULE_SOURCE} "vim._defaults" ${LUA_OPTIONS_MODULE_SOURCE} "vim._options" ${LUA_SHARED_MODULE_SOURCE} "vim.shared" DEPENDS ${CHAR_BLOB_GENERATOR} ${LUA_INIT_PACKAGES_MODULE_SOURCE} ${LUA_INSPECT_MODULE_SOURCE} ${LUA_EDITOR_MODULE_SOURCE} ${LUA_FILETYPE_MODULE_SOURCE} ${LUA_FS_MODULE_SOURCE} ${LUA_F_MODULE_SOURCE} ${LUA_KEYMAP_MODULE_SOURCE} ${LUA_LOADER_MODULE_SOURCE} ${LUA_DEFAULTS_MODULE_SOURCE} ${LUA_OPTIONS_MODULE_SOURCE} ${LUA_SHARED_MODULE_SOURCE} VERBATIM ) list(APPEND NVIM_GENERATED_SOURCES "${LUA_API_C_BINDINGS}" ) add_custom_command( OUTPUT ${GENERATED_UI_EVENTS_CALL} ${GENERATED_UI_EVENTS_REMOTE} ${GENERATED_UI_EVENTS_METADATA} ${GENERATED_UI_EVENTS_CLIENT} COMMAND ${LUA_GEN} ${API_UI_EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h ${GENERATED_UI_EVENTS_CALL} ${GENERATED_UI_EVENTS_REMOTE} ${GENERATED_UI_EVENTS_METADATA} ${GENERATED_UI_EVENTS_CLIENT} DEPENDS ${LUA_GEN_DEPS} ${API_UI_EVENTS_GENERATOR} ${GENERATOR_C_GRAMMAR} ${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h ) list(APPEND NVIM_GENERATED_FOR_HEADERS "${GENERATED_EX_CMDS_ENUM}" "${GENERATED_EVENTS_ENUM}" "${GENERATED_KEYSETS_DEFS}" ) list(APPEND NVIM_GENERATED_FOR_SOURCES "${GENERATED_API_DISPATCH}" "${GENERATED_EX_CMDS_DEFS}" "${GENERATED_EVENTS_NAMES_MAP}" "${GENERATED_OPTIONS}" "${GENERATED_UNICODE_TABLES}" "${VIM_MODULE_FILE}" ) list(APPEND NVIM_GENERATED_SOURCES "${PROJECT_BINARY_DIR}/cmake.config/auto/pathdef.c" ) add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS} COMMAND ${LUA_GEN} ${EX_CMDS_GENERATOR} ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR} DEPENDS ${LUA_GEN_DEPS} ${EX_CMDS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/ex_cmds.lua ) add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA} COMMAND ${LUA_GEN} ${FUNCS_GENERATOR} ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA} DEPENDS ${LUA_GEN_DEPS} ${FUNCS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/eval.lua ${API_METADATA} ) list(APPEND NVIM_GENERATED_FOR_SOURCES "${GENERATED_FUNCS}") add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP} COMMAND ${LUA_GEN} ${EVENTS_GENERATOR} ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP} DEPENDS ${LUA_GEN_DEPS} ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua ) add_custom_command(OUTPUT ${GENERATED_OPTIONS} COMMAND ${LUA_GEN} ${OPTIONS_GENERATOR} ${GENERATED_OPTIONS} DEPENDS ${LUA_GEN_DEPS} ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua ) # NVIM_GENERATED_FOR_SOURCES and NVIM_GENERATED_FOR_HEADERS must be mutually exclusive. foreach(hfile ${NVIM_GENERATED_FOR_HEADERS}) list(FIND NVIM_GENERATED_FOR_SOURCES ${hfile} hfile_idx) if(NOT ${hfile_idx} EQUAL -1) message(FATAL_ERROR "File included in both NVIM_GENERATED_FOR_HEADERS and NVIM_GENERATED_FOR_SOURCES") endif() endforeach() if(PREFER_LUA) message(STATUS "luajit not used, skipping unit tests") else() glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) target_sources(nvim PRIVATE ${UNIT_TEST_FIXTURES}) target_compile_definitions(nvim PRIVATE UNIT_TESTING) endif() target_sources(main_lib INTERFACE ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS} ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}) target_sources(nlua0 PUBLIC ${NLUA0_SOURCES}) target_link_libraries(nvim PRIVATE main_lib PUBLIC libuv) install_helper(TARGETS nvim) if(MSVC) install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) endif() if(ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT IPO_SUPPORTED) if(IPO_SUPPORTED) set_target_properties(nvim PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL TRUE) endif() endif() if(WIN32) # Copy DLLs and third-party tools to bin/ and install them along with nvim add_custom_target(nvim_runtime_deps ALL COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_BINARY_DIR}/windows_runtime_deps/ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) install(DIRECTORY ${PROJECT_BINARY_DIR}/windows_runtime_deps/ DESTINATION ${CMAKE_INSTALL_BINDIR}) add_custom_target(nvim_dll_deps DEPENDS nvim COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/windows_runtime_deps COMMAND ${CMAKE_COMMAND} -D CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -D BINARY="${PROJECT_BINARY_DIR}/bin/nvim${CMAKE_EXECUTABLE_SUFFIX}" -D DST=${PROJECT_BINARY_DIR}/windows_runtime_deps -D CI_BUILD=${CI_BUILD} -P ${PROJECT_SOURCE_DIR}/cmake/WindowsDllCopy.cmake) add_dependencies(nvim_runtime_deps nvim_dll_deps) # A CMake script is used for copying the files to avoid the # "command line is too long" error that occurs when Ninja tries running # a command that exceeds the length limit (8191 characters) on Windows. # See https://developercommunity.visualstudio.com/content/problem/212207/file-open-cmake-the-command-line-is-too-long.html set(EXTERNAL_BLOBS_SCRIPT "file(MAKE_DIRECTORY \"${PROJECT_BINARY_DIR}/windows_runtime_deps/platforms\")") foreach(DEP_FILE IN ITEMS cat.exe tee.exe win32yank.exe xxd.exe) get_filename_component(DEP_FILE_DIR ${DEP_FILE} DIRECTORY) set(EXTERNAL_BLOBS_SCRIPT "${EXTERNAL_BLOBS_SCRIPT}\n" "file(COPY \"${DEPS_PREFIX}/bin/${DEP_FILE}\" DESTINATION \"${PROJECT_BINARY_DIR}/windows_runtime_deps/${DEP_FILE_DIR}\")") endforeach() file(WRITE ${PROJECT_BINARY_DIR}/external_blobs.cmake ${EXTERNAL_BLOBS_SCRIPT}) add_custom_target(external_blobs COMMAND ${CMAKE_COMMAND} -P ${PROJECT_BINARY_DIR}/external_blobs.cmake) add_dependencies(nvim_runtime_deps external_blobs) else() add_custom_target(nvim_runtime_deps) # Stub target to avoid CMP0046. endif() file(MAKE_DIRECTORY ${BINARY_LIB_DIR}) # install treesitter parser if bundled if(EXISTS ${DEPS_PREFIX}/lib/nvim/parser) glob_wrapper(TREESITTER_PARSERS ${DEPS_PREFIX}/lib/nvim/parser/*) foreach(parser_lib ${TREESITTER_PARSERS}) file(COPY ${parser_lib} DESTINATION ${BINARY_LIB_DIR}/parser) endforeach() endif() install(DIRECTORY ${BINARY_LIB_DIR} DESTINATION ${CMAKE_INSTALL_LIBDIR}/nvim/ USE_SOURCE_PERMISSIONS) if(NOT PREFER_LUA) # install luajit runtime files if bundled if(EXISTS ${LUAJIT_RUNTIME_DIR}) install(DIRECTORY ${LUAJIT_RUNTIME_DIR} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/lua USE_SOURCE_PERMISSIONS) endif() endif() add_library(libnvim STATIC EXCLUDE_FROM_ALL) if(MSVC) set(LIBNVIM_NAME libnvim) else() set(LIBNVIM_NAME nvim) endif() set_target_properties( libnvim PROPERTIES OUTPUT_NAME ${LIBNVIM_NAME} ) target_compile_definitions(libnvim PRIVATE MAKE_LIB) target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv) #------------------------------------------------------------------------------- # Lint #------------------------------------------------------------------------------- find_program(CLANG_TIDY_PRG clang-tidy) set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h) if(WIN32) list(APPEND EXCLUDE_CLANG_TIDY os/pty_process_unix.h os/unix_defs.h) else() list(APPEND EXCLUDE_CLANG_TIDY os/win_defs.h os/pty_process_win.h os/pty_conpty_win.h os/os_win_console.h) endif() add_glob_target( TARGET lintc-clang-tidy COMMAND ${CLANG_TIDY_PRG} FILES ${NVIM_SOURCES} ${NVIM_HEADERS} FLAGS --quiet EXCLUDE ${EXCLUDE_CLANG_TIDY}) # These are the same warnings as https://neovim.io/doc/reports/clang/. The # checks we ignore are meant to be removed eventually, but we can only do so # after we properly fix the problems without breaking CI. add_glob_target( TARGET clang-analyzer COMMAND ${CLANG_TIDY_PRG} FILES ${NVIM_SOURCES} ${NVIM_HEADERS} FLAGS --quiet --checks=' -*, clang-analyzer-*, -clang-analyzer-core.NonNullParamChecker, -clang-analyzer-core.NullDereference, -clang-analyzer-core.UndefinedBinaryOperatorResult, -clang-analyzer-core.uninitialized.Assign, -clang-analyzer-optin.performance.Padding, -clang-analyzer-security.insecureAPI.strcpy, ' EXCLUDE ${EXCLUDE_CLANG_TIDY}) add_custom_target(copy_compile_commands COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/compile_commands.json ${PROJECT_SOURCE_DIR}/compile_commands.json) add_dependencies(copy_compile_commands nvim) add_dependencies(lintc-clang-tidy copy_compile_commands) add_dependencies(clang-analyzer copy_compile_commands) if(CI_BUILD) set(LINT_OUTPUT_FORMAT gh_action) else() set(LINT_OUTPUT_FORMAT vs7) endif() add_glob_target( TARGET lintc-clint COMMAND ${PROJECT_SOURCE_DIR}/src/clint.py FLAGS --output=${LINT_OUTPUT_FORMAT} FILES ${LINT_NVIM_SOURCES} EXCLUDE tui/terminfo_defs.h) set(UNCRUSTIFY_PRG ${DEPS_BIN_DIR}/uncrustify) set(UNCRUSTIFY_CONFIG ${PROJECT_SOURCE_DIR}/src/uncrustify.cfg) add_custom_target(uncrustify_update_config ${UNCRUSTIFY_PRG} -c ${UNCRUSTIFY_CONFIG} --update-config-with-doc -o ${UNCRUSTIFY_CONFIG}) add_glob_target( TARGET lintc-uncrustify COMMAND ${UNCRUSTIFY_PRG} FLAGS -c ${UNCRUSTIFY_CONFIG} -q --check FILES ${LINT_NVIM_SOURCES}) add_custom_target(formatc COMMAND ${CMAKE_COMMAND} -D FORMAT_PRG=${UNCRUSTIFY_PRG} -D LANG=c -P ${PROJECT_SOURCE_DIR}/cmake/Format.cmake WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_dependencies(lintc-uncrustify uncrustify_update_config) add_dependencies(formatc uncrustify_update_config) add_dependencies(uncrustify_update_config uncrustify) add_custom_target(lintc) add_dependencies(lintc lintc-clint lintc-uncrustify lintc-clang-tidy) add_custom_target(generated-sources DEPENDS ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} ${NVIM_GENERATED_SOURCES} ) add_subdirectory(po) #------------------------------------------------------------------------------- # Docs #------------------------------------------------------------------------------- set(VIMDOC_FILES ${NVIM_RUNTIME_DIR}/doc/api.mpack ${NVIM_RUNTIME_DIR}/doc/api.txt ${NVIM_RUNTIME_DIR}/doc/diagnostic.mpack ${NVIM_RUNTIME_DIR}/doc/diagnostic.txt ${NVIM_RUNTIME_DIR}/doc/lsp.mpack ${NVIM_RUNTIME_DIR}/doc/lsp.txt ${NVIM_RUNTIME_DIR}/doc/lua.mpack ${NVIM_RUNTIME_DIR}/doc/lua.txt ${NVIM_RUNTIME_DIR}/doc/treesitter.mpack ${NVIM_RUNTIME_DIR}/doc/treesitter.txt ) glob_wrapper(API_SOURCES ${PROJECT_SOURCE_DIR}/src/nvim/api/*.c) glob_wrapper(LUA_SOURCES ${NVIM_RUNTIME_DIR}/lua/vim/*.lua ${NVIM_RUNTIME_DIR}/lua/vim/filetype/*.lua ${NVIM_RUNTIME_DIR}/lua/vim/lsp/*.lua ${NVIM_RUNTIME_DIR}/lua/vim/treesitter/*.lua ) add_custom_command( OUTPUT ${VIMDOC_FILES} COMMAND ${PROJECT_SOURCE_DIR}/scripts/gen_vimdoc.py DEPENDS nvim ${API_SOURCES} ${LUA_SOURCES} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) set(GEN_EVAL_FILES ${NVIM_RUNTIME_DIR}/lua/vim/_meta/vimfn.lua ${NVIM_RUNTIME_DIR}/lua/vim/_meta/api.lua ${NVIM_RUNTIME_DIR}/lua/vim/_meta/api_keysets.lua ${NVIM_RUNTIME_DIR}/doc/builtin.txt ${NVIM_RUNTIME_DIR}/lua/vim/_meta/options.lua ${NVIM_RUNTIME_DIR}/doc/options.txt ) add_custom_command( OUTPUT ${GEN_EVAL_FILES} COMMAND $ -l ${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua DEPENDS ${API_METADATA} ${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua ${PROJECT_SOURCE_DIR}/src/nvim/eval.lua ${PROJECT_SOURCE_DIR}/src/nvim/options.lua ${NVIM_RUNTIME_DIR}/doc/api.mpack WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) add_custom_target(doc-eval DEPENDS ${GEN_EVAL_FILES}) add_custom_target(doc-vim DEPENDS ${VIMDOC_FILES}) add_custom_target(doc) add_dependencies(doc doc-vim doc-eval)