cmake_minimum_required(VERSION 3.20) project(media-image-service VERSION 0.1.0 DESCRIPTION "Polymech image resize service (CLI, REST, IPC) — libvips" LANGUAGES CXX ) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/dist") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}/dist") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_SOURCE_DIR}/dist") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_SOURCE_DIR}/dist") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # MSVC: UTF-8 source/execution charset so wide string literals (L"...") match UTF-8 in .cpp files. if(MSVC) add_compile_options(/utf-8) endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Windows: official libvips dev tree (see scripts/fetch-vips-windows.ps1) — vips-dev-* under third_party/ if(WIN32) file(GLOB _MEDIA_VIPS_SDK "${CMAKE_CURRENT_SOURCE_DIR}/third_party/vips-dev-*") if(_MEDIA_VIPS_SDK) list(APPEND CMAKE_PREFIX_PATH ${_MEDIA_VIPS_SDK}) endif() endif() include(FetchContent) set(JSON_BuildTests OFF CACHE BOOL "" FORCE) FetchContent_Declare( cli11 GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git GIT_TAG v2.4.2 GIT_SHALLOW TRUE ) FetchContent_Declare( asio GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git GIT_TAG asio-1-28-0 GIT_SHALLOW TRUE ) FetchContent_Declare( nlohmann_json GIT_REPOSITORY https://github.com/nlohmann/json.git GIT_TAG v3.11.3 GIT_SHALLOW TRUE ) FetchContent_Declare( cpp_httplib GIT_REPOSITORY https://github.com/yhirose/cpp-httplib.git GIT_TAG v0.16.3 GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(cli11 asio nlohmann_json cpp_httplib) # libcurl — HTTP(S) URL inputs (minimal static build; SChannel on Windows, OpenSSL on Linux). set(CMAKE_POLICY_VERSION_MINIMUM 3.5 CACHE STRING "" FORCE) FetchContent_Declare( CURL URL https://github.com/curl/curl/releases/download/curl-8_12_1/curl-8.12.1.tar.xz DOWNLOAD_EXTRACT_TIMESTAMP TRUE ) set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE) set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) set(BUILD_TESTING OFF CACHE BOOL "" FORCE) if(WIN32) set(CURL_USE_OPENSSL OFF CACHE BOOL "" FORCE) set(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE) else() set(CURL_USE_SCHANNEL OFF CACHE BOOL "" FORCE) set(CURL_USE_OPENSSL ON CACHE BOOL "" FORCE) endif() set(CURL_ZLIB OFF CACHE BOOL "" FORCE) set(CURL_BROTLI OFF CACHE BOOL "" FORCE) set(CURL_ZSTD OFF CACHE BOOL "" FORCE) set(USE_NGHTTP2 OFF CACHE BOOL "" FORCE) set(CURL_USE_LIBSSH2 OFF CACHE BOOL "" FORCE) set(CURL_USE_LIBPSL OFF CACHE BOOL "" FORCE) set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(CURL) # PicoSHA2 — header-only SHA256 for cache keys. FetchContent_Declare( picosha2 GIT_REPOSITORY https://github.com/okdshin/PicoSHA2.git GIT_TAG master GIT_SHALLOW TRUE ) FetchContent_GetProperties(picosha2) if(NOT picosha2_POPULATED) FetchContent_Populate(picosha2) endif() # p-ranav/glob — same as packages/kbot/cpp (glob / rglob for **). FetchContent_Declare( pranav_glob GIT_REPOSITORY https://github.com/p-ranav/glob.git GIT_TAG master GIT_SHALLOW TRUE ) FetchContent_GetProperties(pranav_glob) if(NOT pranav_glob_POPULATED) FetchContent_Populate(pranav_glob) endif() add_library(pranav_glob STATIC ${pranav_glob_SOURCE_DIR}/source/glob.cpp) target_include_directories(pranav_glob PUBLIC ${pranav_glob_SOURCE_DIR}/include) target_compile_features(pranav_glob PUBLIC cxx_std_17) if(MSVC) target_compile_options(pranav_glob PRIVATE /permissive-) endif() # laserpants/dotenv-cpp — load .env (same pattern as packages/kbot/cpp). FetchContent_Declare( laserpants_dotenv GIT_REPOSITORY https://github.com/laserpants/dotenv-cpp.git GIT_TAG master GIT_SHALLOW TRUE ) FetchContent_GetProperties(laserpants_dotenv) if(NOT laserpants_dotenv_POPULATED) FetchContent_Populate(laserpants_dotenv) endif() add_library(laserpants_dotenv INTERFACE) target_include_directories(laserpants_dotenv INTERFACE ${laserpants_dotenv_SOURCE_DIR}/include) add_library(laserpants::dotenv ALIAS laserpants_dotenv) find_package(Vips REQUIRED) add_executable(pm-image src/main.cpp src/core/cache.cpp src/core/glob_paths.cpp src/core/output_path.cpp src/core/resize.cpp src/core/transform.cpp src/core/url_fetch.cpp src/http/serve.cpp src/ipc/ipc_serve.cpp ) if(WIN32) target_sources(pm-image PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/win/register_explorer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/win/resize_ui.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/win/resize_progress_ui.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/win/ui_singleton.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/win/media-img-win.manifest" ) # ── ui_next (Win32++ ribbon + dock UI) ────────────────────────────── set(_UI_NEXT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/win/ui_next") # Try to compile Ribbon.xml → Ribbon.bml + RibbonUI.h + RibbonUI.rc via uicc.exe. find_program(UICC_EXE uicc HINTS "C:/Program Files (x86)/Windows Kits/10/bin" "$ENV{WindowsSdkDir}/bin" PATH_SUFFIXES "${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/x64" "${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/x86" "10.0.22621.0/x64" "10.0.22621.0/x86" "10.0.19041.0/x64" "10.0.19041.0/x86" ) if(UICC_EXE) message(STATUS "uicc found: ${UICC_EXE} — ribbon resources will be compiled") add_custom_command( OUTPUT "${_UI_NEXT_DIR}/Ribbon.bml" "${_UI_NEXT_DIR}/RibbonUI.h" "${_UI_NEXT_DIR}/RibbonUI.rc" COMMAND "${UICC_EXE}" "${_UI_NEXT_DIR}/Ribbon.xml" "${_UI_NEXT_DIR}/Ribbon.bml" "/header:${_UI_NEXT_DIR}/RibbonUI.h" "/res:${_UI_NEXT_DIR}/RibbonUI.rc" "/name:APPLICATION" DEPENDS "${_UI_NEXT_DIR}/Ribbon.xml" COMMENT "Compiling Ribbon.xml → Ribbon.bml + RibbonUI.h/rc (uicc)" VERBATIM ) add_custom_target(pm_image_ribbon DEPENDS "${_UI_NEXT_DIR}/Ribbon.bml" "${_UI_NEXT_DIR}/RibbonUI.h" "${_UI_NEXT_DIR}/RibbonUI.rc" ) else() message(STATUS "uicc NOT found — ribbon disabled; classic menu fallback will be used") add_custom_target(pm_image_ribbon) endif() target_sources(pm-image PRIVATE "${_UI_NEXT_DIR}/App.cpp" "${_UI_NEXT_DIR}/DropView.cpp" "${_UI_NEXT_DIR}/FileQueue.cpp" "${_UI_NEXT_DIR}/SettingsPanel.cpp" "${_UI_NEXT_DIR}/Mainfrm.cpp" "${_UI_NEXT_DIR}/launch_ui_next.cpp" "${_UI_NEXT_DIR}/Resource.rc" ) add_dependencies(pm-image pm_image_ribbon) target_include_directories(pm-image PRIVATE "${_UI_NEXT_DIR}") endif() # Win32++ — header-only (vendor tree under packages/Win32xx). See samples e.g. # packages/Win32xx/samples/MovieShow/ProjectFiles/*_2026.vcxproj: AdditionalIncludeDirectories=..\..\..\include if(WIN32) set(MEDIA_WIN32XX_DIR "${CMAKE_CURRENT_SOURCE_DIR}/packages/Win32xx" CACHE PATH "Win32++ root (expects include/wxx_*.h)") if(EXISTS "${MEDIA_WIN32XX_DIR}/include/wxx_wincore.h") add_library(win32xx INTERFACE) target_include_directories(win32xx INTERFACE "${MEDIA_WIN32XX_DIR}/include") target_compile_definitions(win32xx INTERFACE UNICODE _UNICODE) # Same optional deps as MovieShow (beyond what pragma in our .cpp already pulls). target_link_libraries(win32xx INTERFACE shlwapi Propsys gdiplus Crypt32 uxtheme) add_library(media::win32xx ALIAS win32xx) target_link_libraries(pm-image PRIVATE win32xx) endif() endif() target_include_directories(pm-image PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ${asio_SOURCE_DIR}/asio/include ${picosha2_SOURCE_DIR} ) target_compile_definitions(pm-image PRIVATE ASIO_STANDALONE ASIO_NO_DEPRECATED CPPHTTPLIB_NO_EXCEPTIONS=0 ) if(WIN32) target_compile_definitions(pm-image PRIVATE _WIN32_WINNT=0x0A00 NOMINMAX ) endif() target_link_libraries(pm-image PRIVATE CLI11::CLI11 nlohmann_json::nlohmann_json httplib::httplib laserpants::dotenv pranav_glob CURL::libcurl Vips::vips ) # GObject (g_object_ref / g_object_unref) — not re-exported through libvips import lib on MSVC. if(WIN32) file(GLOB _MEDIA_VIPS_SDK_LIST "${CMAKE_CURRENT_SOURCE_DIR}/third_party/vips-dev-*") if(_MEDIA_VIPS_SDK_LIST) list(GET _MEDIA_VIPS_SDK_LIST 0 _MEDIA_VIPS_SDK) if(EXISTS "${_MEDIA_VIPS_SDK}/lib/libgobject-2.0.lib") target_link_libraries(pm-image PRIVATE "${_MEDIA_VIPS_SDK}/lib/libgobject-2.0.lib" "${_MEDIA_VIPS_SDK}/lib/libglib-2.0.lib" ) endif() endif() endif() if(UNIX AND NOT APPLE) target_link_libraries(pm-image PRIVATE pthread) endif() target_compile_definitions(pm-image PRIVATE "MEDIA_IMG_VERSION=\"${PROJECT_VERSION}\"" ) # Runtime: libvips and deps are DLLs next to pm-image.exe (Windows dev bundle bin/). if(WIN32) file(GLOB _MEDIA_VIPS_SDK_LIST "${CMAKE_CURRENT_SOURCE_DIR}/third_party/vips-dev-*") if(_MEDIA_VIPS_SDK_LIST) list(GET _MEDIA_VIPS_SDK_LIST 0 _MEDIA_VIPS_SDK) if(EXISTS "${_MEDIA_VIPS_SDK}/bin") add_custom_command( TARGET pm-image POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${_MEDIA_VIPS_SDK}/bin" "${CMAKE_SOURCE_DIR}/dist" COMMENT "Copy libvips DLLs to dist/" ) endif() endif() endif()