From 4ecc8d3fba69a06bedf77314cc3e21fda543ff46 Mon Sep 17 00:00:00 2001 From: Pedro Amaral Couto Date: Fri, 27 Mar 2026 01:06:45 +0000 Subject: [PATCH 1/2] Fix build error by replacing `stbi_write_png_to_mem` with `stbi_write_png_to_func` --- src/commands/spratunpack_command.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/commands/spratunpack_command.cpp b/src/commands/spratunpack_command.cpp index 32b17c6..8145ca0 100644 --- a/src/commands/spratunpack_command.cpp +++ b/src/commands/spratunpack_command.cpp @@ -621,13 +621,16 @@ class SpriteUnpacker { } // Encode as PNG in memory - int png_size = 0; - unsigned char* png_buffer_raw = stbi_write_png_to_mem(sprite_data.data(), out_w * NUM_CHANNELS, - out_w, out_h, NUM_CHANNELS, &png_size); - if (png_buffer_raw == nullptr) { + std::vector png_buffer; + auto write_to_vec = [](void* context, void* data, int size) { + auto* vec = static_cast*>(context); + const auto* bytes = static_cast(data); + vec->insert(vec->end(), bytes, bytes + size); + }; + + if (!stbi_write_png_to_func(write_to_vec, &png_buffer, out_w, out_h, NUM_CHANNELS, sprite_data.data(), out_w * NUM_CHANNELS)) { return false; } - std::unique_ptr png_buffer(png_buffer_raw, std::free); std::string filename = frame.name; if (filename.find('.') == std::string::npos) { @@ -640,7 +643,7 @@ class SpriteUnpacker { } archive_entry_set_pathname(entry, filename.c_str()); - archive_entry_set_size(entry, png_size); + archive_entry_set_size(entry, static_cast(png_buffer.size())); archive_entry_set_filetype(entry, AE_IFREG); constexpr int DEFAULT_FILE_PERMISSIONS = 0644; archive_entry_set_perm(entry, DEFAULT_FILE_PERMISSIONS); @@ -652,7 +655,7 @@ class SpriteUnpacker { return false; } - if (archive_write_data(a, png_buffer.get(), png_size) != static_cast(png_size)) { + if (archive_write_data(a, png_buffer.data(), png_buffer.size()) != static_cast(png_buffer.size())) { std::cerr << tr("Error: Failed to write archive data: ") << archive_error_string(a) << '\n'; archive_entry_free(entry); return false; From 0151c4c9de6f0457907742bd4a5fcfaca0c15ca2 Mon Sep 17 00:00:00 2001 From: Pedro Amaral Couto Date: Fri, 27 Mar 2026 01:14:01 +0000 Subject: [PATCH 2/2] Fix build errors on macOS and improve portability - Replace stbi_write_png_to_mem with stbi_write_png_to_func in spratunpack_command.cpp to avoid "undeclared identifier" errors in some stb_image_write.h versions. - Reorder CMakeLists.txt to detect dependencies (libarchive, gettext, zopflipng) before defining targets. This fixes "archive.h not found" errors on macOS where headers are in non-standard brew paths. - Remove redundant source file inclusion in executable targets by linking to spratcore library. --- CMakeLists.txt | 89 +++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1db924f..f8ff290 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,22 +118,6 @@ endfunction() ensure_stb_header(stb_image.h) ensure_stb_header(stb_image_write.h) -add_library(spratcore STATIC - src/core/cli_parse.cpp - src/core/layout_parser.cpp - src/core/output_pattern.cpp - src/core/i18n.cpp - src/core/stb_impl.cpp - src/commands/spratlayout_command.cpp - src/commands/spratpack_command.cpp - src/commands/spratconvert_command.cpp - src/commands/spratframes_command.cpp - src/commands/spratunpack_command.cpp -) -target_include_directories(spratcore PUBLIC src) -target_include_directories(spratcore SYSTEM PRIVATE ${STB_DIR}) -target_include_directories(spratcore PRIVATE ${LIBARCHIVE_INCLUDE_DIRS}) - option(SPRAT_ENABLE_NLS "Enable gettext-based translations when available" ON) option(SPRAT_REQUIRE_GETTEXT "Fail configure if gettext support is requested but unavailable" OFF) @@ -143,12 +127,11 @@ if(SPRAT_ENABLE_NLS) find_package(Intl QUIET) if(Intl_FOUND) set(SPRAT_GETTEXT_AVAILABLE TRUE) - target_compile_definitions(spratcore PUBLIC SPRAT_ENABLE_GETTEXT) if(TARGET Intl::Intl) - target_link_libraries(spratcore PUBLIC Intl::Intl) + set(SPRAT_INTL_LIBRARIES Intl::Intl) else() - target_link_libraries(spratcore PUBLIC ${Intl_LIBRARIES}) - target_include_directories(spratcore PUBLIC ${Intl_INCLUDE_DIRS}) + set(SPRAT_INTL_LIBRARIES ${Intl_LIBRARIES}) + set(SPRAT_INTL_INCLUDE_DIRS ${Intl_INCLUDE_DIRS}) endif() message(STATUS "gettext support enabled (via Intl)") else() @@ -158,13 +141,11 @@ if(SPRAT_ENABLE_NLS) # Some platforms provide libintl through gettext if(TARGET Gettext::Gettext) set(SPRAT_GETTEXT_AVAILABLE TRUE) - target_compile_definitions(spratcore PUBLIC SPRAT_ENABLE_GETTEXT) - target_link_libraries(spratcore PUBLIC Gettext::Gettext) + set(SPRAT_INTL_LIBRARIES Gettext::Gettext) message(STATUS "gettext support enabled (via Gettext target)") elseif(GETTEXT_LIBRARIES) set(SPRAT_GETTEXT_AVAILABLE TRUE) - target_compile_definitions(spratcore PUBLIC SPRAT_ENABLE_GETTEXT) - target_link_libraries(spratcore PUBLIC ${GETTEXT_LIBRARIES}) + set(SPRAT_INTL_LIBRARIES ${GETTEXT_LIBRARIES}) message(STATUS "gettext support enabled (via GETTEXT_LIBRARIES)") endif() endif() @@ -176,11 +157,8 @@ if(SPRAT_ENABLE_NLS) message(STATUS "gettext not found; translations will fallback to source strings") endif() endif() -target_compile_definitions(spratcore PUBLIC SPRAT_LOCALE_DIR="${CMAKE_INSTALL_FULL_LOCALEDIR}") -# Binaries -# For Windows cross-compilation, PkgConfig often leaks host paths. -# We prefer find_package or explicit paths. +# LibArchive detection if(TARGET LibArchive::LibArchive) set(LIBARCHIVE_LIBRARIES LibArchive::LibArchive) set(LIBARCHIVE_FOUND TRUE) @@ -193,6 +171,7 @@ elseif(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows" OR EMSCRIPTEN) set(LIBARCHIVE_LIBRARIES LibArchive::LibArchive) if(NOT LIBARCHIVE_INCLUDE_DIRS) find_path(LIBARCHIVE_INCLUDE_DIR NAMES archive.h) + set(LIBARCHIVE_INCLUDE_DIRS ${LIBARCHIVE_INCLUDE_DIR}) else() set(LIBARCHIVE_INCLUDE_DIR ${LIBARCHIVE_INCLUDE_DIRS}) endif() @@ -220,6 +199,7 @@ else() pkg_check_modules(LIBARCHIVE REQUIRED libarchive) endif() +# Zopfli detection if(PkgConfig_FOUND) pkg_check_modules(ZOPFLIPNG zopflipng) endif() @@ -242,19 +222,38 @@ if(NOT ZOPFLIPNG_FOUND) endif() endif() -add_executable(spratlayout - src/spratlayout.cpp +# Target definitions +add_library(spratcore STATIC + src/core/cli_parse.cpp + src/core/layout_parser.cpp + src/core/output_pattern.cpp + src/core/i18n.cpp + src/core/stb_impl.cpp src/commands/spratlayout_command.cpp + src/commands/spratpack_command.cpp + src/commands/spratconvert_command.cpp + src/commands/spratframes_command.cpp + src/commands/spratunpack_command.cpp ) + +target_include_directories(spratcore PUBLIC src) +target_include_directories(spratcore SYSTEM PRIVATE ${STB_DIR}) +target_include_directories(spratcore PRIVATE ${LIBARCHIVE_INCLUDE_DIRS}) +if(SPRAT_GETTEXT_AVAILABLE) + target_compile_definitions(spratcore PUBLIC SPRAT_ENABLE_GETTEXT) + target_link_libraries(spratcore PUBLIC ${SPRAT_INTL_LIBRARIES}) + if(SPRAT_INTL_INCLUDE_DIRS) + target_include_directories(spratcore PUBLIC ${SPRAT_INTL_INCLUDE_DIRS}) + endif() +endif() +target_compile_definitions(spratcore PUBLIC SPRAT_LOCALE_DIR="${CMAKE_INSTALL_FULL_LOCALEDIR}") + +add_executable(spratlayout src/spratlayout.cpp) target_link_libraries(spratlayout PRIVATE spratcore ${LIBARCHIVE_LIBRARIES}) target_include_directories(spratlayout PRIVATE ${LIBARCHIVE_INCLUDE_DIRS}) target_include_directories(spratlayout SYSTEM PRIVATE ${STB_DIR}) -target_include_directories(spratlayout PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -add_executable(spratpack - src/spratpack.cpp - src/commands/spratpack_command.cpp -) +add_executable(spratpack src/spratpack.cpp) target_link_libraries(spratpack PRIVATE spratcore ${LIBARCHIVE_LIBRARIES}) if(ZOPFLIPNG_FOUND) target_link_libraries(spratpack PRIVATE ${ZOPFLIPNG_LIBRARIES}) @@ -263,32 +262,20 @@ if(ZOPFLIPNG_FOUND) endif() target_include_directories(spratpack PRIVATE ${LIBARCHIVE_INCLUDE_DIRS}) target_include_directories(spratpack SYSTEM PRIVATE ${STB_DIR}) -target_include_directories(spratpack PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -add_executable(spratconvert - src/spratconvert.cpp - src/commands/spratconvert_command.cpp -) +add_executable(spratconvert src/spratconvert.cpp) target_link_libraries(spratconvert PRIVATE spratcore) target_include_directories(spratconvert SYSTEM PRIVATE ${STB_DIR}) -target_include_directories(spratconvert PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -add_executable(spratframes - src/spratframes.cpp - src/commands/spratframes_command.cpp -) +add_executable(spratframes src/spratframes.cpp) target_link_libraries(spratframes PRIVATE spratcore) target_include_directories(spratframes SYSTEM PRIVATE ${STB_DIR}) -target_include_directories(spratframes PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -add_executable(spratunpack - src/spratunpack.cpp - src/commands/spratunpack_command.cpp -) +add_executable(spratunpack src/spratunpack.cpp) target_link_libraries(spratunpack PRIVATE spratcore ${LIBARCHIVE_LIBRARIES}) target_include_directories(spratunpack PRIVATE ${LIBARCHIVE_INCLUDE_DIRS}) target_include_directories(spratunpack SYSTEM PRIVATE ${STB_DIR}) -target_include_directories(spratunpack PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) + target_compile_definitions(spratconvert PRIVATE SPRAT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") target_compile_definitions(spratlayout PRIVATE SPRAT_GLOBAL_PROFILE_CONFIG="${CMAKE_INSTALL_FULL_DATADIR}/sprat/spratprofiles.cfg")