fish-shell/CMakeLists.txt

252 lines
8.7 KiB
CMake
Raw Normal View History

cmake_minimum_required(VERSION 3.5)
if(POLICY CMP0066)
cmake_policy(SET CMP0066 OLD)
endif()
if(POLICY CMP0067)
cmake_policy(SET CMP0067 NEW)
endif()
include(cmake/Mac.cmake)
project(fish)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# We are C++11.
set(CMAKE_CXX_STANDARD 11)
set(DEFAULT_BUILD_TYPE "RelWithDebInfo")
# Generate Xcode schemas (but not for tests).
set(CMAKE_XCODE_GENERATE_SCHEME 1)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to default '${DEFAULT_BUILD_TYPE}'")
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}")
endif()
2023-01-15 06:56:24 +08:00
include(cmake/Rust.cmake)
# Error out when linking statically, it doesn't work.
if (CMAKE_EXE_LINKER_FLAGS MATCHES ".*-static.*")
message(FATAL_ERROR "Fish does not support static linking")
endif()
# Force colored warnings in Ninja's output, if the compiler has -fdiagnostics-color support.
# Rationale in https://github.com/ninja-build/ninja/issues/814
if (CMAKE_GENERATOR STREQUAL "Ninja" AND
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)))
add_compile_options(-fdiagnostics-color=always)
endif()
# Enable a whole bunch of warnings, but turn off:
# - comment because we use a bunch of those, and they're not really all that harmful.
# - address, because that occurs for our mkostemp check (weak-linking requires us to compare `&mkostemp == nullptr`).
add_compile_options(-Wall -Wextra -Wno-comment -Wno-address)
2021-10-01 20:09:04 +08:00
2023-01-15 06:56:24 +08:00
# Get extra C++ files from Rust.
get_property(FISH_EXTRA_SOURCES TARGET fish-rust PROPERTY fish_extra_cpp_files)
2021-10-01 20:09:04 +08:00
if ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
add_compile_options(-Wunused-template -Wunused-local-typedef -Wunused-macros)
2021-10-01 20:09:04 +08:00
endif()
# Disable exception handling.
add_compile_options(-fno-exceptions)
# Undefine NDEBUG to keep assert() in release builds.
add_definitions(-UNDEBUG)
2023-01-15 06:56:24 +08:00
# Allow including Rust headers in normal (not bindgen) builds.
add_definitions(-DINCLUDE_RUST_HEADERS)
# Enable large files on GNU.
add_definitions(-D_LARGEFILE_SOURCE
-D_LARGEFILE64_SOURCE
-D_FILE_OFFSET_BITS=64
-D_ATFILE_SOURCE)
# Hide the CMake Rules directories in Xcode projects.
source_group("CMake Rules" REGULAR_EXPRESSION "^$")
# Put source and header files at top level under targets.
source_group("Source Files" REGULAR_EXPRESSION ".*\\.cpp")
source_group("Header Files" REGULAR_EXPRESSION ".*\\.h")
source_group("Builtins" "builtins/")
# Support folders.
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Work around issue where archive-built libs go in the wrong place.
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
set(FISH_IN_TREE_BUILD TRUE)
else()
set(FISH_IN_TREE_BUILD FALSE)
endif()
# NetBSD does weird things with finding libraries,
# making the tests fail by failing to find pcre.
#
# Keep the rpath used to build.
if(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif()
# List of sources for builtin functions.
set(FISH_BUILTIN_SRCS
2023-06-17 05:38:08 +08:00
src/builtin.cpp src/builtins/bind.cpp
src/builtins/commandline.cpp src/builtins/complete.cpp
2023-02-11 01:19:22 +08:00
src/builtins/disown.cpp
2023-02-19 00:13:58 +08:00
src/builtins/eval.cpp src/builtins/fg.cpp
src/builtins/functions.cpp src/builtins/history.cpp
src/builtins/jobs.cpp src/builtins/path.cpp
2023-03-06 10:38:41 +08:00
src/builtins/read.cpp src/builtins/set.cpp
2023-06-28 01:59:30 +08:00
src/builtins/source.cpp
src/builtins/ulimit.cpp
)
# List of other sources.
set(FISH_SRCS
src/ast.cpp src/autoload.cpp src/color.cpp src/common.cpp src/complete.cpp
src/env.cpp src/env_universal_common.cpp src/event.cpp
Port AST to Rust The translation is fairly direct though it adds some duplication, for example there are multiple "match" statements that mimic function overloading. Rust has no overloading, and we cannot have generic methods in the Node trait (due to a Rust limitation, the error is like "cannot be made into an object") so we include the type name in method names. Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor") that takes care of the AST traversal while the AST consumption remains in C++ for now. In future, "IndentVisitor" should absorb the entirety of "indent_visitor_t". This pattern requires that "fish_indent" be exposed includable header to the CXX bridge. Alternatively, we could define FFI wrappers for recursive AST traversal. Rust requires we separate the AST visitors for "mut" and "const" scenarios. Take this opportunity to concretize both visitors: The only client that requires mutable access is the populator. To match the structure of the C++ populator which makes heavy use of function overloading, we need to add a bunch of functions to the trait. Since there is no other mutable visit, this seems acceptable. The "const" visitors never use "will_visit_fields_of()" or "did_visit_fields_of()", so remove them (though this is debatable). Like in the C++ implementation, the AST nodes themselves are largely defined via macros. Union fields like "Statement" and "ArgumentOrRedirection" do currently not use macros but may in future. This commit also introduces a precedent for a type that is defined in one CXX bridge and used in another one - "ParseErrorList". To make this work we need to manually define "ExternType". There is one annoyance with CXX: functions that take explicit lifetime parameters require to be marked as unsafe. This makes little sense because functions that return `&Foo` with implicit lifetime can be misused the same way on the C++ side. One notable change is that we cannot directly port "find_block_open_keyword()" (which is used to compute an error) because it relies on the stack of visited nodes. We cannot modify a stack of node references while we do the "mut" walk. Happily, an idiomatic solution is easy: we can tell the AST visitor to backtrack to the parent node and create the error there. Since "node_t::accept_base" is no longer a template we don't need the "node_visitation_t" trampoline anymore. The added copying at the FFI boundary makes things slower (memcpy dominates the profile) but it's not unusable, which is good news: $ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'" Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish' Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms] Range (min … max): 193.2 ms … 205.1 ms 15 runs Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish' Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms] Range (min … max): 611.7 ms … 805.5 ms 10 runs Summary './fish.old -c 'source ../share/completions/git.fish'' ran 3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish'' Leftovers: - Enum variants are still snakecase; I didn't get around to changing this yet. - "ast_type_to_string()" still returns a snakecase name. This could be changed since it's not user visible.
2023-04-02 22:42:59 +08:00
src/exec.cpp src/expand.cpp src/fallback.cpp src/fish_indent_common.cpp src/fish_version.cpp
src/flog.cpp src/function.cpp src/highlight.cpp
2020-07-20 07:07:01 +08:00
src/history.cpp src/history_file.cpp src/input.cpp src/input_common.cpp
src/io.cpp src/kill.cpp
2020-07-20 07:07:01 +08:00
src/null_terminated_array.cpp src/operation_context.cpp src/output.cpp
Port AST to Rust The translation is fairly direct though it adds some duplication, for example there are multiple "match" statements that mimic function overloading. Rust has no overloading, and we cannot have generic methods in the Node trait (due to a Rust limitation, the error is like "cannot be made into an object") so we include the type name in method names. Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor") that takes care of the AST traversal while the AST consumption remains in C++ for now. In future, "IndentVisitor" should absorb the entirety of "indent_visitor_t". This pattern requires that "fish_indent" be exposed includable header to the CXX bridge. Alternatively, we could define FFI wrappers for recursive AST traversal. Rust requires we separate the AST visitors for "mut" and "const" scenarios. Take this opportunity to concretize both visitors: The only client that requires mutable access is the populator. To match the structure of the C++ populator which makes heavy use of function overloading, we need to add a bunch of functions to the trait. Since there is no other mutable visit, this seems acceptable. The "const" visitors never use "will_visit_fields_of()" or "did_visit_fields_of()", so remove them (though this is debatable). Like in the C++ implementation, the AST nodes themselves are largely defined via macros. Union fields like "Statement" and "ArgumentOrRedirection" do currently not use macros but may in future. This commit also introduces a precedent for a type that is defined in one CXX bridge and used in another one - "ParseErrorList". To make this work we need to manually define "ExternType". There is one annoyance with CXX: functions that take explicit lifetime parameters require to be marked as unsafe. This makes little sense because functions that return `&Foo` with implicit lifetime can be misused the same way on the C++ side. One notable change is that we cannot directly port "find_block_open_keyword()" (which is used to compute an error) because it relies on the stack of visited nodes. We cannot modify a stack of node references while we do the "mut" walk. Happily, an idiomatic solution is easy: we can tell the AST visitor to backtrack to the parent node and create the error there. Since "node_t::accept_base" is no longer a template we don't need the "node_visitation_t" trampoline anymore. The added copying at the FFI boundary makes things slower (memcpy dominates the profile) but it's not unusable, which is good news: $ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'" Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish' Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms] Range (min … max): 193.2 ms … 205.1 ms 15 runs Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish' Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms] Range (min … max): 611.7 ms … 805.5 ms 10 runs Summary './fish.old -c 'source ../share/completions/git.fish'' ran 3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish'' Leftovers: - Enum variants are still snakecase; I didn't get around to changing this yet. - "ast_type_to_string()" still returns a snakecase name. This could be changed since it's not user visible.
2023-04-02 22:42:59 +08:00
src/pager.cpp src/parse_execution.cpp src/parse_util.cpp
2020-07-20 07:07:01 +08:00
src/parser.cpp src/parser_keywords.cpp src/path.cpp src/postfork.cpp
src/proc.cpp src/reader.cpp src/screen.cpp
src/signals.cpp src/utf8.cpp
src/wcstringutil.cpp src/wgetopt.cpp src/wildcard.cpp
2023-01-15 06:56:24 +08:00
src/wutil.cpp src/fds.cpp src/rustffi.cpp
)
# Header files are just globbed.
file(GLOB FISH_HEADERS src/*.h)
# Set up config.h
include(cmake/ConfigureChecks.cmake)
include(cmake/gettext.cmake)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config_cmake.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
2023-01-15 06:56:24 +08:00
# Pull in our src directory for headers searches, but only quoted ones.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -iquote ${CMAKE_CURRENT_SOURCE_DIR}/src")
# Set up standard directories.
include(GNUInstallDirs)
add_definitions(-D_UNICODE=1
-DLOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}"
-DPREFIX=L"${CMAKE_INSTALL_PREFIX}"
-DDATADIR=L"${CMAKE_INSTALL_FULL_DATADIR}"
-DSYSCONFDIR=L"${CMAKE_INSTALL_FULL_SYSCONFDIR}"
-DBINDIR=L"${CMAKE_INSTALL_FULL_BINDIR}"
-DDOCDIR=L"${CMAKE_INSTALL_FULL_DOCDIR}")
# Set up the machinery around FISH-BUILD-VERSION-FILE
# This defines the FBVF variable.
include(Version)
# Let fish pick up when we're running out of the build directory without installing
get_filename_component(REAL_CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}" REALPATH)
get_filename_component(REAL_CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}" REALPATH)
add_definitions(-DCMAKE_BINARY_DIR="${REAL_CMAKE_BINARY_DIR}")
add_definitions(-DCMAKE_SOURCE_DIR="${REAL_CMAKE_SOURCE_DIR}")
# Teach fish_version.o to rebuild when FBVF changes.
# The standard C++ include detection machinery misses this.
set_source_files_properties(src/fish_version.cpp
PROPERTIES OBJECT_DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/${FBVF})
# Enable thread-safe errno on Solaris (#5611)
add_definitions(-D_REENTRANT)
# Set up PCRE2
include(cmake/PCRE2.cmake)
# Define a function to link dependencies.
function(FISH_LINK_DEPS_AND_SIGN target)
target_link_libraries(${target} fishlib)
codesign_on_mac(${target})
endfunction(FISH_LINK_DEPS_AND_SIGN)
# Define libfish.a.
add_library(fishlib STATIC ${FISH_SRCS} ${FISH_BUILTIN_SRCS})
target_sources(fishlib PRIVATE ${FISH_HEADERS})
target_link_libraries(fishlib
2023-01-15 06:56:24 +08:00
fish-rust
${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY} Threads::Threads ${CMAKE_DL_LIBS}
2023-01-15 06:56:24 +08:00
${PCRE2_LIB} ${Intl_LIBRARIES} ${ATOMIC_LIBRARY}
"fish-rust")
target_include_directories(fishlib PRIVATE
${CURSES_INCLUDE_DIRS})
# Define fish.
add_executable(fish src/fish.cpp)
fish_link_deps_and_sign(fish)
# Define fish_indent.
add_executable(fish_indent
2023-05-29 09:05:10 +08:00
src/fish_indent.cpp)
fish_link_deps_and_sign(fish_indent)
# Define fish_key_reader.
add_executable(fish_key_reader
2023-05-29 09:05:10 +08:00
src/fish_key_reader.cpp)
fish_link_deps_and_sign(fish_key_reader)
# Set up the docs.
include(cmake/Docs.cmake)
# A helper for running tests.
add_executable(fish_test_helper src/fish_test_helper.cpp)
# Set up tests.
include(cmake/Tests.cmake)
# Benchmarking support.
include(cmake/Benchmark.cmake)
# Set up install.
include(cmake/Install.cmake)
2017-11-13 22:21:54 +08:00
2019-01-26 10:43:52 +08:00
# Mac app.
include(cmake/MacApp.cmake)
2019-01-26 10:43:52 +08:00
# ThreadSanitizer likes to muck with signal handlers, which interferes
# with fish_test_helper printing the ignored signal mask.
# Ensure fish_test_helper does not use TSan.
# Note the environment var is CXXFLAGS, but the CMake var is CMAKE_CXX_FLAGS.
if (CMAKE_CXX_FLAGS MATCHES ".*-fsanitize=thread.*")
target_compile_options(fish_test_helper PRIVATE "-fno-sanitize=all")
target_link_libraries(fish_test_helper "-fno-sanitize=all")
endif()
2019-02-19 21:12:04 +08:00
# Lint targets
# This could be implemented as target properties, but the script has the useful feature of only
# checking the currently-staged commands
# The generator expressions below rebuild the command line for the fishlib targets
# CMake does not support the "iquote" flag - https://gitlab.kitware.com/cmake/cmake/issues/15491
set(LINT_ARGS "-D$<JOIN:$<TARGET_PROPERTY:fishlib,COMPILE_DEFINITIONS>, -D>" "-I$<JOIN:$<TARGET_PROPERTY:fishlib,INCLUDE_DIRECTORIES>, -I>")
add_custom_target(lint
COMMAND build_tools/lint.fish -p ${CMAKE_BINARY_DIR} -- ${LINT_ARGS}
2019-02-19 21:12:04 +08:00
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
add_custom_target(lint-all
COMMAND build_tools/lint.fish --all -p ${CMAKE_BINARY_DIR} -- ${LINT_ARGS}
2019-02-19 21:12:04 +08:00
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
include(FeatureSummary)
feature_summary(WHAT ALL)