From e004c97ee02ca4ae8937677b628216b567d4e4a3 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 17 Sep 2026 13:50:07 +0800 Subject: [PATCH] CMake: adds option `-DENABLE_IMAGE_LOGO=` --- .github/workflows/build-no-features-test.yml | 2 +- CHANGELOG.md | 12 +++- CMakeLists.txt | 41 ++++++++++--- src/detection/gpu/gpu_apple.m | 4 +- src/logo/logo.c | 26 ++++++-- src/logo/logo.h | 2 + src/options/logo.c | 64 +++++++++++++++++--- 7 files changed, 118 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build-no-features-test.yml b/.github/workflows/build-no-features-test.yml index fadefe8b9..28e2c483c 100644 --- a/.github/workflows/build-no-features-test.yml +++ b/.github/workflows/build-no-features-test.yml @@ -21,7 +21,7 @@ jobs: run: uname -a - name: configure project - run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_EET=OFF -DENABLE_THREADS=OFF + run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_EET=OFF -DENABLE_THREADS=OFF -DENABLE_IMAGE_LOGO=OFF - name: build project run: cmake --build . --target package --verbose -j4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3416a5a86..272cf2210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Unreleased Changes: -* ImageMagick is no longer used for image logos on Windows and macOS, and has been replaced by the platform image frameworks (WIC on Windows, ImageIO on macOS). (Logo, Windows / macOS) - * Image logos on Windows and macOS no longer depend on ImageMagick being installed. - * Image sources that only ImageMagick could decode, such as SVG, PDF and PostScript, are no longer supported on Windows: neither WIC nor the embedded sixel encoder can decode them. +* ImageMagick is no longer used for image logos on Windows and macOS, and has been replaced by the platform image frameworks (WIC on Windows, ImageIO on macOS). (Logo) +* ImageMagick 6 support is deprecated. It's only kept for old Debian & Ubuntu releases which have no ImageMagick 7 available. + * Intended to be removed in a future release. Users are encouraged to upgrade to ImageMagick 7 when possible. + * The `--logo-recache` option has been replaced by `--logo-cache `, and the `logo.recache` JSON property has been renamed to `logo.cache`. (Logo) * `--logo-cache true` (the default) reuses a cached rendering when it is valid, and writes it back on a cache miss. * `--logo-cache false` ignores the image logo cache completely: nothing is read from it and nothing is written to it. @@ -29,6 +30,11 @@ Features: * The default is `1`, which renders a still image, so nothing changes for anyone who does not opt in. * The frames come from the platform image framework (WIC on Windows, ImageIO on macOS, ImageMagick 7 on Linux). A single frame GIF falls back to a still image. A build with none of those, or with ImageMagick 6, reports an error instead of quietly showing a still image. * A terminal that supports the kitty graphics protocol but not its animation frames, as Konsole does not, shows the first frame. + * Added the CMake option `ENABLE_IMAGE_LOGO`, which defaults to `ON`. Configure with `-DENABLE_IMAGE_LOGO=OFF` to build fastfetch without any image logo support. (Logo) + * Image logos are the only consumer of ImageMagick, of chafa and of the embedded libsixel encoder, so none of the three is looked for at configure time, and no image decoding source is compiled in. + * The `sixel`, `kitty`, `kitty-direct`, `kitty-icat`, `iterm` and `chafa` logo types are rejected with an error, on the command line and in the JSON config alike, and the `auto` logo type never tries an image. + * `--logo-type raw` keeps working: it writes a pre-rendered byte stream through unchanged and needs no decoder, so a logo can still be displayed by converting the image externally. + * This is intended to be used to reduce binary size on embedded systems (such as OpenWrt) only. * Added CPU name and frequency detection support on SPARC. (CPU, Linux) * Added package detection support for CRUX. (Packages, Linux) * Exposed in custom format as `{crux}`. diff --git a/CMakeLists.txt b/CMakeLists.txt index 54fa295c5..88a7ef784 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,10 +88,6 @@ cmake_dependent_option(ENABLE_EET "Enable eet" ON "LINUX OR FreeBSD OR OpenBSD O cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR Haiku OR GNU" OFF) cmake_dependent_option(ENABLE_SQLITE3 "Enable sqlite3" ON "LINUX OR FreeBSD OR APPLE OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_RPM "Enable rpm" ON "LINUX OR GNU" OFF) -cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR Haiku OR GNU" OFF) -cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) -cmake_dependent_option(ENABLE_SIXEL "Enable sixel logo output via the embedded libsixel encoder (Windows and macOS; replaces ImageMagick's SIXEL coder)" ON "WIN32 OR APPLE" OFF) -cmake_dependent_option(ENABLE_CHAFA "Enable chafa" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7 OR WIN32 OR APPLE" OFF) cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF) cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF) @@ -101,6 +97,14 @@ cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF) cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF) cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF) +option(ENABLE_IMAGE_LOGO "Enable image logos (sixel / kitty / iTerm / chafa)" ON) +if(ENABLE_IMAGE_LOGO) + cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR Haiku OR GNU" OFF) + cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) + cmake_dependent_option(ENABLE_SIXEL "Enable sixel logo output via the embedded libsixel encoder (Windows and macOS; replaces ImageMagick's SIXEL coder)" ON "WIN32 OR APPLE" OFF) + cmake_dependent_option(ENABLE_CHAFA "Enable chafa" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7 OR WIN32 OR APPLE" OFF) +endif() + option(ENABLE_ZLIB "Enable zlib" ON) option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF) option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF) @@ -501,10 +505,6 @@ set(LIBFASTFETCH_SRC src/detection/weather/weather.c src/detection/zpool/zpool.c src/logo/builtin.c - src/logo/image/im6.c - src/logo/image/im7.c - src/logo/image/image.c - src/logo/image/sixel.c src/logo/logo.c src/modules/modules.c src/options/display.c @@ -512,6 +512,15 @@ set(LIBFASTFETCH_SRC src/options/general.c ) +if(ENABLE_IMAGE_LOGO) + list(APPEND LIBFASTFETCH_SRC + src/logo/image/image.c + src/logo/image/im6.c + src/logo/image/im7.c + src/logo/image/sixel.c + ) +endif() + foreach(FF_MODULE_DIR ${FF_MODULE_DIRS}) list(APPEND LIBFASTFETCH_SRC src/modules/${FF_MODULE_DIR}/${FF_MODULE_DIR}.c @@ -1023,8 +1032,12 @@ elseif(APPLE) src/detection/de/de_nosupport.c src/detection/wmtheme/wmtheme_apple.c src/detection/camera/camera_apple.m - src/logo/image/imageio.c ) + if(ENABLE_IMAGE_LOGO) + list(APPEND LIBFASTFETCH_SRC + src/logo/image/imageio.c + ) + endif() # CMAKE_SYSTEM_PROCESSOR has been normalized before if(CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") list(APPEND LIBFASTFETCH_SRC @@ -1117,8 +1130,12 @@ elseif(WIN32) src/detection/de/de_nosupport.c src/detection/wmtheme/wmtheme_windows.c src/detection/camera/camera_windows.cpp - src/logo/image/wic.cpp ) + if(ENABLE_IMAGE_LOGO) + list(APPEND LIBFASTFETCH_SRC + src/logo/image/wic.cpp + ) + endif() elseif(SunOS) list(APPEND LIBFASTFETCH_SRC src/common/impl/dbus.c @@ -1846,6 +1863,10 @@ if(ENABLE_THREADS) endif() endif() +if(ENABLE_IMAGE_LOGO) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_IMAGE_LOGO=1) +endif() + if(ENABLE_EMBEDDED_PCIIDS) target_compile_definitions(libfastfetch PUBLIC FF_HAVE_EMBEDDED_PCIIDS=1) endif() diff --git a/src/detection/gpu/gpu_apple.m b/src/detection/gpu/gpu_apple.m index 9596dbe76..d00410c8a 100644 --- a/src/detection/gpu/gpu_apple.m +++ b/src/detection/gpu/gpu_apple.m @@ -46,6 +46,7 @@ const char* ffGpuDetectMetal(FFlist* gpus) { continue; } +#pragma clang diagnostic ignored "-Wdeprecated-declarations" #ifndef MAC_OS_X_VERSION_10_15 if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily2_v1]) { ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 2"); @@ -53,14 +54,11 @@ const char* ffGpuDetectMetal(FFlist* gpus) { ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 1"); } #else // MAC_OS_X_VERSION_10_15 - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wunguarded-availability-new" if ([device supportsFamily:MTLGPUFamilyMetal4]) { ffStrbufSetStatic(&gpu->platformApi, "Metal 4"); } else if ([device supportsFamily:MTLGPUFamilyMetal3]) { ffStrbufSetStatic(&gpu->platformApi, "Metal 3"); } - #pragma clang diagnostic pop else if ([device supportsFamily:MTLGPUFamilyCommon3]) { ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3"); } else if ([device supportsFamily:MTLGPUFamilyCommon2]) { diff --git a/src/logo/logo.c b/src/logo/logo.c index 12af2251a..e0ba24cd2 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -518,6 +518,7 @@ static bool logoPrintFileIfExists(bool doColorReplacement, bool raw) { return true; } +#if FF_HAVE_IMAGE_LOGO static bool logoPrintImageIfExists(FFLogoType logo, bool printError) { if (!ffLogoPrintImageIfExists(logo, printError)) { return false; @@ -526,6 +527,7 @@ static bool logoPrintImageIfExists(FFLogoType logo, bool printError) { logoApplyColors(logoGetBuiltinDetected(FF_LOGO_SIZE_NORMAL), false); return true; } +#endif static bool logoTryKnownType(void) { FFOptionsLogo* options = &instance.config.logo; @@ -593,7 +595,16 @@ static bool logoTryKnownType(void) { return logoPrintFileIfExists(false, true); } +#if FF_HAVE_IMAGE_LOGO return logoPrintImageIfExists(options->type, instance.config.display.showErrors); +#else + // No image logo type can be selected in this build (see ffOptionsParseLogoCommandLine), and + // FF_LOGO_TYPE_IMAGE_RAW was handled above, so nothing printable is left for this source. + if (instance.config.display.showErrors) { + fprintf(stderr, "Logo: Unsupported logo type for source: %s\n", options->source.chars); + } + return false; +#endif } void ffLogoPrint(void) { @@ -638,8 +649,10 @@ void ffLogoPrint(void) { } } +#if FF_HAVE_IMAGE_LOGO + // Try to load the logo as an image. if (!ffStrbufEndsWithIgnCaseS(&options->source, ".txt")) { -#if !FF_MODULE_DISABLE_TERMINAL + #if !FF_MODULE_DISABLE_TERMINAL const FFTerminalResult* terminal = ffDetectTerminal(); bool supportsIterm2 = ffStrbufEqualS(&terminal->prettyName, "iTerm"); @@ -655,21 +668,22 @@ void ffLogoPrint(void) { ffStrbufIgnCaseEqualS(&terminal->processName, "wezterm") || ffStrbufIgnCaseEqualS(&terminal->processName, "wayst") || ffStrbufIgnCaseEqualS(&terminal->processName, "ghostty") || - #ifdef __APPLE__ + #ifdef __APPLE__ ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal") || - #else + #else ffStrbufIgnCaseEqualS(&terminal->processName, "warp") || - #endif + #endif false; -#else + #else bool supportsKitty = false; -#endif + #endif // Try to load the logo as an image. If it succeeds, print it and return. if (logoPrintImageIfExists(supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA, false)) { return; } } +#endif // Try to load the logo as a file. If it succeeds, print it and return. if (logoPrintFileIfExists(true, false)) { diff --git a/src/logo/logo.h b/src/logo/logo.h index 324b590ca..a1cf36ec9 100644 --- a/src/logo/logo.h +++ b/src/logo/logo.h @@ -39,5 +39,7 @@ const FFlogo* ffLogoGetBuiltinDetected(FFLogoSize size); extern const FFlogo* ffLogoBuiltins[]; extern const FFlogo ffLogoUnknown; +#if FF_HAVE_IMAGE_LOGO // image/image.c bool ffLogoPrintImageIfExists(FFLogoType type, bool printError); +#endif diff --git a/src/options/logo.c b/src/options/logo.c index dc64cc607..f4045569c 100644 --- a/src/options/logo.c +++ b/src/options/logo.c @@ -3,6 +3,42 @@ #include "common/jsonconfig.h" #include "common/strutil.h" +#if !FF_HAVE_IMAGE_LOGO +// The image logo types are still accepted by the parsers below in a build that can not render them, +// so that the user is told which type is unavailable instead of being told the type does not exist. +// The one that is deliberately left out is `raw`: it writes a pre-rendered byte stream through +// untouched and needs no decoder, so a build without image logos can still display one. +static bool logoTypeIsImage(FFLogoType type) { + switch (type) { + case FF_LOGO_TYPE_IMAGE_SIXEL: + case FF_LOGO_TYPE_IMAGE_KITTY: + case FF_LOGO_TYPE_IMAGE_KITTY_DIRECT: + case FF_LOGO_TYPE_IMAGE_KITTY_ICAT: + case FF_LOGO_TYPE_IMAGE_ITERM: + case FF_LOGO_TYPE_IMAGE_CHAFA: + return true; + default: + return false; + } +} +#endif + +// --sixel, --kitty, --kitty-direct, --kitty-icat and --iterm. They keep a branch of their own in +// every build so that the error a build without image logos gives names the flag that was used, +// rather than it being rejected as an unknown option. --chafa is not among them: it is gated on +// FF_HAVE_CHAFA, which a build without image logos turns off as well, and it keeps the message it +// has always given in that case. +static void logoParseImageFlag(FFOptionsLogo* options, const char* key, const char* value, FFLogoType type) { +#if FF_HAVE_IMAGE_LOGO + ffOptionParseString(key, value, &options->source); + options->type = type; +#else + FF_UNUSED(options, key, value, type); + fputs("Error: Fastfetch was built without image logo support\n", stderr); + exit(477); +#endif +} + void ffOptionsInitLogo(FFOptionsLogo* options) { ffStrbufInit(&options->source); options->type = FF_LOGO_TYPE_AUTO; @@ -71,6 +107,12 @@ bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, cons { "none", FF_LOGO_TYPE_NONE }, {}, }); +#if !FF_HAVE_IMAGE_LOGO + if (logoTypeIsImage(options->type)) { + fputs("Error: Fastfetch was built without image logo support\n", stderr); + exit(477); + } +#endif } else if (ffStrStartsWithIgnCase(subKey, "color-") && subKey[6] != '\0' && subKey[7] == '\0') // matches "--logo-color-*" { // Map the number to an array index, so that '1' -> 0, '2' -> 1, etc. @@ -151,20 +193,15 @@ bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, cons return false; } } else if (ffStrEqualsIgnCase(key, "--sixel")) { - ffOptionParseString(key, value, &options->source); - options->type = FF_LOGO_TYPE_IMAGE_SIXEL; + logoParseImageFlag(options, key, value, FF_LOGO_TYPE_IMAGE_SIXEL); } else if (ffStrEqualsIgnCase(key, "--kitty")) { - ffOptionParseString(key, value, &options->source); - options->type = FF_LOGO_TYPE_IMAGE_KITTY; + logoParseImageFlag(options, key, value, FF_LOGO_TYPE_IMAGE_KITTY); } else if (ffStrEqualsIgnCase(key, "--kitty-direct")) { - ffOptionParseString(key, value, &options->source); - options->type = FF_LOGO_TYPE_IMAGE_KITTY_DIRECT; + logoParseImageFlag(options, key, value, FF_LOGO_TYPE_IMAGE_KITTY_DIRECT); } else if (ffStrEqualsIgnCase(key, "--kitty-icat")) { - ffOptionParseString(key, value, &options->source); - options->type = FF_LOGO_TYPE_IMAGE_KITTY_ICAT; + logoParseImageFlag(options, key, value, FF_LOGO_TYPE_IMAGE_KITTY_ICAT); } else if (ffStrEqualsIgnCase(key, "--iterm")) { - ffOptionParseString(key, value, &options->source); - options->type = FF_LOGO_TYPE_IMAGE_ITERM; + logoParseImageFlag(options, key, value, FF_LOGO_TYPE_IMAGE_ITERM); } else if (ffStrEqualsIgnCase(key, "--raw")) { ffOptionParseString(key, value, &options->source); options->type = FF_LOGO_TYPE_IMAGE_RAW; @@ -278,6 +315,11 @@ const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* roo if (error) { return error; } +#if !FF_HAVE_IMAGE_LOGO + if (logoTypeIsImage((FFLogoType) value)) { + return "Image logo types are not supported because Fastfetch was built without image logo support"; + } +#endif options->type = (FFLogoType) value; continue; } else if (unsafe_yyjson_equals_str(key, "source")) { @@ -482,6 +524,7 @@ void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options) { case FF_LOGO_TYPE_COMMAND_RAW: yyjson_mut_obj_add_str(doc, obj, "type", "command-raw"); break; +#if FF_HAVE_IMAGE_LOGO case FF_LOGO_TYPE_IMAGE_SIXEL: yyjson_mut_obj_add_str(doc, obj, "type", "sixel"); break; @@ -500,6 +543,7 @@ void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options) { case FF_LOGO_TYPE_IMAGE_CHAFA: yyjson_mut_obj_add_str(doc, obj, "type", "chafa"); break; +#endif case FF_LOGO_TYPE_IMAGE_RAW: yyjson_mut_obj_add_str(doc, obj, "type", "raw"); break;