From 18f5d0a74ba2a4d6882119c210f5ec5faf01bce0 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 14:13:45 +0300 Subject: [PATCH 01/26] Add initial modern CMake build scaffolding --- .editorconfig | 7 +++++++ .gitignore | 5 +++++ CMakeLists.txt | 51 +++++++++++++++++++++++++++++++++++++++++++++++ CMakePresets.json | 22 ++++++++++++++++++++ cmake/config.h.in | 7 +++++++ include/core.h | 3 +++ src/core.c | 7 +++++++ src/main.c | 7 +++++++ 8 files changed, 109 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 cmake/config.h.in create mode 100644 include/core.h create mode 100644 src/core.c create mode 100644 src/main.c diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3c5796c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +insert_final_newline = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e630c40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build/ +.cache/ +.vscode/ +.idea/ +*.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6e81240 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.28) +project(ModernizedApp VERSION 2.3.0 LANGUAGES C) + +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + +if(MSVC) + add_compile_options(/W4 /permissive- /utf-8) +else() + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +include(GNUInstallDirs) +include(CheckIncludeFile) + +# pkg-config deps +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED gtk+-3.0>=3.24) +pkg_check_modules(GLIB REQUIRED glib-2.0>=2.76 gobject-2.0) +pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-base-1.0) +pkg_check_modules(CURL REQUIRED libcurl) + +set(HAVE_GTK ${GTK_FOUND}) +set(HAVE_GSTREAMER ${GST_FOUND}) +set(HAVE_CURL ${CURL_FOUND}) +set(HAVE_TRAY_AYATANA 0) + +# Config header +configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in + ${CMAKE_BINARY_DIR}/generated/config.h @ONLY) +include_directories(${CMAKE_BINARY_DIR}/generated) + +# TEMP: discover sources (to be replaced with explicit lists later) +file(GLOB_RECURSE CORE_SRC CONFIGURE_DEPENDS src/*.c) +add_library(core STATIC ${CORE_SRC}) +target_include_directories(core PUBLIC ${CMAKE_SOURCE_DIR}/include) +target_compile_options(core PRIVATE ${GTK_CFLAGS_OTHER} ${GLIB_CFLAGS_OTHER} ${GST_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) +target_include_directories(core PRIVATE ${GTK_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) +target_link_directories(core PRIVATE ${GTK_LIBRARY_DIRS} ${GLIB_LIBRARY_DIRS} ${GST_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) + +add_executable(app src/main.c) # adjust if main file differs +target_link_libraries(app PRIVATE core + ${GTK_LIBRARIES} ${GLIB_LIBRARIES} ${GST_LIBRARIES} ${CURL_LIBRARIES}) +target_compile_options(app PRIVATE ${GTK_CFLAGS_OTHER} ${GLIB_CFLAGS_OTHER} ${GST_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) +target_include_directories(app PRIVATE ${GTK_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) +target_link_directories(app PRIVATE ${GTK_LIBRARY_DIRS} ${GLIB_LIBRARY_DIRS} ${GST_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) + +enable_testing() + +install(TARGETS app RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..0bf7a37 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,22 @@ +{ + "version": 6, + "cmakeMinimumRequired": { "major": 3, "minor": 28 }, + "configurePresets": [ + { "name": "dev", "generator": "Ninja", "binaryDir": "build/dev", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, + { "name": "rel", "generator": "Ninja", "binaryDir": "build/rel", "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } }, + { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { + "CMAKE_C_COMPILER": "cl", + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_TARGET_TRIPLET": "x64-windows" + } } + ], + "buildPresets": [ + { "name": "dev", "configurePreset": "dev" }, + { "name": "rel", "configurePreset": "rel" }, + { "name": "msvc-vcpkg", "configurePreset": "msvc-vcpkg" } + ], + "testPresets": [ + { "name": "dev", "configurePreset": "dev" }, + { "name": "rel", "configurePreset": "rel" } + ] +} diff --git a/cmake/config.h.in b/cmake/config.h.in new file mode 100644 index 0000000..b1d2f2d --- /dev/null +++ b/cmake/config.h.in @@ -0,0 +1,7 @@ +#pragma once +/* Generated by CMake */ + +#cmakedefine01 HAVE_GTK +#cmakedefine01 HAVE_GSTREAMER +#cmakedefine01 HAVE_CURL +#cmakedefine01 HAVE_TRAY_AYATANA diff --git a/include/core.h b/include/core.h new file mode 100644 index 0000000..cd1f3ec --- /dev/null +++ b/include/core.h @@ -0,0 +1,3 @@ +#pragma once + +int core_dummy(void); diff --git a/src/core.c b/src/core.c new file mode 100644 index 0000000..5dbba08 --- /dev/null +++ b/src/core.c @@ -0,0 +1,7 @@ +#include "config.h" +#include "core.h" + +int core_dummy(void) +{ + return 0; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..65f9c4e --- /dev/null +++ b/src/main.c @@ -0,0 +1,7 @@ +#include "config.h" +#include "core.h" + +int main(void) +{ + return core_dummy(); +} From 3c4047f9283b4089580d83d2e2aef62cf15cace8 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 14:31:37 +0300 Subject: [PATCH 02/26] Modernize optional feature detection --- CMakeLists.txt | 121 ++++++++++++++++++++++++++++++++++++++++++++-- cmake/config.h.in | 8 +++ 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e81240..1f5ec72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,12 +24,21 @@ pkg_check_modules(CURL REQUIRED libcurl) set(HAVE_GTK ${GTK_FOUND}) set(HAVE_GSTREAMER ${GST_FOUND}) set(HAVE_CURL ${CURL_FOUND}) -set(HAVE_TRAY_AYATANA 0) -# Config header -configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in - ${CMAKE_BINARY_DIR}/generated/config.h @ONLY) -include_directories(${CMAKE_BINARY_DIR}/generated) +# ---------- Feature toggles (default ON; compile gracefully without them) ---------- +option(WITH_TRAY "Enable system tray indicator" ON) +option(WITH_PWMD "Enable libpwmd integration" ON) +option(WITH_GNUTLS "Enable GnuTLS backend" ON) +option(WITH_OPENSSL "Enable OpenSSL backend" ON) +option(WITH_GCRYPT "Enable libgcrypt usage" ON) + +set(HAVE_TRAY 0) +set(HAVE_TRAY_AYATANA 0) +set(HAVE_TRAY_APPINDICATOR 0) +set(HAVE_PWMD 0) +set(HAVE_GNUTLS 0) +set(HAVE_OPENSSL 0) +set(HAVE_GCRYPT 0) # TEMP: discover sources (to be replaced with explicit lists later) file(GLOB_RECURSE CORE_SRC CONFIGURE_DEPENDS src/*.c) @@ -46,6 +55,108 @@ target_compile_options(app PRIVATE ${GTK_CFLAGS_OTHER} ${GLIB_CFLAGS_OTHER} ${GS target_include_directories(app PRIVATE ${GTK_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) target_link_directories(app PRIVATE ${GTK_LIBRARY_DIRS} ${GLIB_LIBRARY_DIRS} ${GST_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +# ---------- TRAY (Ayatana/AppIndicator) ---------- +if(WITH_TRAY) + pkg_check_modules(AYATANA QUIET ayatana-appindicator3-0.1) + if(AYATANA_FOUND) + target_include_directories(core PRIVATE ${AYATANA_INCLUDE_DIRS}) + target_link_directories(core PRIVATE ${AYATANA_LIBRARY_DIRS}) + target_link_libraries(core PRIVATE ${AYATANA_LIBRARIES}) + target_compile_definitions(core PRIVATE HAVE_TRAY=1 HAVE_TRAY_AYATANA=1) + set(HAVE_TRAY 1) + set(HAVE_TRAY_AYATANA 1) + message(STATUS "Tray: using ayatana-appindicator3") + else() + pkg_check_modules(APPIND QUIET appindicator3-0.1) + if(APPIND_FOUND) + target_include_directories(core PRIVATE ${APPIND_INCLUDE_DIRS}) + target_link_directories(core PRIVATE ${APPIND_LIBRARY_DIRS}) + target_link_libraries(core PRIVATE ${APPIND_LIBRARIES}) + target_compile_definitions(core PRIVATE HAVE_TRAY=1 HAVE_TRAY_APPINDICATOR=1) + set(HAVE_TRAY 1) + set(HAVE_TRAY_APPINDICATOR 1) + message(STATUS "Tray: using appindicator3-0.1 (legacy)") + else() + message(STATUS "Tray: disabled (ayatana/appindicator not found)") + endif() + endif() +endif() + +# ---------- PWMD ---------- +if(WITH_PWMD) + pkg_check_modules(PWMD QUIET libpwmd) + if(PWMD_FOUND) + target_include_directories(core PRIVATE ${PWMD_INCLUDE_DIRS}) + target_link_directories(core PRIVATE ${PWMD_LIBRARY_DIRS}) + target_link_libraries(core PRIVATE ${PWMD_LIBRARIES}) + target_compile_definitions(core PRIVATE HAVE_PWMD=1) + set(HAVE_PWMD 1) + message(STATUS "PWMD: enabled") + else() + message(STATUS "PWMD: not found; disabling") + endif() +endif() + +# ---------- Crypto/TLS backends ---------- +if(WITH_GNUTLS) + pkg_check_modules(GNUTLS QUIET gnutls) + if(GNUTLS_FOUND) + target_include_directories(core PRIVATE ${GNUTLS_INCLUDE_DIRS}) + target_link_directories(core PRIVATE ${GNUTLS_LIBRARY_DIRS}) + target_link_libraries(core PRIVATE ${GNUTLS_LIBRARIES}) + target_compile_definitions(core PRIVATE HAVE_GNUTLS=1) + set(HAVE_GNUTLS 1) + message(STATUS "TLS: GnuTLS enabled") + else() + message(STATUS "TLS: GnuTLS not found") + endif() +endif() + +if(WITH_OPENSSL) + # Prefer 'openssl' pkg (provides crypto/ssl). On some distros it's 'openssl', on others split: + pkg_check_modules(OPENSSL QUIET openssl) + if(OPENSSL_FOUND) + target_include_directories(core PRIVATE ${OPENSSL_INCLUDE_DIRS}) + target_link_directories(core PRIVATE ${OPENSSL_LIBRARY_DIRS}) + target_link_libraries(core PRIVATE ${OPENSSL_LIBRARIES}) + target_compile_definitions(core PRIVATE HAVE_OPENSSL=1) + set(HAVE_OPENSSL 1) + message(STATUS "TLS: OpenSSL enabled") + else() + # Fallback separate crypto/ssl (if available in your environment) + pkg_check_modules(LIBSSL QUIET libssl) + pkg_check_modules(LIBCRYPTO QUIET libcrypto) + if(LIBSSL_FOUND AND LIBCRYPTO_FOUND) + target_include_directories(core PRIVATE ${LIBSSL_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS}) + target_link_directories(core PRIVATE ${LIBSSL_LIBRARY_DIRS} ${LIBCRYPTO_LIBRARY_DIRS}) + target_link_libraries(core PRIVATE ${LIBSSL_LIBRARIES} ${LIBCRYPTO_LIBRARIES}) + target_compile_definitions(core PRIVATE HAVE_OPENSSL=1) + set(HAVE_OPENSSL 1) + message(STATUS "TLS: OpenSSL (split ssl/crypto) enabled") + else() + message(STATUS "TLS: OpenSSL not found") + endif() + endif() +endif() + +if(WITH_GCRYPT) + pkg_check_modules(GCRYPT QUIET libgcrypt) + if(GCRYPT_FOUND) + target_include_directories(core PRIVATE ${GCRYPT_INCLUDE_DIRS}) + target_link_directories(core PRIVATE ${GCRYPT_LIBRARY_DIRS}) + target_link_libraries(core PRIVATE ${GCRYPT_LIBRARIES}) + target_compile_definitions(core PRIVATE HAVE_GCRYPT=1) + set(HAVE_GCRYPT 1) + message(STATUS "Crypto: libgcrypt enabled") + else() + message(STATUS "Crypto: libgcrypt not found") + endif() +endif() + +configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in + ${CMAKE_BINARY_DIR}/generated/config.h @ONLY) +include_directories(${CMAKE_BINARY_DIR}/generated) + enable_testing() install(TARGETS app RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/cmake/config.h.in b/cmake/config.h.in index b1d2f2d..2601dac 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -4,4 +4,12 @@ #cmakedefine01 HAVE_GTK #cmakedefine01 HAVE_GSTREAMER #cmakedefine01 HAVE_CURL + +/* Feature toggles generated by CMake */ +#cmakedefine01 HAVE_TRAY #cmakedefine01 HAVE_TRAY_AYATANA +#cmakedefine01 HAVE_TRAY_APPINDICATOR +#cmakedefine01 HAVE_PWMD +#cmakedefine01 HAVE_GNUTLS +#cmakedefine01 HAVE_OPENSSL +#cmakedefine01 HAVE_GCRYPT From c681be13a82768e4bf9b9d8f7b351158afe31ce6 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 14:35:04 +0300 Subject: [PATCH 03/26] Enforce consistent warnings and add sanitizer preset --- CMakeLists.txt | 20 ++++++++++++++++++++ CMakePresets.json | 4 ++++ docs/DEVELOPER.md | 15 +++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 docs/DEVELOPER.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f5ec72..5f6fce2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) +option(ENABLE_SANITIZERS "Enable ASan/UBSan in Debug on non-MSVC builds" ON) + if(MSVC) add_compile_options(/W4 /permissive- /utf-8) else() @@ -55,6 +57,24 @@ target_compile_options(app PRIVATE ${GTK_CFLAGS_OTHER} ${GLIB_CFLAGS_OTHER} ${GS target_include_directories(app PRIVATE ${GTK_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) target_link_directories(app PRIVATE ${GTK_LIBRARY_DIRS} ${GLIB_LIBRARY_DIRS} ${GST_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +# --- Project-wide compile warnings (already set globally, but ensure targets inherit) --- +if(MSVC) + target_compile_options(core PRIVATE /W4 /permissive- /utf-8) + target_compile_options(app PRIVATE /W4 /permissive- /utf-8) +else() + target_compile_options(core PRIVATE -Wall -Wextra -Wpedantic) + target_compile_options(app PRIVATE -Wall -Wextra -Wpedantic) +endif() + +# --- Sanitizers: only in Debug, only on non-MSVC --- +if(ENABLE_SANITIZERS AND CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT MSVC) + target_compile_options(core PRIVATE -fsanitize=address,undefined -fno-omit-frame-pointer) + target_link_options( core PRIVATE -fsanitize=address,undefined) + + target_compile_options(app PRIVATE -fsanitize=address,undefined -fno-omit-frame-pointer) + target_link_options( app PRIVATE -fsanitize=address,undefined) +endif() + # ---------- TRAY (Ayatana/AppIndicator) ---------- if(WITH_TRAY) pkg_check_modules(AYATANA QUIET ayatana-appindicator3-0.1) diff --git a/CMakePresets.json b/CMakePresets.json index 0bf7a37..6ef94a2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -3,6 +3,8 @@ "cmakeMinimumRequired": { "major": 3, "minor": 28 }, "configurePresets": [ { "name": "dev", "generator": "Ninja", "binaryDir": "build/dev", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, + { "name": "asan", "inherits": "dev", "binaryDir": "build/asan", + "cacheVariables": { "ENABLE_SANITIZERS": true, "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "rel", "generator": "Ninja", "binaryDir": "build/rel", "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } }, { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { "CMAKE_C_COMPILER": "cl", @@ -12,11 +14,13 @@ ], "buildPresets": [ { "name": "dev", "configurePreset": "dev" }, + { "name": "asan", "configurePreset": "asan" }, { "name": "rel", "configurePreset": "rel" }, { "name": "msvc-vcpkg", "configurePreset": "msvc-vcpkg" } ], "testPresets": [ { "name": "dev", "configurePreset": "dev" }, + { "name": "asan", "configurePreset": "asan" }, { "name": "rel", "configurePreset": "rel" } ] } diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md new file mode 100644 index 0000000..7b03211 --- /dev/null +++ b/docs/DEVELOPER.md @@ -0,0 +1,15 @@ +# Build Presets + +Use CMake presets to configure common build types: + +- `cmake --preset dev` for a standard Debug build. +- `cmake --preset asan` for a Debug build with AddressSanitizer/UndefinedBehaviorSanitizer enabled (Unix-like platforms). +- `cmake --preset rel` for a RelWithDebInfo build. + +When debugging sanitizer builds you can enable stricter behavior with: + +```sh +export ASAN_OPTIONS=halt_on_error=1 +``` + +Set the variable before running the instrumented binary to stop immediately on the first sanitizer report. From 9ec06f4612a31c8cba68986cfdd96de294fbbd8c Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 16:39:11 +0300 Subject: [PATCH 04/26] Add CTest integration for legacy tests --- CMakeLists.txt | 13 ++- tests/CMakeLists.txt | 232 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 tests/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f6fce2..460e264 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,11 +22,19 @@ pkg_check_modules(GTK REQUIRED gtk+-3.0>=3.24) pkg_check_modules(GLIB REQUIRED glib-2.0>=2.76 gobject-2.0) pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-base-1.0) pkg_check_modules(CURL REQUIRED libcurl) +find_package(Threads REQUIRED) + +include(CTest) +if(NOT BUILD_TESTING) + message(STATUS "BUILD_TESTING=OFF: test targets will not be generated") +endif() set(HAVE_GTK ${GTK_FOUND}) set(HAVE_GSTREAMER ${GST_FOUND}) set(HAVE_CURL ${CURL_FOUND}) +add_compile_definitions(HAVE_GLIB=1) + # ---------- Feature toggles (default ON; compile gracefully without them) ---------- option(WITH_TRAY "Enable system tray indicator" ON) option(WITH_PWMD "Enable libpwmd integration" ON) @@ -177,6 +185,9 @@ configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in ${CMAKE_BINARY_DIR}/generated/config.h @ONLY) include_directories(${CMAKE_BINARY_DIR}/generated) -enable_testing() + +if(BUILD_TESTING) + add_subdirectory(tests) +endif() install(TARGETS app RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..0f30f87 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,232 @@ +cmake_minimum_required(VERSION 3.10) + +set(UGLIB_SOURCES + ${CMAKE_SOURCE_DIR}/uglib/UgStdio.c + ${CMAKE_SOURCE_DIR}/uglib/UgString.c + ${CMAKE_SOURCE_DIR}/uglib/UgThread.c + ${CMAKE_SOURCE_DIR}/uglib/UgSocket.c + ${CMAKE_SOURCE_DIR}/uglib/UgUtil.c + ${CMAKE_SOURCE_DIR}/uglib/UgFileUtil.c + ${CMAKE_SOURCE_DIR}/uglib/UgArray.c + ${CMAKE_SOURCE_DIR}/uglib/UgList.c + ${CMAKE_SOURCE_DIR}/uglib/UgSLink.c + ${CMAKE_SOURCE_DIR}/uglib/UgOption.c + ${CMAKE_SOURCE_DIR}/uglib/UgUri.c + ${CMAKE_SOURCE_DIR}/uglib/UgNode.c + ${CMAKE_SOURCE_DIR}/uglib/UgData.c + ${CMAKE_SOURCE_DIR}/uglib/UgInfo.c + ${CMAKE_SOURCE_DIR}/uglib/UgRegistry.c + ${CMAKE_SOURCE_DIR}/uglib/UgValue.c + ${CMAKE_SOURCE_DIR}/uglib/UgEntry.c + ${CMAKE_SOURCE_DIR}/uglib/UgBuffer.c + ${CMAKE_SOURCE_DIR}/uglib/UgJson.c + ${CMAKE_SOURCE_DIR}/uglib/UgJson-custom.c + ${CMAKE_SOURCE_DIR}/uglib/UgJsonFile.c + ${CMAKE_SOURCE_DIR}/uglib/UgJsonrpc.c + ${CMAKE_SOURCE_DIR}/uglib/UgJsonrpcSocket.c + ${CMAKE_SOURCE_DIR}/uglib/UgJsonrpcCurl.c + ${CMAKE_SOURCE_DIR}/uglib/UgHtml.c + ${CMAKE_SOURCE_DIR}/uglib/UgHtmlEntry.c + ${CMAKE_SOURCE_DIR}/uglib/UgHtmlFilter.c +) + +add_library(uglib STATIC ${UGLIB_SOURCES}) +target_include_directories(uglib + PUBLIC + ${CMAKE_SOURCE_DIR}/uglib + ${GLIB_INCLUDE_DIRS} + ${CURL_INCLUDE_DIRS} +) +target_link_directories(uglib PUBLIC ${GLIB_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +target_link_libraries(uglib + PUBLIC + Threads::Threads + ${GLIB_LIBRARIES} + ${CURL_LIBRARIES} +) +target_compile_options(uglib PRIVATE ${GLIB_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) +target_compile_definitions(uglib PUBLIC HAVE_CONFIG_H) + +set(UGET_SOURCES + ${CMAKE_SOURCE_DIR}/uget/UgetSequence.c + ${CMAKE_SOURCE_DIR}/uget/UgetRss.c + ${CMAKE_SOURCE_DIR}/uget/UgetRpc.c + ${CMAKE_SOURCE_DIR}/uget/UgetOption.c + ${CMAKE_SOURCE_DIR}/uget/UgetData.c + ${CMAKE_SOURCE_DIR}/uget/UgetFiles.c + ${CMAKE_SOURCE_DIR}/uget/UgetNode.c + ${CMAKE_SOURCE_DIR}/uget/UgetNode-compare.c + ${CMAKE_SOURCE_DIR}/uget/UgetNode-filter.c + ${CMAKE_SOURCE_DIR}/uget/UgetTask.c + ${CMAKE_SOURCE_DIR}/uget/UgetHash.c + ${CMAKE_SOURCE_DIR}/uget/UgetSite.c + ${CMAKE_SOURCE_DIR}/uget/UgetApp.c + ${CMAKE_SOURCE_DIR}/uget/UgetEvent.c + ${CMAKE_SOURCE_DIR}/uget/UgetPlugin.c + ${CMAKE_SOURCE_DIR}/uget/UgetA2cf.c + ${CMAKE_SOURCE_DIR}/uget/UgetCurl.c + ${CMAKE_SOURCE_DIR}/uget/UgetAria2.c + ${CMAKE_SOURCE_DIR}/uget/UgetMedia.c + ${CMAKE_SOURCE_DIR}/uget/UgetMedia-youtube.c + ${CMAKE_SOURCE_DIR}/uget/UgetPluginCurl.c + ${CMAKE_SOURCE_DIR}/uget/UgetPluginAria2.c + ${CMAKE_SOURCE_DIR}/uget/UgetPluginMedia.c + ${CMAKE_SOURCE_DIR}/uget/UgetPluginAgent.c + ${CMAKE_SOURCE_DIR}/uget/UgetPluginEmpty.c +) + +set(_uget_has_mega FALSE) +if(HAVE_GCRYPT AND HAVE_OPENSSL) + list(APPEND UGET_SOURCES ${CMAKE_SOURCE_DIR}/uget/UgetPluginMega.c) + set(_uget_has_mega TRUE) +else() + message(STATUS "Skipping UgetPluginMega.c (requires libgcrypt and OpenSSL)") +endif() + +if(HAVE_PWMD) + list(APPEND UGET_SOURCES ${CMAKE_SOURCE_DIR}/uget/pwmd.c) +endif() + +add_library(uget STATIC ${UGET_SOURCES}) +target_include_directories(uget + PUBLIC + ${CMAKE_SOURCE_DIR}/uget + ${CMAKE_SOURCE_DIR}/uglib + ${GLIB_INCLUDE_DIRS} + ${CURL_INCLUDE_DIRS} +) +target_link_directories(uget PUBLIC ${GLIB_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +target_link_libraries(uget + PUBLIC + uglib + Threads::Threads + ${GLIB_LIBRARIES} + ${CURL_LIBRARIES} +) +target_compile_options(uget PRIVATE ${GLIB_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) +target_compile_definitions(uget PUBLIC HAVE_CONFIG_H) + +if(HAVE_PWMD) + target_include_directories(uget PUBLIC ${PWMD_INCLUDE_DIRS}) + target_link_directories(uget PUBLIC ${PWMD_LIBRARY_DIRS}) + target_link_libraries(uget PUBLIC ${PWMD_LIBRARIES}) +endif() + +if(HAVE_GNUTLS) + target_include_directories(uget PUBLIC ${GNUTLS_INCLUDE_DIRS}) + target_link_directories(uget PUBLIC ${GNUTLS_LIBRARY_DIRS}) + target_link_libraries(uget PUBLIC ${GNUTLS_LIBRARIES}) +endif() + +if(HAVE_OPENSSL) + set(_openssl_include_dirs) + set(_openssl_library_dirs) + set(_openssl_libs) + if(OPENSSL_FOUND) + list(APPEND _openssl_include_dirs ${OPENSSL_INCLUDE_DIRS}) + list(APPEND _openssl_library_dirs ${OPENSSL_LIBRARY_DIRS}) + list(APPEND _openssl_libs ${OPENSSL_LIBRARIES}) + endif() + if(LIBSSL_FOUND) + list(APPEND _openssl_include_dirs ${LIBSSL_INCLUDE_DIRS}) + list(APPEND _openssl_library_dirs ${LIBSSL_LIBRARY_DIRS}) + list(APPEND _openssl_libs ${LIBSSL_LIBRARIES}) + endif() + if(LIBCRYPTO_FOUND) + list(APPEND _openssl_include_dirs ${LIBCRYPTO_INCLUDE_DIRS}) + list(APPEND _openssl_library_dirs ${LIBCRYPTO_LIBRARY_DIRS}) + list(APPEND _openssl_libs ${LIBCRYPTO_LIBRARIES}) + endif() + if(_openssl_include_dirs) + target_include_directories(uget PUBLIC ${_openssl_include_dirs}) + endif() + if(_openssl_library_dirs) + target_link_directories(uget PUBLIC ${_openssl_library_dirs}) + endif() + if(_openssl_libs) + target_link_libraries(uget PUBLIC ${_openssl_libs}) + endif() +endif() + +if(HAVE_GCRYPT) + target_include_directories(uget PUBLIC ${GCRYPT_INCLUDE_DIRS}) + target_link_directories(uget PUBLIC ${GCRYPT_LIBRARY_DIRS}) + target_link_libraries(uget PUBLIC ${GCRYPT_LIBRARIES}) +endif() + +function(add_uget_test target) + set(options) + set(oneValueArgs LABELS WORKING_DIRECTORY) + set(multiValueArgs SOURCES LIBS) + cmake_parse_arguments(TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT TEST_SOURCES) + message(FATAL_ERROR "add_uget_test(${target}) requires SOURCES") + endif() + + add_executable(${target} ${TEST_SOURCES}) + target_link_libraries(${target} PRIVATE ${TEST_LIBS}) + target_include_directories(${target} PRIVATE + ${CMAKE_SOURCE_DIR}/uglib + ${CMAKE_SOURCE_DIR}/uget + ${GLIB_INCLUDE_DIRS} + ${CURL_INCLUDE_DIRS} + ) + target_compile_options(${target} PRIVATE ${GLIB_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) + target_compile_definitions(${target} PRIVATE HAVE_CONFIG_H) + + add_test(NAME ${target} COMMAND ${target}) + + if(TEST_LABELS) + set(_labels "${TEST_LABELS}") + else() + set(_labels "unit") + endif() + if(TEST_WORKING_DIRECTORY) + set(_work_dir "${TEST_WORKING_DIRECTORY}") + else() + set(_work_dir "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + set_tests_properties(${target} PROPERTIES + LABELS "${_labels}" + WORKING_DIRECTORY "${_work_dir}" ) +endfunction() + +add_uget_test(test_json + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-json.c + LIBS uglib +) + +add_uget_test(test_info + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-info.c + LIBS uglib +) + +add_uget_test(test_uglib + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-uglib.c + LIBS uglib +) + +add_uget_test(test_uget + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-uget.c + LIBS uget + LABELS "unit;net" +) + +add_uget_test(test_jsonrpc + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-jsonrpc.c + LIBS uget + LABELS "unit;net" +) + +if(_uget_has_mega) + add_uget_test(test_plugin_app + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-plugin+app.c + LIBS uget + LABELS "unit;net" + ) +else() + message(STATUS "Skipping test_plugin_app (Mega plug-in not available)") +endif() + +set_property(TEST PROPERTY TIMEOUT 60) From 570cf3e7c9c32b33a0f6b7a193821fa506c6a52c Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 16:52:46 +0300 Subject: [PATCH 05/26] Add vcpkg config and Windows build docs --- .gitignore | 4 ++++ CMakePresets.json | 4 +++- docs/BUILD_WINDOWS.md | 24 ++++++++++++++++++++++++ vcpkg.json | 12 ++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 docs/BUILD_WINDOWS.md create mode 100644 vcpkg.json diff --git a/.gitignore b/.gitignore index e630c40..a7567b5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ build/ .vscode/ .idea/ *.user +*.sln +*.vcxproj +*.vcxproj.filters +*.vcxproj.user diff --git a/CMakePresets.json b/CMakePresets.json index 6ef94a2..9bb7029 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,6 +8,7 @@ { "name": "rel", "generator": "Ninja", "binaryDir": "build/rel", "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } }, { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { "CMAKE_C_COMPILER": "cl", + "CMAKE_BUILD_TYPE": "Debug", "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "VCPKG_TARGET_TRIPLET": "x64-windows" } } @@ -21,6 +22,7 @@ "testPresets": [ { "name": "dev", "configurePreset": "dev" }, { "name": "asan", "configurePreset": "asan" }, - { "name": "rel", "configurePreset": "rel" } + { "name": "rel", "configurePreset": "rel" }, + { "name": "msvc-vcpkg", "configurePreset": "msvc-vcpkg" } ] } diff --git a/docs/BUILD_WINDOWS.md b/docs/BUILD_WINDOWS.md new file mode 100644 index 0000000..ed03ace --- /dev/null +++ b/docs/BUILD_WINDOWS.md @@ -0,0 +1,24 @@ +# Building on Windows (MSVC + vcpkg, x64) + +## Prereqs +- Visual Studio 2022 (Desktop development with C++) +- vcpkg (https://github.com/microsoft/vcpkg) and set `VCPKG_ROOT` + +## One-time setup +```powershell +# In an x64 Native Tools for VS 2022 shell: +git clone https://github.com/microsoft/vcpkg %USERPROFILE%\vcpkg +setx VCPKG_ROOT %USERPROFILE%\vcpkg +``` + +## Configure, build, test +```powershell +cmake --preset msvc-vcpkg +cmake --build build\msvc --config Debug +ctest --test-dir build\msvc -C Debug --output-on-failure +``` + +## Notes +- Dependencies come from vcpkg.json (gtk3, glib, gstreamer, curl, openssl). +- Tray support (Ayatana/AppIndicator) may be unavailable on Windows: the build will continue without it. +- Use RelWithDebInfo for release-like builds: `cmake -S . -B build\msvc -DCMAKE_BUILD_TYPE=RelWithDebInfo --preset msvc-vcpkg` diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..0c36779 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,12 @@ +{ + "name": "modernizedapp", + "version-string": "2.3.0", + "dependencies": [ + "gtk", + "glib", + "gstreamer", + "gstreamer-plugins-base", + "curl", + "openssl" + ] +} From 615d49ca46d1d56ddcd7c6f9cd1debf2db283789 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 16:57:13 +0300 Subject: [PATCH 06/26] Add GitHub Actions CI for Linux and Windows --- .github/workflows/ci.yml | 74 ++++++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 4 +++ 2 files changed, 78 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ff45b88 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,74 @@ +name: ci +on: + push: + branches: [ main, master ] + tags: [ "v*" ] + pull_request: + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-24.04, windows-latest ] + config: [ Debug, RelWithDebInfo ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + # ---------- Linux deps ---------- + - name: Install deps (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + ninja-build pkg-config \ + libgtk-3-dev libglib2.0-dev \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + libcurl4-openssl-dev libayatana-appindicator3-dev + + # ---------- Windows deps via vcpkg ---------- + - name: Setup vcpkg (Windows) + if: runner.os == 'Windows' + uses: lukka/run-vcpkg@v11 + with: + vcpkgJsonGlob: 'vcpkg.json' + + # ---------- Configure ---------- + - name: Configure (Linux) + if: runner.os == 'Linux' + run: cmake --preset ${{ matrix.config == 'Debug' && 'dev' || 'rel' }} + + - name: Configure (Windows) + if: runner.os == 'Windows' + run: cmake --preset msvc-vcpkg -DCMAKE_BUILD_TYPE=${{ matrix.config }} + + # ---------- Build ---------- + - name: Build (Linux) + if: runner.os == 'Linux' + run: cmake --build build/${{ matrix.config == 'Debug' && 'dev' || 'rel' }} --config ${{ matrix.config }} + + - name: Build (Windows) + if: runner.os == 'Windows' + run: cmake --build build/msvc --config ${{ matrix.config }} + + # ---------- Test ---------- + - name: Test (Linux) + if: runner.os == 'Linux' + run: ctest --test-dir build/${{ matrix.config == 'Debug' && 'dev' || 'rel' }} --output-on-failure -LE net + + - name: Test (Windows) + if: runner.os == 'Windows' + run: ctest --test-dir build/msvc -C ${{ matrix.config }} --output-on-failure -LE net + + # ---------- Artifacts ---------- + - name: Upload binaries + if: always() + uses: actions/upload-artifact@v4 + with: + name: ${{ runner.os }}-${{ matrix.config }} + path: | + build/**/app* + build/**/tests/* + !**/*.obj + !**/*.o diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0f30f87..d8985d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -219,6 +219,10 @@ add_uget_test(test_jsonrpc LABELS "unit;net" ) +if(TEST test_http) + set_tests_properties(test_http PROPERTIES LABELS "unit;net") +endif() + if(_uget_has_mega) add_uget_test(test_plugin_app SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-plugin+app.c From 56302fea6b6f1ab9a7143bc5dd01e034a82b43f2 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 20:26:16 +0300 Subject: [PATCH 07/26] CI: fix Windows pkgconf via vcpkg, simplify presets per-OS, enable xvfb for GTK tests, and relax artifact paths --- .github/workflows/ci.yml | 39 ++++++++++++++++++++++----------------- CMakePresets.json | 6 ++++-- vcpkg.json | 3 ++- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff45b88..3bec1c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y \ - ninja-build pkg-config \ + ninja-build pkg-config xvfb \ libgtk-3-dev libglib2.0-dev \ libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ libcurl4-openssl-dev libayatana-appindicator3-dev @@ -35,19 +35,23 @@ jobs: vcpkgJsonGlob: 'vcpkg.json' # ---------- Configure ---------- - - name: Configure (Linux) - if: runner.os == 'Linux' - run: cmake --preset ${{ matrix.config == 'Debug' && 'dev' || 'rel' }} - + - name: Configure (Linux Debug) + if: runner.os == 'Linux' && matrix.config == 'Debug' + run: cmake --preset dev + - name: Configure (Linux RelWithDebInfo) + if: runner.os == 'Linux' && matrix.config == 'RelWithDebInfo' + run: cmake --preset rel - name: Configure (Windows) if: runner.os == 'Windows' run: cmake --preset msvc-vcpkg -DCMAKE_BUILD_TYPE=${{ matrix.config }} # ---------- Build ---------- - - name: Build (Linux) - if: runner.os == 'Linux' - run: cmake --build build/${{ matrix.config == 'Debug' && 'dev' || 'rel' }} --config ${{ matrix.config }} - + - name: Build (Linux Debug) + if: runner.os == 'Linux' && matrix.config == 'Debug' + run: cmake --build build/dev + - name: Build (Linux RelWithDebInfo) + if: runner.os == 'Linux' && matrix.config == 'RelWithDebInfo' + run: cmake --build build/rel - name: Build (Windows) if: runner.os == 'Windows' run: cmake --build build/msvc --config ${{ matrix.config }} @@ -55,20 +59,21 @@ jobs: # ---------- Test ---------- - name: Test (Linux) if: runner.os == 'Linux' - run: ctest --test-dir build/${{ matrix.config == 'Debug' && 'dev' || 'rel' }} --output-on-failure -LE net - + run: | + if command -v xvfb-run >/dev/null 2>&1; then + xvfb-run -a ctest --test-dir ${{ matrix.config == 'Debug' && 'build/dev' || 'build/rel' }} --output-on-failure -LE net + else + ctest --test-dir ${{ matrix.config == 'Debug' && 'build/dev' || 'build/rel' }} --output-on-failure -LE net + fi - name: Test (Windows) if: runner.os == 'Windows' run: ctest --test-dir build/msvc -C ${{ matrix.config }} --output-on-failure -LE net # ---------- Artifacts ---------- - - name: Upload binaries + - name: Upload build dir if: always() uses: actions/upload-artifact@v4 with: name: ${{ runner.os }}-${{ matrix.config }} - path: | - build/**/app* - build/**/tests/* - !**/*.obj - !**/*.o + path: build/** + if-no-files-found: warn diff --git a/CMakePresets.json b/CMakePresets.json index 9bb7029..f17e5c9 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -5,12 +5,14 @@ { "name": "dev", "generator": "Ninja", "binaryDir": "build/dev", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "asan", "inherits": "dev", "binaryDir": "build/asan", "cacheVariables": { "ENABLE_SANITIZERS": true, "CMAKE_BUILD_TYPE": "Debug" } }, - { "name": "rel", "generator": "Ninja", "binaryDir": "build/rel", "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } }, + { "name": "rel", "generator": "Ninja", "binaryDir": "build/rel", "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } +}, { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { "CMAKE_C_COMPILER": "cl", "CMAKE_BUILD_TYPE": "Debug", "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", - "VCPKG_TARGET_TRIPLET": "x64-windows" + "VCPKG_TARGET_TRIPLET": "x64-windows", + "PKG_CONFIG_EXECUTABLE": "$env{VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe" } } ], "buildPresets": [ diff --git a/vcpkg.json b/vcpkg.json index 0c36779..7226195 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -7,6 +7,7 @@ "gstreamer", "gstreamer-plugins-base", "curl", - "openssl" + "openssl", + "pkgconf" ] } From bad7a12f58cd9595df1d49ff71b9743fddc84fd6 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Thu, 25 Sep 2025 21:36:08 +0300 Subject: [PATCH 08/26] build: restore autoconf-style header checks and feature macros; define _GNU_SOURCE to expose POSIX prototypes --- CMakeLists.txt | 54 ++++++++++++++++++++++++++++++++++++++++++++ cmake/config.h.in | 21 +++++++++++++++++ tests/CMakeLists.txt | 1 + 3 files changed, 76 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 460e264..6e3f500 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,58 @@ endif() include(GNUInstallDirs) include(CheckIncludeFile) +include(CheckSymbolExists) + +# Feature test macros on non-MSVC to expose POSIX prototypes (getaddrinfo, ftruncate, popen, etc.) +if(NOT MSVC) + add_compile_definitions(_GNU_SOURCE) +endif() + +set(HEADER_NAMES + "sys/types.h" + "sys/select.h" + "sys/socket.h" + "netdb.h" + "arpa/inet.h" + "netinet/in.h" + "sys/time.h" + "unistd.h" + "fcntl.h" + "poll.h" + "sys/stat.h" + "inttypes.h" + "stdint.h" +) +set(HEADER_MACROS + HAVE_SYS_TYPES_H + HAVE_SYS_SELECT_H + HAVE_SYS_SOCKET_H + HAVE_NETDB_H + HAVE_ARPA_INET_H + HAVE_NETINET_IN_H + HAVE_SYS_TIME_H + HAVE_UNISTD_H + HAVE_FCNTL_H + HAVE_POLL_H + HAVE_SYS_STAT_H + HAVE_INTTYPES_H + HAVE_STDINT_H +) + +list(LENGTH HEADER_NAMES _header_count) +if(_header_count GREATER 0) + math(EXPR _header_last "${_header_count} - 1") + foreach(_idx RANGE 0 ${_header_last}) + list(GET HEADER_NAMES ${_idx} _hdr) + list(GET HEADER_MACROS ${_idx} _macro) + check_include_file("${_hdr}" ${_macro}) + endforeach() +endif() + +check_symbol_exists(fileno "stdio.h" HAVE_FILENO) +check_symbol_exists(ftruncate "unistd.h" HAVE_FTRUNCATE) +check_symbol_exists(popen "stdio.h" HAVE_POPEN) +check_symbol_exists(pclose "stdio.h" HAVE_PCLOSE) # pkg-config deps find_package(PkgConfig REQUIRED) @@ -57,6 +109,8 @@ target_include_directories(core PUBLIC ${CMAKE_SOURCE_DIR}/include) target_compile_options(core PRIVATE ${GTK_CFLAGS_OTHER} ${GLIB_CFLAGS_OTHER} ${GST_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) target_include_directories(core PRIVATE ${GTK_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) target_link_directories(core PRIVATE ${GTK_LIBRARY_DIRS} ${GLIB_LIBRARY_DIRS} ${GST_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +target_compile_definitions(core PRIVATE HAVE_CONFIG_H) +target_include_directories(core PRIVATE ${CMAKE_BINARY_DIR}/generated) add_executable(app src/main.c) # adjust if main file differs target_link_libraries(app PRIVATE core diff --git a/cmake/config.h.in b/cmake/config.h.in index 2601dac..9b49f62 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -13,3 +13,24 @@ #cmakedefine01 HAVE_GNUTLS #cmakedefine01 HAVE_OPENSSL #cmakedefine01 HAVE_GCRYPT + +/* Autoconf-like header availability */ +#cmakedefine01 HAVE_SYS_TYPES_H +#cmakedefine01 HAVE_SYS_SELECT_H +#cmakedefine01 HAVE_SYS_SOCKET_H +#cmakedefine01 HAVE_NETDB_H +#cmakedefine01 HAVE_ARPA_INET_H +#cmakedefine01 HAVE_NETINET_IN_H +#cmakedefine01 HAVE_SYS_TIME_H +#cmakedefine01 HAVE_UNISTD_H +#cmakedefine01 HAVE_FCNTL_H +#cmakedefine01 HAVE_POLL_H +#cmakedefine01 HAVE_SYS_STAT_H +#cmakedefine01 HAVE_INTTYPES_H +#cmakedefine01 HAVE_STDINT_H + +/* Common functions */ +#cmakedefine01 HAVE_FILENO +#cmakedefine01 HAVE_FTRUNCATE +#cmakedefine01 HAVE_POPEN +#cmakedefine01 HAVE_PCLOSE diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d8985d2..7963763 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -171,6 +171,7 @@ function(add_uget_test target) ${CMAKE_SOURCE_DIR}/uget ${GLIB_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR}/generated ) target_compile_options(${target} PRIVATE ${GLIB_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) target_compile_definitions(${target} PRIVATE HAVE_CONFIG_H) From 66e75705b8af230ee69121a8364e6c16d99be53b Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 00:05:27 +0300 Subject: [PATCH 09/26] ci: enable verbose ninja output to surface failing ar/ranlib or link commands --- .github/workflows/ci.yml | 6 +++--- CMakeLists.txt | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3bec1c0..1e6d7ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,13 +48,13 @@ jobs: # ---------- Build ---------- - name: Build (Linux Debug) if: runner.os == 'Linux' && matrix.config == 'Debug' - run: cmake --build build/dev + run: cmake --build build/dev -- -v - name: Build (Linux RelWithDebInfo) if: runner.os == 'Linux' && matrix.config == 'RelWithDebInfo' - run: cmake --build build/rel + run: cmake --build build/rel -- -v - name: Build (Windows) if: runner.os == 'Windows' - run: cmake --build build/msvc --config ${{ matrix.config }} + run: cmake --build build/msvc --config ${{ matrix.config }} -- -v # ---------- Test ---------- - name: Test (Linux) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e3f500..772a965 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.28) project(ModernizedApp VERSION 2.3.0 LANGUAGES C) +set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "Verbose build" FORCE) + set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) From 5a1d5489ae0531a64ff1908f29f474bb8a889ee5 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 00:55:51 +0300 Subject: [PATCH 10/26] tests: fix POSIX symbol clash by renaming file-scope `link` to `ug_links` in test-uglib.c --- tests/test-uglib.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/test-uglib.c b/tests/test-uglib.c index 598999b..f04332c 100644 --- a/tests/test-uglib.c +++ b/tests/test-uglib.c @@ -129,7 +129,7 @@ void test_uri (void) // ---------------------------------------------------------------------------- // test UgList -static UgLink link[4]; +static UgLink ug_links[4]; void test_list (void) { @@ -138,16 +138,16 @@ void test_list (void) uintptr_t index; ug_list_init (&list); - for (index = 0; index < 4; index++) - link[index].data = (void*) index; + for (index = 0; index < 4; index++) + ug_links[index].data = (void*) index; - ug_list_append (&list, link + 0); - ug_list_append (&list, link + 1); - ug_list_append (&list, link + 2); - ug_list_append (&list, link + 3); + ug_list_append (&list, ug_links + 0); + ug_list_append (&list, ug_links + 1); + ug_list_append (&list, ug_links + 2); + ug_list_append (&list, ug_links + 3); - ug_list_remove (&list, link + 2); - ug_list_insert (&list, link + 3, link + 2); + ug_list_remove (&list, ug_links + 2); + ug_list_insert (&list, ug_links + 3, ug_links + 2); for (temp = list.head; temp; temp = temp->next) { printf ("%d, %p, %p\n", From 8ea219df1c77551a356c707e2e00b9a170fe99ff Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 01:04:00 +0300 Subject: [PATCH 11/26] ci(windows): provide vcpkgGitCommitId dynamically to run-vcpkg to satisfy baseline requirement --- .github/workflows/ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e6d7ff..5b8753a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,12 +27,25 @@ jobs: libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ libcurl4-openssl-dev libayatana-appindicator3-dev + # ---------- Resolve a vcpkg commit ---------- + - name: Resolve vcpkg commit (Windows) + if: runner.os == 'Windows' + id: vcpkgsha + shell: bash + run: | + set -e + # Fetch latest commit on vcpkg's master (main) branch + SHA=$(git ls-remote https://github.com/microsoft/vcpkg refs/heads/master | cut -f1) + echo "sha=$SHA" >> "$GITHUB_OUTPUT" + echo "Using vcpkg commit: $SHA" + # ---------- Windows deps via vcpkg ---------- - name: Setup vcpkg (Windows) if: runner.os == 'Windows' uses: lukka/run-vcpkg@v11 with: vcpkgJsonGlob: 'vcpkg.json' + vcpkgGitCommitId: ${{ steps.vcpkgsha.outputs.sha }} # ---------- Configure ---------- - name: Configure (Linux Debug) From 4878cbf3d5c4f226680b0aada04f317825503fc1 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 01:20:50 +0300 Subject: [PATCH 12/26] ci(windows): use gstreamer[plugins-base] and skip GUI deps on Windows; install Ninja; init submodule --- .github/workflows/ci.yml | 8 +++++++- vcpkg.json | 8 +++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b8753a..a810e51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + with: + submodules: recursive # ---------- Linux deps ---------- - name: Install deps (Linux) @@ -47,6 +49,10 @@ jobs: vcpkgJsonGlob: 'vcpkg.json' vcpkgGitCommitId: ${{ steps.vcpkgsha.outputs.sha }} + - name: Setup Ninja (Windows) + if: runner.os == 'Windows' + uses: seanmiddleditch/gha-setup-ninja@v4 + # ---------- Configure ---------- - name: Configure (Linux Debug) if: runner.os == 'Linux' && matrix.config == 'Debug' @@ -56,7 +62,7 @@ jobs: run: cmake --preset rel - name: Configure (Windows) if: runner.os == 'Windows' - run: cmake --preset msvc-vcpkg -DCMAKE_BUILD_TYPE=${{ matrix.config }} + run: cmake --preset msvc-vcpkg -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DWITH_GUI=OFF -DWITH_TRAY=OFF # ---------- Build ---------- - name: Build (Linux Debug) diff --git a/vcpkg.json b/vcpkg.json index 7226195..86819e9 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,12 +2,10 @@ "name": "modernizedapp", "version-string": "2.3.0", "dependencies": [ - "gtk", - "glib", - "gstreamer", - "gstreamer-plugins-base", "curl", "openssl", - "pkgconf" + "pkgconf", + { "name": "gtk", "platform": "!windows" }, + { "name": "gstreamer", "features": ["plugins-base"], "platform": "!windows" } ] } From a866f6c25d996fad8611c5053964df42aab1dc06 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 01:35:56 +0300 Subject: [PATCH 13/26] ci(windows): initialize MSVC vcvars via msvc-dev-cmd so CMake/Ninja can find cl.exe --- .github/workflows/ci.yml | 6 ++++++ CMakePresets.json | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a810e51..2854757 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,12 @@ jobs: if: runner.os == 'Windows' uses: seanmiddleditch/gha-setup-ninja@v4 + - name: Setup MSVC dev environment (x64) + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + # ---------- Configure ---------- - name: Configure (Linux Debug) if: runner.os == 'Linux' && matrix.config == 'Debug' diff --git a/CMakePresets.json b/CMakePresets.json index f17e5c9..bad8622 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,7 +8,6 @@ { "name": "rel", "generator": "Ninja", "binaryDir": "build/rel", "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } }, { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { - "CMAKE_C_COMPILER": "cl", "CMAKE_BUILD_TYPE": "Debug", "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "VCPKG_TARGET_TRIPLET": "x64-windows", From 75a4b72d84c13eba7ba734d4cab0fdce297bf9e1 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 01:42:28 +0300 Subject: [PATCH 14/26] ci(windows): use run-vcpkg toolchain via RUNVCPKG_VCPKG_ROOT; rely on msvc-dev-cmd for cl; keep Ninja --- CMakePresets.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index bad8622..955108f 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -9,9 +9,9 @@ }, { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_TOOLCHAIN_FILE": "$env{RUNVCPKG_VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "VCPKG_TARGET_TRIPLET": "x64-windows", - "PKG_CONFIG_EXECUTABLE": "$env{VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe" + "PKG_CONFIG_EXECUTABLE": "$env{RUNVCPKG_VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe" } } ], "buildPresets": [ From e8a3d2ca82d6548be075955c7a93e3509dfb17b3 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 01:56:42 +0300 Subject: [PATCH 15/26] cmake/ci: auto-detect pkgconf/pkg-config; remove hardcoded path; add vcpkg tools dir to PATH on Windows --- .github/workflows/ci.yml | 19 +++++++++++++++++++ CMakeLists.txt | 11 +++++++++++ CMakePresets.json | 3 +-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2854757..30b02ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,25 @@ jobs: vcpkgJsonGlob: 'vcpkg.json' vcpkgGitCommitId: ${{ steps.vcpkgsha.outputs.sha }} + - name: Add vcpkg tools to PATH (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $root = "$env:RUNVCPKG_VCPKG_ROOT" + $paths = @( + Join-Path $root 'installed\x64-windows\tools\pkgconf' + Join-Path $root 'installed\x64-windows\tools' + ) + foreach ($p in $paths) { + if (Test-Path $p) { + Write-Host "Adding $p to PATH" + $p | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + } + } + # show which pkgconf will be used + Write-Host "pkgconf = " (Get-Command pkgconf -ErrorAction SilentlyContinue) + Write-Host "pkg-config = " (Get-Command pkg-config -ErrorAction SilentlyContinue) + - name: Setup Ninja (Windows) if: runner.os == 'Windows' uses: seanmiddleditch/gha-setup-ninja@v4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 772a965..0e6f73d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,17 @@ include(GNUInstallDirs) include(CheckIncludeFile) include(CheckSymbolExists) +# ---- Robust pkg-config discovery (works with vcpkg, MSYS2, Linux) ---- +# Prefer 'pkgconf' on Windows (vcpkg installs it), 'pkg-config' elsewhere. +find_program(PKG_CONFIG_EXECUTABLE NAMES pkgconf pkg-config) +if(PKG_CONFIG_EXECUTABLE) + message(STATUS "Using pkg-config at: ${PKG_CONFIG_EXECUTABLE}") + # Some FindPkgConfig variants also read the env var: + set(ENV{PKG_CONFIG} "${PKG_CONFIG_EXECUTABLE}") +else() + message(STATUS "pkg-config not found on PATH yet; FindPkgConfig may fail unless the toolchain provides it.") +endif() + # Feature test macros on non-MSVC to expose POSIX prototypes (getaddrinfo, ftruncate, popen, etc.) if(NOT MSVC) add_compile_definitions(_GNU_SOURCE) diff --git a/CMakePresets.json b/CMakePresets.json index 955108f..bd9c2a6 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -10,8 +10,7 @@ { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "CMAKE_TOOLCHAIN_FILE": "$env{RUNVCPKG_VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", - "VCPKG_TARGET_TRIPLET": "x64-windows", - "PKG_CONFIG_EXECUTABLE": "$env{RUNVCPKG_VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe" + "VCPKG_TARGET_TRIPLET": "x64-windows" } } ], "buildPresets": [ From 6953d6a8d333b1079c5d3a6945b860c73414a609 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 02:20:16 +0300 Subject: [PATCH 16/26] cmake: gate GTK/GLib/GStreamer discovery behind WITH_GUI --- CMakeLists.txt | 33 ++++++++++++++++++++++++--------- cmake/config.h.in | 1 + 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e6f73d..4b88b1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) option(ENABLE_SANITIZERS "Enable ASan/UBSan in Debug on non-MSVC builds" ON) +option(WITH_GUI "Enable GTK-based GUI components" ON) if(MSVC) add_compile_options(/W4 /permissive- /utf-8) @@ -82,11 +83,29 @@ check_symbol_exists(popen "stdio.h" HAVE_POPEN) check_symbol_exists(pclose "stdio.h" HAVE_PCLOSE) # pkg-config deps -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED gtk+-3.0>=3.24) -pkg_check_modules(GLIB REQUIRED glib-2.0>=2.76 gobject-2.0) -pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-base-1.0) -pkg_check_modules(CURL REQUIRED libcurl) +set(HAVE_GTK 0) +set(HAVE_GSTREAMER 0) +set(HAVE_GLIB 0) + +if(WITH_GUI) + if(NOT DEFINED PkgConfig_FOUND OR NOT PkgConfig_FOUND) + find_package(PkgConfig REQUIRED) + endif() + pkg_check_modules(GTK REQUIRED gtk+-3.0>=3.24) + pkg_check_modules(GLIB REQUIRED glib-2.0>=2.76 gobject-2.0) + pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-base-1.0) + + set(HAVE_GTK ${GTK_FOUND}) + set(HAVE_GSTREAMER ${GST_FOUND}) + set(HAVE_GLIB ${GLIB_FOUND}) +else() + message(STATUS "WITH_GUI=OFF: skipping GTK/GLib/GStreamer detection") +endif() + +if(NOT DEFINED PkgConfig_FOUND OR NOT PkgConfig_FOUND) + find_package(PkgConfig REQUIRED) +endif() +pkg_check_modules(CURL REQUIRED libcurl) find_package(Threads REQUIRED) include(CTest) @@ -94,12 +113,8 @@ if(NOT BUILD_TESTING) message(STATUS "BUILD_TESTING=OFF: test targets will not be generated") endif() -set(HAVE_GTK ${GTK_FOUND}) -set(HAVE_GSTREAMER ${GST_FOUND}) set(HAVE_CURL ${CURL_FOUND}) -add_compile_definitions(HAVE_GLIB=1) - # ---------- Feature toggles (default ON; compile gracefully without them) ---------- option(WITH_TRAY "Enable system tray indicator" ON) option(WITH_PWMD "Enable libpwmd integration" ON) diff --git a/cmake/config.h.in b/cmake/config.h.in index 9b49f62..34268f7 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -3,6 +3,7 @@ #cmakedefine01 HAVE_GTK #cmakedefine01 HAVE_GSTREAMER +#cmakedefine01 HAVE_GLIB #cmakedefine01 HAVE_CURL /* Feature toggles generated by CMake */ From 6f7fed9e60bd4a484aa863c3def3ea73744550da Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 02:33:20 +0300 Subject: [PATCH 17/26] tests: skip legacy GLib/GTK tests when WITH_GUI=OFF to allow Windows CI to build cleanly --- CMakeLists.txt | 6 +++++- tests/CMakeLists.txt | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b88b1f..20d11ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,7 +269,11 @@ include_directories(${CMAKE_BINARY_DIR}/generated) if(BUILD_TESTING) - add_subdirectory(tests) + if(WITH_GUI) + add_subdirectory(tests) + else() + message(STATUS "BUILD_TESTING=ON but WITH_GUI=OFF -> skipping GLib/GTK tests on this platform") + endif() endif() install(TARGETS app RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7963763..8bca7f7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,10 @@ cmake_minimum_required(VERSION 3.10) +if(NOT WITH_GUI) + message(STATUS "tests/: WITH_GUI=OFF -> not building legacy GLib/GTK tests") + return() +endif() + set(UGLIB_SOURCES ${CMAKE_SOURCE_DIR}/uglib/UgStdio.c ${CMAKE_SOURCE_DIR}/uglib/UgString.c From 71aaea153741f58908fe10db4daf365ee0911d85 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 03:49:19 +0300 Subject: [PATCH 18/26] deps(cmake): modernize dependency probing (#7) * deps(cmake): require GTK>=3.24/GLib>=2.76, GStreamer 1.x only; prefer Ayatana tray; libcurl via pkg-config; default to OpenSSL; keep GnuTLS/libgcrypt optional * cmake: guard pkg-config usage by availability --- CMakeLists.txt | 315 +++++++++++++++++++++++++------------------ cmake/config.h.in | 6 +- tests/CMakeLists.txt | 62 +++------ 3 files changed, 202 insertions(+), 181 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20d11ff..8312bc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,12 @@ set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) +option(WITH_GUI "Build GTK-based UI and GStreamer integrations" ON) +option(WITH_TRAY "Build system tray integration (requires GUI)" ON) +option(WITH_OPENSSL "Enable OpenSSL-based crypto/TLS" ON) +option(WITH_GNUTLS "Enable GnuTLS/libgcrypt backend" OFF) +option(WITH_PWMD "Enable libpwmd integration" ON) option(ENABLE_SANITIZERS "Enable ASan/UBSan in Debug on non-MSVC builds" ON) -option(WITH_GUI "Enable GTK-based GUI components" ON) if(MSVC) add_compile_options(/W4 /permissive- /utf-8) @@ -31,6 +35,8 @@ else() message(STATUS "pkg-config not found on PATH yet; FindPkgConfig may fail unless the toolchain provides it.") endif() +find_package(PkgConfig QUIET) + # Feature test macros on non-MSVC to expose POSIX prototypes (getaddrinfo, ftruncate, popen, etc.) if(NOT MSVC) add_compile_definitions(_GNU_SOURCE) @@ -83,29 +89,87 @@ check_symbol_exists(popen "stdio.h" HAVE_POPEN) check_symbol_exists(pclose "stdio.h" HAVE_PCLOSE) # pkg-config deps +if(NOT WITH_GUI AND WITH_TRAY) + message(STATUS "WITH_GUI=OFF -> disabling system tray support") + set(WITH_TRAY OFF CACHE BOOL "" FORCE) +endif() + set(HAVE_GTK 0) set(HAVE_GSTREAMER 0) set(HAVE_GLIB 0) +set(HAVE_CURL 0) + +set(_uget_private_include_dirs) +set(_uget_private_library_dirs) +set(_uget_private_libraries) +set(_uget_private_compile_options) if(WITH_GUI) - if(NOT DEFINED PkgConfig_FOUND OR NOT PkgConfig_FOUND) - find_package(PkgConfig REQUIRED) + if(PkgConfig_FOUND) + pkg_check_modules(GTK REQUIRED gtk+-3.0>=3.24) + pkg_check_modules(GLIB REQUIRED glib-2.0>=2.76 gobject-2.0) + pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-base-1.0) + add_compile_definitions(HAVE_GLIB=1) + + set(HAVE_GTK 1) + set(HAVE_GSTREAMER 1) + set(HAVE_GLIB 1) + + list(APPEND _uget_private_include_dirs + ${GTK_INCLUDE_DIRS} + ${GLIB_INCLUDE_DIRS} + ${GST_INCLUDE_DIRS}) + list(APPEND _uget_private_library_dirs + ${GTK_LIBRARY_DIRS} + ${GLIB_LIBRARY_DIRS} + ${GST_LIBRARY_DIRS}) + list(APPEND _uget_private_libraries + ${GTK_LIBRARIES} + ${GLIB_LIBRARIES} + ${GST_LIBRARIES}) + list(APPEND _uget_private_compile_options + ${GTK_CFLAGS_OTHER} + ${GLIB_CFLAGS_OTHER} + ${GST_CFLAGS_OTHER}) + else() + message(FATAL_ERROR "WITH_GUI=ON but pkg-config is unavailable on this toolchain.") endif() - pkg_check_modules(GTK REQUIRED gtk+-3.0>=3.24) - pkg_check_modules(GLIB REQUIRED glib-2.0>=2.76 gobject-2.0) - pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-base-1.0) - - set(HAVE_GTK ${GTK_FOUND}) - set(HAVE_GSTREAMER ${GST_FOUND}) - set(HAVE_GLIB ${GLIB_FOUND}) else() message(STATUS "WITH_GUI=OFF: skipping GTK/GLib/GStreamer detection") endif() -if(NOT DEFINED PkgConfig_FOUND OR NOT PkgConfig_FOUND) - find_package(PkgConfig REQUIRED) +if(WIN32) + find_package(CURL REQUIRED) + if(TARGET CURL::libcurl) + set(LIBCURL_LIBRARIES CURL::libcurl) + endif() + set(HAVE_CURL 1) +else() + if(PkgConfig_FOUND) + pkg_check_modules(LIBCURL REQUIRED libcurl) + set(HAVE_CURL 1) + else() + message(FATAL_ERROR "libcurl detection on this platform requires pkg-config.") + endif() +endif() + +if(WIN32) + set(UGET_CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIRS}) + set(UGET_CURL_LIBRARY_DIRS "") + set(UGET_CURL_LIBRARIES ${CURL_LIBRARIES}) + set(UGET_CURL_CFLAGS_OTHER "") +else() + set(UGET_CURL_INCLUDE_DIRS ${LIBCURL_INCLUDE_DIRS}) + set(UGET_CURL_LIBRARY_DIRS ${LIBCURL_LIBRARY_DIRS}) + set(UGET_CURL_LIBRARIES ${LIBCURL_LIBRARIES}) + set(UGET_CURL_CFLAGS_OTHER ${LIBCURL_CFLAGS_OTHER}) endif() -pkg_check_modules(CURL REQUIRED libcurl) + +list(APPEND _uget_private_include_dirs ${UGET_CURL_INCLUDE_DIRS}) +list(APPEND _uget_private_library_dirs ${UGET_CURL_LIBRARY_DIRS}) +list(APPEND _uget_private_libraries ${UGET_CURL_LIBRARIES}) +list(APPEND _uget_private_compile_options ${UGET_CURL_CFLAGS_OTHER}) + find_package(Threads REQUIRED) include(CTest) @@ -113,39 +177,126 @@ if(NOT BUILD_TESTING) message(STATUS "BUILD_TESTING=OFF: test targets will not be generated") endif() -set(HAVE_CURL ${CURL_FOUND}) - -# ---------- Feature toggles (default ON; compile gracefully without them) ---------- -option(WITH_TRAY "Enable system tray indicator" ON) -option(WITH_PWMD "Enable libpwmd integration" ON) -option(WITH_GNUTLS "Enable GnuTLS backend" ON) -option(WITH_OPENSSL "Enable OpenSSL backend" ON) -option(WITH_GCRYPT "Enable libgcrypt usage" ON) - set(HAVE_TRAY 0) -set(HAVE_TRAY_AYATANA 0) -set(HAVE_TRAY_APPINDICATOR 0) +set(HAVE_AYATANA 0) +set(HAVE_APPINDICATOR 0) set(HAVE_PWMD 0) set(HAVE_GNUTLS 0) set(HAVE_OPENSSL 0) -set(HAVE_GCRYPT 0) +set(HAVE_LIBGCRYPT 0) + +# ---------- TRAY (Ayatana/AppIndicator) ---------- +if(WITH_GUI AND WITH_TRAY) + if(PkgConfig_FOUND) + pkg_check_modules(AYATANA QUIET ayatana-appindicator3-0.1) + if(AYATANA_FOUND) + add_compile_definitions(HAVE_AYATANA=1) + list(APPEND _uget_private_include_dirs ${AYATANA_INCLUDE_DIRS}) + list(APPEND _uget_private_library_dirs ${AYATANA_LIBRARY_DIRS}) + list(APPEND _uget_private_libraries ${AYATANA_LIBRARIES}) + set(HAVE_TRAY 1) + set(HAVE_AYATANA 1) + message(STATUS "Tray: using ayatana-appindicator3") + else() + pkg_check_modules(APPINDICATOR QUIET appindicator3-0.1) + if(APPINDICATOR_FOUND) + add_compile_definitions(HAVE_APPINDICATOR=1) + list(APPEND _uget_private_include_dirs ${APPINDICATOR_INCLUDE_DIRS}) + list(APPEND _uget_private_library_dirs ${APPINDICATOR_LIBRARY_DIRS}) + list(APPEND _uget_private_libraries ${APPINDICATOR_LIBRARIES}) + set(HAVE_TRAY 1) + set(HAVE_APPINDICATOR 1) + message(STATUS "Tray: using appindicator3-0.1 (fallback)") + else() + message(STATUS "Tray requested, but no Ayatana/AppIndicator found -> tray disabled") + set(WITH_TRAY OFF CACHE BOOL "" FORCE) + endif() + endif() + else() + message(FATAL_ERROR "WITH_TRAY=ON requires pkg-config.") + endif() +elseif(WITH_TRAY) + message(STATUS "WITH_TRAY requested but WITH_GUI=OFF -> disabling tray support") + set(WITH_TRAY OFF CACHE BOOL "" FORCE) +endif() + +# ---------- PWMD ---------- +if(WITH_PWMD) + if(PkgConfig_FOUND) + pkg_check_modules(PWMD QUIET libpwmd) + if(PWMD_FOUND) + list(APPEND _uget_private_include_dirs ${PWMD_INCLUDE_DIRS}) + list(APPEND _uget_private_library_dirs ${PWMD_LIBRARY_DIRS}) + list(APPEND _uget_private_libraries ${PWMD_LIBRARIES}) + set(HAVE_PWMD 1) + message(STATUS "PWMD: enabled") + else() + message(STATUS "PWMD: not found; disabling") + endif() + else() + message(FATAL_ERROR "WITH_PWMD=ON requires pkg-config.") + endif() +endif() + +# ---------- Crypto/TLS backends ---------- +if(WITH_OPENSSL) + find_package(OpenSSL REQUIRED) + add_compile_definitions(HAVE_OPENSSL=1) + list(APPEND _uget_private_libraries OpenSSL::SSL OpenSSL::Crypto) + set(HAVE_OPENSSL 1) +endif() + +if(WITH_GNUTLS) + if(PkgConfig_FOUND) + pkg_check_modules(GNUTLS REQUIRED gnutls) + pkg_check_modules(GCRYPT REQUIRED libgcrypt) + add_compile_definitions(HAVE_GNUTLS=1 HAVE_LIBGCRYPT=1) + set(HAVE_GNUTLS 1) + set(HAVE_LIBGCRYPT 1) + + list(APPEND _uget_private_include_dirs ${GNUTLS_INCLUDE_DIRS} ${GCRYPT_INCLUDE_DIRS}) + list(APPEND _uget_private_library_dirs ${GNUTLS_LIBRARY_DIRS} ${GCRYPT_LIBRARY_DIRS}) + list(APPEND _uget_private_libraries ${GNUTLS_LIBRARIES} ${GCRYPT_LIBRARIES}) + else() + message(FATAL_ERROR "WITH_GNUTLS=ON requires pkg-config.") + endif() +endif() # TEMP: discover sources (to be replaced with explicit lists later) file(GLOB_RECURSE CORE_SRC CONFIGURE_DEPENDS src/*.c) add_library(core STATIC ${CORE_SRC}) target_include_directories(core PUBLIC ${CMAKE_SOURCE_DIR}/include) -target_compile_options(core PRIVATE ${GTK_CFLAGS_OTHER} ${GLIB_CFLAGS_OTHER} ${GST_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) -target_include_directories(core PRIVATE ${GTK_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) -target_link_directories(core PRIVATE ${GTK_LIBRARY_DIRS} ${GLIB_LIBRARY_DIRS} ${GST_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) target_compile_definitions(core PRIVATE HAVE_CONFIG_H) target_include_directories(core PRIVATE ${CMAKE_BINARY_DIR}/generated) +if(_uget_private_compile_options) + target_compile_options(core PRIVATE ${_uget_private_compile_options}) +endif() +if(_uget_private_include_dirs) + target_include_directories(core PRIVATE ${_uget_private_include_dirs}) +endif() +if(_uget_private_library_dirs) + target_link_directories(core PRIVATE ${_uget_private_library_dirs}) +endif() +if(_uget_private_libraries) + target_link_libraries(core PRIVATE ${_uget_private_libraries}) +endif() + add_executable(app src/main.c) # adjust if main file differs -target_link_libraries(app PRIVATE core - ${GTK_LIBRARIES} ${GLIB_LIBRARIES} ${GST_LIBRARIES} ${CURL_LIBRARIES}) -target_compile_options(app PRIVATE ${GTK_CFLAGS_OTHER} ${GLIB_CFLAGS_OTHER} ${GST_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) -target_include_directories(app PRIVATE ${GTK_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) -target_link_directories(app PRIVATE ${GTK_LIBRARY_DIRS} ${GLIB_LIBRARY_DIRS} ${GST_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +target_link_libraries(app PRIVATE core) + +if(_uget_private_compile_options) + target_compile_options(app PRIVATE ${_uget_private_compile_options}) +endif() +if(_uget_private_include_dirs) + target_include_directories(app PRIVATE ${_uget_private_include_dirs}) +endif() +if(_uget_private_library_dirs) + target_link_directories(app PRIVATE ${_uget_private_library_dirs}) +endif() +if(_uget_private_libraries) + target_link_libraries(app PRIVATE ${_uget_private_libraries}) +endif() # --- Project-wide compile warnings (already set globally, but ensure targets inherit) --- if(MSVC) @@ -165,104 +316,6 @@ if(ENABLE_SANITIZERS AND CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT MSVC) target_link_options( app PRIVATE -fsanitize=address,undefined) endif() -# ---------- TRAY (Ayatana/AppIndicator) ---------- -if(WITH_TRAY) - pkg_check_modules(AYATANA QUIET ayatana-appindicator3-0.1) - if(AYATANA_FOUND) - target_include_directories(core PRIVATE ${AYATANA_INCLUDE_DIRS}) - target_link_directories(core PRIVATE ${AYATANA_LIBRARY_DIRS}) - target_link_libraries(core PRIVATE ${AYATANA_LIBRARIES}) - target_compile_definitions(core PRIVATE HAVE_TRAY=1 HAVE_TRAY_AYATANA=1) - set(HAVE_TRAY 1) - set(HAVE_TRAY_AYATANA 1) - message(STATUS "Tray: using ayatana-appindicator3") - else() - pkg_check_modules(APPIND QUIET appindicator3-0.1) - if(APPIND_FOUND) - target_include_directories(core PRIVATE ${APPIND_INCLUDE_DIRS}) - target_link_directories(core PRIVATE ${APPIND_LIBRARY_DIRS}) - target_link_libraries(core PRIVATE ${APPIND_LIBRARIES}) - target_compile_definitions(core PRIVATE HAVE_TRAY=1 HAVE_TRAY_APPINDICATOR=1) - set(HAVE_TRAY 1) - set(HAVE_TRAY_APPINDICATOR 1) - message(STATUS "Tray: using appindicator3-0.1 (legacy)") - else() - message(STATUS "Tray: disabled (ayatana/appindicator not found)") - endif() - endif() -endif() - -# ---------- PWMD ---------- -if(WITH_PWMD) - pkg_check_modules(PWMD QUIET libpwmd) - if(PWMD_FOUND) - target_include_directories(core PRIVATE ${PWMD_INCLUDE_DIRS}) - target_link_directories(core PRIVATE ${PWMD_LIBRARY_DIRS}) - target_link_libraries(core PRIVATE ${PWMD_LIBRARIES}) - target_compile_definitions(core PRIVATE HAVE_PWMD=1) - set(HAVE_PWMD 1) - message(STATUS "PWMD: enabled") - else() - message(STATUS "PWMD: not found; disabling") - endif() -endif() - -# ---------- Crypto/TLS backends ---------- -if(WITH_GNUTLS) - pkg_check_modules(GNUTLS QUIET gnutls) - if(GNUTLS_FOUND) - target_include_directories(core PRIVATE ${GNUTLS_INCLUDE_DIRS}) - target_link_directories(core PRIVATE ${GNUTLS_LIBRARY_DIRS}) - target_link_libraries(core PRIVATE ${GNUTLS_LIBRARIES}) - target_compile_definitions(core PRIVATE HAVE_GNUTLS=1) - set(HAVE_GNUTLS 1) - message(STATUS "TLS: GnuTLS enabled") - else() - message(STATUS "TLS: GnuTLS not found") - endif() -endif() - -if(WITH_OPENSSL) - # Prefer 'openssl' pkg (provides crypto/ssl). On some distros it's 'openssl', on others split: - pkg_check_modules(OPENSSL QUIET openssl) - if(OPENSSL_FOUND) - target_include_directories(core PRIVATE ${OPENSSL_INCLUDE_DIRS}) - target_link_directories(core PRIVATE ${OPENSSL_LIBRARY_DIRS}) - target_link_libraries(core PRIVATE ${OPENSSL_LIBRARIES}) - target_compile_definitions(core PRIVATE HAVE_OPENSSL=1) - set(HAVE_OPENSSL 1) - message(STATUS "TLS: OpenSSL enabled") - else() - # Fallback separate crypto/ssl (if available in your environment) - pkg_check_modules(LIBSSL QUIET libssl) - pkg_check_modules(LIBCRYPTO QUIET libcrypto) - if(LIBSSL_FOUND AND LIBCRYPTO_FOUND) - target_include_directories(core PRIVATE ${LIBSSL_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS}) - target_link_directories(core PRIVATE ${LIBSSL_LIBRARY_DIRS} ${LIBCRYPTO_LIBRARY_DIRS}) - target_link_libraries(core PRIVATE ${LIBSSL_LIBRARIES} ${LIBCRYPTO_LIBRARIES}) - target_compile_definitions(core PRIVATE HAVE_OPENSSL=1) - set(HAVE_OPENSSL 1) - message(STATUS "TLS: OpenSSL (split ssl/crypto) enabled") - else() - message(STATUS "TLS: OpenSSL not found") - endif() - endif() -endif() - -if(WITH_GCRYPT) - pkg_check_modules(GCRYPT QUIET libgcrypt) - if(GCRYPT_FOUND) - target_include_directories(core PRIVATE ${GCRYPT_INCLUDE_DIRS}) - target_link_directories(core PRIVATE ${GCRYPT_LIBRARY_DIRS}) - target_link_libraries(core PRIVATE ${GCRYPT_LIBRARIES}) - target_compile_definitions(core PRIVATE HAVE_GCRYPT=1) - set(HAVE_GCRYPT 1) - message(STATUS "Crypto: libgcrypt enabled") - else() - message(STATUS "Crypto: libgcrypt not found") - endif() -endif() - configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in ${CMAKE_BINARY_DIR}/generated/config.h @ONLY) include_directories(${CMAKE_BINARY_DIR}/generated) diff --git a/cmake/config.h.in b/cmake/config.h.in index 34268f7..f2d3d19 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -8,12 +8,12 @@ /* Feature toggles generated by CMake */ #cmakedefine01 HAVE_TRAY -#cmakedefine01 HAVE_TRAY_AYATANA -#cmakedefine01 HAVE_TRAY_APPINDICATOR +#cmakedefine01 HAVE_AYATANA +#cmakedefine01 HAVE_APPINDICATOR #cmakedefine01 HAVE_PWMD #cmakedefine01 HAVE_GNUTLS #cmakedefine01 HAVE_OPENSSL -#cmakedefine01 HAVE_GCRYPT +#cmakedefine01 HAVE_LIBGCRYPT /* Autoconf-like header availability */ #cmakedefine01 HAVE_SYS_TYPES_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8bca7f7..6351eef 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -40,16 +40,16 @@ target_include_directories(uglib PUBLIC ${CMAKE_SOURCE_DIR}/uglib ${GLIB_INCLUDE_DIRS} - ${CURL_INCLUDE_DIRS} + ${UGET_CURL_INCLUDE_DIRS} ) -target_link_directories(uglib PUBLIC ${GLIB_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +target_link_directories(uglib PUBLIC ${GLIB_LIBRARY_DIRS} ${UGET_CURL_LIBRARY_DIRS}) target_link_libraries(uglib PUBLIC Threads::Threads ${GLIB_LIBRARIES} - ${CURL_LIBRARIES} + ${UGET_CURL_LIBRARIES} ) -target_compile_options(uglib PRIVATE ${GLIB_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) +target_compile_options(uglib PRIVATE ${GLIB_CFLAGS_OTHER} ${UGET_CURL_CFLAGS_OTHER}) target_compile_definitions(uglib PUBLIC HAVE_CONFIG_H) set(UGET_SOURCES @@ -81,7 +81,7 @@ set(UGET_SOURCES ) set(_uget_has_mega FALSE) -if(HAVE_GCRYPT AND HAVE_OPENSSL) +if(HAVE_LIBGCRYPT AND HAVE_OPENSSL) list(APPEND UGET_SOURCES ${CMAKE_SOURCE_DIR}/uget/UgetPluginMega.c) set(_uget_has_mega TRUE) else() @@ -98,17 +98,17 @@ target_include_directories(uget ${CMAKE_SOURCE_DIR}/uget ${CMAKE_SOURCE_DIR}/uglib ${GLIB_INCLUDE_DIRS} - ${CURL_INCLUDE_DIRS} + ${UGET_CURL_INCLUDE_DIRS} ) -target_link_directories(uget PUBLIC ${GLIB_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS}) +target_link_directories(uget PUBLIC ${GLIB_LIBRARY_DIRS} ${UGET_CURL_LIBRARY_DIRS}) target_link_libraries(uget PUBLIC uglib Threads::Threads ${GLIB_LIBRARIES} - ${CURL_LIBRARIES} + ${UGET_CURL_LIBRARIES} ) -target_compile_options(uget PRIVATE ${GLIB_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) +target_compile_options(uget PRIVATE ${GLIB_CFLAGS_OTHER} ${UGET_CURL_CFLAGS_OTHER}) target_compile_definitions(uget PUBLIC HAVE_CONFIG_H) if(HAVE_PWMD) @@ -118,45 +118,13 @@ if(HAVE_PWMD) endif() if(HAVE_GNUTLS) - target_include_directories(uget PUBLIC ${GNUTLS_INCLUDE_DIRS}) - target_link_directories(uget PUBLIC ${GNUTLS_LIBRARY_DIRS}) - target_link_libraries(uget PUBLIC ${GNUTLS_LIBRARIES}) + target_include_directories(uget PUBLIC ${GNUTLS_INCLUDE_DIRS} ${GCRYPT_INCLUDE_DIRS}) + target_link_directories(uget PUBLIC ${GNUTLS_LIBRARY_DIRS} ${GCRYPT_LIBRARY_DIRS}) + target_link_libraries(uget PUBLIC ${GNUTLS_LIBRARIES} ${GCRYPT_LIBRARIES}) endif() if(HAVE_OPENSSL) - set(_openssl_include_dirs) - set(_openssl_library_dirs) - set(_openssl_libs) - if(OPENSSL_FOUND) - list(APPEND _openssl_include_dirs ${OPENSSL_INCLUDE_DIRS}) - list(APPEND _openssl_library_dirs ${OPENSSL_LIBRARY_DIRS}) - list(APPEND _openssl_libs ${OPENSSL_LIBRARIES}) - endif() - if(LIBSSL_FOUND) - list(APPEND _openssl_include_dirs ${LIBSSL_INCLUDE_DIRS}) - list(APPEND _openssl_library_dirs ${LIBSSL_LIBRARY_DIRS}) - list(APPEND _openssl_libs ${LIBSSL_LIBRARIES}) - endif() - if(LIBCRYPTO_FOUND) - list(APPEND _openssl_include_dirs ${LIBCRYPTO_INCLUDE_DIRS}) - list(APPEND _openssl_library_dirs ${LIBCRYPTO_LIBRARY_DIRS}) - list(APPEND _openssl_libs ${LIBCRYPTO_LIBRARIES}) - endif() - if(_openssl_include_dirs) - target_include_directories(uget PUBLIC ${_openssl_include_dirs}) - endif() - if(_openssl_library_dirs) - target_link_directories(uget PUBLIC ${_openssl_library_dirs}) - endif() - if(_openssl_libs) - target_link_libraries(uget PUBLIC ${_openssl_libs}) - endif() -endif() - -if(HAVE_GCRYPT) - target_include_directories(uget PUBLIC ${GCRYPT_INCLUDE_DIRS}) - target_link_directories(uget PUBLIC ${GCRYPT_LIBRARY_DIRS}) - target_link_libraries(uget PUBLIC ${GCRYPT_LIBRARIES}) + target_link_libraries(uget PUBLIC OpenSSL::SSL OpenSSL::Crypto) endif() function(add_uget_test target) @@ -175,10 +143,10 @@ function(add_uget_test target) ${CMAKE_SOURCE_DIR}/uglib ${CMAKE_SOURCE_DIR}/uget ${GLIB_INCLUDE_DIRS} - ${CURL_INCLUDE_DIRS} + ${UGET_CURL_INCLUDE_DIRS} ${CMAKE_BINARY_DIR}/generated ) - target_compile_options(${target} PRIVATE ${GLIB_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER}) + target_compile_options(${target} PRIVATE ${GLIB_CFLAGS_OTHER} ${UGET_CURL_CFLAGS_OTHER}) target_compile_definitions(${target} PRIVATE HAVE_CONFIG_H) add_test(NAME ${target} COMMAND ${target}) From 660d598cc9f27449a66a80eac711d0ff4355ef89 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Fri, 26 Sep 2025 04:11:10 +0300 Subject: [PATCH 19/26] Retire legacy build tooling (#8) --- CMakeLists.txt | 2 +- Makefile.am | 20 -- Windows/Makefile.am | 28 --- Windows/msvc/test-json.vcxproj | 103 ----------- Windows/msvc/test-jsonrpc.vcxproj | 89 --------- Windows/msvc/test-plugin+app.vcxproj | 103 ----------- Windows/msvc/test-uget.vcxproj | 103 ----------- Windows/msvc/test-uglib.vcxproj | 103 ----------- Windows/msvc/uget.sln | 79 -------- Windows/msvc/uget.vcxproj | 124 ------------- Windows/msvc/uglib.vcxproj | 132 ------------- Windows/msvc/ui-gtk.vcxproj | 155 ---------------- autogen.sh | 36 ---- configure.ac | 265 --------------------------- doc/Makefile.am | 6 - doc/To_build_uGet_in_MinGW.txt | 20 -- docs/BUILDING.md | 57 ++++++ docs/BUILD_WINDOWS.md | 5 + docs/DEVELOPER.md | 1 + pixmaps/Makefile.am | 48 ----- sounds/Makefile.am | 6 - tests/Makefile.am | 50 ----- uget/Android.mk | 37 ---- uget/Makefile.am | 74 -------- uglib/Android.mk | 37 ---- uglib/Makefile.am | 76 -------- ui-gtk-1to2/Makefile.am | 40 ---- ui-gtk/Makefile.am | 62 ------- 28 files changed, 64 insertions(+), 1797 deletions(-) delete mode 100644 Makefile.am delete mode 100644 Windows/Makefile.am delete mode 100644 Windows/msvc/test-json.vcxproj delete mode 100644 Windows/msvc/test-jsonrpc.vcxproj delete mode 100644 Windows/msvc/test-plugin+app.vcxproj delete mode 100644 Windows/msvc/test-uget.vcxproj delete mode 100644 Windows/msvc/test-uglib.vcxproj delete mode 100644 Windows/msvc/uget.sln delete mode 100644 Windows/msvc/uget.vcxproj delete mode 100644 Windows/msvc/uglib.vcxproj delete mode 100644 Windows/msvc/ui-gtk.vcxproj delete mode 100644 autogen.sh delete mode 100644 configure.ac delete mode 100644 doc/Makefile.am delete mode 100644 doc/To_build_uGet_in_MinGW.txt create mode 100644 docs/BUILDING.md delete mode 100644 pixmaps/Makefile.am delete mode 100644 sounds/Makefile.am delete mode 100644 tests/Makefile.am delete mode 100644 uget/Android.mk delete mode 100644 uget/Makefile.am delete mode 100644 uglib/Android.mk delete mode 100644 uglib/Makefile.am delete mode 100644 ui-gtk-1to2/Makefile.am delete mode 100644 ui-gtk/Makefile.am diff --git a/CMakeLists.txt b/CMakeLists.txt index 8312bc6..47c9bbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.28) +cmake_minimum_required(VERSION 3.24) project(ModernizedApp VERSION 2.3.0 LANGUAGES C) set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "Verbose build" FORCE) diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 0003b59..0000000 --- a/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# intltool : add "po" in SUBDIRS - -SUBDIRS = \ - uglib \ - uget \ - ui-gtk \ - ui-gtk-1to2 \ - pixmaps \ - sounds \ - tests \ - po \ - doc \ - Windows - -EXTRA_DIST = \ - uget-gtk.desktop \ - .snapcraft.yaml - -appsdir = $(datadir)/applications -apps_DATA = uget-gtk.desktop diff --git a/Windows/Makefile.am b/Windows/Makefile.am deleted file mode 100644 index b8c2588..0000000 --- a/Windows/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -EXTRA_DIST = \ - resources/uget.rc \ - resources/uget-icon.ico \ - msvc/msvc-config.txt \ - msvc/stdint.h \ - msvc/test-json.vcxproj \ - msvc/test-jsonrpc.vcxproj \ - msvc/test-plugin+app.vcxproj \ - msvc/test-uget.vcxproj \ - msvc/test-uglib.vcxproj \ - msvc/uget.sln \ - msvc/uget.vcxproj \ - msvc/uglib.vcxproj \ - msvc/ui-gtk.vcxproj \ - CodeBlocks/mingw-config.txt \ - CodeBlocks/test-json.cbp \ - CodeBlocks/test-jsonrpc.cbp \ - CodeBlocks/test-plugin+app.cbp \ - CodeBlocks/test-uget.cbp \ - CodeBlocks/test-uget-cxx.cbp \ - CodeBlocks/test-uglib.cbp \ - CodeBlocks/test-uglib-cxx.cbp \ - CodeBlocks/uget.cbp \ - CodeBlocks/uglib.cbp \ - CodeBlocks/ui-gtk.cbp \ - CodeBlocks/ui-gtk-1to2.cbp \ - CodeBlocks/uget.workspace - diff --git a/Windows/msvc/test-json.vcxproj b/Windows/msvc/test-json.vcxproj deleted file mode 100644 index 49a1374..0000000 --- a/Windows/msvc/test-json.vcxproj +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {D0C49F36-9ECC-4B87-9360-A7EE570DA73C} - testjson - Win32Proj - - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - false - - - - Disabled - ..\..\uglib;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - uglib.lib;glib-2.0.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;Debug;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - MaxSpeed - true - ..\..\uglib;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - - - uglib.lib;glib-2.0.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;Release;%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - - - - - - - - {8e8a46b4-6b62-4bd0-bcaf-ba9cf1090dea} - false - - - - - - \ No newline at end of file diff --git a/Windows/msvc/test-jsonrpc.vcxproj b/Windows/msvc/test-jsonrpc.vcxproj deleted file mode 100644 index 8756f52..0000000 --- a/Windows/msvc/test-jsonrpc.vcxproj +++ /dev/null @@ -1,89 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {BE2BF360-69F6-406F-A89D-77B0F9A92C04} - Win32Proj - testjsonrpc - - - - Application - true - Unicode - - - Application - false - Unicode - - - - - - - - - - - - - true - - - false - - - - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - Level3 - Disabled - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;%(PreprocessorDefinitions) - - - - - uglib.lib;glib-2.0.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;D:\devpack\curl-msvc\lib\Debug;Debug;%(AdditionalLibraryDirectories) - true - uglib.lib;uget.lib;Ws2_32.lib;curllib.lib;glib-2.0.lib;intl.lib;%(AdditionalDependencies) - Console - - - - - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - Level3 - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;%(PreprocessorDefinitions) - - - - - uglib.lib;glib-2.0.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;D:\devpack\curl-msvc\lib\Release;Release;%(AdditionalLibraryDirectories) - true - uglib.lib;uget.lib;Ws2_32.lib;curllib.lib;glib-2.0.lib;intl.lib;%(AdditionalDependencies) - Console - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Windows/msvc/test-plugin+app.vcxproj b/Windows/msvc/test-plugin+app.vcxproj deleted file mode 100644 index 4b5ce0b..0000000 --- a/Windows/msvc/test-plugin+app.vcxproj +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {CAD0E048-8211-4F6B-9975-215A526AC645} - testjson - Win32Proj - - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - false - - - - Disabled - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - uglib.lib;uget.lib;Ws2_32.lib;curllib.lib;glib-2.0.lib;intl.lib;%(AdditionalDependencies) - D:\devpack\curl-msvc\lib\Debug;D:\devpack\gtk3-msvc\lib;Debug;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - MaxSpeed - true - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - - - uglib.lib;uget.lib;Ws2_32.lib;curllib.lib;glib-2.0.lib;intl.lib;%(AdditionalDependencies) - D:\devpack\curl-msvc\lib\Release;D:\devpack\gtk3-msvc\lib;Release;%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - - - - - {8e8a46b4-6b62-4bd0-bcaf-ba9cf1090dea} - false - - - - - - - - - \ No newline at end of file diff --git a/Windows/msvc/test-uget.vcxproj b/Windows/msvc/test-uget.vcxproj deleted file mode 100644 index a46ab9d..0000000 --- a/Windows/msvc/test-uget.vcxproj +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {FFAC27EA-E43A-4A78-924D-41E868A4F27F} - testuget - Win32Proj - - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - false - - - - Disabled - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - uglib.lib;uget.lib;Ws2_32.lib;curllib.lib;glib-2.0.lib;intl.lib;%(AdditionalDependencies) - D:\devpack\curl-msvc\lib\Debug;D:\devpack\gtk3-msvc\lib;Debug;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - MaxSpeed - true - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - - - uglib.lib;uget.lib;Ws2_32.lib;curllib.lib;glib-2.0.lib;intl.lib;%(AdditionalDependencies) - D:\devpack\curl-msvc\lib\Release;D:\devpack\gtk3-msvc\lib;Release;%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - - - - - - - - {8e8a46b4-6b62-4bd0-bcaf-ba9cf1090dea} - false - - - - - - \ No newline at end of file diff --git a/Windows/msvc/test-uglib.vcxproj b/Windows/msvc/test-uglib.vcxproj deleted file mode 100644 index 5091680..0000000 --- a/Windows/msvc/test-uglib.vcxproj +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {A5591A27-B27A-4FF2-88E6-E6C534C96E02} - testuglib - Win32Proj - - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - false - - - - Disabled - ..\..\uglib;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - uglib.lib;glib-2.0.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;Debug;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - MaxSpeed - true - ..\..\uglib;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;_CONSOLE;HAVE_GLIB;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - - - uglib.lib;glib-2.0.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;Release;%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - - - - - - - - {8e8a46b4-6b62-4bd0-bcaf-ba9cf1090dea} - false - - - - - - \ No newline at end of file diff --git a/Windows/msvc/uget.sln b/Windows/msvc/uget.sln deleted file mode 100644 index 0c1d6a1..0000000 --- a/Windows/msvc/uget.sln +++ /dev/null @@ -1,79 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual C++ Express 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uglib", "uglib.vcxproj", "{8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-json", "test-json.vcxproj", "{D0C49F36-9ECC-4B87-9360-A7EE570DA73C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uget", "uget.vcxproj", "{A98D36E8-7119-4AC4-8820-65B902C6B69E}" - ProjectSection(ProjectDependencies) = postProject - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA} = {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-plugin+app", "test-plugin+app.vcxproj", "{CAD0E048-8211-4F6B-9975-215A526AC645}" - ProjectSection(ProjectDependencies) = postProject - {A98D36E8-7119-4AC4-8820-65B902C6B69E} = {A98D36E8-7119-4AC4-8820-65B902C6B69E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ui-gtk", "ui-gtk.vcxproj", "{9D164547-3F37-4C14-BCCE-91EB2F3DC317}" - ProjectSection(ProjectDependencies) = postProject - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA} = {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA} - {A98D36E8-7119-4AC4-8820-65B902C6B69E} = {A98D36E8-7119-4AC4-8820-65B902C6B69E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-jsonrpc", "test-jsonrpc.vcxproj", "{BE2BF360-69F6-406F-A89D-77B0F9A92C04}" - ProjectSection(ProjectDependencies) = postProject - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA} = {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA} - {A98D36E8-7119-4AC4-8820-65B902C6B69E} = {A98D36E8-7119-4AC4-8820-65B902C6B69E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-uglib", "test-uglib.vcxproj", "{A5591A27-B27A-4FF2-88E6-E6C534C96E02}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-uget", "test-uget.vcxproj", "{FFAC27EA-E43A-4A78-924D-41E868A4F27F}" - ProjectSection(ProjectDependencies) = postProject - {A98D36E8-7119-4AC4-8820-65B902C6B69E} = {A98D36E8-7119-4AC4-8820-65B902C6B69E} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA}.Debug|Win32.ActiveCfg = Debug|Win32 - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA}.Debug|Win32.Build.0 = Debug|Win32 - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA}.Release|Win32.ActiveCfg = Release|Win32 - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA}.Release|Win32.Build.0 = Release|Win32 - {D0C49F36-9ECC-4B87-9360-A7EE570DA73C}.Debug|Win32.ActiveCfg = Debug|Win32 - {D0C49F36-9ECC-4B87-9360-A7EE570DA73C}.Debug|Win32.Build.0 = Debug|Win32 - {D0C49F36-9ECC-4B87-9360-A7EE570DA73C}.Release|Win32.ActiveCfg = Release|Win32 - {D0C49F36-9ECC-4B87-9360-A7EE570DA73C}.Release|Win32.Build.0 = Release|Win32 - {A98D36E8-7119-4AC4-8820-65B902C6B69E}.Debug|Win32.ActiveCfg = Debug|Win32 - {A98D36E8-7119-4AC4-8820-65B902C6B69E}.Debug|Win32.Build.0 = Debug|Win32 - {A98D36E8-7119-4AC4-8820-65B902C6B69E}.Release|Win32.ActiveCfg = Release|Win32 - {A98D36E8-7119-4AC4-8820-65B902C6B69E}.Release|Win32.Build.0 = Release|Win32 - {CAD0E048-8211-4F6B-9975-215A526AC645}.Debug|Win32.ActiveCfg = Debug|Win32 - {CAD0E048-8211-4F6B-9975-215A526AC645}.Debug|Win32.Build.0 = Debug|Win32 - {CAD0E048-8211-4F6B-9975-215A526AC645}.Release|Win32.ActiveCfg = Release|Win32 - {CAD0E048-8211-4F6B-9975-215A526AC645}.Release|Win32.Build.0 = Release|Win32 - {9D164547-3F37-4C14-BCCE-91EB2F3DC317}.Debug|Win32.ActiveCfg = Debug|Win32 - {9D164547-3F37-4C14-BCCE-91EB2F3DC317}.Debug|Win32.Build.0 = Debug|Win32 - {9D164547-3F37-4C14-BCCE-91EB2F3DC317}.Release|Win32.ActiveCfg = Release|Win32 - {9D164547-3F37-4C14-BCCE-91EB2F3DC317}.Release|Win32.Build.0 = Release|Win32 - {BE2BF360-69F6-406F-A89D-77B0F9A92C04}.Debug|Win32.ActiveCfg = Debug|Win32 - {BE2BF360-69F6-406F-A89D-77B0F9A92C04}.Debug|Win32.Build.0 = Debug|Win32 - {BE2BF360-69F6-406F-A89D-77B0F9A92C04}.Release|Win32.ActiveCfg = Release|Win32 - {BE2BF360-69F6-406F-A89D-77B0F9A92C04}.Release|Win32.Build.0 = Release|Win32 - {A5591A27-B27A-4FF2-88E6-E6C534C96E02}.Debug|Win32.ActiveCfg = Debug|Win32 - {A5591A27-B27A-4FF2-88E6-E6C534C96E02}.Debug|Win32.Build.0 = Debug|Win32 - {A5591A27-B27A-4FF2-88E6-E6C534C96E02}.Release|Win32.ActiveCfg = Release|Win32 - {A5591A27-B27A-4FF2-88E6-E6C534C96E02}.Release|Win32.Build.0 = Release|Win32 - {FFAC27EA-E43A-4A78-924D-41E868A4F27F}.Debug|Win32.ActiveCfg = Debug|Win32 - {FFAC27EA-E43A-4A78-924D-41E868A4F27F}.Debug|Win32.Build.0 = Debug|Win32 - {FFAC27EA-E43A-4A78-924D-41E868A4F27F}.Release|Win32.ActiveCfg = Release|Win32 - {FFAC27EA-E43A-4A78-924D-41E868A4F27F}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Windows/msvc/uget.vcxproj b/Windows/msvc/uget.vcxproj deleted file mode 100644 index 7e11fa4..0000000 --- a/Windows/msvc/uget.vcxproj +++ /dev/null @@ -1,124 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {A98D36E8-7119-4AC4-8820-65B902C6B69E} - uget - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - - - - Disabled - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;D:\devpack\gtk3-msvc\include;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - - - ..\..\uglib;..\..\uget;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;D:\devpack\gtk3-msvc\include;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - - - - - - \ No newline at end of file diff --git a/Windows/msvc/uglib.vcxproj b/Windows/msvc/uglib.vcxproj deleted file mode 100644 index d0a2467..0000000 --- a/Windows/msvc/uglib.vcxproj +++ /dev/null @@ -1,132 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {8E8A46B4-6B62-4BD0-BCAF-BA9CF1090DEA} - uglib - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Configuration)\ - $(Configuration)\$(ProjectName)\ - - - - Disabled - ..\..\uglib;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\include\glib-2.0;D:\devpack\gtk3-msvc\lib\glib-2.0\include;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - - - ..\..\uglib;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\include\glib-2.0;D:\devpack\gtk3-msvc\lib\glib-2.0\include;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Windows/msvc/ui-gtk.vcxproj b/Windows/msvc/ui-gtk.vcxproj deleted file mode 100644 index 551e658..0000000 --- a/Windows/msvc/ui-gtk.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - ui-gtk - {9D164547-3F37-4C14-BCCE-91EB2F3DC317} - ugetgtk - Win32Proj - - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)$(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - true - $(SolutionDir)$(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - false - - - - Disabled - ..\..\uglib;..\..\uget;..\..\ui-gtk;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;D:\devpack\gtk3-msvc\lib\gtk-3.0\include;D:\devpack\gtk3-msvc\include\gtk-3.0;D:\devpack\gtk3-msvc\include\gdk-pixbuf-2.0;D:\devpack\gtk3-msvc\include\pango-1.0;D:\devpack\gtk3-msvc\include\atk-1.0;D:\devpack\gtk3-msvc\include\cairo;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;_DEBUG;_CONSOLE;DATADIR_WIN_PROG;HAVE_PLUGIN_ARIA2;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - glib-2.0.lib;gthread-2.0.lib;gmodule-2.0.lib;gobject-2.0.lib;gio-2.0.lib;gtk-win32-3.0.lib;gdk-win32-3.0.lib;gdk_pixbuf-2.0.lib;pango-1.0.lib;pangocairo-1.0.lib;pangowin32-1.0.lib;atk-1.0.lib;intl.lib;cairo.lib;libcurl.lib;Ws2_32.lib;winmm.lib;uget.lib;uglib.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;D:\devpack\curl-msvc;Debug;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - MaxSpeed - true - ..\..\uglib;..\..\uget;..\..\ui-gtk;D:\devpack\curl-msvc\include;D:\devpack\gtk3-msvc\include;D:\devpack\gtk3-msvc\lib\glib-2.0\include;D:\devpack\gtk3-msvc\include\glib-2.0;D:\devpack\gtk3-msvc\lib\gtk-3.0\include;D:\devpack\gtk3-msvc\include\gtk-3.0;D:\devpack\gtk3-msvc\include\gdk-pixbuf-2.0;D:\devpack\gtk3-msvc\include\pango-1.0;D:\devpack\gtk3-msvc\include\atk-1.0;D:\devpack\gtk3-msvc\include\cairo;%(AdditionalIncludeDirectories) - WIN32;HAVE_GLIB;inline=__inline;NDEBUG;_WINDOWS;DATADIR_WIN_PROG;HAVE_PLUGIN_ARIA2;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - - - glib-2.0.lib;gthread-2.0.lib;gmodule-2.0.lib;gobject-2.0.lib;gio-2.0.lib;gtk-win32-3.0.lib;gdk-win32-3.0.lib;gdk_pixbuf-2.0.lib;pango-1.0.lib;pangocairo-1.0.lib;pangowin32-1.0.lib;atk-1.0.lib;cairo.lib;intl.lib;libcurl.lib;Ws2_32.lib;winmm.lib;uget.lib;uglib.lib;%(AdditionalDependencies) - D:\devpack\gtk3-msvc\lib;D:\devpack\curl-msvc\;Release;%(AdditionalLibraryDirectories) - true - Windows - true - true - MachineX86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/autogen.sh b/autogen.sh deleted file mode 100644 index c3e671d..0000000 --- a/autogen.sh +++ /dev/null @@ -1,36 +0,0 @@ -if [ ! -f AUTHORS ]; then - touch AUTHORS -fi - -if [ ! -f NEWS ]; then - touch NEWS -fi - -if [ ! -f README ]; then - touch README -fi - -if [ ! -f ChangeLog ]; then - touch ChangeLog -fi - -# autoscan - -## Generate `aclocal.m4' by scanning `configure.ac' or `configure.in' -aclocal - -## --- AC_CONFIG_HEADERS -autoheader - -## --- AC_PROG_INTLTOOL -intltoolize - -## --- AC_PROG_LIBTOOL -# libtoolize --copy - -## --- AM_INIT_AUTOMAKE -automake --add-missing - -autoconf - - diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 2f7bc5e..0000000 --- a/configure.ac +++ /dev/null @@ -1,265 +0,0 @@ -AC_INIT(uget, 2.2.3) - -## Use automake (add automake to autogen.sh) -AM_INIT_AUTOMAKE - -## --- Use config.h (autogen.sh add autoheader) -AC_CONFIG_HEADERS([config.h]) - -## --- Determine a C compiler to use. -AC_PROG_CC - -## --- Check C compiler -c -o options. -AM_PROG_CC_C_O - -## --- Determine a C++ compiler to use. -# AC_PROG_CXX - -## --- Check for the ar command to use -AM_PROG_AR - -## Use library (static library) -AC_PROG_RANLIB - -## --- Check function posix_fallocate() -AC_CHECK_FUNCS([posix_fallocate]) - -## --- Check function ftruncate() -AC_CHECK_FUNCS([ftruncate]) - -## ---------------------------------------------- -## L10N (add intltoolize to autogen.sh) -AC_PROG_INTLTOOL -## replace ALL_LINGUAS with po/LINGUAS -# ALL_LINGUAS="" -GETTEXT_PACKAGE="$PACKAGE" -AC_SUBST(GETTEXT_PACKAGE) -AM_GLIB_GNU_GETTEXT -AM_GLIB_DEFINE_LOCALEDIR(LOCALEDIR) -## Use AM_GLIB_DEFINE_LOCALEDIR with AC_CONFIG_HEADERS - -## ---------------------------------------------- -## GTK+ -PKG_CHECK_MODULES(GTK, gtk+-3.0 >= 3.4) - -## ---------------- -## glib (add HAVE_GLIB definition to config.h) -PKG_CHECK_EXISTS([glib-2.0], - [have_glib="yes"], - [have_glib="no"]) -if test x$have_glib = xyes ; then - PKG_CHECK_MODULES(GLIB, glib-2.0) - AC_SUBST(GLIB_CFLAGS) - AC_SUBST(GLIB_LIBS) - AC_DEFINE(HAVE_GLIB, 1, [Define to 1 if glib support is required.]) -fi - -## ---------------- -## pthread -AC_CHECK_LIB(pthread, pthread_create,, - [AC_MSG_ERROR([required library pthread missing])]) -PTHREAD_CFLAGS="-pthread" -PTHREAD_LIBS="-pthread" -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_LIBS) - -## ---------------- -## LFS -AC_PATH_PROG(GETCONF, getconf) -if test "x$GETCONF" != "x" ; then - LFS_CFLAGS=`$GETCONF LFS_CFLAGS` - LFS_LDFLAGS=`$GETCONF LFS_LDFLAGS` -fi -AC_SUBST(LFS_CFLAGS) -AC_SUBST(LFS_LDFLAGS) - -## ---------------- -## cURL -AC_PATH_PROG(CURL_CONFIG, curl-config) -if test "x$CURL_CONFIG" = "x" ; then - AC_MSG_ERROR(Unable to find curl-config, please install libcurl) -fi -CURL_CFLAGS=`$CURL_CONFIG --cflags` -CURL_LIBS=`$CURL_CONFIG --libs` -let CURL_VERNUM=0x0`$CURL_CONFIG --vernum` -let CURL_VERMIN=0x071301 # 7.19.1 -if test $CURL_VERNUM -lt $CURL_VERMIN; then - AC_MSG_ERROR(Requires libcurl version >= 7.19.1) -fi -AC_SUBST(CURL_CFLAGS) -AC_SUBST(CURL_LIBS) - -## ---------------- -## GnuTLS -AC_ARG_WITH( - [gnutls], - AC_HELP_STRING([--with-gnutls[=@<:@no/auto/yes@:>@]], [Enable GnuTLS support. (default is auto)]), - [with_gnutls="$withval"], - [with_gnutls="no"] -) -if test "x$with_gnutls" != "xno"; then -# AC_CHECK_HEADER(gcrypt.h, [USE_GNUTLS_GCRYPT=1], [USE_GNUTLS_GCRYPT=0]) -# if test "$USE_GNUTLS_GCRYPT" = "1"; then -# LIBGCRYPT_CFLAGS="" -# AC_SUBST(LIBGCRYPT_CFLAGS) -# fi -# AC_CHECK_HEADER(gcrypt/gcrypt.h, [USE_GNUTLS_GCRYPT=1], [USE_GNUTLS_GCRYPT=0]) -# if test "$USE_GNUTLS_GCRYPT" = "1"; then -# LIBGCRYPT_CFLAGS="" -# AC_SUBST(LIBGCRYPT_CFLAGS, [""]) -# fi -# AC_CHECK_LIB(gcrypt, gcry_control, [USE_GNUTLS_GCRYPT=1], [USE_GNUTLS_GCRYPT=0]) -# if test "$USE_GNUTLS_GCRYPT" = "1"; then -# LIBGCRYPT_LIBS="-lgcrypt" -# AC_SUBST(LIBGCRYPT_LIBS, ["-lgcrypt"]) -# fi - AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config) - if test "x$LIBGCRYPT_CONFIG" = "x" ; then - if test "x$with_gnutls" = "xyes"; then - AC_MSG_ERROR(Unable to find libgcrypt-config, please install libgcrypt) - fi - else - LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` - LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` - AC_SUBST(LIBGCRYPT_CFLAGS) - AC_SUBST(LIBGCRYPT_LIBS) - AC_DEFINE(USE_GNUTLS, 1, [Define to 1 if gnutls support is required.]) - fi -fi - -## ---------------- -## OpenSSL -AC_ARG_WITH( - [openssl], - AC_HELP_STRING([--with-openssl[=@<:@no/yes@:>@]], [Enable OpenSSL support.]), - [with_openssl="$withval"], - [with_openssl="yes"] -) -if test "x$LIBGCRYPT_CONFIG" = "x" ; then - if test "x$with_openssl" = "xyes"; then - PKG_CHECK_MODULES(LIBCRYPTO, libcrypto) - AC_SUBST(LIBCRYPTO_CFLAGS) - AC_SUBST(LIBCRYPTO_LIBS) - AC_DEFINE(USE_OPENSSL, 1, [Define to 1 if openssl support is required.]) - fi -fi - -## ---------------- -## libnotify -AC_ARG_ENABLE( - [notify], - AC_HELP_STRING([--disable-notify], [Disable libnotify support.]), - [enable_notify="$enableval"], - [enable_notify="yes"] -) -if test "x$enable_notify" = "xyes"; then - PKG_CHECK_MODULES(LIBNOTIFY, libnotify) - AC_DEFINE(HAVE_LIBNOTIFY, 1, [Define to 1 if libnotify support is required.]) - # for ArchLinux - AC_SUBST(LIBNOTIFY_CFLAGS) - AC_SUBST(LIBNOTIFY_LIBS) -fi - -## ---------------- -## appindicator -AC_ARG_ENABLE( - [appindicator], - AS_HELP_STRING([--enable-appindicator[=@<:@no/auto/yes@:>@]],[Build support for application indicators.]), - [enable_appindicator=$enableval], - [enable_appindicator="auto"] -) -if test x$enable_appindicator = xauto ; then - PKG_CHECK_EXISTS([appindicator3-0.1], - [enable_appindicator="yes"], - [enable_appindicator="no"]) -fi -if test x$enable_appindicator = xyes ; then - PKG_CHECK_MODULES(APP_INDICATOR, appindicator3-0.1) - AC_SUBST(APP_INDICATOR_CFLAGS) - AC_SUBST(APP_INDICATOR_LIBS) - AC_DEFINE(HAVE_APP_INDICATOR, 1, [Have AppIndicator]) -fi - -## ---------------- -## gstreamer -AC_ARG_ENABLE( - [gstreamer], - AC_HELP_STRING([--disable-gstreamer], [Disable GStreamer audio support.]), - [enable_gstreamer="$enableval"], - [enable_gstreamer="yes"] -) -if test "x$enable_gstreamer" = "xyes"; then - PKG_CHECK_EXISTS([gstreamer-1.0], - [enable_gstreamer1="yes"], - [enable_gstreamer1="no"]) -fi -if test "x$enable_gstreamer1" = "xyes"; then - PKG_CHECK_MODULES(GSTREAMER, gstreamer-1.0) - AC_DEFINE(HAVE_GSTREAMER, 1, [Define to 1 if gstreamer support is required.]) - # for ArchLinux - AC_SUBST(GSTREAMER_CFLAGS) - AC_SUBST(GSTREAMER_LIBS) -elif test "x$enable_gstreamer" = "xyes"; then - PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10) - AC_DEFINE(HAVE_GSTREAMER, 1, [Define to 1 if gstreamer support is required.]) - # for ArchLinux - AC_SUBST(GSTREAMER_CFLAGS) - AC_SUBST(GSTREAMER_LIBS) -fi - -## ----------------- -## libpwmd -AC_ARG_ENABLE( - [pwmd], - AC_HELP_STRING([--enable-pwmd], [Enable pwmd support.]), - [enable_pwmd="$enableval"], - [enable_pwmd="no"] -) -if test "x$enable_pwmd" = "xyes"; then - PKG_CHECK_MODULES(LIBPWMD, [libpwmd-8.0 >= 8.3.0]) - AC_DEFINE(HAVE_LIBPWMD, 1, [Define to 1 if libpwmd support is required.]) -fi -AM_CONDITIONAL([WITH_LIBPWMD], [test "x$enable_pwmd" = "xyes"]) - -## ----------------- -## RSS Notify -AC_ARG_ENABLE( - [rss-notify], - AC_HELP_STRING([--disable-rss-notify], [Disable RSS Notify.]), - [enable_rss_notify="$enableval"], - [enable_rss_notify="yes"] -) -if test "x$enable_rss_notify" = "xyes"; then - AC_DEFINE(HAVE_RSS_NOTIFY, 1, [Define to 1 to enable RSS Notify.]) -fi - -## ----------------- -## UNIX Domain Socket -AC_ARG_ENABLE( - [unix-socket], - AC_HELP_STRING([--enable-unix-socket], [Enable UNIX Domain Socket.]), - [enable_unix_socket="$enableval"], - [enable_unix_socket="no"] -) -if test "x$enable_unix_socket" = "xyes"; then - AC_DEFINE(USE_UNIX_DOMAIN_SOCKET, 1, [Define to 1 to use UNIX Domain Socket.]) -fi - -## ---------------------------------------------- -## output -AC_CONFIG_FILES([ - Makefile - doc/Makefile - tests/Makefile - uget/Makefile - uglib/Makefile - ui-gtk/Makefile - ui-gtk-1to2/Makefile - pixmaps/Makefile - sounds/Makefile - po/Makefile.in - Windows/Makefile -]) - -AC_OUTPUT - diff --git a/doc/Makefile.am b/doc/Makefile.am deleted file mode 100644 index 1c3a899..0000000 --- a/doc/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -EXTRA_DIST = \ - uget.txt \ - folders.txt \ - JSON-RPC_interface.txt \ - To_build_uGet_in_MinGW.txt - diff --git a/doc/To_build_uGet_in_MinGW.txt b/doc/To_build_uGet_in_MinGW.txt deleted file mode 100644 index a628847..0000000 --- a/doc/To_build_uGet_in_MinGW.txt +++ /dev/null @@ -1,20 +0,0 @@ -To build uGet in MinGW environment - -# ------------ Install packages -------------- -# toolchain -pacman -S mingw-w64-i686-binutils mingw-w64-i686-gcc mingw-w64-i686-gdb - -# make and Autotools -pacman -S make pkgconfig autoconf automake libtool intltool - -# gtk familiy -pacman -S mingw-w64-i686-gtk3 - -# curl -pacman -S mingw-w64-i686-curl - -# ------------ Build uGet -------------- -. autogen.sh -./configure --disable-notify --disable-gstreamer _WINDOWS=1 NDEBUG=1 -make - diff --git a/docs/BUILDING.md b/docs/BUILDING.md new file mode 100644 index 0000000..5e4735b --- /dev/null +++ b/docs/BUILDING.md @@ -0,0 +1,57 @@ +# Building uGet with CMake + +uGet now uses a single CMake-based build across platforms. You will need **CMake +3.24 or newer** plus a C and C++ toolchain that can compile GTK-based +applications. + +## Linux and other Unix-like platforms + +```sh +cmake --preset dev +cmake --build build/dev +ctest --test-dir build/dev --output-on-failure +``` + +Install the GTK 3, GLib, GStreamer and libcurl development packages from your +distribution. The configure step will fail if these packages are missing while +`WITH_GUI` is enabled (the default). For headless or minimal builds you can pass +`-DWITH_GUI=OFF` to skip those requirements. + +Other useful presets: + +- `cmake --preset asan` – Debug build with AddressSanitizer and + UndefinedBehaviorSanitizer enabled (requires clang or gcc with sanitizer + support). +- `cmake --preset rel` – RelWithDebInfo configuration suitable for + release/packaging validation. + +The presets drive dependency discovery via `pkg-config`. Optional components +(such as Ayatana/AppIndicator tray icons, OpenSSL, libpwmd and GnuTLS) are +picked up automatically when their development packages are available. If a +library is missing the feature falls back gracefully or is disabled without +failing the configuration. You can also toggle features explicitly with +`-DWITH_TRAY=OFF`, `-DWITH_OPENSSL=OFF`, `-DWITH_PWMD=OFF`, or +`-DWITH_GNUTLS=ON` when running `cmake`. + +## Windows (MSVC + vcpkg) + +Install Visual Studio 2022 with the "Desktop development with C++" workload and +set up [vcpkg](https://github.com/microsoft/vcpkg). With `VCPKG_ROOT` pointing +at your vcpkg checkout, run the Windows preset: + +```powershell +cmake --preset msvc-vcpkg +cmake --build build\msvc --config Debug +ctest --test-dir build\msvc -C Debug --output-on-failure +``` + +The vcpkg manifest (vcpkg.json) pulls in gtk3, glib, gstreamer, curl and +openssl. Tray integration will automatically use Ayatana/AppIndicator when those +libraries are available in vcpkg; otherwise the build continues without tray +support. Additional options described above work on Windows as well. + +For release-like builds use the RelWithDebInfo configuration: + +```powershell +cmake --build build\msvc --config RelWithDebInfo +``` diff --git a/docs/BUILD_WINDOWS.md b/docs/BUILD_WINDOWS.md index ed03ace..1121f1e 100644 --- a/docs/BUILD_WINDOWS.md +++ b/docs/BUILD_WINDOWS.md @@ -1,5 +1,7 @@ # Building on Windows (MSVC + vcpkg, x64) +> Requires CMake 3.24 or newer. + ## Prereqs - Visual Studio 2022 (Desktop development with C++) - vcpkg (https://github.com/microsoft/vcpkg) and set `VCPKG_ROOT` @@ -21,4 +23,7 @@ ctest --test-dir build\msvc -C Debug --output-on-failure ## Notes - Dependencies come from vcpkg.json (gtk3, glib, gstreamer, curl, openssl). - Tray support (Ayatana/AppIndicator) may be unavailable on Windows: the build will continue without it. +- Optional components such as OpenSSL, libpwmd or GnuTLS follow the same + autodetection as on Linux; toggle them manually by passing + `-DWITH_OPENSSL=OFF`, `-DWITH_PWMD=OFF`, or `-DWITH_GNUTLS=ON` to `cmake`. - Use RelWithDebInfo for release-like builds: `cmake -S . -B build\msvc -DCMAKE_BUILD_TYPE=RelWithDebInfo --preset msvc-vcpkg` diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index 7b03211..8b79dfa 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -5,6 +5,7 @@ Use CMake presets to configure common build types: - `cmake --preset dev` for a standard Debug build. - `cmake --preset asan` for a Debug build with AddressSanitizer/UndefinedBehaviorSanitizer enabled (Unix-like platforms). - `cmake --preset rel` for a RelWithDebInfo build. +- `cmake --preset msvc-vcpkg` for the Visual Studio + vcpkg toolchain on Windows. When debugging sanitizer builds you can enable stricter behavior with: diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am deleted file mode 100644 index 0074c7c..0000000 --- a/pixmaps/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -# icons installing path: -# $(datadir)/icons/hicolor/16x16/apps/uget-icon.png -# $(datadir)/icons/hicolor/22x22/apps/uget-icon.png -# $(datadir)/icons/hicolor/24x24/apps/uget-icon.png -# $(datadir)/icons/hicolor/32x32/apps/uget-icon.png -# $(datadir)/icons/hicolor/48x48/apps/uget-icon.png -# $(datadir)/icons/hicolor/64x64/apps/uget-icon.png -# $(datadir)/icons/hicolor/96x96/apps/uget-icon.png -# $(datadir)/icons/hicolor/128x128/apps/uget-icon.png -# $(datadir)/icons/hicolor/scalable/apps/uget-icon.svg -# -iconsdir = $(datadir) -nobase_dist_icons_DATA = \ - icons/hicolor/16x16/apps/uget-icon.png \ - icons/hicolor/22x22/apps/uget-icon.png \ - icons/hicolor/24x24/apps/uget-icon.png \ - icons/hicolor/32x32/apps/uget-icon.png \ - icons/hicolor/48x48/apps/uget-icon.png \ - icons/hicolor/64x64/apps/uget-icon.png \ - icons/hicolor/96x96/apps/uget-icon.png \ - icons/hicolor/128x128/apps/uget-icon.png \ - icons/hicolor/scalable/apps/uget-icon.svg \ - icons/hicolor/16x16/apps/uget-tray-default.png \ - icons/hicolor/22x22/apps/uget-tray-default.png \ - icons/hicolor/24x24/apps/uget-tray-default.png \ - icons/hicolor/32x32/apps/uget-tray-default.png \ - icons/hicolor/48x48/apps/uget-tray-default.png \ - icons/hicolor/16x16/apps/uget-tray-downloading.png \ - icons/hicolor/22x22/apps/uget-tray-downloading.png \ - icons/hicolor/24x24/apps/uget-tray-downloading.png \ - icons/hicolor/32x32/apps/uget-tray-downloading.png \ - icons/hicolor/48x48/apps/uget-tray-downloading.png \ - icons/hicolor/16x16/apps/uget-tray-error.png \ - icons/hicolor/22x22/apps/uget-tray-error.png \ - icons/hicolor/24x24/apps/uget-tray-error.png \ - icons/hicolor/32x32/apps/uget-tray-error.png \ - icons/hicolor/48x48/apps/uget-tray-error.png - - -# pixmaps -# -ugetpixmapdir = $(datadir)/pixmaps/uget -dist_ugetpixmap_DATA = logo.png - -# icons/hicolor/index.theme is needed by gtk_icon_theme_append_search_path() -# -EXTRA_DIST = icons/hicolor/index.theme - diff --git a/sounds/Makefile.am b/sounds/Makefile.am deleted file mode 100644 index 657412b..0000000 --- a/sounds/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -soundsdir = $(datadir)/sounds/uget - -sounds_DATA = notification.wav - -EXTRA_DIST = $(sounds_DATA) - diff --git a/tests/Makefile.am b/tests/Makefile.am deleted file mode 100644 index c0f9de0..0000000 --- a/tests/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -noinst_PROGRAMS = \ - test-json test-jsonrpc test-plugin+app test-info \ - test-uglib test-uget -# test-uglib-cxx test-uget-cxx -TESTS_LIBS = @PTHREAD_LIBS@ @CURL_LIBS@ @GLIB_LIBS@ - -if WITH_LIBPWMD -TESTS_LIBS += @LIBPWMD_LIBS@ -endif - -# set the include path found by configure -AM_CPPFLAGS = -I$(top_srcdir)/uglib -I$(top_srcdir)/uget -AM_CFLAGS = @PTHREAD_CFLAGS@ @LFS_CFLAGS@ @CURL_CFLAGS@ @GLIB_CFLAGS@ -AM_LDFLAGS = @LFS_LDFLAGS@ - -# test_json_CPPFLAGS = -I$(top_srcdir)/uglib -test_json_LDADD = $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) -test_json_SOURCES = test-json.c - -# test_jsonrpc_CPPFLAGS = -I$(top_srcdir)/uglib -I$(top_srcdir)/uget -test_jsonrpc_LDADD = $(top_builddir)/uget/libuget.a $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) -test_jsonrpc_SOURCES = test-jsonrpc.c - -test_plugin_app_CPPFLAGS = -I$(top_srcdir)/uglib -I$(top_srcdir)/uget @LIBGCRYPT_CFLAGS@ @LIBCRYPTO_CFLAGS@ -test_plugin_app_LDADD = $(top_builddir)/uget/libuget.a $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) @LIBGCRYPT_LIBS@ @LIBCRYPTO_LIBS@ -test_plugin_app_SOURCES = test-plugin+app.c - -# test_info_CPPFLAGS = -I$(top_srcdir)/uglib -test_info_LDADD = $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) -test_info_SOURCES = test-info.c - -# test_uglib_CPPFLAGS = -I$(top_srcdir)/uglib -test_uglib_LDADD = $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) -test_uglib_SOURCES = test-uglib.c - -# test_uget_CPPFLAGS = -I$(top_srcdir)/uglib -I$(top_srcdir)/uget -test_uget_LDADD = $(top_builddir)/uget/libuget.a $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) -test_uget_SOURCES = test-uget.c - -## test C++ standard-layout -#test_uglib_cxx_CPPFLAGS = -I$(top_srcdir)/uglib -#test_uglib_cxx_CXXFLAGS = -std=c++11 -#test_uglib_cxx_LDADD = $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) -#test_uglib_cxx_SOURCES = test-uglib-cxx.cxx - -## test_uget_cxx_CPPFLAGS = -I$(top_srcdir)/uglib -I$(top_srcdir)/uget -#test_uget_cxx_CXXFLAGS = -std=c++11 -#test_uget_cxx_LDADD = $(top_builddir)/uget/libuget.a $(top_builddir)/uglib/libuglib.a $(TESTS_LIBS) -#test_uget_cxx_SOURCES = test-uget-cxx.cxx - diff --git a/uget/Android.mk b/uget/Android.mk deleted file mode 100644 index d824c76..0000000 --- a/uget/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libuget -LOCAL_CPPFLAGS += -DNDEBUG -## -DNO_RETRY_IF_CONNECT_FAILED - -LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/../uglib $(LOCAL_PATH)/../curl/include $(LOCAL_PATH)/../openssl/include -LOCAL_SRC_FILES := \ - UgetSequence.c \ - UgetRpc.c \ - UgetOption.c \ - UgetData.c \ - UgetFiles.c \ - UgetNode.c \ - UgetNode-compare.c \ - UgetNode-filter.c \ - UgetTask.c \ - UgetHash.c \ - UgetSite.c \ - UgetApp.c \ - UgetEvent.c \ - UgetPlugin.c \ - UgetA2cf.c \ - UgetCurl.c \ - UgetAria2.c \ - UgetMedia.c \ - UgetMedia-youtube.c \ - UgetPluginCurl.c \ - UgetPluginAria2.c \ - UgetPluginMedia.c \ - UgetPluginAgent.c \ - UgetPluginMega.c - -include $(BUILD_STATIC_LIBRARY) - diff --git a/uget/Makefile.am b/uget/Makefile.am deleted file mode 100644 index 669af9e..0000000 --- a/uget/Makefile.am +++ /dev/null @@ -1,74 +0,0 @@ -## To enable LFS (Large File Support) in 32bit platform -## add `getconf LFS_CFLAGS` to CFLAGS -## add `getconf LFS_LDFLAGS` to LDFLAGS - -## static library --- - -# lib_LIBRARIES = libuget.a -noinst_LIBRARIES = libuget.a - -libuget_a_CPPFLAGS = -I$(top_srcdir)/uglib -I$(top_srcdir)/uget -libuget_a_CFLAGS = @PTHREAD_CFLAGS@ @GLIB_CFLAGS@ - -libuget_a_SOURCES = \ - UgetSequence.c \ - UgetRss.c \ - UgetRpc.c \ - UgetOption.c \ - UgetData.c \ - UgetFiles.c \ - UgetNode.c \ - UgetNode-compare.c \ - UgetNode-filter.c \ - UgetTask.c \ - UgetHash.c \ - UgetSite.c \ - UgetApp.c \ - UgetEvent.c \ - UgetPlugin.c \ - UgetA2cf.c \ - UgetCurl.c \ - UgetAria2.c \ - UgetMedia.c \ - UgetMedia-youtube.c \ - UgetPluginCurl.c \ - UgetPluginAria2.c \ - UgetPluginMedia.c \ - UgetPluginAgent.c \ - UgetPluginMega.c \ - UgetPluginEmpty.c - -noinst_HEADERS = \ - UgetSequence.h \ - UgetRss.h \ - UgetRpc.h \ - UgetOption.h \ - UgetData.h \ - UgetFiles.h \ - UgetNode.h \ - UgetTask.h \ - UgetHash.h \ - UgetSite.h \ - UgetApp.h \ - UgetEvent.h \ - UgetPlugin.h \ - UgetA2cf.h \ - UgetCurl.h \ - UgetAria2.h \ - UgetMedia.h \ - UgetPluginCurl.h \ - UgetPluginAria2.h \ - UgetPluginMedia.h \ - UgetPluginAgent.h \ - UgetPluginMega.h \ - UgetPluginEmpty.h - -if WITH_LIBPWMD -libuget_a_CFLAGS += @LIBPWMD_CFLAGS@ -libuget_a_SOURCES += pwmd.c -noinst_HEADERS += pwmd.h -endif - -EXTRA_DIST = \ - Android.mk \ - CMakeLists.txt diff --git a/uglib/Android.mk b/uglib/Android.mk deleted file mode 100644 index 996910f..0000000 --- a/uglib/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libuglib -LOCAL_CPPFLAGS := -DNDEBUG -LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/../curl/include -LOCAL_SRC_FILES := \ - UgStdio.c \ - UgString.c \ - UgThread.c \ - UgSocket.c \ - UgUtil.c \ - UgFileUtil.c \ - UgArray.c \ - UgList.c \ - UgSLink.c \ - UgOption.c \ - UgUri.c \ - UgNode.c \ - UgData.c \ - UgInfo.c \ - UgRegistry.c \ - UgValue.c \ - UgEntry.c \ - UgBuffer.c \ - UgJson.c \ - UgJson-custom.c \ - UgJsonFile.c \ - UgJsonrpc.c \ - UgJsonrpcSocket.c \ - UgJsonrpcCurl.c \ - UgHtml.c \ - UgHtmlEntry.c \ - UgHtmlFilter.c - -include $(BUILD_STATIC_LIBRARY) diff --git a/uglib/Makefile.am b/uglib/Makefile.am deleted file mode 100644 index ec902e8..0000000 --- a/uglib/Makefile.am +++ /dev/null @@ -1,76 +0,0 @@ -## To enable LFS (Large File Support) in 32bit platform -## add `getconf LFS_CFLAGS` to CFLAGS -## add `getconf LFS_LDFLAGS` to LDFLAGS - -AUTOMAKE_OPTIONS = no-dependencies - -## static library --- - -# lib_LIBRARIES = libuglib.a -noinst_LIBRARIES = libuglib.a - -libuglib_a_CPPFLAGS = -I$(top_srcdir)/uglib -libuglib_a_CFLAGS = @PTHREAD_CFLAGS@ @LFS_CFLAGS@ @CURL_CFLAGS@ @GLIB_CFLAGS@ - -libuglib_a_SOURCES = \ - UgStdio.c \ - UgString.c \ - UgThread.c \ - UgSocket.c \ - UgUtil.c \ - UgFileUtil.c \ - UgArray.c \ - UgList.c \ - UgSLink.c \ - UgOption.c \ - UgUri.c \ - UgNode.c \ - UgData.c \ - UgInfo.c \ - UgRegistry.c \ - UgValue.c \ - UgEntry.c \ - UgBuffer.c \ - UgJson.c \ - UgJson-custom.c \ - UgJsonFile.c \ - UgJsonrpc.c \ - UgJsonrpcSocket.c \ - UgJsonrpcCurl.c \ - UgHtml.c \ - UgHtmlEntry.c \ - UgHtmlFilter.c - -noinst_HEADERS = \ - UgDefine.h \ - UgStdio.h \ - UgString.h \ - UgThread.h \ - UgSocket.h \ - UgUtil.h \ - UgFileUtil.h \ - UgArray.h \ - UgList.h \ - UgSLink.h \ - UgOption.h \ - UgUri.h \ - UgNode.h \ - UgData.h \ - UgInfo.h \ - UgRegistry.h \ - UgValue.h \ - UgEntry.h \ - UgBuffer.h \ - UgJson.h \ - UgJson-custom.h \ - UgJsonFile.h \ - UgJsonrpc.h \ - UgJsonrpcSocket.h \ - UgJsonrpcCurl.h \ - UgHtml.h \ - UgHtmlEntry.h \ - UgHtmlFilter.h - -EXTRA_DIST = \ - Android.mk \ - CMakeLists.txt diff --git a/ui-gtk-1to2/Makefile.am b/ui-gtk-1to2/Makefile.am deleted file mode 100644 index f3da88a..0000000 --- a/ui-gtk-1to2/Makefile.am +++ /dev/null @@ -1,40 +0,0 @@ -AUTOMAKE_OPTIONS = subdir-objects no-dependencies - -bin_PROGRAMS = uget-gtk-1to2 - -uget_gtk_1to2_CPPFLAGS = \ - -DDATADIR='"$(datadir)"' \ - -I$(top_srcdir)/ui-gtk \ - -I$(top_srcdir)/uget \ - -I$(top_srcdir)/uglib - -uget_gtk_1to2_CFLAGS = \ - @GTK_CFLAGS@ - -uget_gtk_1to2_LDADD = \ - $(top_builddir)/uget/libuget.a \ - $(top_builddir)/uglib/libuglib.a \ - @GTK_LIBS@ - -uget_gtk_1to2_SOURCES = \ - UgCategory.c \ - UgData1.c \ - UgData-download.c \ - UgDataset.c \ - UgMarkup.c \ - UgRegistry1.c \ - UgSetting.c \ - Ugtk1to2.c \ - ../ui-gtk/UgtkSetting.c \ - main.c - -noinst_HEADERS = \ - UgCategory.h \ - UgData1.h \ - UgData-download.h \ - UgDataset.h \ - UgMarkup.h \ - UgRegistry1.h \ - UgSetting.h \ - Ugtk1to2.h \ - ../ui-gtk/UgtkSetting.h diff --git a/ui-gtk/Makefile.am b/ui-gtk/Makefile.am deleted file mode 100644 index 8446a34..0000000 --- a/ui-gtk/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -bin_PROGRAMS = uget-gtk - -uget_gtk_CPPFLAGS = \ - -DUG_DATADIR='"$(datadir)"' \ - -I$(top_srcdir)/ui-gtk \ - -I$(top_srcdir)/uget \ - -I$(top_srcdir)/uglib - -uget_gtk_CFLAGS = \ - @PTHREAD_CFLAGS@ \ - @LFS_CFLAGS@ \ - @CURL_CFLAGS@ \ - @LIBGCRYPT_CFLAGS@ \ - @LIBCRYPTO_CFLAGS@ \ - @GTK_CFLAGS@ \ - @LIBNOTIFY_CFLAGS@ \ - @APP_INDICATOR_CFLAGS@ \ - @GSTREAMER_CFLAGS@ \ - @LIBPWMD_CFLAGS@ - -uget_gtk_LDFLAGS = @LFS_LDFLAGS@ - -uget_gtk_LDADD = \ - $(top_builddir)/uget/libuget.a \ - $(top_builddir)/uglib/libuglib.a \ - @PTHREAD_LIBS@ \ - @CURL_LIBS@ \ - @LIBGCRYPT_LIBS@ \ - @LIBCRYPTO_LIBS@ \ - @GTK_LIBS@ \ - @LIBNOTIFY_LIBS@ \ - @APP_INDICATOR_LIBS@ \ - @GSTREAMER_LIBS@ \ - @LIBPWMD_LIBS@ - -uget_gtk_SOURCES = \ - UgtkUtil.c UgtkConfig.c UgtkSetting.c \ - UgtkNodeList.c UgtkNodeTree.c UgtkNodeView.c \ - UgtkTraveler.c UgtkSummary.c \ - UgtkTrayIcon.c UgtkBanner.c \ - UgtkSequence.c UgtkSelector.c \ - UgtkProxyForm.c UgtkDownloadForm.c UgtkCategoryForm.c \ - UgtkNodeDialog.c UgtkBatchDialog.c \ - UgtkScheduleForm.c UgtkSettingForm.c UgtkSettingDialog.c \ - UgtkConfirmDialog.c UgtkAboutDialog.c \ - UgtkMenubar.c UgtkMenubar-ui.c \ - UgtkApp.c UgtkApp-ui.c UgtkApp-callback.c \ - UgtkApp-timeout.c UgtkApp-main.c - -noinst_HEADERS = \ - UgtkUtil.h UgtkConfig.h UgtkSetting.h \ - UgtkNodeList.h UgtkNodeTree.h UgtkNodeView.h \ - UgtkTraveler.h UgtkSummary.h \ - UgtkTrayIcon.h UgtkBanner.h \ - UgtkSequence.h UgtkSelector.h \ - UgtkProxyForm.h UgtkDownloadForm.h UgtkCategoryForm.h \ - UgtkNodeDialog.h UgtkBatchDialog.h \ - UgtkScheduleForm.h UgtkSettingForm.h UgtkSettingDialog.h \ - UgtkConfirmDialog.h UgtkAboutDialog.h \ - UgtkMenubar.h \ - UgtkApp.h - From 2982f87b4553d145d82cfea2d022cd0f19486bb6 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Tue, 16 Dec 2025 18:20:20 +0300 Subject: [PATCH 20/26] Fix CI build failures and modernize CMake configuration This PR resolves build failures on Windows and Linux and modernizes the CMake build system. Changes include: - Fixed Windows compilation error (snprintf macro redefinition) - Fixed Linux segmentation fault in tests (pointer arithmetic) - Refactored CMakeLists.txt to build proper targets - Fixed memory leaks and linking issues in tests - Added optional toggle for Mega plugin with robust detection - Updated vcpkg baseline and dependencies --- .github/workflows/ci.yml | 63 ++-- .gitignore | 1 + CMakeLists.txt | 540 +++++++++++++++++++++++-------- CMakePresets.json | 2 +- tests/CMakeLists.txt | 161 ++-------- tests/test-json.c | 28 ++ tests/test-jsonrpc.c | 27 +- tests/test-plugin+app.c | 642 +++++++++++++++++++------------------ tests/test-uglib.c | 6 +- uget/UgetAria2.c | 263 ++++++++++----- uget/UgetAria2.h | 12 +- uglib/UgJson-custom.c | 670 +++++++++++++++++++-------------------- uglib/UgJsonrpc.c | 17 +- uglib/UgJsonrpc.h | 5 +- uglib/UgStdio.h | 6 + ui-gtk/UgtkApp.c | 16 +- vcpkg.json | 20 +- 17 files changed, 1401 insertions(+), 1078 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30b02ab..d4b1eef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,10 @@ jobs: os: [ ubuntu-24.04, windows-latest ] config: [ Debug, RelWithDebInfo ] runs-on: ${{ matrix.os }} + env: + VCPKG_DOWNLOADS_DIR: ${{ github.workspace }}\.vcpkg_downloads + VCPKG_DOWNLOADS: ${{ github.workspace }}\.vcpkg_downloads + VCPKG_FTPMIRROR_URL: https://ftpmirror.gnu.org/gnu/{path} steps: - uses: actions/checkout@v4 with: @@ -27,47 +31,10 @@ jobs: ninja-build pkg-config xvfb \ libgtk-3-dev libglib2.0-dev \ libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - libcurl4-openssl-dev libayatana-appindicator3-dev - - # ---------- Resolve a vcpkg commit ---------- - - name: Resolve vcpkg commit (Windows) - if: runner.os == 'Windows' - id: vcpkgsha - shell: bash - run: | - set -e - # Fetch latest commit on vcpkg's master (main) branch - SHA=$(git ls-remote https://github.com/microsoft/vcpkg refs/heads/master | cut -f1) - echo "sha=$SHA" >> "$GITHUB_OUTPUT" - echo "Using vcpkg commit: $SHA" - - # ---------- Windows deps via vcpkg ---------- - - name: Setup vcpkg (Windows) - if: runner.os == 'Windows' - uses: lukka/run-vcpkg@v11 - with: - vcpkgJsonGlob: 'vcpkg.json' - vcpkgGitCommitId: ${{ steps.vcpkgsha.outputs.sha }} - - - name: Add vcpkg tools to PATH (Windows) - if: runner.os == 'Windows' - shell: pwsh - run: | - $root = "$env:RUNVCPKG_VCPKG_ROOT" - $paths = @( - Join-Path $root 'installed\x64-windows\tools\pkgconf' - Join-Path $root 'installed\x64-windows\tools' - ) - foreach ($p in $paths) { - if (Test-Path $p) { - Write-Host "Adding $p to PATH" - $p | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - } - } - # show which pkgconf will be used - Write-Host "pkgconf = " (Get-Command pkgconf -ErrorAction SilentlyContinue) - Write-Host "pkg-config = " (Get-Command pkg-config -ErrorAction SilentlyContinue) + libcurl4-openssl-dev libayatana-appindicator3-dev \ + libgcrypt20-dev + # ---------- Windows build tooling ---------- - name: Setup Ninja (Windows) if: runner.os == 'Windows' uses: seanmiddleditch/gha-setup-ninja@v4 @@ -78,16 +45,24 @@ jobs: with: arch: x64 + # ---------- Windows deps via vcpkg ---------- + - name: Setup vcpkg (Windows) + if: runner.os == 'Windows' + uses: lukka/run-vcpkg@v11 + with: + vcpkgJsonGlob: 'vcpkg.json' + + # ---------- Configure ---------- - name: Configure (Linux Debug) if: runner.os == 'Linux' && matrix.config == 'Debug' - run: cmake --preset dev + run: cmake --preset dev -DENABLE_MEGA=OFF - name: Configure (Linux RelWithDebInfo) if: runner.os == 'Linux' && matrix.config == 'RelWithDebInfo' - run: cmake --preset rel + run: cmake --preset rel -DENABLE_MEGA=OFF - name: Configure (Windows) if: runner.os == 'Windows' - run: cmake --preset msvc-vcpkg -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DWITH_GUI=OFF -DWITH_TRAY=OFF + run: cmake --preset msvc-vcpkg -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DWITH_GUI=OFF -DWITH_TRAY=OFF -DENABLE_MEGA=OFF # ---------- Build ---------- - name: Build (Linux Debug) @@ -98,7 +73,7 @@ jobs: run: cmake --build build/rel -- -v - name: Build (Windows) if: runner.os == 'Windows' - run: cmake --build build/msvc --config ${{ matrix.config }} -- -v + run: cmake --build --preset msvc-vcpkg --config ${{ matrix.config }} -- -v # ---------- Test ---------- - name: Test (Linux) diff --git a/.gitignore b/.gitignore index a7567b5..4f7bccc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build/ *.vcxproj *.vcxproj.filters *.vcxproj.user +logs/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 47c9bbb..7e7b631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.24) -project(ModernizedApp VERSION 2.3.0 LANGUAGES C) +project(uget VERSION 2.3.0 LANGUAGES C) set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "Verbose build" FORCE) @@ -7,11 +7,17 @@ set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) -option(WITH_GUI "Build GTK-based UI and GStreamer integrations" ON) +option(UGET_WITH_GUI "Build the GTK front-end" ON) +if(DEFINED WITH_GUI) + set(UGET_WITH_GUI ${WITH_GUI}) +endif() +set_property(CACHE UGET_WITH_GUI PROPERTY VALUE ${UGET_WITH_GUI}) +set(WITH_GUI ${UGET_WITH_GUI}) option(WITH_TRAY "Build system tray integration (requires GUI)" ON) option(WITH_OPENSSL "Enable OpenSSL-based crypto/TLS" ON) option(WITH_GNUTLS "Enable GnuTLS/libgcrypt backend" OFF) option(WITH_PWMD "Enable libpwmd integration" ON) +option(ENABLE_MEGA "Enable MEGA plugin" ON) option(ENABLE_SANITIZERS "Enable ASan/UBSan in Debug on non-MSVC builds" ON) if(MSVC) @@ -20,7 +26,31 @@ else() add_compile_options(-Wall -Wextra -Wpedantic) endif() +if(ENABLE_SANITIZERS AND NOT MSVC) + set(_uget_sanitize_flags -fsanitize=address,undefined) + if(CMAKE_CONFIGURATION_TYPES) + add_compile_options($<$:${_uget_sanitize_flags}>) + add_compile_options($<$:-fno-omit-frame-pointer>) + add_link_options($<$:${_uget_sanitize_flags}>) + if(UNIX AND NOT APPLE) + add_link_options($<$:-Wl,--no-as-needed>) + endif() + else() + string(TOUPPER "${CMAKE_BUILD_TYPE}" _uget_build_type_upper) + if(_uget_build_type_upper STREQUAL "DEBUG") + add_compile_options(${_uget_sanitize_flags} -fno-omit-frame-pointer) + add_link_options(${_uget_sanitize_flags}) + if(UNIX AND NOT APPLE) + add_link_options(-Wl,--no-as-needed) + endif() + endif() + endif() +endif() + include(GNUInstallDirs) + +set(UG_DATADIR "${CMAKE_INSTALL_FULL_DATADIR}/uget" CACHE STRING + "Path used for UG_DATADIR (where shared data files live)") include(CheckIncludeFile) include(CheckSymbolExists) @@ -35,7 +65,7 @@ else() message(STATUS "pkg-config not found on PATH yet; FindPkgConfig may fail unless the toolchain provides it.") endif() -find_package(PkgConfig QUIET) +find_package(PkgConfig REQUIRED) # Feature test macros on non-MSVC to expose POSIX prototypes (getaddrinfo, ftruncate, popen, etc.) if(NOT MSVC) @@ -89,8 +119,8 @@ check_symbol_exists(popen "stdio.h" HAVE_POPEN) check_symbol_exists(pclose "stdio.h" HAVE_PCLOSE) # pkg-config deps -if(NOT WITH_GUI AND WITH_TRAY) - message(STATUS "WITH_GUI=OFF -> disabling system tray support") +if(NOT UGET_WITH_GUI AND WITH_TRAY) + message(STATUS "UGET_WITH_GUI=OFF -> disabling system tray support") set(WITH_TRAY OFF CACHE BOOL "" FORCE) endif() @@ -99,43 +129,71 @@ set(HAVE_GSTREAMER 0) set(HAVE_GLIB 0) set(HAVE_CURL 0) -set(_uget_private_include_dirs) -set(_uget_private_library_dirs) -set(_uget_private_libraries) -set(_uget_private_compile_options) - -if(WITH_GUI) - if(PkgConfig_FOUND) - pkg_check_modules(GTK REQUIRED gtk+-3.0>=3.24) - pkg_check_modules(GLIB REQUIRED glib-2.0>=2.76 gobject-2.0) - pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-base-1.0) - add_compile_definitions(HAVE_GLIB=1) - - set(HAVE_GTK 1) - set(HAVE_GSTREAMER 1) - set(HAVE_GLIB 1) - - list(APPEND _uget_private_include_dirs - ${GTK_INCLUDE_DIRS} - ${GLIB_INCLUDE_DIRS} - ${GST_INCLUDE_DIRS}) - list(APPEND _uget_private_library_dirs - ${GTK_LIBRARY_DIRS} - ${GLIB_LIBRARY_DIRS} - ${GST_LIBRARY_DIRS}) - list(APPEND _uget_private_libraries - ${GTK_LIBRARIES} - ${GLIB_LIBRARIES} - ${GST_LIBRARIES}) - list(APPEND _uget_private_compile_options - ${GTK_CFLAGS_OTHER} - ${GLIB_CFLAGS_OTHER} - ${GST_CFLAGS_OTHER}) - else() - message(FATAL_ERROR "WITH_GUI=ON but pkg-config is unavailable on this toolchain.") +set(_uget_common_include_dirs) +set(_uget_common_library_dirs) +set(_uget_common_libraries) +set(_uget_common_compile_options) + +pkg_check_modules(GLIB2 QUIET glib-2.0>=2.76 gobject-2.0) +if(NOT GLIB2_FOUND) + find_package(GLIB CONFIG QUIET) + if(GLIB_FOUND) + set(GLIB2_FOUND TRUE) + if(DEFINED GLIB_INCLUDE_DIRS) + set(GLIB2_INCLUDE_DIRS ${GLIB_INCLUDE_DIRS}) + endif() + if(DEFINED GLIB_LIBRARY_DIRS) + set(GLIB2_LIBRARY_DIRS ${GLIB_LIBRARY_DIRS}) + endif() + if(DEFINED GLIB_LIBRARIES) + set(GLIB2_LIBRARIES ${GLIB_LIBRARIES}) + endif() + if(DEFINED GLIB_CFLAGS_OTHER) + set(GLIB2_CFLAGS_OTHER ${GLIB_CFLAGS_OTHER}) + endif() endif() -else() - message(STATUS "WITH_GUI=OFF: skipping GTK/GLib/GStreamer detection") +endif() + +if(NOT GLIB2_FOUND) + message(FATAL_ERROR "Required GLib not found. Install via vcpkg (manifest) or system packages.") +endif() + +if(NOT DEFINED GLIB2_INCLUDE_DIRS) + set(GLIB2_INCLUDE_DIRS "") +endif() +if(NOT DEFINED GLIB2_LIBRARY_DIRS) + set(GLIB2_LIBRARY_DIRS "") +endif() +if(NOT DEFINED GLIB2_LIBRARIES) + set(GLIB2_LIBRARIES "") +endif() +if(NOT DEFINED GLIB2_CFLAGS_OTHER) + set(GLIB2_CFLAGS_OTHER "") +endif() + +set(GLIB_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS}) +set(GLIB_LIBRARY_DIRS ${GLIB2_LIBRARY_DIRS}) +set(GLIB_LIBRARIES ${GLIB2_LIBRARIES}) +set(GLIB_CFLAGS_OTHER ${GLIB2_CFLAGS_OTHER}) + +add_compile_definitions(HAVE_GLIB=1) +set(HAVE_GLIB 1) + +list(APPEND _uget_common_include_dirs ${GLIB2_INCLUDE_DIRS}) +list(APPEND _uget_common_library_dirs ${GLIB2_LIBRARY_DIRS}) +list(APPEND _uget_common_libraries ${GLIB2_LIBRARIES}) +list(APPEND _uget_common_compile_options ${GLIB2_CFLAGS_OTHER}) + +pkg_check_modules(GTK3 QUIET gtk+-3.0>=3.24) +pkg_check_modules(GST QUIET gstreamer-1.0 gstreamer-base-1.0) +pkg_check_modules(AYATANA QUIET ayatana-appindicator3-0.1) +pkg_check_modules(APPINDICATOR QUIET appindicator3-0.1) + +if(GTK3_FOUND) + set(HAVE_GTK 1) +endif() +if(GST_FOUND) + set(HAVE_GSTREAMER 1) endif() if(WIN32) @@ -165,10 +223,17 @@ else() set(UGET_CURL_CFLAGS_OTHER ${LIBCURL_CFLAGS_OTHER}) endif() -list(APPEND _uget_private_include_dirs ${UGET_CURL_INCLUDE_DIRS}) -list(APPEND _uget_private_library_dirs ${UGET_CURL_LIBRARY_DIRS}) -list(APPEND _uget_private_libraries ${UGET_CURL_LIBRARIES}) -list(APPEND _uget_private_compile_options ${UGET_CURL_CFLAGS_OTHER}) +if(NOT DEFINED CURL_LIBRARIES OR CURL_LIBRARIES STREQUAL "") + set(CURL_LIBRARIES ${UGET_CURL_LIBRARIES}) +endif() +if(NOT DEFINED CURL_INCLUDE_DIRS OR CURL_INCLUDE_DIRS STREQUAL "") + set(CURL_INCLUDE_DIRS ${UGET_CURL_INCLUDE_DIRS}) +endif() + +list(APPEND _uget_common_include_dirs ${UGET_CURL_INCLUDE_DIRS}) +list(APPEND _uget_common_library_dirs ${UGET_CURL_LIBRARY_DIRS}) +list(APPEND _uget_common_libraries ${UGET_CURL_LIBRARIES}) +list(APPEND _uget_common_compile_options ${UGET_CURL_CFLAGS_OTHER}) find_package(Threads REQUIRED) @@ -186,37 +251,23 @@ set(HAVE_OPENSSL 0) set(HAVE_LIBGCRYPT 0) # ---------- TRAY (Ayatana/AppIndicator) ---------- -if(WITH_GUI AND WITH_TRAY) - if(PkgConfig_FOUND) - pkg_check_modules(AYATANA QUIET ayatana-appindicator3-0.1) - if(AYATANA_FOUND) - add_compile_definitions(HAVE_AYATANA=1) - list(APPEND _uget_private_include_dirs ${AYATANA_INCLUDE_DIRS}) - list(APPEND _uget_private_library_dirs ${AYATANA_LIBRARY_DIRS}) - list(APPEND _uget_private_libraries ${AYATANA_LIBRARIES}) - set(HAVE_TRAY 1) - set(HAVE_AYATANA 1) - message(STATUS "Tray: using ayatana-appindicator3") - else() - pkg_check_modules(APPINDICATOR QUIET appindicator3-0.1) - if(APPINDICATOR_FOUND) - add_compile_definitions(HAVE_APPINDICATOR=1) - list(APPEND _uget_private_include_dirs ${APPINDICATOR_INCLUDE_DIRS}) - list(APPEND _uget_private_library_dirs ${APPINDICATOR_LIBRARY_DIRS}) - list(APPEND _uget_private_libraries ${APPINDICATOR_LIBRARIES}) - set(HAVE_TRAY 1) - set(HAVE_APPINDICATOR 1) - message(STATUS "Tray: using appindicator3-0.1 (fallback)") - else() - message(STATUS "Tray requested, but no Ayatana/AppIndicator found -> tray disabled") - set(WITH_TRAY OFF CACHE BOOL "" FORCE) - endif() - endif() +if(UGET_WITH_GUI AND WITH_TRAY) + if(AYATANA_FOUND) + add_compile_definitions(HAVE_AYATANA=1) + set(HAVE_TRAY 1) + set(HAVE_AYATANA 1) + message(STATUS "Tray: using ayatana-appindicator3") + elseif(APPINDICATOR_FOUND) + add_compile_definitions(HAVE_APPINDICATOR=1) + set(HAVE_TRAY 1) + set(HAVE_APPINDICATOR 1) + message(STATUS "Tray: using appindicator3-0.1 (fallback)") else() - message(FATAL_ERROR "WITH_TRAY=ON requires pkg-config.") + message(STATUS "Tray requested, but no Ayatana/AppIndicator found -> tray disabled") + set(WITH_TRAY OFF CACHE BOOL "" FORCE) endif() elseif(WITH_TRAY) - message(STATUS "WITH_TRAY requested but WITH_GUI=OFF -> disabling tray support") + message(STATUS "WITH_TRAY requested but UGET_WITH_GUI=OFF -> disabling tray support") set(WITH_TRAY OFF CACHE BOOL "" FORCE) endif() @@ -225,9 +276,9 @@ if(WITH_PWMD) if(PkgConfig_FOUND) pkg_check_modules(PWMD QUIET libpwmd) if(PWMD_FOUND) - list(APPEND _uget_private_include_dirs ${PWMD_INCLUDE_DIRS}) - list(APPEND _uget_private_library_dirs ${PWMD_LIBRARY_DIRS}) - list(APPEND _uget_private_libraries ${PWMD_LIBRARIES}) + list(APPEND _uget_common_include_dirs ${PWMD_INCLUDE_DIRS}) + list(APPEND _uget_common_library_dirs ${PWMD_LIBRARY_DIRS}) + list(APPEND _uget_common_libraries ${PWMD_LIBRARIES}) set(HAVE_PWMD 1) message(STATUS "PWMD: enabled") else() @@ -242,91 +293,320 @@ endif() if(WITH_OPENSSL) find_package(OpenSSL REQUIRED) add_compile_definitions(HAVE_OPENSSL=1) - list(APPEND _uget_private_libraries OpenSSL::SSL OpenSSL::Crypto) + list(APPEND _uget_common_libraries OpenSSL::SSL OpenSSL::Crypto) set(HAVE_OPENSSL 1) endif() -if(WITH_GNUTLS) - if(PkgConfig_FOUND) - pkg_check_modules(GNUTLS REQUIRED gnutls) - pkg_check_modules(GCRYPT REQUIRED libgcrypt) - add_compile_definitions(HAVE_GNUTLS=1 HAVE_LIBGCRYPT=1) - set(HAVE_GNUTLS 1) - set(HAVE_LIBGCRYPT 1) - - list(APPEND _uget_private_include_dirs ${GNUTLS_INCLUDE_DIRS} ${GCRYPT_INCLUDE_DIRS}) - list(APPEND _uget_private_library_dirs ${GNUTLS_LIBRARY_DIRS} ${GCRYPT_LIBRARY_DIRS}) - list(APPEND _uget_private_libraries ${GNUTLS_LIBRARIES} ${GCRYPT_LIBRARIES}) - else() - message(FATAL_ERROR "WITH_GNUTLS=ON requires pkg-config.") +pkg_check_modules(GNUTLS QUIET gnutls) + +set(GCRYPT_FOUND FALSE) +set(_uget_gcrypt_module "") +foreach(_gcrypt_candidate libgcrypt gcrypt) + if(NOT GCRYPT_FOUND) + pkg_check_modules(GCRYPT QUIET ${_gcrypt_candidate}) + if(GCRYPT_FOUND) + set(_uget_gcrypt_module "${_gcrypt_candidate}") + endif() endif() -endif() +endforeach() -# TEMP: discover sources (to be replaced with explicit lists later) -file(GLOB_RECURSE CORE_SRC CONFIGURE_DEPENDS src/*.c) -add_library(core STATIC ${CORE_SRC}) -target_include_directories(core PUBLIC ${CMAKE_SOURCE_DIR}/include) -target_compile_definitions(core PRIVATE HAVE_CONFIG_H) -target_include_directories(core PRIVATE ${CMAKE_BINARY_DIR}/generated) +set(HAVE_GNUTLS ${GNUTLS_FOUND}) +set(HAVE_LIBGCRYPT ${GCRYPT_FOUND}) -if(_uget_private_compile_options) - target_compile_options(core PRIVATE ${_uget_private_compile_options}) +if(OPENSSL_FOUND) + set(HAVE_OPENSSL 1) endif() -if(_uget_private_include_dirs) - target_include_directories(core PRIVATE ${_uget_private_include_dirs}) + +if(WITH_GNUTLS) + if(NOT GNUTLS_FOUND) + message(FATAL_ERROR "WITH_GNUTLS=ON but gnutls was not found") + endif() + if(NOT GCRYPT_FOUND) + message(FATAL_ERROR "WITH_GNUTLS=ON but libgcrypt was not found") + endif() + add_compile_definitions(HAVE_GNUTLS=1 HAVE_LIBGCRYPT=1) + set(HAVE_GNUTLS 1) + set(HAVE_LIBGCRYPT 1) +else() + # Treat GnuTLS as unavailable if the feature is explicitly disabled + set(HAVE_GNUTLS 0) endif() -if(_uget_private_library_dirs) - target_link_directories(core PRIVATE ${_uget_private_library_dirs}) + +if(HAVE_LIBGCRYPT) + add_compile_definitions(HAVE_LIBGCRYPT=1) + if(_uget_gcrypt_module) + message(STATUS "libgcrypt: enabled via pkg-config module '${_uget_gcrypt_module}'") + endif() endif() -if(_uget_private_libraries) - target_link_libraries(core PRIVATE ${_uget_private_libraries}) + +# ---- Libraries and executables ---- +set(UGLIB_SOURCES + uglib/UgArray.c + uglib/UgBuffer.c + uglib/UgData.c + uglib/UgEntry.c + uglib/UgFileUtil.c + uglib/UgHtml.c + uglib/UgHtmlEntry.c + uglib/UgHtmlFilter.c + uglib/UgInfo.c + uglib/UgJson-custom.c + uglib/UgJson.c + uglib/UgJsonFile.c + uglib/UgJsonrpc.c + uglib/UgJsonrpcCurl.c + uglib/UgJsonrpcSocket.c + uglib/UgList.c + uglib/UgNode.c + uglib/UgOption.c + uglib/UgRegistry.c + uglib/UgSocket.c + uglib/UgSLink.c + uglib/UgStdio.c + uglib/UgString.c + uglib/UgThread.c + uglib/UgUri.c + uglib/UgUtil.c + uglib/UgValue.c +) + +add_library(uglib STATIC ${UGLIB_SOURCES}) +target_include_directories(uglib + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/uglib + ${CMAKE_BINARY_DIR}/generated) +target_compile_definitions(uglib PUBLIC HAVE_CONFIG_H) +target_link_libraries(uglib PUBLIC Threads::Threads) + +set(uget_core_sources + uget/UgetA2cf.c + uget/UgetApp.c + uget/UgetAria2.c + uget/UgetCurl.c + uget/UgetData.c + uget/UgetEvent.c + uget/UgetFiles.c + uget/UgetHash.c + uget/UgetMedia-youtube.c + uget/UgetMedia.c + uget/UgetNode-compare.c + uget/UgetNode-filter.c + uget/UgetNode.c + uget/UgetOption.c + uget/UgetPlugin.c + uget/UgetPluginAgent.c + uget/UgetPluginAria2.c + uget/UgetPluginCurl.c + uget/UgetPluginEmpty.c + uget/UgetPluginMedia.c + uget/UgetRpc.c + uget/UgetRss.c + uget/UgetSequence.c + uget/UgetSite.c + uget/UgetTask.c +) + +if(HAVE_PWMD) + list(APPEND uget_core_sources uget/pwmd.c) endif() -add_executable(app src/main.c) # adjust if main file differs -target_link_libraries(app PRIVATE core) +add_library(uget_core STATIC ${uget_core_sources}) +target_include_directories(uget_core + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/uget + ${CMAKE_CURRENT_SOURCE_DIR}/uglib + ${CMAKE_BINARY_DIR}/generated) +target_compile_definitions(uget_core PUBLIC HAVE_CONFIG_H) +target_link_libraries(uget_core PUBLIC uglib Threads::Threads) + +if(HAVE_GNUTLS) + target_include_directories(uget_core PRIVATE ${GNUTLS_INCLUDE_DIRS}) + target_link_libraries(uget_core PUBLIC ${GNUTLS_LIBRARIES}) + target_compile_definitions(uget_core PRIVATE HAVE_GNUTLS=1) +endif() -if(_uget_private_compile_options) - target_compile_options(app PRIVATE ${_uget_private_compile_options}) +if(HAVE_LIBGCRYPT) + target_include_directories(uget_core PRIVATE ${GCRYPT_INCLUDE_DIRS}) + target_link_libraries(uget_core PUBLIC ${GCRYPT_LIBRARIES}) + target_compile_definitions(uget_core PRIVATE HAVE_LIBGCRYPT=1) endif() -if(_uget_private_include_dirs) - target_include_directories(app PRIVATE ${_uget_private_include_dirs}) + +set(_uget_mega_module "") +if(ENABLE_MEGA) + set(_uget_mega_candidates mega megasdk) + unset(MEGA_FOUND) + unset(MEGA_LIBRARIES) + unset(MEGA_LIBRARY_DIRS) + unset(MEGA_INCLUDE_DIRS) + unset(MEGA_CFLAGS_OTHER) + foreach(_mega_candidate ${_uget_mega_candidates}) + if(NOT MEGA_FOUND) + pkg_check_modules(MEGA QUIET ${_mega_candidate}) + if(MEGA_FOUND) + set(_uget_mega_module "${_mega_candidate}") + endif() + endif() + endforeach() + if(NOT MEGA_FOUND) + list(JOIN _uget_mega_candidates ", " _uget_mega_list) + message(FATAL_ERROR "ENABLE_MEGA=ON but no Mega SDK pkg-config module was found (tried: ${_uget_mega_list})") + endif() + target_sources(uget_core PRIVATE uget/UgetPluginMega.c) + target_include_directories(uget_core PRIVATE ${MEGA_INCLUDE_DIRS}) + if(MEGA_LIBRARY_DIRS) + target_link_directories(uget_core PRIVATE ${MEGA_LIBRARY_DIRS}) + endif() + target_link_libraries(uget_core PRIVATE ${MEGA_LIBRARIES}) + if(MEGA_CFLAGS_OTHER) + target_compile_options(uget_core PRIVATE ${MEGA_CFLAGS_OTHER}) + endif() + target_compile_definitions(uget_core PUBLIC HAVE_MEGA=1) + message(STATUS "Mega: enabled via pkg-config module '${_uget_mega_module}'") +else() + message(STATUS "Mega: disabled (ENABLE_MEGA=OFF)") endif() -if(_uget_private_library_dirs) - target_link_directories(app PRIVATE ${_uget_private_library_dirs}) + +# --- CLI entrypoint discovery +set(UGET_CLI_CANDIDATES + ${CMAKE_SOURCE_DIR}/uget/cli/uget.c + ${CMAKE_SOURCE_DIR}/uget/uget.c + ${CMAKE_SOURCE_DIR}/uget/main.c + ${CMAKE_SOURCE_DIR}/src/uget.c +) + +set(UGET_CLI_MAIN "") +foreach(_c ${UGET_CLI_CANDIDATES}) + if(EXISTS "${_c}") + set(UGET_CLI_MAIN "${_c}") + break() + endif() +endforeach() + +option(UGET_CLI_STUB "Generate a minimal CLI main() if no real CLI is found" OFF) + +if(UGET_CLI_MAIN) + message(STATUS "uget CLI: using ${UGET_CLI_MAIN}") + add_executable(uget ${UGET_CLI_MAIN}) +elseif(UGET_CLI_STUB) + message(WARNING "uget CLI: real entrypoint not found; generating stub (prints version and exits 0)") + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/generated) + file(WRITE ${CMAKE_BINARY_DIR}/generated/uget_stub.c +"#include \n" +"int main(int argc, char** argv){\n" +" (void)argc; (void)argv;\n" +" printf(\"uget (stub) built with CMake %s\\n\", \"${CMAKE_VERSION}\");\n" +" return 0;\n" +"}\n") + add_executable(uget ${CMAKE_BINARY_DIR}/generated/uget_stub.c) +else() + message(STATUS "uget CLI: no entrypoint found; skipping CLI build") endif() -if(_uget_private_libraries) - target_link_libraries(app PRIVATE ${_uget_private_libraries}) + +if(TARGET uget) + target_link_libraries(uget PRIVATE uget_core uglib Threads::Threads ${CURL_LIBRARIES}) + target_include_directories(uget PRIVATE + ${CMAKE_SOURCE_DIR}/uget + ${CMAKE_SOURCE_DIR}/uglib + ${CMAKE_BINARY_DIR}/generated + ${CURL_INCLUDE_DIRS} + ) + target_compile_definitions(uget PRIVATE + $ + ) + install(TARGETS uget RUNTIME DESTINATION bin) endif() -# --- Project-wide compile warnings (already set globally, but ensure targets inherit) --- -if(MSVC) - target_compile_options(core PRIVATE /W4 /permissive- /utf-8) - target_compile_options(app PRIVATE /W4 /permissive- /utf-8) +if(UGET_WITH_GUI AND GTK3_FOUND) + file(GLOB UGET_GTK_SOURCES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/ui-gtk/*.c") + if(UGET_GTK_SOURCES) + add_executable(uget-gtk ${UGET_GTK_SOURCES}) + target_include_directories(uget-gtk PRIVATE + ${CMAKE_SOURCE_DIR}/uget + ${CMAKE_SOURCE_DIR}/uglib + ${CMAKE_SOURCE_DIR}/ui-gtk + ${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${GST_INCLUDE_DIRS} ${AYATANA_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR}/generated) + target_compile_options(uget-gtk PRIVATE + ${GLIB_CFLAGS_OTHER} ${GTK3_CFLAGS_OTHER} ${GST_CFLAGS_OTHER} ${AYATANA_CFLAGS_OTHER}) + target_compile_definitions(uget-gtk PRIVATE HAVE_CONFIG_H UG_DATADIR="${UG_DATADIR}") + target_link_libraries(uget-gtk PRIVATE + uget_core + uglib + Threads::Threads + ${GLIB_LIBRARIES} + ${GTK3_LIBRARIES} + ${GST_LIBRARIES} + ${AYATANA_LIBRARIES}) + if(UNIX AND NOT APPLE) + target_link_libraries(uget-gtk PRIVATE m dl) + target_link_options(uget-gtk PRIVATE -Wl,--as-needed) + endif() + install(TARGETS uget-gtk RUNTIME DESTINATION bin) + message(STATUS "GUI: enabled (gtk+-3.0)") + else() + message(WARNING "UGET_WITH_GUI=ON but no GTK sources were found in ui-gtk/") + message(STATUS "GUI: disabled (gtk+-3.0 not found or UGET_WITH_GUI=OFF)") + endif() else() - target_compile_options(core PRIVATE -Wall -Wextra -Wpedantic) - target_compile_options(app PRIVATE -Wall -Wextra -Wpedantic) + message(STATUS "GUI: disabled (gtk+-3.0 not found or UGET_WITH_GUI=OFF)") endif() -# --- Sanitizers: only in Debug, only on non-MSVC --- -if(ENABLE_SANITIZERS AND CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT MSVC) - target_compile_options(core PRIVATE -fsanitize=address,undefined -fno-omit-frame-pointer) - target_link_options( core PRIVATE -fsanitize=address,undefined) +set(_uget_targets uglib uget_core) +if(TARGET uget) + list(APPEND _uget_targets uget) +endif() +if(TARGET uget-gtk) + list(APPEND _uget_targets uget-gtk) +endif() - target_compile_options(app PRIVATE -fsanitize=address,undefined -fno-omit-frame-pointer) - target_link_options( app PRIVATE -fsanitize=address,undefined) +foreach(_target IN LISTS _uget_targets) + if(TARGET ${_target}) + if(_uget_common_compile_options) + target_compile_options(${_target} PRIVATE ${_uget_common_compile_options}) + endif() + if(_uget_common_include_dirs) + target_include_directories(${_target} PRIVATE ${_uget_common_include_dirs}) + endif() + if(_uget_common_library_dirs) + target_link_directories(${_target} PRIVATE ${_uget_common_library_dirs}) + endif() + endif() +endforeach() + +if(_uget_common_libraries) + if(TARGET uglib) + target_link_libraries(uglib PUBLIC ${_uget_common_libraries}) + endif() + if(TARGET uget_core) + target_link_libraries(uget_core PUBLIC ${_uget_common_libraries}) + endif() endif() + +# --- Project-wide compile warnings (already set globally, but ensure targets inherit) --- +foreach(_target IN LISTS _uget_targets) + if(TARGET ${_target}) + if(MSVC) + target_compile_options(${_target} PRIVATE /W4 /permissive- /utf-8) + else() + target_compile_options(${_target} PRIVATE -Wall -Wextra -Wpedantic) + endif() + endif() +endforeach() + configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in ${CMAKE_BINARY_DIR}/generated/config.h @ONLY) include_directories(${CMAKE_BINARY_DIR}/generated) if(BUILD_TESTING) - if(WITH_GUI) + if(UGET_WITH_GUI) add_subdirectory(tests) else() - message(STATUS "BUILD_TESTING=ON but WITH_GUI=OFF -> skipping GLib/GTK tests on this platform") + message(STATUS "BUILD_TESTING=ON but UGET_WITH_GUI=OFF -> skipping GLib/GTK tests on this platform") endif() endif() -install(TARGETS app RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/data") + install(DIRECTORY data/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/uget) +endif() diff --git a/CMakePresets.json b/CMakePresets.json index bd9c2a6..4a3221e 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -9,7 +9,7 @@ }, { "name": "msvc-vcpkg", "generator": "Ninja", "binaryDir": "build/msvc", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_TOOLCHAIN_FILE": "$env{RUNVCPKG_VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "VCPKG_TARGET_TRIPLET": "x64-windows" } } ], diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6351eef..0ad38c3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,130 +1,22 @@ cmake_minimum_required(VERSION 3.10) +cmake_policy(SET CMP0079 NEW) -if(NOT WITH_GUI) - message(STATUS "tests/: WITH_GUI=OFF -> not building legacy GLib/GTK tests") +find_package(PkgConfig REQUIRED) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) + +if(NOT UGET_WITH_GUI) + message(STATUS "tests/: UGET_WITH_GUI=OFF -> not building legacy GLib/GTK tests") return() endif() -set(UGLIB_SOURCES - ${CMAKE_SOURCE_DIR}/uglib/UgStdio.c - ${CMAKE_SOURCE_DIR}/uglib/UgString.c - ${CMAKE_SOURCE_DIR}/uglib/UgThread.c - ${CMAKE_SOURCE_DIR}/uglib/UgSocket.c - ${CMAKE_SOURCE_DIR}/uglib/UgUtil.c - ${CMAKE_SOURCE_DIR}/uglib/UgFileUtil.c - ${CMAKE_SOURCE_DIR}/uglib/UgArray.c - ${CMAKE_SOURCE_DIR}/uglib/UgList.c - ${CMAKE_SOURCE_DIR}/uglib/UgSLink.c - ${CMAKE_SOURCE_DIR}/uglib/UgOption.c - ${CMAKE_SOURCE_DIR}/uglib/UgUri.c - ${CMAKE_SOURCE_DIR}/uglib/UgNode.c - ${CMAKE_SOURCE_DIR}/uglib/UgData.c - ${CMAKE_SOURCE_DIR}/uglib/UgInfo.c - ${CMAKE_SOURCE_DIR}/uglib/UgRegistry.c - ${CMAKE_SOURCE_DIR}/uglib/UgValue.c - ${CMAKE_SOURCE_DIR}/uglib/UgEntry.c - ${CMAKE_SOURCE_DIR}/uglib/UgBuffer.c - ${CMAKE_SOURCE_DIR}/uglib/UgJson.c - ${CMAKE_SOURCE_DIR}/uglib/UgJson-custom.c - ${CMAKE_SOURCE_DIR}/uglib/UgJsonFile.c - ${CMAKE_SOURCE_DIR}/uglib/UgJsonrpc.c - ${CMAKE_SOURCE_DIR}/uglib/UgJsonrpcSocket.c - ${CMAKE_SOURCE_DIR}/uglib/UgJsonrpcCurl.c - ${CMAKE_SOURCE_DIR}/uglib/UgHtml.c - ${CMAKE_SOURCE_DIR}/uglib/UgHtmlEntry.c - ${CMAKE_SOURCE_DIR}/uglib/UgHtmlFilter.c -) - -add_library(uglib STATIC ${UGLIB_SOURCES}) -target_include_directories(uglib - PUBLIC - ${CMAKE_SOURCE_DIR}/uglib - ${GLIB_INCLUDE_DIRS} - ${UGET_CURL_INCLUDE_DIRS} -) -target_link_directories(uglib PUBLIC ${GLIB_LIBRARY_DIRS} ${UGET_CURL_LIBRARY_DIRS}) -target_link_libraries(uglib - PUBLIC - Threads::Threads - ${GLIB_LIBRARIES} - ${UGET_CURL_LIBRARIES} -) -target_compile_options(uglib PRIVATE ${GLIB_CFLAGS_OTHER} ${UGET_CURL_CFLAGS_OTHER}) -target_compile_definitions(uglib PUBLIC HAVE_CONFIG_H) - -set(UGET_SOURCES - ${CMAKE_SOURCE_DIR}/uget/UgetSequence.c - ${CMAKE_SOURCE_DIR}/uget/UgetRss.c - ${CMAKE_SOURCE_DIR}/uget/UgetRpc.c - ${CMAKE_SOURCE_DIR}/uget/UgetOption.c - ${CMAKE_SOURCE_DIR}/uget/UgetData.c - ${CMAKE_SOURCE_DIR}/uget/UgetFiles.c - ${CMAKE_SOURCE_DIR}/uget/UgetNode.c - ${CMAKE_SOURCE_DIR}/uget/UgetNode-compare.c - ${CMAKE_SOURCE_DIR}/uget/UgetNode-filter.c - ${CMAKE_SOURCE_DIR}/uget/UgetTask.c - ${CMAKE_SOURCE_DIR}/uget/UgetHash.c - ${CMAKE_SOURCE_DIR}/uget/UgetSite.c - ${CMAKE_SOURCE_DIR}/uget/UgetApp.c - ${CMAKE_SOURCE_DIR}/uget/UgetEvent.c - ${CMAKE_SOURCE_DIR}/uget/UgetPlugin.c - ${CMAKE_SOURCE_DIR}/uget/UgetA2cf.c - ${CMAKE_SOURCE_DIR}/uget/UgetCurl.c - ${CMAKE_SOURCE_DIR}/uget/UgetAria2.c - ${CMAKE_SOURCE_DIR}/uget/UgetMedia.c - ${CMAKE_SOURCE_DIR}/uget/UgetMedia-youtube.c - ${CMAKE_SOURCE_DIR}/uget/UgetPluginCurl.c - ${CMAKE_SOURCE_DIR}/uget/UgetPluginAria2.c - ${CMAKE_SOURCE_DIR}/uget/UgetPluginMedia.c - ${CMAKE_SOURCE_DIR}/uget/UgetPluginAgent.c - ${CMAKE_SOURCE_DIR}/uget/UgetPluginEmpty.c -) +add_library(uglib_alias ALIAS uglib) +add_library(uget_core_alias ALIAS uget_core) set(_uget_has_mega FALSE) -if(HAVE_LIBGCRYPT AND HAVE_OPENSSL) - list(APPEND UGET_SOURCES ${CMAKE_SOURCE_DIR}/uget/UgetPluginMega.c) +if(HAVE_LIBGCRYPT AND (HAVE_OPENSSL OR HAVE_GNUTLS)) set(_uget_has_mega TRUE) else() - message(STATUS "Skipping UgetPluginMega.c (requires libgcrypt and OpenSSL)") -endif() - -if(HAVE_PWMD) - list(APPEND UGET_SOURCES ${CMAKE_SOURCE_DIR}/uget/pwmd.c) -endif() - -add_library(uget STATIC ${UGET_SOURCES}) -target_include_directories(uget - PUBLIC - ${CMAKE_SOURCE_DIR}/uget - ${CMAKE_SOURCE_DIR}/uglib - ${GLIB_INCLUDE_DIRS} - ${UGET_CURL_INCLUDE_DIRS} -) -target_link_directories(uget PUBLIC ${GLIB_LIBRARY_DIRS} ${UGET_CURL_LIBRARY_DIRS}) -target_link_libraries(uget - PUBLIC - uglib - Threads::Threads - ${GLIB_LIBRARIES} - ${UGET_CURL_LIBRARIES} -) -target_compile_options(uget PRIVATE ${GLIB_CFLAGS_OTHER} ${UGET_CURL_CFLAGS_OTHER}) -target_compile_definitions(uget PUBLIC HAVE_CONFIG_H) - -if(HAVE_PWMD) - target_include_directories(uget PUBLIC ${PWMD_INCLUDE_DIRS}) - target_link_directories(uget PUBLIC ${PWMD_LIBRARY_DIRS}) - target_link_libraries(uget PUBLIC ${PWMD_LIBRARIES}) -endif() - -if(HAVE_GNUTLS) - target_include_directories(uget PUBLIC ${GNUTLS_INCLUDE_DIRS} ${GCRYPT_INCLUDE_DIRS}) - target_link_directories(uget PUBLIC ${GNUTLS_LIBRARY_DIRS} ${GCRYPT_LIBRARY_DIRS}) - target_link_libraries(uget PUBLIC ${GNUTLS_LIBRARIES} ${GCRYPT_LIBRARIES}) -endif() - -if(HAVE_OPENSSL) - target_link_libraries(uget PUBLIC OpenSSL::SSL OpenSSL::Crypto) + message(STATUS "Skipping test_plugin_app (Mega plug-in not available)") endif() function(add_uget_test target) @@ -138,18 +30,10 @@ function(add_uget_test target) endif() add_executable(${target} ${TEST_SOURCES}) - target_link_libraries(${target} PRIVATE ${TEST_LIBS}) - target_include_directories(${target} PRIVATE - ${CMAKE_SOURCE_DIR}/uglib - ${CMAKE_SOURCE_DIR}/uget - ${GLIB_INCLUDE_DIRS} - ${UGET_CURL_INCLUDE_DIRS} - ${CMAKE_BINARY_DIR}/generated - ) - target_compile_options(${target} PRIVATE ${GLIB_CFLAGS_OTHER} ${UGET_CURL_CFLAGS_OTHER}) + target_link_libraries(${target} PRIVATE PkgConfig::GLIB ${TEST_LIBS}) target_compile_definitions(${target} PRIVATE HAVE_CONFIG_H) - add_test(NAME ${target} COMMAND ${target}) + add_test(NAME ${target} COMMAND $) if(TEST_LABELS) set(_labels "${TEST_LABELS}") @@ -163,48 +47,45 @@ function(add_uget_test target) endif() set_tests_properties(${target} PROPERTIES LABELS "${_labels}" - WORKING_DIRECTORY "${_work_dir}" ) + WORKING_DIRECTORY "${_work_dir}" + TIMEOUT 60) endfunction() add_uget_test(test_json SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-json.c - LIBS uglib + LIBS uglib_alias ) add_uget_test(test_info SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-info.c - LIBS uglib + LIBS uglib_alias ) add_uget_test(test_uglib SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-uglib.c - LIBS uglib + LIBS uglib_alias ) add_uget_test(test_uget SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-uget.c - LIBS uget + LIBS uget_core_alias uglib_alias LABELS "unit;net" ) add_uget_test(test_jsonrpc SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-jsonrpc.c - LIBS uget + LIBS uget_core_alias uglib_alias LABELS "unit;net" ) if(TEST test_http) - set_tests_properties(test_http PROPERTIES LABELS "unit;net") + set_tests_properties(test_http PROPERTIES LABELS "unit;net" TIMEOUT 60) endif() if(_uget_has_mega) add_uget_test(test_plugin_app SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-plugin+app.c - LIBS uget + LIBS uget_core_alias uglib_alias LABELS "unit;net" ) -else() - message(STATUS "Skipping test_plugin_app (Mega plug-in not available)") endif() - -set_property(TEST PROPERTY TIMEOUT 60) diff --git a/tests/test-json.c b/tests/test-json.c index 250a11c..bf418e6 100644 --- a/tests/test-json.c +++ b/tests/test-json.c @@ -261,9 +261,34 @@ SampleJs* sample_js_new (void) void sample_js_free (SampleJs* samplejs) { + int index; + + if (samplejs == NULL) + return; + + ug_free (samplejs->name); + samplejs->name = NULL; + + ug_free (samplejs->info.ftp.user); + samplejs->info.ftp.user = NULL; + ug_free (samplejs->info.ftp.password); + samplejs->info.ftp.password = NULL; + + ug_free (samplejs->info.http.user_agent); + samplejs->info.http.user_agent = NULL; + ug_free (samplejs->info.http.referrer); + samplejs->info.http.referrer = NULL; + + for (index = 0; index < samplejs->info.sarray.length; index++) + ug_free (samplejs->info.sarray.at[index]); ug_array_clear (&samplejs->info.sarray); + ug_array_clear (&samplejs->info.iarray); + + for (index = 0; index < samplejs->info.oarray.length; index++) + worked_id_final (&samplejs->info.oarray.at[index]); ug_array_clear (&samplejs->info.oarray); + free (samplejs); } @@ -508,6 +533,7 @@ void sample_js_to_file (SampleJs* samplejs, const char* filename) ug_json_end_write (&json); ug_json_final (&json); + ug_buffer_clear (&buffer, 1); fclose (file); } @@ -844,6 +870,8 @@ void test_array (void) "array.length = '%d'\n" "array.allocated = '%d'\n", array.at, array.length, array.allocated); + + ug_array_clear (&array); } // ---------------------------------------------------------------------------- diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c index 674db50..b6dcc68 100644 --- a/tests/test-jsonrpc.c +++ b/tests/test-jsonrpc.c @@ -35,6 +35,7 @@ */ #include +#include #include #include #include @@ -55,10 +56,17 @@ #define ug_sleep(millisecond) usleep (millisecond * 1000) #endif +static void +free_rpc_array_container (UgJsonrpcArray* array) +{ + ug_jsonrpc_array_free (array); +} + static void socket_receiver (UgSocketServer* server, SOCKET client_fd, void* data) { - char buf[5]; + (void)data; + char buf[5]; ug_socket_server_ref (server); @@ -166,6 +174,7 @@ void print_rpc_object (UgJsonrpcObject* jobj) ug_buffer_write_char (&buffer, '\0'); puts (buffer.beg); + ug_buffer_clear (&buffer, 1); } void test_rpc_parser (void) @@ -198,8 +207,7 @@ void test_rpc_parser (void) parse_rpc_object (jobj, json_string3); print_rpc_object (jobj); - ug_jsonrpc_array_clear (jarray, 1); - free (jarray); + free_rpc_array_container (jarray); } void test_rpc_curl_packet (UgJsonrpcCurl* jrcurl) @@ -257,8 +265,7 @@ void test_jsonrpc_curl (void) ug_jsonrpc_curl_final (jrcurl); free (jrcurl); - ug_jsonrpc_array_clear (jarray, 1); - free (jarray); + free_rpc_array_container (jarray); } // ---------------------------------------------------------------------------- @@ -266,8 +273,10 @@ void test_jsonrpc_curl (void) static void jsonrpc_accepted (UgJsonrpc* jrpc, void* data, void* data2) { - UgJsonrpcObject* request; - UgJsonrpcObject* response; + (void)data; + (void)data2; + UgJsonrpcObject* request; + UgJsonrpcObject* response; int result; request = ug_jsonrpc_object_new (); @@ -419,8 +428,8 @@ void test_uget_aria2 (void) test_uget_aria2_rpc_object (uaria2); // uget_aria2_shutdown (uaria2); - uget_aria2_stop_thread (uaria2); - uget_aria2_unref (uaria2); + uget_aria2_stop_thread (uaria2); + uget_aria2_free (uaria2); ug_sleep (2000); } diff --git a/tests/test-plugin+app.c b/tests/test-plugin+app.c index 0a57c0a..68774fe 100644 --- a/tests/test-plugin+app.c +++ b/tests/test-plugin+app.c @@ -34,368 +34,384 @@ * */ -#include +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include -#include #include +#include +#include #include #include -#include +#include #if defined _WIN32 || defined _WIN64 #include -#define ug_sleep Sleep +#define ug_sleep Sleep #else -#include // usleep() -#define ug_sleep(millisecond) usleep (millisecond * 1000) +#include // usleep() +#define ug_sleep(millisecond) usleep(millisecond * 1000) #endif // _WIN32 || _WIN64 // ---------------------------------------------------------------------------- // test_download -void download_by_plugin(UgInfo* info, const UgetPluginInfo* pinfo) -{ - UgetCommon* common; - UgetFiles* files; - UgetFile* file1; - UgetPlugin* plugin; - UgetEvent* events; - UgetEvent* cur; - UgetEvent* next; - UgetProgress* progress; - int index; - int speed_limit[2]; - char* string[5]; - - speed_limit[0] = 1000000; - speed_limit[1] = 1000000; - - plugin = uget_plugin_new(pinfo); - uget_plugin_accept(plugin, info); - uget_plugin_ctrl(plugin, UGET_PLUGIN_CTRL_SPEED, speed_limit); - if (uget_plugin_start(plugin) == FALSE) { - uget_plugin_unref(plugin); - puts("plug-in failed to start."); - return; - } - - while (uget_plugin_sync(plugin, info)) { - ug_sleep(1000); - // event - events = uget_plugin_pop(plugin); - for (cur = events; cur; cur = next) { - next = cur->next; - printf ("\n" "Event type: %d - %s\n", cur->type, cur->string); - uget_event_free(cur); - } - // progress - progress = ug_info_get(info, UgetProgressInfo); - if (progress == NULL) - continue; - string[0] = ug_str_from_int_unit(progress->complete, NULL); - string[1] = ug_str_from_int_unit(progress->total, NULL); - string[2] = ug_str_from_int_unit(progress->uploaded, NULL); - string[3] = ug_str_from_int_unit(progress->download_speed, "/s"); - string[4] = ug_str_from_int_unit(progress->upload_speed, "/s"); - printf("\r" "DL: %s / %s, %d%%, %s | UL: %s, %s" " ", - string[0], string[1], progress->percent, - string[3], string[2], string[4]); - for (index = 0; index < 5; index++) - ug_free(string[index]); - } - // these data may changed, print them. - common = ug_info_get(info, UgetCommonInfo); - printf("\n" - "common->name : %s\n" - "common->uri : %s\n" - "common->file : %s\n", - common->name, common->uri, common->file); - // print children - files = ug_info_realloc(info, UgetFilesInfo); - for (file1 = (UgetFile*)files->list.head; file1; file1 = file1->next) - printf("file name : %s\n", file1->path); - - uget_plugin_unref(plugin); +void download_by_plugin(UgInfo *info, const UgetPluginInfo *pinfo) { + UgetCommon *common; + UgetFiles *files; + UgetFile *file1; + UgetPlugin *plugin; + UgetEvent *events; + UgetEvent *cur; + UgetEvent *next; + UgetProgress *progress; + int index; + int speed_limit[2]; + char *string[5]; + + speed_limit[0] = 1000000; + speed_limit[1] = 1000000; + + plugin = uget_plugin_new(pinfo); + uget_plugin_accept(plugin, info); + uget_plugin_ctrl(plugin, UGET_PLUGIN_CTRL_SPEED, speed_limit); + if (uget_plugin_start(plugin) == FALSE) { + uget_plugin_unref(plugin); + puts("plug-in failed to start."); + return; + } + + while (uget_plugin_sync(plugin, info)) { + ug_sleep(1000); + // event + events = uget_plugin_pop(plugin); + for (cur = events; cur; cur = next) { + next = cur->next; + printf("\n" + "Event type: %d - %s\n", + cur->type, cur->string); + uget_event_free(cur); + } + // progress + progress = ug_info_get(info, UgetProgressInfo); + if (progress == NULL) + continue; + string[0] = ug_str_from_int_unit(progress->complete, NULL); + string[1] = ug_str_from_int_unit(progress->total, NULL); + string[2] = ug_str_from_int_unit(progress->uploaded, NULL); + string[3] = ug_str_from_int_unit(progress->download_speed, "/s"); + string[4] = ug_str_from_int_unit(progress->upload_speed, "/s"); + printf("\r" + "DL: %s / %s, %d%%, %s | UL: %s, %s" + " ", + string[0], string[1], progress->percent, string[3], string[2], + string[4]); + for (index = 0; index < 5; index++) + ug_free(string[index]); + } + // these data may changed, print them. + common = ug_info_get(info, UgetCommonInfo); + printf("\n" + "common->name : %s\n" + "common->uri : %s\n" + "common->file : %s\n", + common->name, common->uri, common->file); + // print children + files = ug_info_realloc(info, UgetFilesInfo); + for (file1 = (UgetFile *)files->list.head; file1; file1 = file1->next) + printf("file name : %s\n", file1->path); + + uget_plugin_unref(plugin); } -void test_download(void) -{ - UgetCommon* common; - UgetHttp* http; - UgInfo* info; - char* referrer; - char* uri; - char* mirrors; - - uri = "https://mega.nz/#F!i5FXiSoD!TObpvqxETCq8TbEhFevzpg"; -// uri = "https://mega.nz/#!MSpjBRhZ!nZBsUQCAnf71842wXuals_ftSkga3fIQypzBsKEZbmk"; -// uri = "https://www.youtube.com/watch?v=y2004Xaz2HU"; -// uri = "http://download.tuxfamily.org/notepadplus/6.5.3/npp.6.5.3.Installer.exe"; -// uri = "http://ftp.gimp.org/pub/gimp/v2.8/windows/gimp-2.8.10-setup.exe"; -// mirrors = "ftp://195.220.108.108/linux/fedora/linux/updates/19/x86_64/kernel-3.11.2-201.fc19.x86_64.rpm"; - mirrors = NULL; - -// referrer = "http://code.google.com/p/tortoisegit/wiki/Download?tm=2"; - referrer = NULL; - - info = ug_info_new(8, 0); - // commom options - common = ug_info_realloc(info, UgetCommonInfo); - common->uri = ug_strdup(uri); - if (mirrors) - common->mirrors = ug_strdup(mirrors); -// common->folder = ug_strdup ("D:\\Downloads"); -// common->max_connections = 2; - common->debug_level = 1; - common->retry_limit = 1; - common->connect_timeout = 30; - - // http options - http = ug_info_realloc(info, UgetHttpInfo); - if (referrer) - http->referrer = ug_strdup(referrer); +void test_download(void) { + UgetCommon *common; + UgetHttp *http; + UgInfo *info; + char *referrer; + char *uri; + char *mirrors; + + uri = "https://mega.nz/#F!i5FXiSoD!TObpvqxETCq8TbEhFevzpg"; + // uri = + //"https://mega.nz/#!MSpjBRhZ!nZBsUQCAnf71842wXuals_ftSkga3fIQypzBsKEZbmk"; + // uri = "https://www.youtube.com/watch?v=y2004Xaz2HU"; + // uri = + //"http://download.tuxfamily.org/notepadplus/6.5.3/npp.6.5.3.Installer.exe"; + // uri = "http://ftp.gimp.org/pub/gimp/v2.8/windows/gimp-2.8.10-setup.exe"; + // mirrors = + //"ftp://195.220.108.108/linux/fedora/linux/updates/19/x86_64/kernel-3.11.2-201.fc19.x86_64.rpm"; + mirrors = NULL; + + // referrer = "http://code.google.com/p/tortoisegit/wiki/Download?tm=2"; + referrer = NULL; + + info = ug_info_new(8, 0); + // commom options + common = ug_info_realloc(info, UgetCommonInfo); + common->uri = ug_strdup(uri); + if (mirrors) + common->mirrors = ug_strdup(mirrors); + // common->folder = ug_strdup ("D:\\Downloads"); + // common->max_connections = 2; + common->debug_level = 1; + common->retry_limit = 1; + common->connect_timeout = 30; + + // http options + http = ug_info_realloc(info, UgetHttpInfo); + if (referrer) + http->referrer = ug_strdup(referrer); // download_by_plugin(info, UgetPluginCurlInfo); // download_by_plugin(info, UgetPluginAria2Info); // download_by_plugin(info, UgetPluginMediaInfo); - download_by_plugin(info, UgetPluginMegaInfo); - ug_info_unref(info); +#ifdef HAVE_MEGA + download_by_plugin(info, UgetPluginMegaInfo); +#endif + + ug_info_unref(info); } // ---------------------------------------------------------------------------- // test_plugin -void test_setup_plugin_aria2 (void) -{ - const UgetPluginInfo* pinfo; +void test_setup_plugin_aria2(void) { + const UgetPluginInfo *pinfo; - pinfo = UgetPluginAria2Info; - uget_plugin_global_set(pinfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); - uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_URI, - "http://localhost/jsonrpc"); + pinfo = UgetPluginAria2Info; + uget_plugin_global_set(pinfo, UGET_PLUGIN_GLOBAL_INIT, (void *)TRUE); + uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_URI, + "http://localhost/jsonrpc"); #if defined _WIN32 || defined _WIN64 - uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_PATH, - "C:\\Program Files\\uGet\\bin\\aria2c.exe"); + uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_PATH, + "C:\\Program Files\\uGet\\bin\\aria2c.exe"); #endif - uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_ARGUMENT, - "--enable-rpc=true -D --check-certificate=false"); - uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_LAUNCH, (void*) TRUE); - uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_SHUTDOWN, (void*) TRUE); - ug_sleep (1000); - uget_plugin_global_set(pinfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); - ug_sleep (1000); + uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_ARGUMENT, + "--enable-rpc=true -D --check-certificate=false"); + uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_LAUNCH, (void *)TRUE); + uget_plugin_global_set(pinfo, UGET_PLUGIN_ARIA2_GLOBAL_SHUTDOWN, + (void *)TRUE); + ug_sleep(1000); + uget_plugin_global_set(pinfo, UGET_PLUGIN_GLOBAL_INIT, (void *)FALSE); + ug_sleep(1000); } // ---------------------------------------------------------------------------- // test_task -void print_speed_limit (UgetNode** dnode, int count) -{ - int total[2] = {0,0}; - UgetRelation* relation; - - for (count = 0; count < 7; count++) { - relation = ug_info_get (dnode[count]->info, UgetRelationInfo); - if (relation->task) { - printf ("limit D: %d, U: %d | speed D: %d, U: %d\n", - relation->task->limit[0], - relation->task->limit[1], - relation->task->speed[0], - relation->task->speed[1]); - total[0] += relation->task->limit[0]; - total[1] += relation->task->limit[1]; - } - } - - printf ("total limit D: %d, U: %d\n", - total[0], - total[1]); +void print_speed_limit(UgetNode **dnode, int count) { + int total[2] = {0, 0}; + UgetRelation *relation; + + for (count = 0; count < 7; count++) { + relation = ug_info_get(dnode[count]->info, UgetRelationInfo); + if (relation->task) { + printf("limit D: %d, U: %d | speed D: %d, U: %d\n", + relation->task->limit[0], relation->task->limit[1], + relation->task->speed[0], relation->task->speed[1]); + total[0] += relation->task->limit[0]; + total[1] += relation->task->limit[1]; + } + } + + printf("total limit D: %d, U: %d\n", total[0], total[1]); } -void test_task (void) -{ - UgetTask* task; - UgetNode* dnode[7]; - UgetRelation* relation; - int count; - - task = calloc (1, sizeof (UgetTask)); - uget_task_init (task); - - // task speed control ------------------- - for (count = 0; count < 7; count++) { - dnode[count] = uget_node_new (NULL); - relation = ug_info_realloc (dnode[count]->info, UgetRelationInfo); - uget_task_add (task, dnode[count], UgetPluginEmptyInfo); - if (relation->task) { - relation->task->limit[0] = 2000; - relation->task->limit[1] = 1500; - relation->task->speed[0] = 2000 - count * 200; - relation->task->speed[1] = 1500 - count * 200; - } - } - if (relation->task) { - relation->task->limit[0] = 0; - relation->task->limit[1] = 0; - } - - uget_task_set_speed (task, 12000, 8000); - print_speed_limit(dnode, 7); - puts ("---"); - uget_task_adjust_speed (task); - print_speed_limit(dnode, 7); - - uget_task_remove_all (task); - uget_task_final (task); - free (task); - - for (count = 0; count < 7; count++) - uget_node_free (dnode[count]); +void test_task(void) { + UgetTask *task; + UgetNode *dnode[7]; + UgetRelation *relation; + int count; + + task = calloc(1, sizeof(UgetTask)); + uget_task_init(task); + + // task speed control ------------------- + for (count = 0; count < 7; count++) { + dnode[count] = uget_node_new(NULL); + relation = ug_info_realloc(dnode[count]->info, UgetRelationInfo); + uget_task_add(task, dnode[count], UgetPluginEmptyInfo); + if (relation->task) { + relation->task->limit[0] = 2000; + relation->task->limit[1] = 1500; + relation->task->speed[0] = 2000 - count * 200; + relation->task->speed[1] = 1500 - count * 200; + } + } + if (relation->task) { + relation->task->limit[0] = 0; + relation->task->limit[1] = 0; + } + + uget_task_set_speed(task, 12000, 8000); + print_speed_limit(dnode, 7); + puts("---"); + uget_task_adjust_speed(task); + print_speed_limit(dnode, 7); + + uget_task_remove_all(task); + uget_task_final(task); + free(task); + + for (count = 0; count < 7; count++) + uget_node_free(dnode[count]); } // ---------------------------------------------------------------------------- // test_app -void setup_app (UgetApp* app) -{ - UgetNode* cnode; - UgetCategory* category; - UgetCommon* common; - - cnode = uget_node_new (NULL); - category = ug_info_realloc (cnode->info, UgetCategoryInfo); - *(char**)ug_array_alloc (&category->schemes, 1) = ug_strdup ("http"); - *(char**)ug_array_alloc (&category->schemes, 1) = ug_strdup ("https"); - *(char**)ug_array_alloc (&category->schemes, 1) = ug_strdup ("ftp"); - common = ug_info_realloc (cnode->info, UgetCommonInfo); - common->name = ug_strdup ("Home Category"); - common->max_connections = 2; - uget_app_add_category (app, cnode, TRUE); - - uget_app_add_plugin (app, UgetPluginAria2Info); - uget_app_add_plugin (app, UgetPluginCurlInfo); - uget_app_clear_plugins (app); - uget_app_set_default_plugin (app, UgetPluginCurlInfo); -} - -void start_app (UgetApp* app) -{ - UgetNode* dnode; - UgetCommon* common; - char* string[2]; - - dnode = uget_node_new (NULL); - common = ug_info_realloc (dnode->info, UgetCommonInfo); - common->name = ug_strdup ("Download"); - common->uri = ug_strdup ("http://www.utorrent.com/scripts/dl.php?track=stable&build=29812&client=utorrent"); - common->folder = ug_strdup ("D:\\Downloads"); - common->debug_level = 1; -// common->keeping.enable = TRUE; -// common->keeping.uri = TRUE; -// common->keeping.folder = TRUE; -// common->keeping.debug_level = TRUE; - - uget_app_add_download (app, dnode, NULL, FALSE); - puts ("uget_app_grow()"); - while (uget_app_grow (app, FALSE)) { - ug_sleep (1000); - string[0] = ug_str_from_int_unit (app->task.speed.download, "/s"); - string[1] = ug_str_from_int_unit (app->task.speed.upload, "/s"); - printf ("\r" "DL: %s | UL %s" " ", string[0], string[1]); - ug_free (string[0]); - ug_free (string[1]); - } - puts ("uget_app_grow() return 0"); - - puts ("call uget_app_grow() again"); - uget_app_grow (app, FALSE); +void setup_app(UgetApp *app) { + UgetNode *cnode; + UgetCategory *category; + UgetCommon *common; + + cnode = uget_node_new(NULL); + category = ug_info_realloc(cnode->info, UgetCategoryInfo); + *(char **)ug_array_alloc(&category->schemes, 1) = ug_strdup("http"); + *(char **)ug_array_alloc(&category->schemes, 1) = ug_strdup("https"); + *(char **)ug_array_alloc(&category->schemes, 1) = ug_strdup("ftp"); + common = ug_info_realloc(cnode->info, UgetCommonInfo); + common->name = ug_strdup("Home Category"); + common->max_connections = 2; + uget_app_add_category(app, cnode, TRUE); + + uget_app_add_plugin(app, UgetPluginAria2Info); + uget_app_add_plugin(app, UgetPluginCurlInfo); + uget_app_clear_plugins(app); + uget_app_set_default_plugin(app, UgetPluginCurlInfo); } -void close_app (UgetApp* app) -{ - uget_app_clear_plugins (app); +void start_app(UgetApp *app) { + UgetNode *dnode; + UgetCommon *common; + char *string[2]; + + dnode = uget_node_new(NULL); + common = ug_info_realloc(dnode->info, UgetCommonInfo); + common->name = ug_strdup("Download"); + common->uri = ug_strdup("http://www.utorrent.com/scripts/" + "dl.php?track=stable&build=29812&client=utorrent"); + common->folder = ug_strdup("D:\\Downloads"); + common->debug_level = 1; + // common->keeping.enable = TRUE; + // common->keeping.uri = TRUE; + // common->keeping.folder = TRUE; + // common->keeping.debug_level = TRUE; + + uget_app_add_download(app, dnode, NULL, FALSE); + puts("uget_app_grow()"); + while (uget_app_grow(app, FALSE)) { + ug_sleep(1000); + string[0] = ug_str_from_int_unit(app->task.speed.download, "/s"); + string[1] = ug_str_from_int_unit(app->task.speed.upload, "/s"); + printf("\r" + "DL: %s | UL %s" + " ", + string[0], string[1]); + ug_free(string[0]); + ug_free(string[1]); + } + puts("uget_app_grow() return 0"); + + puts("call uget_app_grow() again"); + uget_app_grow(app, FALSE); } -void test_app_node (UgetApp* app) -{ - UgetNode* dnode[7]; - UgetNode* cnode; - UgetCommon* common; - int count; - - for (count = 0; count < 7; count++) { - dnode[count] = uget_node_new (NULL); - common = ug_info_realloc (dnode[count]->info, UgetCommonInfo); - common->uri = ug_strdup ("ftp://127.0.0.1/"); - common->folder = ug_strdup ("D:\\Downloads"); - common->keeping.enable = TRUE; - common->keeping.uri = FALSE; - common->keeping.folder = FALSE; - uget_app_add_download (app, dnode[count], NULL, TRUE); - } - - uget_app_move_download (app, dnode[5], NULL); - uget_app_delete_download (app, dnode[2], TRUE); - uget_app_delete_download (app, dnode[4], FALSE); - uget_app_delete_download (app, dnode[6], FALSE); - - cnode = app->real.children; - if (cnode) - printf ("%d\n", cnode->n_children); - - cnode = app->split.children; - if (cnode) - printf ("%d\n", cnode->n_children); - - cnode = app->mix.children; - if (cnode) - printf ("%d\n", cnode->n_children); - - cnode = app->mix_split.children; - if (cnode) - printf ("%d\n", cnode->n_children); +void close_app(UgetApp *app) { uget_app_clear_plugins(app); } + +void test_app_node(UgetApp *app) { + UgetNode *dnode[7]; + UgetNode *cnode; + UgetCommon *common; + int count; + + for (count = 0; count < 7; count++) { + dnode[count] = uget_node_new(NULL); + common = ug_info_realloc(dnode[count]->info, UgetCommonInfo); + common->uri = ug_strdup("ftp://127.0.0.1/"); + common->folder = ug_strdup("D:\\Downloads"); + common->keeping.enable = TRUE; + common->keeping.uri = FALSE; + common->keeping.folder = FALSE; + uget_app_add_download(app, dnode[count], NULL, TRUE); + } + + uget_app_move_download(app, dnode[5], NULL); + uget_app_delete_download(app, dnode[2], TRUE); + uget_app_delete_download(app, dnode[4], FALSE); + uget_app_delete_download(app, dnode[6], FALSE); + + cnode = app->real.children; + if (cnode) + printf("%d\n", cnode->n_children); + + cnode = app->split.children; + if (cnode) + printf("%d\n", cnode->n_children); + + cnode = app->mix.children; + if (cnode) + printf("%d\n", cnode->n_children); + + cnode = app->mix_split.children; + if (cnode) + printf("%d\n", cnode->n_children); } -void test_app (void) -{ - UgetApp* app; - - app = calloc (1, sizeof (UgetApp)); - uget_app_init (app); - setup_app (app); - start_app (app); -// test_app_node (app); - uget_app_save_categories (app, NULL); -// uget_app_load_categories (app, NULL); - uget_app_final (app); - free (app); +void test_app(void) { + UgetApp *app; + + app = calloc(1, sizeof(UgetApp)); + uget_app_init(app); + setup_app(app); + start_app(app); + // test_app_node (app); + uget_app_save_categories(app, NULL); + // uget_app_load_categories (app, NULL); + uget_app_final(app); + free(app); } // ---------------------------------------------------------------------------- // main -int main (void) -{ - // initialize plug-in - uget_plugin_global_set(UgetPluginCurlInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); - uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); - uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); - uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); -// test_setup_plugin_aria2(); - - test_download(); -// test_task(); -// test_app(); - -// uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_SHUTDOWN_NOW, (void*) TRUE); - // finalize plug-in - uget_plugin_global_set(UgetPluginCurlInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); - uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); - uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); - uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); - ug_sleep(1000); - - return 0; -} +int main(void) { + // initialize plug-in + uget_plugin_global_set(UgetPluginCurlInfo, UGET_PLUGIN_GLOBAL_INIT, + (void *)TRUE); + uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, + (void *)TRUE); + uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, + (void *)TRUE); +#ifdef HAVE_MEGA + uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, + (void *)TRUE); +#endif + // test_setup_plugin_aria2(); + + test_download(); + // test_task(); + // test_app(); + + // uget_plugin_global_set(UgetPluginAria2Info, + //UGET_PLUGIN_ARIA2_GLOBAL_SHUTDOWN_NOW, (void*) TRUE); + // finalize plug-in + uget_plugin_global_set(UgetPluginCurlInfo, UGET_PLUGIN_GLOBAL_INIT, + (void *)FALSE); + uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, + (void *)FALSE); + uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, + (void *)FALSE); +#ifdef HAVE_MEGA + uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, + (void *)FALSE); +#endif + + ug_sleep(1000); + + return 0; +} diff --git a/tests/test-uglib.c b/tests/test-uglib.c index f04332c..e51df6e 100644 --- a/tests/test-uglib.c +++ b/tests/test-uglib.c @@ -371,7 +371,7 @@ int print_option_callback (UgOption* option, void test_option (void) { UgOption option; - struct Opt dest; + struct Opt dest = {0}; ug_option_init (&option); // ug_option_set_parser (&option, print_option_callback, NULL, NULL); @@ -379,6 +379,8 @@ void test_option (void) ug_option_parse (&option, "--category-index=1", -1); ug_option_parse (&option, "-cn=hhk", -1); ug_option_final (&option); + + ug_free (dest.name); } void test_cmd_arg (void) @@ -446,6 +448,8 @@ void test_html (void) ug_html_parse (uhtml, "< p attr1=\"value1\" attr2=val2/> < &xxxxx; ", -1); ug_html_end_parse (uhtml); puts("\n"); + + ug_html_free (uhtml); } void test_unicode (void) diff --git a/uget/UgetAria2.c b/uget/UgetAria2.c index ba36a0e..af048ab 100644 --- a/uget/UgetAria2.c +++ b/uget/UgetAria2.c @@ -34,6 +34,8 @@ * */ +#include + #include #include #include @@ -72,8 +74,7 @@ struct UgetAria2Thread { - UgThread thread; - UgetAria2* uaria2; + UgetAria2* uaria2; UgJsonrpcArray queuing; UgJsonrpcArray request; UgJsonrpcArray response; @@ -81,27 +82,24 @@ struct UgetAria2Thread int finalized; }; -static UgThreadResult uget_aria2_thread (UgetAria2Thread* uathread); +static gpointer uget_aria2_thread (gpointer data); static UgetAria2Thread* uget_aria2_thread_new (UgetAria2* uaria2) { - UgetAria2Thread* uat; - UgThread thread; + UgetAria2Thread* uat; - uat = ug_malloc (sizeof (UgetAria2Thread)); - uat->uaria2 = uaria2; - ug_jsonrpc_array_init (&uat->queuing, 16); - ug_jsonrpc_array_init (&uat->request, 16); - ug_jsonrpc_array_init (&uat->response, 16); - ug_jsonrpc_curl_init (&uat->json); - ug_jsonrpc_curl_set_url (&uat->json, uaria2->uri); - uat->finalized = FALSE; + uat = ug_malloc (sizeof (UgetAria2Thread)); + uat->uaria2 = uaria2; + ug_jsonrpc_array_init (&uat->queuing, 16); + ug_jsonrpc_array_init (&uat->request, 16); + ug_jsonrpc_array_init (&uat->response, 16); + ug_jsonrpc_curl_init (&uat->json); + ug_jsonrpc_curl_set_url (&uat->json, uaria2->uri); + uat->finalized = FALSE; - uget_aria2_ref (uaria2); - ug_thread_create (&thread, (UgThreadFunc) uget_aria2_thread, uat); - ug_thread_unjoin (&thread); + uget_aria2_ref (uaria2); - return uat; + return uat; } static void uget_aria2_thread_free (UgetAria2Thread* uat) @@ -285,23 +283,26 @@ static void recycle_speed_request (UgetAria2* uaria2, UgJsonrpcObject* jreq) uget_aria2_recycle (uaria2, jres); } -static UgThreadResult uget_aria2_thread (UgetAria2Thread* uathread) +static gpointer uget_aria2_thread (gpointer data) { - UgetAria2* uaria2; - UgJsonrpcObject* jreq = NULL; - UgJsonrpcObject* jobj = NULL; - UgJsonrpcObject* jreq_shutdown = NULL; - int counts; + UgetAria2Thread* uathread = data; + UgetAria2* uaria2; + UgJsonrpcObject* jreq = NULL; + UgJsonrpcObject* jobj = NULL; + UgJsonrpcObject* jreq_shutdown = NULL; + int counts; uaria2 = uathread->uaria2; // temp.index = ug_jsonrpc_array_find_ptr (uaria2); - for (counts = 0; ; counts++) { - // finalize - if (uathread->finalized == TRUE) { - // shutdown request - if (uaria2->shutdown && jreq_shutdown == NULL) { - jreq_shutdown = uget_aria2_alloc (uaria2, TRUE, TRUE); + for (counts = 0; ; counts++) { + if (g_atomic_int_get (&uaria2->stop)) + uathread->finalized = TRUE; + // finalize + if (uathread->finalized == TRUE) { + // shutdown request + if (uaria2->shutdown && jreq_shutdown == NULL) { + jreq_shutdown = uget_aria2_alloc (uaria2, TRUE, TRUE); jreq_shutdown->method_static = "aria2.shutdown"; uget_aria2_request (uaria2, jreq_shutdown); } @@ -329,11 +330,19 @@ static UgThreadResult uget_aria2_thread (UgetAria2Thread* uathread) } // get requests from queue - if (uget_aria2_thread_queuing (uathread) == 0) { - // default: sleep 0.5 second - ug_sleep (uaria2->polling_interval); - continue; - } + if (uget_aria2_thread_queuing (uathread) == 0) { + g_mutex_lock (&uaria2->thread_lock); + if (!g_atomic_int_get (&uaria2->stop) && + uathread->finalized == FALSE) { + gint64 end_time = g_get_monotonic_time () + + (gint64) uaria2->polling_interval * G_TIME_SPAN_MILLISECOND; + g_cond_wait_until (&uaria2->thread_cond, + &uaria2->thread_lock, + end_time); + } + g_mutex_unlock (&uaria2->thread_lock); + continue; + } // send requests & get responses uget_aria2_thread_request (uathread); @@ -357,9 +366,13 @@ static UgThreadResult uget_aria2_thread (UgetAria2Thread* uathread) uget_aria2_recycle (uaria2, jobj); } - uget_aria2_thread_free (uathread); - uget_aria2_unref (uaria2); - return UG_THREAD_RESULT; + g_mutex_lock (&uaria2->thread_lock); + uaria2->worker = NULL; + g_mutex_unlock (&uaria2->thread_lock); + + uget_aria2_thread_free (uathread); + uget_aria2_unref (uaria2); + return NULL; } // ---------------------------------------------------------------------------- @@ -377,20 +390,23 @@ UgetAria2* uget_aria2_new (void) #endif // _WIN32 || _WIN64 curl_global_init (CURL_GLOBAL_ALL); - uaria2 = ug_malloc0 (sizeof (UgetAria2)); - uaria2->ref_count = 1; - uaria2->batch_len = RPC_BATCH_LEN; - uaria2->polling_interval = RPC_INTERVAL; - uaria2->speed_required = FALSE; - uaria2->limit_required = FALSE; - uaria2->uri = ug_strdup (RPC_URI); - uaria2->path = ug_strdup (ARIA2_PATH); - uaria2->args = ug_strdup (ARIA2_ARGS); - ug_mutex_init (&uaria2->mutex); - ug_mutex_init (&uaria2->completed_mutex); - - ug_jsonrpc_array_init (&uaria2->queuing, 16); - ug_jsonrpc_array_init (&uaria2->recycled, 16); + uaria2 = ug_malloc0 (sizeof (UgetAria2)); + uaria2->ref_count = 1; + uaria2->batch_len = RPC_BATCH_LEN; + uaria2->polling_interval = RPC_INTERVAL; + uaria2->speed_required = FALSE; + uaria2->limit_required = FALSE; + uaria2->uri = ug_strdup (RPC_URI); + uaria2->path = ug_strdup (ARIA2_PATH); + uaria2->args = ug_strdup (ARIA2_ARGS); + ug_mutex_init (&uaria2->mutex); + ug_mutex_init (&uaria2->completed_mutex); + g_mutex_init (&uaria2->thread_lock); + g_cond_init (&uaria2->thread_cond); + g_atomic_int_set (&uaria2->stop, 0); + + ug_jsonrpc_array_init (&uaria2->queuing, 16); + ug_jsonrpc_array_init (&uaria2->recycled, 16); ug_slinks_init (&uaria2->requested, 16); ug_slinks_init (&uaria2->responsed, 16); uaria2->completed_changed = 0; @@ -433,43 +449,132 @@ void uget_aria2_ref (UgetAria2* uaria2) uaria2->ref_count++; } -void uget_aria2_unref (UgetAria2* uaria2) +static void +uget_aria2_dispose (UgetAria2* uaria2) { - if (--uaria2->ref_count == 0) { - ug_jsonrpc_array_clear (&uaria2->queuing, TRUE); - ug_jsonrpc_array_clear (&uaria2->recycled, TRUE); - ug_slinks_foreach (&uaria2->requested, (void*)ug_jsonrpc_object_free, NULL); - ug_slinks_foreach (&uaria2->responsed, (void*)ug_jsonrpc_object_free, NULL); - ug_slinks_final (&uaria2->requested); - ug_slinks_final (&uaria2->responsed); + int index; - ug_value_foreach (&uaria2->status_keys, ug_value_set_string, NULL); - ug_value_clear (&uaria2->status_keys); + if (uaria2 == NULL) + return; - ug_mutex_clear (&uaria2->completed_mutex); - ug_mutex_clear (&uaria2->mutex); - ug_free (uaria2->uri); - ug_free (uaria2->path); - ug_free (uaria2->args); - ug_free (uaria2); + uget_aria2_stop_thread (uaria2); - curl_global_cleanup (); + ug_mutex_lock (&uaria2->mutex); + for (index = 0; index < uaria2->queuing.length; index++) + if (uaria2->queuing.at[index]) + ug_jsonrpc_object_free (uaria2->queuing.at[index]); + ug_jsonrpc_array_clear (&uaria2->queuing, 0); + + for (index = 0; index < uaria2->recycled.length; index++) + if (uaria2->recycled.at[index]) + ug_jsonrpc_object_free (uaria2->recycled.at[index]); + ug_jsonrpc_array_clear (&uaria2->recycled, 0); + ug_mutex_unlock (&uaria2->mutex); + + ug_slinks_foreach (&uaria2->requested, (void*)ug_jsonrpc_object_free, NULL); + ug_slinks_foreach (&uaria2->responsed, (void*)ug_jsonrpc_object_free, NULL); + ug_slinks_final (&uaria2->requested); + ug_slinks_final (&uaria2->responsed); + + ug_value_foreach (&uaria2->status_keys, ug_value_set_string, NULL); + ug_value_clear (&uaria2->status_keys); + + ug_mutex_clear (&uaria2->completed_mutex); + ug_mutex_clear (&uaria2->mutex); + g_cond_clear (&uaria2->thread_cond); + g_mutex_clear (&uaria2->thread_lock); + + ug_free (uaria2->token); + ug_free (uaria2->uri); + ug_free (uaria2->path); + ug_free (uaria2->args); + ug_free (uaria2); + + curl_global_cleanup (); #if defined _WIN32 || defined _WIN64 - WSACleanup (); + WSACleanup (); #endif // _WIN32 || _WIN64 - } +} + +void uget_aria2_unref (UgetAria2* uaria2) +{ + if (uaria2 == NULL) + return; + + if (--uaria2->ref_count == 0) + uget_aria2_dispose (uaria2); +} + +void uget_aria2_free (UgetAria2* uaria2) +{ + if (uaria2 == NULL) + return; + + uaria2->ref_count = 1; + uget_aria2_unref (uaria2); } void uget_aria2_start_thread (UgetAria2* uaria2) { - if (uaria2->thread == NULL) - uaria2->thread = uget_aria2_thread_new (uaria2); + UgetAria2Thread* worker; + + if (uaria2 == NULL) + return; + + g_mutex_lock (&uaria2->thread_lock); + if (uaria2->thread != NULL) { + g_mutex_unlock (&uaria2->thread_lock); + return; + } + + if (uaria2->worker == NULL) + uaria2->worker = uget_aria2_thread_new (uaria2); + + g_atomic_int_set (&uaria2->stop, 0); + worker = uaria2->worker; + uaria2->thread = g_thread_new ("uget-aria2", uget_aria2_thread, worker); + + if (uaria2->thread == NULL) { + uaria2->worker = NULL; + g_mutex_unlock (&uaria2->thread_lock); + if (worker) { + uget_aria2_thread_free (worker); + uget_aria2_unref (uaria2); + } + return; + } + + g_mutex_unlock (&uaria2->thread_lock); } void uget_aria2_stop_thread (UgetAria2* uaria2) { - uaria2->thread->finalized = TRUE; - uaria2->thread = NULL; + GThread* thread; + + if (uaria2 == NULL) + return; + + g_mutex_lock (&uaria2->thread_lock); + if (uaria2->thread == NULL && uaria2->worker == NULL) { + g_mutex_unlock (&uaria2->thread_lock); + return; + } + + g_atomic_int_set (&uaria2->stop, 1); + if (uaria2->worker) + uaria2->worker->finalized = TRUE; + g_cond_broadcast (&uaria2->thread_cond); + + thread = uaria2->thread; + uaria2->thread = NULL; + g_mutex_unlock (&uaria2->thread_lock); + + if (thread && thread != g_thread_self()) + g_thread_join (thread); + + g_mutex_lock (&uaria2->thread_lock); + uaria2->worker = NULL; + g_mutex_unlock (&uaria2->thread_lock); } void uget_aria2_set_uri (UgetAria2* uaria2, const char* uri) @@ -711,9 +816,13 @@ UgJsonrpcObject* uget_aria2_alloc (UgetAria2* uaria2, int is_request, int has_r void uget_aria2_request (UgetAria2* uaria2, UgJsonrpcObject* request) { - ug_mutex_lock (&uaria2->mutex); - *(UgJsonrpcObject**)ug_array_alloc (&uaria2->queuing, 1) = request; - ug_mutex_unlock (&uaria2->mutex); + ug_mutex_lock (&uaria2->mutex); + *(UgJsonrpcObject**)ug_array_alloc (&uaria2->queuing, 1) = request; + ug_mutex_unlock (&uaria2->mutex); + + g_mutex_lock (&uaria2->thread_lock); + g_cond_signal (&uaria2->thread_cond); + g_mutex_unlock (&uaria2->thread_lock); } UgJsonrpcObject* uget_aria2_respond (UgetAria2* uaria2, UgJsonrpcObject* request) diff --git a/uget/UgetAria2.h b/uget/UgetAria2.h index e7f6832..fac5e80 100644 --- a/uget/UgetAria2.h +++ b/uget/UgetAria2.h @@ -37,6 +37,8 @@ #ifndef UGET_ARIA2_H #define UGET_ARIA2_H +#include + #include #include #include @@ -59,8 +61,13 @@ struct UgetAria2 { int ref_count; - UgMutex mutex; - UgetAria2Thread* thread; + UgMutex mutex; + UgetAria2Thread* worker; + + GThread* thread; + GMutex thread_lock; + GCond thread_cond; + volatile gint stop; // request -> global thread -> requested + responsed // @@ -112,6 +119,7 @@ struct UgetAria2 UgetAria2* uget_aria2_new (void); void uget_aria2_ref (UgetAria2* ua2); void uget_aria2_unref (UgetAria2* ua2); +void uget_aria2_free (UgetAria2* ua2); void uget_aria2_start_thread (UgetAria2* uaria2); void uget_aria2_stop_thread (UgetAria2* uaria2); diff --git a/uglib/UgJson-custom.c b/uglib/UgJson-custom.c index 5392d3f..bbeb68c 100644 --- a/uglib/UgJson-custom.c +++ b/uglib/UgJson-custom.c @@ -36,273 +36,256 @@ #if defined(_MSC_VER) #define _CRT_SECURE_NO_WARNINGS -#define strtoll _strtoi64 -#define snprintf _snprintf +#if _MSC_VER < 1800 +#define strtoll _strtoi64 +#endif +#if _MSC_VER < 1900 +#define snprintf _snprintf +#endif #endif -#include // time_t -#include // INT_MIN, INT_MAX, UINT_MAX +#include +#include // INT_MIN, INT_MAX, UINT_MAX #include -#include #include -#include +#include +#include // time_t // ---------------------------------------------------------------------------- -UgJsonError ug_json_parse_int_string(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) - *(int*) dest = strtol(value, NULL, 10); - else - return UG_JSON_ERROR_TYPE_NOT_MATCH; - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_int_string(UgJson *json, const char *name, + const char *value, void *dest, + void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) + *(int *)dest = strtol(value, NULL, 10); + else + return UG_JSON_ERROR_TYPE_NOT_MATCH; + return UG_JSON_ERROR_NONE; } -UgJsonError ug_json_parse_uint_string(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) - *(unsigned int*) dest = strtoul(value, NULL, 10); - else - return UG_JSON_ERROR_TYPE_NOT_MATCH; - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_uint_string(UgJson *json, const char *name, + const char *value, void *dest, + void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) + *(unsigned int *)dest = strtoul(value, NULL, 10); + else + return UG_JSON_ERROR_TYPE_NOT_MATCH; + return UG_JSON_ERROR_NONE; } -UgJsonError ug_json_parse_int64_string(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) - *(int64_t*) dest = strtoll(value, NULL, 10); - else - return UG_JSON_ERROR_TYPE_NOT_MATCH; - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_int64_string(UgJson *json, const char *name, + const char *value, void *dest, + void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) + *(int64_t *)dest = strtoll(value, NULL, 10); + else + return UG_JSON_ERROR_TYPE_NOT_MATCH; + return UG_JSON_ERROR_NONE; } -UgJsonError ug_json_parse_double_string(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) - *(double*) dest = strtod(value, NULL); - else - return UG_JSON_ERROR_TYPE_NOT_MATCH; - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_double_string(UgJson *json, const char *name, + const char *value, void *dest, + void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + if (json->type == UG_JSON_STRING || json->type == UG_JSON_NUMBER) + *(double *)dest = strtod(value, NULL); + else + return UG_JSON_ERROR_TYPE_NOT_MATCH; + return UG_JSON_ERROR_NONE; } -void ug_json_write_int_string(UgJson* json, int* value) -{ - int len; - char* buf; +void ug_json_write_int_string(UgJson *json, int *value) { + int len; + char *buf; - len = snprintf(NULL, 0, "%d", *value) + 1; - buf = ug_malloc(len); - snprintf(buf, len, "%d", *value); - ug_json_write_string(json, buf); - ug_free(buf); + len = snprintf(NULL, 0, "%d", *value) + 1; + buf = ug_malloc(len); + snprintf(buf, len, "%d", *value); + ug_json_write_string(json, buf); + ug_free(buf); } -void ug_json_write_uint_string(UgJson* json, unsigned int* value) -{ - int len; - char* buf; +void ug_json_write_uint_string(UgJson *json, unsigned int *value) { + int len; + char *buf; - len = snprintf(NULL, 0, "%u", *value) + 1; - buf = ug_malloc(len); - snprintf(buf, len, "%u", *value); - ug_json_write_string(json, buf); - ug_free(buf); + len = snprintf(NULL, 0, "%u", *value) + 1; + buf = ug_malloc(len); + snprintf(buf, len, "%u", *value); + ug_json_write_string(json, buf); + ug_free(buf); } -void ug_json_write_int64_string(UgJson* json, int64_t* value) -{ - int len; - char* buf; +void ug_json_write_int64_string(UgJson *json, int64_t *value) { + int len; + char *buf; -#if defined (_MSC_VER) || defined (__MINGW32__) - len = snprintf(NULL, 0, "%I64d", *value) + 1; - buf = ug_malloc(len); - snprintf(buf, len, "%I64d", *value); +#if defined(_MSC_VER) || defined(__MINGW32__) + len = snprintf(NULL, 0, "%I64d", *value) + 1; + buf = ug_malloc(len); + snprintf(buf, len, "%I64d", *value); #else - len = snprintf(NULL, 0, "%lld", (long long) *value) + 1; - buf = ug_malloc(len); - snprintf(buf, len, "%lld", (long long) *value); + len = snprintf(NULL, 0, "%lld", (long long)*value) + 1; + buf = ug_malloc(len); + snprintf(buf, len, "%lld", (long long)*value); #endif - ug_json_write_string(json, buf); - ug_free(buf); + ug_json_write_string(json, buf); + ug_free(buf); } -void ug_json_write_double_string(UgJson* json, double* value) -{ - int len; - char* buf; +void ug_json_write_double_string(UgJson *json, double *value) { + int len; + char *buf; - len = snprintf(NULL, 0, "%f", *value) + 1; - buf = ug_malloc(len); - snprintf(buf, len, "%f", *value); - ug_json_write_string(json, buf); - ug_free(buf); + len = snprintf(NULL, 0, "%f", *value) + 1; + buf = ug_malloc(len); + snprintf(buf, len, "%f", *value); + ug_json_write_string(json, buf); + ug_free(buf); } // ---------------------------------------------------------------------------- // parse and write JSON number for C types - uint8_t, int16_t, and int32_t -UgJsonError ug_json_parse_uint8(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - if (json->type != UG_JSON_NUMBER) - return UG_JSON_ERROR_TYPE_NOT_MATCH; - *(uint8_t*) dest = strtol(value, NULL, 10); - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_uint8(UgJson *json, const char *name, + const char *value, void *dest, void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + if (json->type != UG_JSON_NUMBER) + return UG_JSON_ERROR_TYPE_NOT_MATCH; + *(uint8_t *)dest = strtol(value, NULL, 10); + return UG_JSON_ERROR_NONE; } -UgJsonError ug_json_parse_int16(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - if (json->type != UG_JSON_NUMBER) - return UG_JSON_ERROR_TYPE_NOT_MATCH; - *(int16_t*) dest = strtol(value, NULL, 10); - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_int16(UgJson *json, const char *name, + const char *value, void *dest, void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + if (json->type != UG_JSON_NUMBER) + return UG_JSON_ERROR_TYPE_NOT_MATCH; + *(int16_t *)dest = strtol(value, NULL, 10); + return UG_JSON_ERROR_NONE; } -UgJsonError ug_json_parse_int32(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - if (json->type != UG_JSON_NUMBER) - return UG_JSON_ERROR_TYPE_NOT_MATCH; - *(int32_t*) dest = strtol(value, NULL, 10); - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_int32(UgJson *json, const char *name, + const char *value, void *dest, void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + if (json->type != UG_JSON_NUMBER) + return UG_JSON_ERROR_TYPE_NOT_MATCH; + *(int32_t *)dest = strtol(value, NULL, 10); + return UG_JSON_ERROR_NONE; } -void ug_json_write_uint8(UgJson* json, uint8_t* value) -{ - ug_json_write_int(json, *(uint8_t*)value); +void ug_json_write_uint8(UgJson *json, uint8_t *value) { + ug_json_write_int(json, *(uint8_t *)value); } -void ug_json_write_int16(UgJson* json, int16_t* value) -{ - ug_json_write_int(json, *(int16_t*)value); +void ug_json_write_int16(UgJson *json, int16_t *value) { + ug_json_write_int(json, *(int16_t *)value); } -void ug_json_write_int32(UgJson* json, int32_t* value) -{ - ug_json_write_int(json, *(int32_t*)value); +void ug_json_write_int32(UgJson *json, int32_t *value) { + ug_json_write_int(json, *(int32_t *)value); } // ---------------------------------------------------------------------------- // parse string "true" and "false" to integer (boolean). // write integer (boolean) to string "true" and "false". -UgJsonError ug_json_parse_bool_string(UgJson* json, - const char* name, const char* value, - void* dest, void* data) -{ -// if (json->type >= UG_JSON_OBJECT) { -// ug_json_push(json, ug_json_parse_unknown, NULL, NULL); -// return UG_JSON_ERROR_TYPE_NOT_MATCH; -// } - - switch (json->type) { - case UG_JSON_TRUE: - *(int*) dest = TRUE; - break; - - case UG_JSON_FALSE: - *(int*) dest = FALSE; - break; - -// case UG_JSON_NUMBER: -// if (strtol(value, NULL, 10) == 0) -// *(int*) dest = FALSE; -// else -// *(int*) dest = TRUE; -// break; - - case UG_JSON_STRING: - if (strcmp(value, "true") == 0) - *(int*) dest = TRUE; - else if (strcmp(value, "false") == 0) - *(int*) dest = FALSE; - break; - - default: - return UG_JSON_ERROR_TYPE_NOT_MATCH; - } - return UG_JSON_ERROR_NONE; +UgJsonError ug_json_parse_bool_string(UgJson *json, const char *name, + const char *value, void *dest, + void *data) { + // if (json->type >= UG_JSON_OBJECT) { + // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + // return UG_JSON_ERROR_TYPE_NOT_MATCH; + // } + + switch (json->type) { + case UG_JSON_TRUE: + *(int *)dest = TRUE; + break; + + case UG_JSON_FALSE: + *(int *)dest = FALSE; + break; + + // case UG_JSON_NUMBER: + // if (strtol(value, NULL, 10) == 0) + // *(int*) dest = FALSE; + // else + // *(int*) dest = TRUE; + // break; + + case UG_JSON_STRING: + if (strcmp(value, "true") == 0) + *(int *)dest = TRUE; + else if (strcmp(value, "false") == 0) + *(int *)dest = FALSE; + break; + + default: + return UG_JSON_ERROR_TYPE_NOT_MATCH; + } + return UG_JSON_ERROR_NONE; } -void ug_json_write_bool_string(UgJson* json, int* value) -{ - if (*value == FALSE) - ug_json_write_string(json, "false"); - else - ug_json_write_string(json, "true"); +void ug_json_write_bool_string(UgJson *json, int *value) { + if (*value == FALSE) + ug_json_write_string(json, "false"); + else + ug_json_write_string(json, "true"); } // ---------------------------------------------------------------------------- // UgJsonParseFunc and UgJsonWriteFunc for time_t -UgJsonError ug_json_parse_time_t(UgJson* json, - const char* name, const char* value, - void* dest, void* none) -{ +UgJsonError ug_json_parse_time_t(UgJson *json, const char *name, + const char *value, void *dest, void *none) { #if 1 - if (json->type != UG_JSON_NUMBER) - return UG_JSON_ERROR_TYPE_NOT_MATCH; - *(time_t*) dest = strtoll(value, NULL, 10); - return UG_JSON_ERROR_NONE; + if (json->type != UG_JSON_NUMBER) + return UG_JSON_ERROR_TYPE_NOT_MATCH; + *(time_t *)dest = strtoll(value, NULL, 10); + return UG_JSON_ERROR_NONE; #else - struct tm timem; + struct tm timem; - timem.tm_year = year - 1900; - timem.tm_mon = month - 1; - timem.tm_mday = day; - timem.tm_hour = hour; - timem.tm_min = minute; - timem.tm_sec) = second; - timem.tm_isdst = 0; - *(time_t*) dest = mktime(timem); + timem.tm_year = year - 1900; + timem.tm_mon = month - 1; + timem.tm_mday = day; + timem.tm_hour = hour; + timem.tm_min = minute; + timem.tm_sec) = second; + timem.tm_isdst = 0; + *(time_t *)dest = mktime(timem); // if (json->type >= UG_JSON_OBJECT) { // ug_json_push(json, ug_json_parse_unknown, NULL, NULL); @@ -311,26 +294,21 @@ UgJsonError ug_json_parse_time_t(UgJson* json, #endif } -void ug_json_write_time_t(UgJson* json, void* data) -{ +void ug_json_write_time_t(UgJson *json, void *data) { #if 1 - ug_json_write_int64(json, *(time_t*) data); + ug_json_write_int64(json, *(time_t *)data); #else - struct tm* timem; - char* timestr; - - timem = gmtime((time_t*) dest); // localtime((time_t*) dest); - timestr = ug_malloc(32); - // output format : "2013-02-05 21:25:15" - snprintf(timestr, 32, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", - timem->tm_year + 1900, - timem->tm_mon + 1, - timem->tm_mday, - timem->tm_hour, - timem->tm_min, - timem->tm_sec); - ug_json_write_string(json, timestr); - ug_free(timestr); + struct tm *timem; + char *timestr; + + timem = gmtime((time_t *)dest); // localtime((time_t*) dest); + timestr = ug_malloc(32); + // output format : "2013-02-05 21:25:15" + snprintf(timestr, 32, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", timem->tm_year + 1900, + timem->tm_mon + 1, timem->tm_mday, timem->tm_hour, timem->tm_min, + timem->tm_sec); + ug_json_write_string(json, timestr); + ug_free(timestr); #endif } @@ -343,135 +321,131 @@ void ug_json_write_time_t(UgJson* json, void* data) // ug_json_end_parse(json); enum { - PARSER_STACK_BASE, // 0 - PARSER_STACK_TYPE, // 1 - PARSER_STACK_DATA2, // 2 - PARSER_STACK_DATA1, // 3 - PARSER_STACK_FUNC, // 4 - PARSER_STACK_UNIT = PARSER_STACK_FUNC, // equal with STACK_MULTIPLY_VALUE + PARSER_STACK_BASE, // 0 + PARSER_STACK_TYPE, // 1 + PARSER_STACK_DATA2, // 2 + PARSER_STACK_DATA1, // 3 + PARSER_STACK_FUNC, // 4 + PARSER_STACK_UNIT = PARSER_STACK_FUNC, // equal with STACK_MULTIPLY_VALUE }; // static function -static void ug_json_call_parser_value(UgJson* json, UgValue* uvalue, const char* value) -{ - UgJsonParseFunc parser; - void** stack; - char error; - int stackLen; - - // get parser and data from stack - if (json->stack.length && json->type < UG_JSON_N_TYPE) { - stackLen = json->stack.length; - stack = json->stack.at + json->stack.length; - parser = *(stack - PARSER_STACK_FUNC); - error = parser(json, - uvalue->name, - value, - *(stack - PARSER_STACK_DATA1), - *(stack - PARSER_STACK_DATA2)); - if (error) - json->error = error; - // It must push parser when getting UG_JSON_OBJECT or UG_JSON_ARRAY. - // If callback function does NOT push any parser, push default one. - if (json->type >= UG_JSON_OBJECT && stackLen == json->stack.length) - ug_json_push(json, ug_json_parse_unknown, NULL, NULL); - } - - // reset state - json->type = 0; // UG_JSON_VALUE - // reset buffer - json->buf.at[0] = 0; - json->buf.length = 1; +static void ug_json_call_parser_value(UgJson *json, UgValue *uvalue, + const char *value) { + UgJsonParseFunc parser; + void **stack; + char error; + int stackLen; + + // get parser and data from stack + if (json->stack.length && json->type < UG_JSON_N_TYPE) { + stackLen = json->stack.length; + stack = json->stack.at + json->stack.length; + parser = *(stack - PARSER_STACK_FUNC); + error = parser(json, uvalue->name, value, *(stack - PARSER_STACK_DATA1), + *(stack - PARSER_STACK_DATA2)); + if (error) + json->error = error; + // It must push parser when getting UG_JSON_OBJECT or UG_JSON_ARRAY. + // If callback function does NOT push any parser, push default one. + if (json->type >= UG_JSON_OBJECT && stackLen == json->stack.length) + ug_json_push(json, ug_json_parse_unknown, NULL, NULL); + } + + // reset state + json->type = 0; // UG_JSON_VALUE + // reset buffer + json->buf.at[0] = 0; + json->buf.length = 1; } -void ug_json_parse_by_value(UgJson* json, UgValue* value) -{ - UgValue* end; - - switch (value->type) { - case UG_VALUE_NONE: - default: - // skip this value - break; - - case UG_VALUE_OBJECT: - json->type = UG_JSON_OBJECT; - ug_json_call_parser_value(json, value, NULL); - json->scope = UG_JSON_OBJECT; - end = value->c.object->at + value->c.object->length; - for (value = value->c.object->at; value < end; value++) - ug_json_parse_by_value(json, value); - ug_json_pop(json); - break; - - case UG_VALUE_ARRAY: - json->type = UG_JSON_ARRAY; - ug_json_call_parser_value(json, value, NULL); - json->scope = UG_JSON_ARRAY; - end = value->c.array->at + value->c.array->length; - for (value = value->c.array->at; value < end; value++) - ug_json_parse_by_value(json, value); - ug_json_pop(json); - break; - - case UG_VALUE_BOOL: - if (value->c.boolean == FALSE) { - json->type = UG_JSON_FALSE; - ug_json_call_parser_value(json, value, "false"); - } - else { - json->type = UG_JSON_TRUE; - ug_json_call_parser_value(json, value, "true"); - } - break; - - case UG_VALUE_INT: - json->type = UG_JSON_NUMBER; - snprintf(json->buf.at, json->buf.allocated, "%d", value->c.integer); - ug_json_call_parser_value(json, value, json->buf.at); - break; - - case UG_VALUE_UINT: - json->type = UG_JSON_NUMBER; - snprintf(json->buf.at, json->buf.allocated, "%u", value->c.uinteger); - ug_json_call_parser_value(json, value, json->buf.at); - break; - - case UG_VALUE_INT64: - json->type = UG_JSON_NUMBER; -#if defined (_MSC_VER) || defined (__MINGW32__) - snprintf(json->buf.at, json->buf.allocated, "%I64d", value->c.integer64); +void ug_json_parse_by_value(UgJson *json, UgValue *value) { + UgValue *end; + + switch (value->type) { + case UG_VALUE_NONE: + default: + // skip this value + break; + + case UG_VALUE_OBJECT: + json->type = UG_JSON_OBJECT; + ug_json_call_parser_value(json, value, NULL); + json->scope = UG_JSON_OBJECT; + end = value->c.object->at + value->c.object->length; + for (value = value->c.object->at; value < end; value++) + ug_json_parse_by_value(json, value); + ug_json_pop(json); + break; + + case UG_VALUE_ARRAY: + json->type = UG_JSON_ARRAY; + ug_json_call_parser_value(json, value, NULL); + json->scope = UG_JSON_ARRAY; + end = value->c.array->at + value->c.array->length; + for (value = value->c.array->at; value < end; value++) + ug_json_parse_by_value(json, value); + ug_json_pop(json); + break; + + case UG_VALUE_BOOL: + if (value->c.boolean == FALSE) { + json->type = UG_JSON_FALSE; + ug_json_call_parser_value(json, value, "false"); + } else { + json->type = UG_JSON_TRUE; + ug_json_call_parser_value(json, value, "true"); + } + break; + + case UG_VALUE_INT: + json->type = UG_JSON_NUMBER; + snprintf(json->buf.at, json->buf.allocated, "%d", value->c.integer); + ug_json_call_parser_value(json, value, json->buf.at); + break; + + case UG_VALUE_UINT: + json->type = UG_JSON_NUMBER; + snprintf(json->buf.at, json->buf.allocated, "%u", value->c.uinteger); + ug_json_call_parser_value(json, value, json->buf.at); + break; + + case UG_VALUE_INT64: + json->type = UG_JSON_NUMBER; +#if defined(_MSC_VER) || defined(__MINGW32__) + snprintf(json->buf.at, json->buf.allocated, "%I64d", value->c.integer64); #else - snprintf(json->buf.at, json->buf.allocated, "%lld", (long long int) value->c.integer64); + snprintf(json->buf.at, json->buf.allocated, "%lld", + (long long int)value->c.integer64); #endif - ug_json_call_parser_value(json, value, json->buf.at); - break; + ug_json_call_parser_value(json, value, json->buf.at); + break; - case UG_VALUE_UINT64: - json->type = UG_JSON_NUMBER; -#if defined (_MSC_VER) || defined (__MINGW32__) - snprintf(json->buf.at, json->buf.allocated, "%I64u", value->c.uinteger64); + case UG_VALUE_UINT64: + json->type = UG_JSON_NUMBER; +#if defined(_MSC_VER) || defined(__MINGW32__) + snprintf(json->buf.at, json->buf.allocated, "%I64u", value->c.uinteger64); #else - snprintf(json->buf.at, json->buf.allocated, "%llu", (long long int) value->c.uinteger64 ); + snprintf(json->buf.at, json->buf.allocated, "%llu", + (long long int)value->c.uinteger64); #endif - ug_json_call_parser_value(json, value, json->buf.at); - break; - - case UG_VALUE_DOUBLE: - json->type = UG_JSON_NUMBER; - snprintf(json->buf.at, json->buf.allocated, "%f", value->c.fraction); - ug_json_call_parser_value(json, value, json->buf.at); - break; - - case UG_VALUE_STRING: - if (value->c.string == NULL) { - json->type = UG_JSON_NULL; - ug_json_call_parser_value(json, value, NULL); - } - else { - json->type = UG_JSON_STRING; - ug_json_call_parser_value(json, value, value->c.string); - } - break; - } + ug_json_call_parser_value(json, value, json->buf.at); + break; + + case UG_VALUE_DOUBLE: + json->type = UG_JSON_NUMBER; + snprintf(json->buf.at, json->buf.allocated, "%f", value->c.fraction); + ug_json_call_parser_value(json, value, json->buf.at); + break; + + case UG_VALUE_STRING: + if (value->c.string == NULL) { + json->type = UG_JSON_NULL; + ug_json_call_parser_value(json, value, NULL); + } else { + json->type = UG_JSON_STRING; + ug_json_call_parser_value(json, value, value->c.string); + } + break; + } } diff --git a/uglib/UgJsonrpc.c b/uglib/UgJsonrpc.c index 4805248..cd14624 100644 --- a/uglib/UgJsonrpc.c +++ b/uglib/UgJsonrpc.c @@ -430,7 +430,22 @@ int ug_jsonrpc_call_batch(UgJsonrpc* jrpc, jrpc->error = n; // parser --- end --- - return 0; // no error + return 0; // no error +} + +void ug_jsonrpc_array_free (UgJsonrpcArray* array) +{ + if (array == NULL) + return; + + for (int index = 0; index < array->length; ++index) { + UgJsonrpcObject* object = array->at[index]; + if (object) + ug_jsonrpc_object_free (object); + } + + ug_array_clear (array); + ug_free (array); } // ------------------------------------ diff --git a/uglib/UgJsonrpc.h b/uglib/UgJsonrpc.h index 24fbca5..a2ffb82 100644 --- a/uglib/UgJsonrpc.h +++ b/uglib/UgJsonrpc.h @@ -123,11 +123,14 @@ void ug_json_write_rpc_object(UgJson* json, UgJsonrpcObject* jrobj); //void ug_jsonrpc_array_init(UgJsonrpcArray* joarray, int allocated_len); #define ug_jsonrpc_array_init(array, allocated_len) \ - ug_array_init(array, sizeof(UgJsonrpcObject*), allocated_len) + ug_array_init(array, sizeof(UgJsonrpcObject*), allocated_len) // param free_objects: TRUE or FALSE void ug_jsonrpc_array_clear(UgJsonrpcArray* joarray, int free_objects); +// Free a batch returned by ug_jsonrpc_call_batch (frees elements + container). +void ug_jsonrpc_array_free (UgJsonrpcArray* array); + UgJsonrpcObject* ug_jsonrpc_array_find(UgJsonrpcArray* joarray, UgValue* id, int* index); UgJsonrpcObject* ug_jsonrpc_array_alloc(UgJsonrpcArray* joarray); diff --git a/uglib/UgStdio.h b/uglib/UgStdio.h index 9b2707e..bde3358 100644 --- a/uglib/UgStdio.h +++ b/uglib/UgStdio.h @@ -50,9 +50,11 @@ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS +#if _MSC_VER < 1900 #ifndef snprintf #define snprintf _snprintf #endif // snprintf +#endif // _MSC_VER < 1900 #endif // _MSC_VER #ifdef HAVE_GLIB @@ -70,6 +72,10 @@ #include // for O_* flags //#include #include // for S_* mode +#ifdef HAVE_CONFIG_H +#include +#endif + #include #ifdef __cplusplus diff --git a/ui-gtk/UgtkApp.c b/ui-gtk/UgtkApp.c index a4a88f4..4a1b9a0 100644 --- a/ui-gtk/UgtkApp.c +++ b/ui-gtk/UgtkApp.c @@ -73,8 +73,10 @@ void ugtk_app_init (UgtkApp* app, UgetRpc* rpc) // plug-in initialize uget_plugin_global_set(UgetPluginCurlInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); - uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); - uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); + uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); +#ifdef HAVE_MEGA + uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE); +#endif // apply UgtkSetting ugtk_app_set_plugin_setting (app, &app->setting); ugtk_app_set_window_setting (app, &app->setting); @@ -125,8 +127,10 @@ void ugtk_app_final (UgtkApp* app) (void*)(intptr_t) shutdown_now); uget_plugin_global_set(UgetPluginCurlInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); - uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); - uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); + uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); +#ifdef HAVE_MEGA + uget_plugin_global_set(UgetPluginMegaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE); +#endif } void ugtk_app_save (UgtkApp* app) @@ -529,7 +533,9 @@ void ugtk_app_set_plugin_setting (UgtkApp* app, UgtkSetting* setting) uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_MEDIA_GLOBAL_TYPE, (void*)(intptr_t) setting->media.type); // set MEGA plug-in - uget_app_add_plugin ((UgetApp*) app, UgetPluginMegaInfo); +#ifdef HAVE_MEGA + uget_app_add_plugin ((UgetApp*) app, UgetPluginMegaInfo); +#endif // set aria2 plug-in if (setting->plugin_order >= UGTK_PLUGIN_ORDER_ARIA2) { uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_URI, diff --git a/vcpkg.json b/vcpkg.json index 86819e9..5035bd0 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,11 +1,19 @@ { - "name": "modernizedapp", - "version-string": "2.3.0", + "name": "uget", + "version-string": "dev", + "builtin-baseline": "594ad8871e1e8e45f8e626c015fd611163430207", "dependencies": [ "curl", + "glib", + { + "name": "libgcrypt", + "platform": "!windows | mingw" + }, + { + "name": "libgpg-error", + "platform": "!windows | mingw" + }, "openssl", - "pkgconf", - { "name": "gtk", "platform": "!windows" }, - { "name": "gstreamer", "features": ["plugins-base"], "platform": "!windows" } + "pkgconf" ] -} +} \ No newline at end of file From 91f70712f12f8770761224966aa34fecee887487 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Tue, 16 Dec 2025 18:32:48 +0300 Subject: [PATCH 21/26] fix: enable building of uget CLI executable This adds src/main.c to CMakeLists.txt and makes it a valid entry point, ensuring uget.exe is built. --- CMakeLists.txt | 1 + src/main.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e7b631..25f79a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -472,6 +472,7 @@ set(UGET_CLI_CANDIDATES ${CMAKE_SOURCE_DIR}/uget/uget.c ${CMAKE_SOURCE_DIR}/uget/main.c ${CMAKE_SOURCE_DIR}/src/uget.c + ${CMAKE_SOURCE_DIR}/src/main.c ) set(UGET_CLI_MAIN "") diff --git a/src/main.c b/src/main.c index 65f9c4e..156623a 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,12 @@ #include "config.h" #include "core.h" +#include -int main(void) -{ - return core_dummy(); +int main(int argc, char **argv) { + // For now, this is a minimal CLI stub to verify the build. + // In the future, this should parse arguments and call uget_core functions. + (void)argc; + (void)argv; + printf("uget (cli) built with CMake\n"); + return core_dummy(); } From a0eb6b3166600c114520f5bcf8cb0324c32a8377 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Wed, 17 Dec 2025 15:22:58 +0300 Subject: [PATCH 22/26] fix: resolve compiler and linker errors for CLI build --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25f79a4..19e1357 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -508,9 +508,11 @@ if(TARGET uget) target_include_directories(uget PRIVATE ${CMAKE_SOURCE_DIR}/uget ${CMAKE_SOURCE_DIR}/uglib + ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/generated ${CURL_INCLUDE_DIRS} ) + target_sources(uget PRIVATE ${CMAKE_SOURCE_DIR}/src/core.c) target_compile_definitions(uget PRIVATE $ ) From f52e24990d4d3c6ae86583a5d59eee46ee568674 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Wed, 17 Dec 2025 16:08:43 +0300 Subject: [PATCH 23/26] fix: disable sanitizers by default for better portability --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19e1357..eaf445b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ option(WITH_OPENSSL "Enable OpenSSL-based crypto/TLS" ON) option(WITH_GNUTLS "Enable GnuTLS/libgcrypt backend" OFF) option(WITH_PWMD "Enable libpwmd integration" ON) option(ENABLE_MEGA "Enable MEGA plugin" ON) -option(ENABLE_SANITIZERS "Enable ASan/UBSan in Debug on non-MSVC builds" ON) +option(ENABLE_SANITIZERS "Enable ASan/UBSan in Debug on non-MSVC builds" OFF) if(MSVC) add_compile_options(/W4 /permissive- /utf-8) From 80e51804a27d2d9a0be4d2254ce94ec5830eca91 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Wed, 17 Dec 2025 16:45:50 +0300 Subject: [PATCH 24/26] fix: enable GUI build by adding gtk dependency and ensuring uget.exe output --- CMakeLists.txt | 4 +++- src/main.c | 12 ------------ vcpkg.json | 1 + 3 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 src/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index eaf445b..918c773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -472,7 +472,6 @@ set(UGET_CLI_CANDIDATES ${CMAKE_SOURCE_DIR}/uget/uget.c ${CMAKE_SOURCE_DIR}/uget/main.c ${CMAKE_SOURCE_DIR}/src/uget.c - ${CMAKE_SOURCE_DIR}/src/main.c ) set(UGET_CLI_MAIN "") @@ -523,6 +522,9 @@ if(UGET_WITH_GUI AND GTK3_FOUND) file(GLOB UGET_GTK_SOURCES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/ui-gtk/*.c") if(UGET_GTK_SOURCES) add_executable(uget-gtk ${UGET_GTK_SOURCES}) + if(WIN32) + set_target_properties(uget-gtk PROPERTIES OUTPUT_NAME "uget") + endif() target_include_directories(uget-gtk PRIVATE ${CMAKE_SOURCE_DIR}/uget ${CMAKE_SOURCE_DIR}/uglib diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 156623a..0000000 --- a/src/main.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "config.h" -#include "core.h" -#include - -int main(int argc, char **argv) { - // For now, this is a minimal CLI stub to verify the build. - // In the future, this should parse arguments and call uget_core functions. - (void)argc; - (void)argv; - printf("uget (cli) built with CMake\n"); - return core_dummy(); -} diff --git a/vcpkg.json b/vcpkg.json index 5035bd0..be17ac6 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -5,6 +5,7 @@ "dependencies": [ "curl", "glib", + "gtk", { "name": "libgcrypt", "platform": "!windows | mingw" From 55e5792d8b2f78b3bd21c5cc89cec8bcdb72f081 Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Wed, 17 Dec 2025 16:53:43 +0300 Subject: [PATCH 25/26] fix(gtk): add defensive checks for banner and window widget validity --- ui-gtk/UgtkApp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui-gtk/UgtkApp.c b/ui-gtk/UgtkApp.c index 4a1b9a0..7f1694d 100644 --- a/ui-gtk/UgtkApp.c +++ b/ui-gtk/UgtkApp.c @@ -95,14 +95,15 @@ void ugtk_app_init (UgtkApp* app, UgetRpc* rpc) uget_rss_add_builtin (app->rss_builtin, UGET_RSS_NEWS); uget_rss_add_builtin (app->rss_builtin, UGET_RSS_TUTORIALS); uget_rss_update (app->rss_builtin, FALSE); - gtk_widget_hide (app->banner.self); + if (app->banner.self && GTK_IS_WIDGET(app->banner.self)) + gtk_widget_hide (app->banner.self); uget_app_use_uri_hash ((UgetApp*) app); ugtk_app_init_timeout (app); if (app->setting.ui.start_in_tray) ugtk_tray_icon_set_visible (&app->trayicon, TRUE); - else + else if (app->window.self && GTK_IS_WIDGET(app->window.self)) gtk_widget_show ((GtkWidget*) app->window.self); // offline if (app->setting.ui.start_in_offline_mode) From a14523a3e459318ea27ab0524088d7c0932a017d Mon Sep 17 00:00:00 2001 From: Ozgur As Date: Wed, 17 Dec 2025 17:05:46 +0300 Subject: [PATCH 26/26] Revert "fix(gtk): add defensive checks for banner and window widget validity" This reverts commit 55e5792d8b2f78b3bd21c5cc89cec8bcdb72f081. --- ui-gtk/UgtkApp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui-gtk/UgtkApp.c b/ui-gtk/UgtkApp.c index 7f1694d..4a1b9a0 100644 --- a/ui-gtk/UgtkApp.c +++ b/ui-gtk/UgtkApp.c @@ -95,15 +95,14 @@ void ugtk_app_init (UgtkApp* app, UgetRpc* rpc) uget_rss_add_builtin (app->rss_builtin, UGET_RSS_NEWS); uget_rss_add_builtin (app->rss_builtin, UGET_RSS_TUTORIALS); uget_rss_update (app->rss_builtin, FALSE); - if (app->banner.self && GTK_IS_WIDGET(app->banner.self)) - gtk_widget_hide (app->banner.self); + gtk_widget_hide (app->banner.self); uget_app_use_uri_hash ((UgetApp*) app); ugtk_app_init_timeout (app); if (app->setting.ui.start_in_tray) ugtk_tray_icon_set_visible (&app->trayicon, TRUE); - else if (app->window.self && GTK_IS_WIDGET(app->window.self)) + else gtk_widget_show ((GtkWidget*) app->window.self); // offline if (app->setting.ui.start_in_offline_mode)