From 7b4802091a3bd1500663dd148084ed0ae6f41744 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Mon, 17 Nov 2025 10:50:41 +0100 Subject: [PATCH] cmake: install fish_{indent,key_reader} as hardlinks to fish As mentioned in https://github.com/fish-shell/fish-shell/issues/11921#issuecomment-3540587001, binaries duplicate a lot of information unnecessarily. $ cargo b --release $ du -h target/release/fish{,_indent,_key_reader} 15M target/release/fish 15M target/release/fish_indent 4.1M target/release/fish_key_reader 34M total Remove the duplication in CMake-installed builds by creating hard links. I'm not sure how to do that for Cargo binaries yet (can we write a portable wrapper script)? This is still a bit weird because hardlinks are rarely used like this; but symlinks may cause issues on MSYS2. Maybe we should write a /bin/sh wrapper script instead. --- CHANGELOG.rst | 1 + CMakeLists.txt | 51 ++++++++++++++++++++++++--------------------- cmake/Install.cmake | 12 ++++++++--- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 506dc31e7..57438cc1b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,7 @@ Interactive improvements For distributors and developers ------------------------------- +- ``fish_key_reader`` and ``fish_indent`` are now hardlinks to ``fish``. fish 4.2.1 (released November 13, 2025) ======================================= diff --git a/CMakeLists.txt b/CMakeLists.txt index 764ed19a3..4f1780ed8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,37 +58,40 @@ if(NOT "${CMAKE_BUILD_TYPE}" IN_LIST build_types) message(WARNING "Unsupported build type ${CMAKE_BUILD_TYPE}. If this doesn't build, try one of Release, RelWithDebInfo or Debug") endif() -# Define a function to build and link dependencies. -function(CREATE_TARGET target) +add_custom_target( + fish ALL + COMMAND + "${CMAKE_COMMAND}" -E + env ${VARS_FOR_CARGO} + ${Rust_CARGO} + build --bin fish + $<$:--release> + $<$:--profile=release-with-debug> + --target ${Rust_CARGO_TARGET} + --no-default-features + --features=${FISH_CARGO_FEATURES} + ${CARGO_FLAGS} + && + "${CMAKE_COMMAND}" -E + copy "${rust_target_dir}/${rust_profile}/fish" "${CMAKE_CURRENT_BINARY_DIR}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + USES_TERMINAL +) + +function(CREATE_LINK target) add_custom_target( ${target} ALL - COMMAND - "${CMAKE_COMMAND}" -E - env ${VARS_FOR_CARGO} - ${Rust_CARGO} - build --bin ${target} - $<$:--release> - $<$:--profile=release-with-debug> - --target ${Rust_CARGO_TARGET} - --no-default-features - --features=${FISH_CARGO_FEATURES} - ${CARGO_FLAGS} - && - "${CMAKE_COMMAND}" -E - copy "${rust_target_dir}/${rust_profile}/${target}" "${CMAKE_CURRENT_BINARY_DIR}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - USES_TERMINAL + DEPENDS fish + COMMAND ln -f fish ${target} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) -endfunction(CREATE_TARGET) - -# Define fish. -create_target(fish) +endfunction(CREATE_LINK) # Define fish_indent. -create_target(fish_indent) +create_link(fish_indent) # Define fish_key_reader. -create_target(fish_key_reader) +create_link(fish_key_reader) # Set up tests. include(cmake/Tests.cmake) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index bb5543a61..8e9f96ccf 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -1,7 +1,5 @@ set(CMAKE_INSTALL_MESSAGE NEVER) -set(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fish ${CMAKE_CURRENT_BINARY_DIR}/fish_indent ${CMAKE_CURRENT_BINARY_DIR}/fish_key_reader) - set(prefix ${CMAKE_INSTALL_PREFIX}) set(bindir ${CMAKE_INSTALL_BINDIR}) set(sysconfdir ${CMAKE_INSTALL_SYSCONFDIR}) @@ -75,11 +73,19 @@ function(FISH_TRY_CREATE_DIRS) endforeach() endfunction(FISH_TRY_CREATE_DIRS) -install(PROGRAMS ${PROGRAMS} +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fish PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${bindir}) +if(NOT IS_ABSOLUTE ${bindir}) + set(abs_bindir "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${bindir}") +else() + set(abs_bindir "\$ENV{DESTDIR}${bindir}") +endif() +install(CODE "file(CREATE_LINK ${abs_bindir}/fish ${abs_bindir}/fish_indent)") +install(CODE "file(CREATE_LINK ${abs_bindir}/fish ${abs_bindir}/fish_key_reader)") + fish_create_dirs(${sysconfdir}/fish/conf.d ${sysconfdir}/fish/completions ${sysconfdir}/fish/functions) install(FILES etc/config.fish DESTINATION ${sysconfdir}/fish/)