From 5e144e703303c68323b3663c6c74dea1fc0981c5 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Mon, 15 Dec 2025 11:59:47 -0800 Subject: [PATCH 01/29] .gitignore: ignore CMakeCache.txt and CMakeFiles --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 8d6683d5..3d4d3b52 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,9 @@ libpath_mangled Makefile Makefile.in +CMakeFiles +CMakeCache.txt + /*.zip /*.tar.* /*.sig From f9cff679fef6ff0199c633c96eb84d668332fdef Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Mon, 15 Dec 2025 16:21:47 -0800 Subject: [PATCH 02/29] msvc: don't define FILENAME_MAX if it already exists --- src/msvc/dirent.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/msvc/dirent.h b/src/msvc/dirent.h index b312dea7..b5ca733a 100644 --- a/src/msvc/dirent.h +++ b/src/msvc/dirent.h @@ -20,7 +20,9 @@ #include // +#ifndef FILENAME_MAX #define FILENAME_MAX _MAX_FNAME +#endif #define __MINGW_NOTHROW // From 3baa45ecb9ef0d525b51e1492ad94f289e82978c Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 15:11:18 -0800 Subject: [PATCH 03/29] Windows: MSVC: Poison GD_TRUNC for now - it is unsafe to unlink while iterating Without this poison, the following tests segfault: 1426 - test_trunc (SEGFAULT) 1427 - test_trunc_dir (SEGFAULT) 1429 - test_trunc_truncsub (SEGFAULT) --- cmake/test/CMakeLists.txt | 6 ++++++ src/open.c | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt index 79d91153..cc4bd10e 100644 --- a/cmake/test/CMakeLists.txt +++ b/cmake/test/CMakeLists.txt @@ -78,6 +78,12 @@ set(tests_ignored zzslim_get zzslim_nframes zzslim_seek zzslim_seek_far ) +# Windows-specific: GD_TRUNC has a known issue with directory iteration +# (modifying directory while iterating is unsafe with FindFirst/FindNext API) +if(WIN32) + list(APPEND tests_ignored trunc trunc_dir trunc_truncsub) +endif() + foreach(_item ${tests_ignored}) list(REMOVE_ITEM gd_sources ${GD_DIR}/test/${_item}.c) endforeach() diff --git a/src/open.c b/src/open.c index ec1f3611..699539b0 100644 --- a/src/open.c +++ b/src/open.c @@ -263,12 +263,21 @@ static FILE *_GD_CreateDirfile(DIRFILE *restrict D, int dirfd, int dir_error, return NULL; } +#ifdef __MSVCRT__ + /* GD_TRUNC is unsafe on Windows: modifying a directory while iterating + * causes crashes with the FindFirst/FindNext API. Return error instead. */ + _GD_SetError(D, GD_E_UNSUPPORTED, 0, NULL, 0, NULL); + free(dirfile); + dreturn("%p", NULL); + return NULL; +#else format_trunc = _GD_TruncDir(D, dirfd, dirfile, 1); if (format_trunc < 0) { free(dirfile); dreturn("%p", NULL); return NULL; } +#endif } /* Create, if needed */ From fe8536d9274b23c332492dc04e6cf32dec3fddfe Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Mon, 15 Dec 2025 10:07:59 -0800 Subject: [PATCH 04/29] big_test.py (Python tests): Python 2.x -> 3.x exception update --- bindings/python/test/big_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/test/big_test.py b/bindings/python/test/big_test.py index bb37c273..7def2daa 100644 --- a/bindings/python/test/big_test.py +++ b/bindings/python/test/big_test.py @@ -43,12 +43,12 @@ def B(s): def CheckOK(t): global ne ne+=1 - print ("e[", t, "] =", sys.exc_info()[0], sys.exc_value) + print ("e[", t, "] =", sys.exc_info()[0], sys.exc_info()[1]) def CheckOK2(t,m): global ne ne+=1 - print ("e[", t, ",", m, "] =", sys.exc_info()[0], sys.exc_value) + print ("e[", t, ",", m, "] =", sys.exc_info()[0], sys.exc_info()[1]) def CheckException(t,g): global ne From 235508246344d2bb4906603595094e19bb0387a7 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 10:30:23 -0800 Subject: [PATCH 05/29] big_test.py (Python tests): gracefully handle builds without regex/pcre support --- bindings/python/test/big_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/test/big_test.py b/bindings/python/test/big_test.py index 7def2daa..b4dc287f 100644 --- a/bindings/python/test/big_test.py +++ b/bindings/python/test/big_test.py @@ -2247,9 +2247,9 @@ def CheckEOS(t,v,g): # 305: gd_match_entries try: n = d.match_entries(regex='^lin', fragment=0) + CheckSimple2(305, 1, n, [ B('lincom'), B('linterp') ]) except: - CheckOK2(305, 0) -CheckSimple2(305, 1, n, [ B('lincom'), B('linterp') ]) + CheckException2(305, 0, pygetdata.UnsupportedError) # Expected when regex unsupported # 306: gd_open_limit try: From f99b6536909feb65bb068612b381878e2b0e217c Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 10:44:28 -0800 Subject: [PATCH 06/29] big_test.py (Python tests): CheckEOS: escape input before using re.search() This has no impact on the current codebase, but in a future commit we'll be adding Windows support (which means backslashes, which need to be escaped.) --- bindings/python/test/big_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/test/big_test.py b/bindings/python/test/big_test.py index b4dc287f..951b7bd5 100644 --- a/bindings/python/test/big_test.py +++ b/bindings/python/test/big_test.py @@ -88,7 +88,7 @@ def CheckSimple2(t,m,v,g): def CheckEOS(t,v,g): global ne - if (re.search(g + "$", v) == None): + if (re.search(re.escape(g) + "$", v) == None): ne+=1 print ("n[", t, "] =", v, "expected", g) From 50927900506e2cea518612cbf9db68fd76d8f8a7 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 10:27:46 -0800 Subject: [PATCH 07/29] big_test.py (Python tests): use path.join for "expected results" with paths --- bindings/python/test/big_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/python/test/big_test.py b/bindings/python/test/big_test.py index 951b7bd5..1c4809ed 100644 --- a/bindings/python/test/big_test.py +++ b/bindings/python/test/big_test.py @@ -641,7 +641,7 @@ def CheckEOS(t,v,g): f = d.fragment(0) except: CheckOK(64) -CheckEOS(64,f.name,"dirfile/format") +CheckEOS(64,f.name,os.path.join("dirfile","format")) # 65: nfragments check try: @@ -1053,7 +1053,7 @@ def CheckEOS(t,v,g): n = d.raw_filename("data") except: CheckOK(116) -CheckEOS(116,n,"dirfile/data") +CheckEOS(116,n,os.path.join("dirfile","data")) # 117: reference check try: @@ -1976,7 +1976,7 @@ def CheckEOS(t,v,g): n = d.linterp_tablename("linterp") except: CheckOK(241) -CheckEOS(241,n,"dirfile/lut") +CheckEOS(241,n,os.path.join("dirfile","lut")) # 242: mcarrays try: From 7053593716758aca20c446a00f214ae52cb0604a Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Wed, 17 Dec 2025 10:33:47 -0800 Subject: [PATCH 08/29] bindings/python: callback.py tests: win32 portability (CRLF and path separators) --- bindings/python/test/callback.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/python/test/callback.py b/bindings/python/test/callback.py index 0c67da98..cf46f037 100644 --- a/bindings/python/test/callback.py +++ b/bindings/python/test/callback.py @@ -20,7 +20,6 @@ import sys import os -import re import array import pygetdata @@ -42,7 +41,8 @@ def parser_callback(pdata, extra): print ("linenum =", pdata["linenum"]) sys.exit(1) - if (re.search("dirfile/format$", pdata["filename"]) == None): + path = os.path.join("dirfile", "format") + if not pdata["filename"].endswith(path): print ("filename =", pdata["filename"]) sys.exit(1) @@ -52,12 +52,12 @@ def parser_callback(pdata, extra): data=array.array("H",range(3,7000,7)) os.system("rm -rf dirfile") os.mkdir("dirfile") -file=open("dirfile/data", 'wb') +file=open(os.path.join("dirfile", "data"), 'wb') data.tofile(file) file.close() -file=open("dirfile/format", "w") -file.write("data RAW UINT16 8\nbad line\n") +file=open(os.path.join("dirfile", "format"), "wb") +file.write(b"data RAW UINT16 8\nbad line\n") file.close() d=pygetdata.dirfile("dirfile", pygetdata.RDONLY, callback=parser_callback, From c3be1718e884669d6ca07a0988fbdbccd411576d Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Sun, 14 Dec 2025 10:14:10 -0800 Subject: [PATCH 09/29] cmake modernization and python bindings --- bindings/make_parameters.c | 2 + cmake/CMakeLists.txt | 372 +++++++++++++++++++++------ cmake/bindings/CMakeLists.txt | 10 + cmake/bindings/python/CMakeLists.txt | 34 +++ cmake/gd_config.h.in | 133 ++++++++++ cmake/src/CMakeLists.txt | 83 +++++- cmake/test/CMakeLists.txt | 162 ++++++++---- 7 files changed, 653 insertions(+), 143 deletions(-) create mode 100644 cmake/bindings/python/CMakeLists.txt create mode 100644 cmake/gd_config.h.in diff --git a/bindings/make_parameters.c b/bindings/make_parameters.c index e71f4fd7..a5926d4a 100644 --- a/bindings/make_parameters.c +++ b/bindings/make_parameters.c @@ -24,7 +24,9 @@ #include #include +#ifdef HAVE_UNISTD_H #include +#endif #define GD_NO_LEGACY_API #include "getdata.h" diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 91d4b461..f0f778b7 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,13 +1,90 @@ -cmake_minimum_required(VERSION 2.6.4) +cmake_minimum_required(VERSION 3.15) project(getdata) - +option(BUILD_PYTHON "Build Python bindings" ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +if(BUILD_PYTHON) + set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries" FORCE) + find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module NumPy) + set(HAVE_NUMPY_ARRAYOBJECT_H TRUE) +endif() + +# Optional encoding libraries +find_package(BZip2) +find_package(ZLIB) +find_package(LibLZMA) +find_package(PkgConfig) +if(PKG_CONFIG_FOUND) + pkg_check_modules(PCRE libpcre) + pkg_check_modules(FLAC flac) + pkg_check_modules(ZZIP zziplib) +endif() + +# Find external compression tools for tests +find_program(BZIP2 bzip2) +find_program(BUNZIP2 bunzip2) +find_program(FLAC flac) +find_program(GZIP gzip) +find_program(GUNZIP gunzip) +find_program(UNZIP unzip) +find_program(XZ xz) +find_program(ZIP zip) + +if(BZIP2_FOUND) + include(CheckIncludeFile) + check_include_file(bzlib.h HAVE_BZLIB_H) + if(NOT HAVE_BZLIB_H) + set(BZIP2_FOUND FALSE) + endif() +endif() +if(ZLIB_FOUND) + check_include_file(zlib.h HAVE_ZLIB_H) + if(NOT HAVE_ZLIB_H) + set(ZLIB_FOUND FALSE) + endif() +endif() + +if(LIBLZMA_FOUND) + set(CMAKE_REQUIRED_INCLUDES ${LIBLZMA_INCLUDE_DIRS}) + check_include_file(lzma.h HAVE_LZMA_H) + unset(CMAKE_REQUIRED_INCLUDES) + if(NOT HAVE_LZMA_H) + set(LIBLZMA_FOUND FALSE) + endif() +endif() + +if(FLAC_FOUND) + set(CMAKE_REQUIRED_INCLUDES ${FLAC_INCLUDE_DIRS}) + check_include_file(FLAC/all.h HAVE_FLAC_ALL_H) + unset(CMAKE_REQUIRED_INCLUDES) + if(NOT HAVE_FLAC_ALL_H) + set(FLAC_FOUND FALSE) + endif() +endif() + +if(ZZIP_FOUND) + set(CMAKE_REQUIRED_INCLUDES ${ZZIP_INCLUDE_DIRS}) + check_include_file(zzip/lib.h HAVE_ZZIP_LIB_H) + unset(CMAKE_REQUIRED_INCLUDES) + if(NOT HAVE_ZZIP_LIB_H) + set(ZZIP_FOUND FALSE) + endif() +endif() + +if(PCRE_FOUND) + set(CMAKE_REQUIRED_INCLUDES ${PCRE_INCLUDE_DIRS}) + check_include_file(pcre.h HAVE_PCRE_H) + unset(CMAKE_REQUIRED_INCLUDES) + if(NOT HAVE_PCRE_H) + set(PCRE_FOUND FALSE) + endif() +endif() if(NOT GD_DIR) set(GD_DIR ${CMAKE_SOURCE_DIR}/..) @@ -23,28 +100,148 @@ macro(GD_FILES name folder) include_directories(${CMAKE_SOURCE_DIR}/${folder}) endmacro() -#TODO add configure add_definitions( - -DPACKAGE_NAME=\"GetData\" - -DPACKAGE_VERSION=\"0.10.x\" - -DGETDATA_LIB_VERSION=\"0.10.x\" - -DPACKAGE_BUGREPORT=\"https://github.com/ketiltrout/getdata/issues\" -DUNALIGNED_ACCESS_OK ) # kst2 doesn't need the legacy API set(DEFINE_GD_LEGACY_API "/* #undef GD_LEGACY_API */") -# Disable REGEX support -set(DEFINE_GD_NO_REGEX "#define GD_NO_REGEX 1") -set(DEFINE_GD_NO_PCRE "#define GD_NO_PCRE 1") - # Version macros -set(DEFINE_GD_GETDATA_VERSION "#define GD_GETDATA_VERSION \"0.10.x\"") -set(DEFINE_GD_GETDATA_INT_VERSION "#define GD_GETDATA_INT_VERSION 1000") +set(DEFINE_GD_GETDATA_VERSION "#define GD_GETDATA_VERSION \"0.11.0\"") +set(DEFINE_GD_GETDATA_INT_VERSION "#define GD_GETDATA_INT_VERSION 1100") + +# Platform-independent configuration checks +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckCSourceCompiles) + +# Check for headers +check_include_file(asm/unaligned.h HAVE_ASM_UNALIGNED_H) +check_include_file(Availability.h HAVE_AVAILABILITY_H) +check_include_file(byteswap.h HAVE_BYTESWAP_H) +check_include_file(complex.h HAVE_COMPLEX_H) +check_include_file(crtdefs.h HAVE_CRTDEFS_H) +check_include_file(ctype.h HAVE_CTYPE_H) +check_include_file(direct.h HAVE_DIRECT_H) +check_include_file(dirent.h HAVE_DIRENT_H) +check_include_file(errno.h HAVE_ERRNO_H) +check_include_file(fcntl.h HAVE_FCNTL_H) +check_include_file(features.h HAVE_FEATURES_H) +check_include_file(float.h HAVE_FLOAT_H) +check_include_file(inttypes.h HAVE_INTTYPES_H) +check_include_file(io.h HAVE_IO_H) +check_include_file(libgen.h HAVE_LIBGEN_H) +check_include_file(libkern/OSByteOrder.h HAVE_LIBKERN_OSBYTEORDER_H) +check_include_file(limits.h HAVE_LIMITS_H) +check_include_file(math.h HAVE_MATH_H) +check_include_file(memory.h HAVE_MEMORY_H) +check_include_file(regex.h HAVE_REGEX_H) +check_include_file(stddef.h HAVE_STDDEF_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stdlib.h HAVE_STDLIB_H) +check_include_file(string.h HAVE_STRING_H) +check_include_file(strings.h HAVE_STRINGS_H) +check_include_file(sys/endian.h HAVE_SYS_ENDIAN_H) +check_include_file(sys/file.h HAVE_SYS_FILE_H) +check_include_file(sys/param.h HAVE_SYS_PARAM_H) +check_include_file(sys/stat.h HAVE_SYS_STAT_H) +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(time.h HAVE_TIME_H) +check_include_file(unistd.h HAVE_UNISTD_H) + +# Check for functions +check_symbol_exists(basename "string.h" HAVE_BASENAME) +check_symbol_exists(dirname "libgen.h" HAVE_DIRNAME) +check_function_exists(fchmod HAVE_FCHMOD) +check_function_exists(fdopendir HAVE_FDOPENDIR) +check_function_exists(fseeko HAVE_FSEEKO) +check_function_exists(fseeko64 HAVE_FSEEKO64) +check_function_exists(fstatat HAVE_FSTATAT) +check_function_exists(fsync HAVE_FSYNC) +check_function_exists(ftello HAVE_FTELLO) +check_function_exists(ftello64 HAVE_FTELLO64) +check_function_exists(ftruncate HAVE_FTRUNCATE) +check_function_exists(getcwd HAVE_GETCWD) +check_function_exists(gmtime HAVE_GMTIME) +check_function_exists(gmtime_r HAVE_GMTIME_R) +check_function_exists(lseek64 HAVE_LSEEK64) +check_function_exists(lstat HAVE_LSTAT) +check_function_exists(openat HAVE_OPENAT) +check_function_exists(readdir_r HAVE_READDIR_R) +check_function_exists(readlink HAVE_READLINK) +check_function_exists(regcomp HAVE_REGCOMP) +check_function_exists(renameat HAVE_RENAMEAT) +check_function_exists(snprintf HAVE_SNPRINTF) +check_function_exists(strtoll HAVE_STRTOLL) +check_function_exists(strtoull HAVE_STRTOULL) +check_function_exists(symlink HAVE_SYMLINK) +check_function_exists(unlinkat HAVE_UNLINKAT) + +if(UNIX) + set(CMAKE_REQUIRED_LIBRARIES m) +endif() +check_function_exists(cabs HAVE_CABS) +check_function_exists(isnan HAVE_ISNAN) +check_function_exists(nan HAVE_NAN) +unset(CMAKE_REQUIRED_LIBRARIES) + +# Check for strerror_r (GNU vs XSI versions) +# GNU version returns char*, XSI returns int - prefer XSI +set(CMAKE_REQUIRED_FLAGS "-Werror") +check_c_source_compiles(" + #include + int main() { + char buf[100]; + char *p = strerror_r(0, buf, sizeof(buf)); + return 0; + } +" HAVE_STRERROR_R_GNU) +unset(CMAKE_REQUIRED_FLAGS) + +if(NOT HAVE_STRERROR_R_GNU) + check_function_exists(strerror_r HAVE_STRERROR_R) +endif() + +# Check for type sizes (all platforms) +set(CMAKE_EXTRA_INCLUDE_FILES "stdint.h") +check_type_size(int SIZEOF_INT) +check_type_size("unsigned int" SIZEOF_UNSIGNED_INT) +check_type_size("short int" SIZEOF_SHORT_INT) +check_type_size("unsigned short int" SIZEOF_UNSIGNED_SHORT_INT) +check_type_size("long int" SIZEOF_LONG_INT) +check_type_size("unsigned long int" SIZEOF_UNSIGNED_LONG_INT) +check_type_size("long long int" SIZEOF_LONG_LONG_INT) +check_type_size("unsigned long long int" SIZEOF_UNSIGNED_LONG_LONG_INT) +check_type_size(size_t SIZEOF_SIZE_T) +check_type_size("void*" SIZEOF_VOID_P) +check_type_size(off64_t OFF64_T) +set(CMAKE_EXTRA_INCLUDE_FILES) + +# Determine 64-bit integer types (matching autotools logic) +if(SIZEOF_INT EQUAL 8) + set(gd_int64_t "int") +elseif(SIZEOF_SHORT_INT EQUAL 8) + set(gd_int64_t "short int") +elseif(SIZEOF_LONG_INT EQUAL 8) + set(gd_int64_t "long int") +elseif(SIZEOF_LONG_LONG_INT EQUAL 8) + set(gd_int64_t "long long int") +endif() + +if(SIZEOF_UNSIGNED_INT EQUAL 8) + set(gd_uint64_t "unsigned int") +elseif(SIZEOF_UNSIGNED_SHORT_INT EQUAL 8) + set(gd_uint64_t "unsigned short int") +elseif(SIZEOF_UNSIGNED_LONG_INT EQUAL 8) + set(gd_uint64_t "unsigned long int") +elseif(SIZEOF_UNSIGNED_LONG_LONG_INT EQUAL 8) + set(gd_uint64_t "unsigned long long int") +endif() if(MSVC) - ## Substitutions needed to build getdata.h # build in ANSI C mode set(DEFINE_GD_NO_C99_API "#define GD_NO_C99_API") @@ -52,8 +249,17 @@ if(MSVC) set(DEFINE_gd_int64_t "#define gd_int64_t __int64") set(DEFINE_gd_uint64_t "#define gd_uint64_t unsigned __int64") - add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS) + # Check if _strtoi64 and _strtoui64 are declared in modern SDK + include(CheckSymbolExists) + check_symbol_exists(_strtoi64 "stdlib.h" HAVE_DECL__STRTOI64) + check_symbol_exists(_strtoui64 "stdlib.h" HAVE_DECL__STRTOUI64) + + # Check if isfinite is declared in modern SDK (C99 function) + check_symbol_exists(isfinite "math.h" HAVE_DECL_ISFINITE) + add_definitions( + -D_CRT_SECURE_NO_WARNINGS + -D_CRT_NONSTDC_NO_WARNINGS -D__MSVCRT__ -D_USE_MATH_DEFINES -DHAVE__CHSIZE @@ -68,77 +274,45 @@ if(MSVC) -DHAVE__STAT64 -DHAVE__STRTOI64 -DHAVE__STRTOUI64 - -DHAVE_DECL__STRTOI64=0 - -DHAVE_DECL__STRTOUI64=0 + -DHAVE_STRUCT___STAT64 + -DHAVE_ISNAN -DHAVE_DIRENT_H - -DHAVE_DIRECT_H - -DHAVE_FCNTL_H - -DHAVE_FLOAT_H + -DHAVE_DIRNAME -DHAVE_LIBGEN_H - -DHAVE_INTTYPES_H - -DHAVE_IO_H - -DHAVE_STDINT_H - -DHAVE_STRUCT___STAT64 - -DHAVE_SYS_STAT_H -DGD_DIRSEP='\\\\' -DMKDIR_NO_MODE -Dmode_t=int -Drestrict= - -DSIZEOF_INT=4 - -DSIZEOF_UNSIGNED_INT=4 - ) - set(CMAKE_DEBUG_POSTFIX d) + ) - # ANSI C - #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Za") + if(HAVE_DECL__STRTOI64) + add_definitions(-DHAVE_DECL__STRTOI64=1) + else() + add_definitions(-DHAVE_DECL__STRTOI64=0) + endif() + if(HAVE_DECL__STRTOUI64) + add_definitions(-DHAVE_DECL__STRTOUI64=1) + else() + add_definitions(-DHAVE_DECL__STRTOUI64=0) + endif() + if(HAVE_DECL_ISFINITE) + add_definitions(-DHAVE_DECL_ISFINITE=1) + else() + add_definitions(-DHAVE_DECL_ISFINITE=0) + endif() - # Suppress warnings + set(CMAKE_DEBUG_POSTFIX d) string(REGEX REPLACE "/W[0-4]" "/W0" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - include_directories(${GD_DIR}/src/msvc) -endif() -if(MINGW) +elseif(MINGW) + set(DEFINE_gd_int64_t "#define gd_int64_t __int64") set(DEFINE_gd_uint64_t "#define gd_uint64_t unsigned __int64") add_definitions( -D__MSVCRT_VERSION__=0x0601 -DGD_DIRSEP='\\\\' - -DGD_RESTRICT_ARRAY_OK=1 - -DHAVE_BASENAME - -DHAVE_CABS - -DHAVE_COMPLEX_H - -DHAVE_DIRECT_H - -DHAVE_DIRENT_H - -DHAVE_FCNTL_H - -DHAVE_FLOAT_H - -DHAVE_FSEEKO64 - -DHAVE_FTELLO64 - -DHAVE_FTRUNCATE - -DHAVE_GETCWD - -DHAVE_INTTYPES_H - -DHAVE_IO_H - -DHAVE_ISNAN - -DHAVE_LIBGEN_H - -DHAVE_LSEEK64 - -DHAVE_MEMORY_H - -DHAVE_NAN - -DHAVE_OFF64_T - -DHAVE_SNPRINTF - -DHAVE_STDDEF_H - -DHAVE_STDINT_H - -DHAVE_STDLIB_H - -DHAVE_STRINGS_H - -DHAVE_STRING_H - -DHAVE_STRTOLL - -DHAVE_STRTOULL - -DHAVE_STRUCT___STAT64 - -DHAVE_SYS_FILE_H - -DHAVE_SYS_PARAM_H - -DHAVE_SYS_STAT_H - -DHAVE_SYS_TYPES_H - -DHAVE_UNISTD_H -DHAVE__CHSIZE -DHAVE__COMMIT -DHAVE__COMPLEX_DOUBLE @@ -159,20 +333,52 @@ if(MINGW) -DHAVE__STRTOUI64 -DHAVE__UNLINK -DHAVE__WRITE + -DHAVE_STRUCT___STAT64 -DMKDIR_NO_MODE - -DSIZEOF_INT=4 - -DSIZEOF_UNSIGNED_INT=4 - -DSTDC_HEADERS - -D_BSD_SOURCE=1 - -D_GNU_SOURCE=1 - -D_POSIX_C_SOURCE=1200809L - -D_POSIX_SOURCE=1 - -D_SVID_SOURCE=0 -Drestrict=__restrict - ) + ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") + +else() # Unix/Linux/macOS + set(DEFINE_gd_int64_t "#define gd_int64_t ${gd_int64_t}") + set(DEFINE_gd_uint64_t "#define gd_uint64_t ${gd_uint64_t}") + + set(CMAKE_C_STANDARD 99) + # _DEFAULT_SOURCE provides BSD extensions (M_PI, mktemp) with XSI strerror_r (glibc >= 2.19) + # _BSD_SOURCE needed for older glibc (e.g. CentOS 7 with glibc 2.17) + add_definitions(-DGD_DIRSEP='/' -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -D_BSD_SOURCE) + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Drestrict=") endif() +# HAVE_* macros are defined in gd_config.h via #cmakedefine +# Only special logic for getdata.h template variables remains here + +# Set template variables for getdata.h (these control API availability) +if(HAVE_REGEX_H AND HAVE_REGCOMP) + set(DEFINE_GD_NO_REGEX "/* #undef GD_NO_REGEX */") +else() + set(DEFINE_GD_NO_REGEX "#define GD_NO_REGEX 1") +endif() + +if(PCRE_FOUND AND HAVE_PCRE_H) + set(DEFINE_GD_NO_PCRE "/* #undef GD_NO_PCRE */") +else() + set(DEFINE_GD_NO_PCRE "#define GD_NO_PCRE 1") +endif() + +add_definitions( + -DSIZEOF_INT=${SIZEOF_INT} + -DSIZEOF_UNSIGNED_INT=${SIZEOF_UNSIGNED_INT} + -DSIZEOF_SIZE_T=${SIZEOF_SIZE_T} + -DSIZEOF_VOID_P=${SIZEOF_VOID_P} + -DGETDATA_MAJOR=0 + -DGETDATA_MINOR=11 + -DGETDATA_REVISION=0 + -DSTDC_HEADERS + -DGD_RESTRICT_ARRAY_OK=1 +) + if(GD_TEST) enable_testing() endif() @@ -185,6 +391,9 @@ if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/INSTALLED CACHE PATH "install path" FORCE) endif() +# Generate gd_config.h +configure_file(${CMAKE_SOURCE_DIR}/gd_config.h.in ${GD_DIR}/src/gd_config.h @ONLY) + add_subdirectory(src) add_subdirectory(bindings) @@ -195,6 +404,3 @@ endif() if(GD_TEST) add_subdirectory(test) endif() - - - diff --git a/cmake/bindings/CMakeLists.txt b/cmake/bindings/CMakeLists.txt index 45abe8f1..11c7bb50 100644 --- a/cmake/bindings/CMakeLists.txt +++ b/cmake/bindings/CMakeLists.txt @@ -1,4 +1,14 @@ add_subdirectory(cxx) +if(BUILD_PYTHON) + # Build make_parameters utility for generating pyconstants.c + add_executable(make_parameters ${GD_DIR}/bindings/make_parameters.c) + target_include_directories(make_parameters PRIVATE ${GD_DIR}/src ${CMAKE_BINARY_DIR}) + target_link_libraries(make_parameters PRIVATE getdata) + target_compile_definitions(make_parameters PRIVATE HAVE_CONFIG_H) + + add_subdirectory(python) +endif() + diff --git a/cmake/bindings/python/CMakeLists.txt b/cmake/bindings/python/CMakeLists.txt new file mode 100644 index 00000000..963c4f65 --- /dev/null +++ b/cmake/bindings/python/CMakeLists.txt @@ -0,0 +1,34 @@ +# Generate pyconstants.c using make_parameters +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pyconstants.c + COMMAND make_parameters p > ${CMAKE_CURRENT_BINARY_DIR}/pyconstants.c + DEPENDS make_parameters getdata + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating pyconstants.c" +) + +# Build Python extension module +Python3_add_library(pygetdata MODULE + ${GD_DIR}/bindings/python/pydirfile.c + ${GD_DIR}/bindings/python/pyentry.c + ${GD_DIR}/bindings/python/pyfragment.c + ${GD_DIR}/bindings/python/pygetdata.c + ${CMAKE_CURRENT_BINARY_DIR}/pyconstants.c +) + +target_include_directories(pygetdata PRIVATE + ${GD_DIR}/src + ${GD_DIR}/bindings/python + ${CMAKE_BINARY_DIR} + ${Python3_NumPy_INCLUDE_DIRS} +) + +# Link against static library for self-contained wheels +target_link_libraries(pygetdata PRIVATE getdata_static) + +target_compile_definitions(pygetdata PRIVATE HAVE_CONFIG_H) + +# Remove 'lib' prefix on Unix-like systems +set_target_properties(pygetdata PROPERTIES PREFIX "") + +install(TARGETS pygetdata LIBRARY DESTINATION .) diff --git a/cmake/gd_config.h.in b/cmake/gd_config.h.in new file mode 100644 index 00000000..3deb5892 --- /dev/null +++ b/cmake/gd_config.h.in @@ -0,0 +1,133 @@ +/* gd_config.h - Generated by CMake */ + +#ifndef GD_CONFIG_H +#define GD_CONFIG_H + +/* Package information */ +#define PACKAGE_NAME "GetData" +#define PACKAGE_VERSION "0.11.0" +#define PACKAGE_STRING "GetData 0.11.0" +#define PACKAGE_BUGREPORT "https://github.com/ketiltrout/getdata/issues" + +/* Headers */ +#cmakedefine HAVE_ASM_UNALIGNED_H 1 +#cmakedefine HAVE_AVAILABILITY_H 1 +#cmakedefine HAVE_BYTESWAP_H 1 +#cmakedefine HAVE_COMPLEX_H 1 +#cmakedefine HAVE_CRTDEFS_H 1 +#cmakedefine HAVE_CTYPE_H 1 +#cmakedefine HAVE_DIRECT_H 1 +#cmakedefine HAVE_DIRENT_H 1 +#cmakedefine HAVE_ERRNO_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE_FEATURES_H 1 +#cmakedefine HAVE_FLOAT_H 1 +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_IO_H 1 +#cmakedefine HAVE_LIBGEN_H 1 +#cmakedefine HAVE_LIBKERN_OSBYTEORDER_H 1 +#cmakedefine HAVE_LIMITS_H 1 +#cmakedefine HAVE_MATH_H 1 +#cmakedefine HAVE_MEMORY_H 1 +#cmakedefine HAVE_STDDEF_H 1 +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_STDLIB_H 1 +#cmakedefine HAVE_STRING_H 1 +#cmakedefine HAVE_STRINGS_H 1 +#cmakedefine HAVE_SYS_ENDIAN_H 1 +#cmakedefine HAVE_SYS_FILE_H 1 +#cmakedefine HAVE_SYS_PARAM_H 1 +#cmakedefine HAVE_SYS_STAT_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 +#cmakedefine HAVE_TIME_H 1 +#cmakedefine HAVE_UNISTD_H 1 + +/* Encoding library headers */ +#cmakedefine HAVE_BZLIB_H 1 +#cmakedefine HAVE_ZLIB_H 1 +#cmakedefine HAVE_LZMA_H 1 +#cmakedefine HAVE_FLAC_ALL_H 1 +#cmakedefine HAVE_ZZIP_LIB_H 1 + +/* NumPy */ +#cmakedefine HAVE_NUMPY_ARRAYOBJECT_H 1 + +/* Regex support */ +#cmakedefine HAVE_PCRE_H 1 +#cmakedefine HAVE_REGEX_H 1 +#cmakedefine HAVE_REGCOMP 1 + +/* Functions */ +#cmakedefine HAVE_BASENAME 1 +#cmakedefine HAVE_CABS 1 +#cmakedefine HAVE_DIRNAME 1 +#cmakedefine HAVE_FCHMOD 1 +#cmakedefine HAVE_FDOPENDIR 1 +#cmakedefine HAVE_FSEEKO 1 +#cmakedefine HAVE_FSEEKO64 1 +#cmakedefine HAVE_FSTATAT 1 +#cmakedefine HAVE_FSYNC 1 +#cmakedefine HAVE_FTELLO 1 +#cmakedefine HAVE_FTELLO64 1 +#cmakedefine HAVE_FTRUNCATE 1 +#cmakedefine HAVE_GETCWD 1 +#cmakedefine HAVE_GMTIME 1 +#cmakedefine HAVE_GMTIME_R 1 +#cmakedefine HAVE_ISNAN 1 +#cmakedefine HAVE_LSEEK64 1 +#cmakedefine HAVE_LSTAT 1 +#cmakedefine HAVE_NAN 1 +#cmakedefine HAVE_OPENAT 1 +#cmakedefine HAVE_READDIR_R 1 +#cmakedefine HAVE_READLINK 1 +#cmakedefine HAVE_REGCOMP 1 +#cmakedefine HAVE_RENAMEAT 1 +#cmakedefine HAVE_SNPRINTF 1 +#cmakedefine HAVE_STRERROR_R 1 +#cmakedefine HAVE_STRTOLL 1 +#cmakedefine HAVE_STRTOULL 1 +#cmakedefine HAVE_SYMLINK 1 +#cmakedefine HAVE_UNLINKAT 1 +#cmakedefine STRERROR_R_CHAR_P 1 + +/* Libraries */ +#cmakedefine HAVE_LIBBZ2 1 +#cmakedefine HAVE_LIBZ 1 +#cmakedefine HAVE_LIBLZMA 1 +#cmakedefine HAVE_LIBFLAC 1 +#cmakedefine HAVE_LIBZZIP 1 + +/* External tools (for tests) */ +#cmakedefine BZIP2 "@BZIP2@" +#cmakedefine BUNZIP2 "@BUNZIP2@" +#cmakedefine FLAC "@FLAC@" +#cmakedefine GZIP "@GZIP@" +#cmakedefine GUNZIP "@GUNZIP@" +#cmakedefine UNZIP "@UNZIP@" +#cmakedefine XZ "@XZ@" +#cmakedefine ZIP "@ZIP@" + +/* Type sizes */ +#define SIZEOF_INT @SIZEOF_INT@ +#define SIZEOF_UNSIGNED_INT @SIZEOF_UNSIGNED_INT@ +#define SIZEOF_SIZE_T @SIZEOF_SIZE_T@ +#define SIZEOF_VOID_P @SIZEOF_VOID_P@ + +/* off64_t support */ +#cmakedefine HAVE_OFF64_T 1 +#cmakedefine HAVE_LSEEK64 1 + +/* Version macros */ +#define GETDATA_MAJOR 0 +#define GETDATA_MINOR 11 +#define GETDATA_REVISION 0 +#define GETDATA_VERSION_SUFFIX "" + +/* Feature flags */ +#define STDC_HEADERS 1 +#define GD_RESTRICT_ARRAY_OK 1 + +/* Platform flags */ +#define _POSIX_C_SOURCE 200809L + +#endif /* GD_CONFIG_H */ diff --git a/cmake/src/CMakeLists.txt b/cmake/src/CMakeLists.txt index 98106598..ace471b0 100644 --- a/cmake/src/CMakeLists.txt +++ b/cmake/src/CMakeLists.txt @@ -1,15 +1,27 @@ set(files_ignored - ${GD_DIR}/src/bzip.c - ${GD_DIR}/src/flac.c - ${GD_DIR}/src/gzip.c - ${GD_DIR}/src/lzma.c ${GD_DIR}/src/legacy.c ${GD_DIR}/src/slim.c ${GD_DIR}/src/zzslim.c - ${GD_DIR}/src/zzip.c ) +# Conditionally include encoding modules based on found libraries +if(NOT BZIP2_FOUND) + list(APPEND files_ignored ${GD_DIR}/src/bzip.c) +endif() +if(NOT FLAC_FOUND) + list(APPEND files_ignored ${GD_DIR}/src/flac.c) +endif() +if(NOT ZLIB_FOUND) + list(APPEND files_ignored ${GD_DIR}/src/gzip.c) +endif() +if(NOT LIBLZMA_FOUND) + list(APPEND files_ignored ${GD_DIR}/src/lzma.c) +endif() +if(NOT ZZIP_FOUND) + list(APPEND files_ignored ${GD_DIR}/src/zzip.c) +endif() + GD_FILES(gd src) if(MSVC) @@ -35,11 +47,66 @@ endif() list(REMOVE_ITEM gd_sources ${files_ignored}) -add_library(getdata STATIC ${gd_sources} ${gd_headers} ${CMAKE_BINARY_DIR}/getdata.h) +# Build shared library (parallel to autotools .so) +add_library(getdata SHARED ${gd_sources} ${gd_headers} ${CMAKE_BINARY_DIR}/getdata.h) +set_target_properties(getdata PROPERTIES + VERSION 11.0.0 + SOVERSION 11 +) +target_compile_definitions(getdata PRIVATE HAVE_CONFIG_H) +# Build static library (parallel to autotools .a) +add_library(getdata_static STATIC ${gd_sources} ${gd_headers} ${CMAKE_BINARY_DIR}/getdata.h) +set_target_properties(getdata_static PROPERTIES + OUTPUT_NAME getdata + POSITION_INDEPENDENT_CODE ON +) +target_compile_definitions(getdata_static PRIVATE HAVE_CONFIG_H) -install(FILES ${CMAKE_BINARY_DIR}/getdata.h DESTINATION include) -install(TARGETS getdata DESTINATION lib) +# Macro to configure both shared and static libraries with the same dependencies +macro(configure_getdata_target target) + if(BZIP2_FOUND) + target_include_directories(${target} PRIVATE ${BZIP2_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE BZip2::BZip2) + target_compile_definitions(${target} PRIVATE HAVE_LIBBZ2 HAVE_BZLIB_H USE_BZIP2) + endif() + if(ZLIB_FOUND) + target_include_directories(${target} PRIVATE ${ZLIB_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE ZLIB::ZLIB) + target_compile_definitions(${target} PRIVATE HAVE_LIBZ HAVE_ZLIB_H USE_GZIP) + endif() + if(LIBLZMA_FOUND) + target_include_directories(${target} PRIVATE ${LIBLZMA_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE LibLZMA::LibLZMA) + target_compile_definitions(${target} PRIVATE HAVE_LIBLZMA HAVE_LZMA_H USE_LZMA) + endif() + if(FLAC_FOUND) + target_include_directories(${target} PRIVATE ${FLAC_INCLUDE_DIRS}) + target_link_directories(${target} PRIVATE ${FLAC_LIBRARY_DIRS}) + target_link_libraries(${target} PRIVATE ${FLAC_LIBRARIES}) + target_compile_definitions(${target} PRIVATE HAVE_LIBFLAC HAVE_FLAC_ALL_H USE_FLAC) + endif() + if(ZZIP_FOUND) + target_include_directories(${target} PRIVATE ${ZZIP_INCLUDE_DIRS}) + target_link_directories(${target} PRIVATE ${ZZIP_LIBRARY_DIRS}) + target_link_libraries(${target} PRIVATE ${ZZIP_LIBRARIES}) + target_compile_definitions(${target} PRIVATE HAVE_LIBZZIP HAVE_ZZIP_LIB_H USE_ZZIP) + endif() + if(PCRE_FOUND) + target_include_directories(${target} PRIVATE ${PCRE_INCLUDE_DIRS}) + target_link_directories(${target} PRIVATE ${PCRE_LIBRARY_DIRS}) + target_link_libraries(${target} PRIVATE ${PCRE_LIBRARIES}) + target_compile_definitions(${target} PRIVATE HAVE_LIBPCRE HAVE_PCRE_H) + endif() +endmacro() +configure_getdata_target(getdata) +configure_getdata_target(getdata_static) +install(FILES ${CMAKE_BINARY_DIR}/getdata.h DESTINATION include) +# Install both shared and static libraries +install(TARGETS getdata getdata_static + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib) diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt index cc4bd10e..c74f30ee 100644 --- a/cmake/test/CMakeLists.txt +++ b/cmake/test/CMakeLists.txt @@ -4,80 +4,107 @@ GD_FILES(gd test) add_definitions(-DGD_C89_API) -set(tests_ignored - ascii_complex128 ascii_complex64 ascii_float32 ascii_float64 - - bzip_add bzip_complex128 bzip_complex64 bzip_del bzip_enoent bzip_float32 - bzip_float64 bzip_get bzip_get_cont bzip_get_far bzip_get_get bzip_get_get2 - bzip_get_put bzip_int16 bzip_int32 bzip_int64 bzip_int8 bzip_move_from - bzip_move_to bzip_nframes bzip_put bzip_put_back bzip_put_endian bzip_put_get - bzip_put_offs bzip_put_pad bzip_put_sub bzip_seek bzip_seek_far bzip_sync - bzip_uint16 bzip_uint32 bzip_uint64 bzip_uint8 - - desync_path +if(BZIP2_FOUND) + add_definitions(-DTEST_BZIP -DUSE_BZIP2) +endif() +if(ZLIB_FOUND) + add_definitions(-DTEST_GZIP -DUSE_GZIP) +endif() +if(LIBLZMA_FOUND) + add_definitions(-DTEST_LZMA -DUSE_LZMA) +endif() +if(FLAC_FOUND) + add_definitions(-DTEST_FLAC -DUSE_FLAC) +endif() +if(ZZIP_FOUND) + add_definitions(-DTEST_ZZIP -DUSE_ZZIP) +endif() +set(tests_ignored + # Helper files (not standalone tests - included by encoding tests) enc_add enc_complex128 enc_complex64 enc_del enc_enoent enc_float32 enc_float64 enc_get_cont enc_int16 enc_int32 enc_int64 enc_int8 enc_move_from enc_nframes enc_put_offs enc_seek enc_uint16 enc_uint32 enc_uint64 enc_uint8 + desync_path error_verbose error_verbose_prefix - - flac_add flac_complex128 flac_complex64 flac_del flac_enoent flac_float32 - flac_float64 flac_get_big flac_get_cont flac_get_far flac_get_get - flac_get_get2 flac_get_int64 flac_get_int8 flac_get_little flac_get_long - flac_int16 flac_int32 flac_int64 flac_int8 flac_move_from flac_nframes - flac_put_big flac_put_complex128 flac_put_float64 flac_put_int32 - flac_put_little flac_put_offs flac_seek flac_seek_far flac_sync flac_uint16 - flac_uint32 flac_uint64 flac_uint8 - get_off64 - - gzip_add gzip_complex128 gzip_complex64 gzip_del gzip_enoent gzip_float32 - gzip_float64 gzip_get gzip_get_cont gzip_get_far gzip_get_get gzip_get_get2 - gzip_get_put gzip_int16 gzip_int32 gzip_int64 gzip_int8 gzip_move_from - gzip_move_to gzip_nframes gzip_put gzip_put_back gzip_put_endian gzip_put_get - gzip_put_nframes gzip_put_off gzip_put_offs gzip_put_pad gzip_put_sub - gzip_seek gzip_seek_far gzip_seek_put gzip_sync gzip_uint16 gzip_uint32 - gzip_uint64 gzip_uint8 - header_off64t - - lzma_enoent lzma_get lzma_nframes lzma_put lzma_xz_add lzma_xz_complex128 - lzma_xz_complex64 lzma_xz_del lzma_xz_float32 lzma_xz_float64 lzma_xz_get - lzma_xz_get_cont lzma_xz_get_far lzma_xz_get_get lzma_xz_get_get2 - lzma_xz_get_put lzma_xz_int16 lzma_xz_int32 lzma_xz_int64 lzma_xz_int8 - lzma_xz_move_from lzma_xz_move_to lzma_xz_nframes lzma_xz_offs_clear - lzma_xz_put lzma_xz_put_back lzma_xz_put_endian lzma_xz_put_get - lzma_xz_put_offs lzma_xz_put_pad lzma_xz_seek lzma_xz_seek_far lzma_xz_sync - lzma_xz_uint16 lzma_xz_uint32 lzma_xz_uint64 lzma_xz_uint8 - legacy_error legacy_estring legacy_format legacy_get legacy_get_put legacy_get_rofs legacy_nframes legacy_nonexistent legacy_put legacy_spf - - match_fragment match_pcre match_pcre_bad match_pcre_caseless match_pcre_ext - match_pcre_js match_pcre_utf8 match_regex match_regex_bad match_regex_ext - match_regex_icase - open_eaccess open_sym_a open_sym_al open_sym_as open_sym_at open_sym_c open_sym_cl open_sym_ct open_sym_d open_sym_l open_sym_p open_sym_pl open_sym_pt - parse_huge - put_off64 put_nofile - slim_get slim_nframes slim_seek slim_seek_far - trunc_rofs - xz_get xz_nframes - - zzip_data zzip_get zzip_get_get zzip_nframes zzip_seek zzip_seek_far - zzslim_get zzslim_nframes zzslim_seek zzslim_seek_far ) +if(NOT BZIP2_FOUND OR NOT BUNZIP2 OR NOT BZIP2) + list(APPEND tests_ignored + bzip_add bzip_complex128 bzip_complex64 bzip_del bzip_enoent bzip_float32 + bzip_float64 bzip_get bzip_get_cont bzip_get_far bzip_get_get bzip_get_get2 + bzip_get_put bzip_int16 bzip_int32 bzip_int64 bzip_int8 bzip_move_from + bzip_move_to bzip_nframes bzip_put bzip_put_back bzip_put_endian bzip_put_get + bzip_put_offs bzip_put_pad bzip_put_sub bzip_seek bzip_seek_far bzip_sync + bzip_uint16 bzip_uint32 bzip_uint64 bzip_uint8) +endif() + +if(NOT ZLIB_FOUND OR NOT GZIP OR NOT GUNZIP) + list(APPEND tests_ignored + ascii_complex128 ascii_complex64 ascii_float32 ascii_float64 + gzip_add gzip_complex128 gzip_complex64 gzip_del gzip_enoent gzip_float32 + gzip_float64 gzip_get gzip_get_cont gzip_get_far gzip_get_get gzip_get_get2 + gzip_get_put gzip_int16 gzip_int32 gzip_int64 gzip_int8 gzip_move_from + gzip_move_to gzip_nframes gzip_put gzip_put_back gzip_put_endian gzip_put_get + gzip_put_nframes gzip_put_off gzip_put_offs gzip_put_pad gzip_put_sub + gzip_seek gzip_seek_far gzip_seek_put gzip_sync gzip_uint16 gzip_uint32 + gzip_uint64 gzip_uint8) +endif() + +if(NOT FLAC_FOUND OR NOT FLAC) + list(APPEND tests_ignored + flac_add flac_complex128 flac_complex64 flac_del flac_enoent flac_float32 + flac_float64 flac_get_big flac_get_cont flac_get_far flac_get_get + flac_get_get2 flac_get_int64 flac_get_int8 flac_get_little flac_get_long + flac_int16 flac_int32 flac_int64 flac_int8 flac_move_from flac_nframes + flac_put_big flac_put_complex128 flac_put_float64 flac_put_int32 + flac_put_little flac_put_offs flac_seek flac_seek_far flac_sync flac_uint16 + flac_uint32 flac_uint64 flac_uint8) +endif() + +if(NOT LIBLZMA_FOUND OR NOT XZ) + list(APPEND tests_ignored + lzma_enoent lzma_get lzma_nframes lzma_put lzma_xz_add lzma_xz_complex128 + lzma_xz_complex64 lzma_xz_del lzma_xz_float32 lzma_xz_float64 lzma_xz_get + lzma_xz_get_cont lzma_xz_get_far lzma_xz_get_get lzma_xz_get_get2 + lzma_xz_get_put lzma_xz_int16 lzma_xz_int32 lzma_xz_int64 lzma_xz_int8 + lzma_xz_move_from lzma_xz_move_to lzma_xz_nframes lzma_xz_offs_clear + lzma_xz_put lzma_xz_put_back lzma_xz_put_endian lzma_xz_put_get + lzma_xz_put_offs lzma_xz_put_pad lzma_xz_seek lzma_xz_seek_far lzma_xz_sync + lzma_xz_uint16 lzma_xz_uint32 lzma_xz_uint64 lzma_xz_uint8) +endif() + +if(NOT ZZIP_FOUND OR NOT ZIP OR NOT UNZIP) + list(APPEND tests_ignored + zzip_data zzip_get zzip_get_get zzip_nframes zzip_seek zzip_seek_far) +endif() + +if(NOT PCRE_FOUND) + list(APPEND tests_ignored + match_fragment match_pcre match_pcre_bad match_pcre_caseless match_pcre_ext + match_pcre_js match_pcre_utf8) +endif() + +if(NOT HAVE_REGEX_H OR NOT HAVE_REGCOMP) + list(APPEND tests_ignored + match_regex match_regex_bad match_regex_ext match_regex_icase) +endif() + # Windows-specific: GD_TRUNC has a known issue with directory iteration # (modifying directory while iterating is unsafe with FindFirst/FindNext API) if(WIN32) @@ -95,5 +122,36 @@ foreach(_test ${gd_sources}) set(testname test_${testname}) add_executable(${testname} ${_test}) target_link_libraries(${testname} getdata) + if(UNIX) + target_link_libraries(${testname} m) + endif() + if(PCRE_FOUND AND PCRE_LIBRARIES) + target_include_directories(${testname} PRIVATE ${PCRE_INCLUDE_DIRS}) + target_link_directories(${testname} PRIVATE ${PCRE_LIBRARY_DIRS}) + target_link_libraries(${testname} ${PCRE_LIBRARIES}) + endif() add_test(NAME ${testname} COMMAND ${testname}) endforeach() + +# Python tests +if(BUILD_PYTHON) + set(python_tests callback.py char_enc1.py char_enc2.py char_enc3.py big_test.py) + if(WIN32) + # char_enc tests are invalid on win32 platforms (koi8-r fails to fsdecode()) + list(REMOVE_ITEM python_tests + char_enc1.py char_enc2.py char_enc3.py) + endif() + foreach(_test ${python_tests}) + get_filename_component(testname ${_test} NAME_WE) + add_test( + NAME python_${testname} + COMMAND ${Python3_EXECUTABLE} ${GD_DIR}/bindings/python/test/${_test} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bindings/python + ) + # Set PYTHONPATH to find pygetdata module + # $ is Release/Debug on multi-config (Windows), empty on single-config (Unix) + set_tests_properties(python_${testname} PROPERTIES + ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib/$" + ) + endforeach() +endif() From da9913bcfbb11c662278f779d95fbd8219b7f2eb Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Mon, 15 Dec 2025 10:10:48 -0800 Subject: [PATCH 10/29] CMake: correctly wrangle tests with exit code 77 (autotools convention for "skip me") --- cmake/test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt index c74f30ee..5009dced 100644 --- a/cmake/test/CMakeLists.txt +++ b/cmake/test/CMakeLists.txt @@ -131,6 +131,8 @@ foreach(_test ${gd_sources}) target_link_libraries(${testname} ${PCRE_LIBRARIES}) endif() add_test(NAME ${testname} COMMAND ${testname}) + # Exit code 77 means "test skipped" in autotools convention + set_tests_properties(${testname} PROPERTIES SKIP_RETURN_CODE 77) endforeach() # Python tests From a77fb0a083889cf021495b7926d5cc63370f5dfc Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Mon, 15 Dec 2025 12:26:55 -0800 Subject: [PATCH 11/29] bindings/python: move pyproject.toml to CMake backend We now have two Python packaging/backend combinations: - setup.py: setuptools, invoked explicitly by the autotools build, and - pyproject.toml: scikit-build-core, invoked by the cmake build It's slightly awkward having these two coexist side-by-side, but the two build systems already do that. --- bindings/python/pyproject.toml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 3efd272c..69e2aaad 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,16 +1,15 @@ [build-system] -requires = ["setuptools", "setuptools-scm", "wheel", "numpy>=2.0"] -build-backend = "setuptools.build_meta" +requires = ["scikit-build-core>=0.5", "numpy>=2.0"] +build-backend = "scikit_build_core.build" [project] name = "pygetdata" dependencies = ["numpy>=1.7"] dynamic = ["version"] -[tool.setuptools] -script-files = ["../../util/dirfile2ascii", "../../util/checkdirfile"] - -[tool.setuptools_scm] -version_scheme = "only-version" -local_scheme = "no-local-version" +[tool.scikit-build] +cmake.source-dir = "../../cmake" +cmake.build-type = "Release" +cmake.args = ["-DBUILD_PYTHON=ON", "-DGD_TEST=OFF", "-DGD_UTIL=OFF"] +wheel.install-dir = "." From ddbb147a98b5c40ee60d14e3801038e30baa4915 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 11:12:05 -0800 Subject: [PATCH 12/29] Github workflows: add CMake regression tests and Windows wheels --- .github/workflows/bootstrap.sh | 23 ---------------- .github/workflows/cmake-ci.yml | 49 ++++++++++++++++++++++++++++++++++ .github/workflows/package.yml | 40 ++++++++++++++------------- 3 files changed, 71 insertions(+), 41 deletions(-) delete mode 100755 .github/workflows/bootstrap.sh create mode 100644 .github/workflows/cmake-ci.yml diff --git a/.github/workflows/bootstrap.sh b/.github/workflows/bootstrap.sh deleted file mode 100755 index 399eb96c..00000000 --- a/.github/workflows/bootstrap.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -set -e - -here=$(cd `dirname $0`; pwd -P) -echo $here -cd $here/../../ - -autoreconf -i -./configure --disable-php \ - --disable-fortran \ - --disable-perl \ - --disable-matlab \ - --disable-idl \ - --disable-cplusplus \ - --disable-modules \ - --with-python=`which python3` \ - --with-pcre=$PREFIX \ - --with-ltdl=$PREFIX \ - --with-liblzma=$PREFIX \ - --with-libFLAC=$PREFIX \ - --with-libzzip=$PREFIX \ - $@ diff --git a/.github/workflows/cmake-ci.yml b/.github/workflows/cmake-ci.yml new file mode 100644 index 00000000..5f84b005 --- /dev/null +++ b/.github/workflows/cmake-ci.yml @@ -0,0 +1,49 @@ +name: CMake CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + cmake-build-test: + name: CMake on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + deps: sudo apt-get update && sudo apt-get install -y cmake bzip2 gzip xz-utils flac zip unzip libbz2-dev liblzma-dev libflac-dev libpcre3-dev libzzip-dev + - os: macos-latest + deps: brew install --quiet cmake bzip2 flac xz pcre libzzip + - os: windows-latest + deps: choco install cmake --no-progress + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Python dependencies + run: python -m pip install numpy>2 + + - name: Install system dependencies + run: ${{ matrix.deps }} + + - name: Configure CMake + working-directory: cmake + run: cmake -B build -DBUILD_PYTHON=ON -DGD_TEST=ON + + - name: Build + working-directory: cmake + run: cmake --build build --config Release + + - name: Run tests + working-directory: cmake + run: ctest --test-dir build --output-on-failure --build-config Release --no-tests=error diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 84d20c74..66309108 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -69,6 +69,11 @@ jobs: build: 'cp*-manylinux_x86_64' prefix: /usr + - os: windows-latest + python: '3.12' + build: 'cp*-win_amd64' + prefix: 'C:\Program Files' + steps: - name: Setup environment run: echo "PREFIX=${{ matrix.prefix }}" >> $GITHUB_ENV @@ -87,9 +92,7 @@ jobs: - name: Setup macOS environment if: runner.os == 'macOS' run: | - brew install automake libtool echo "MACOSX_DEPLOYMENT_TARGET=${{ matrix.target }}" >> $GITHUB_ENV - echo CPPFLAGS="`python3-config --includes`" >> $GITHUB_ENV - name: Install cibuildwheel run: python -m pip install cibuildwheel==2.21.3 @@ -100,25 +103,26 @@ jobs: CIBW_BUILD: ${{ matrix.build }} CIBW_SKIP: cp36* cp37* cp38* CIBW_BEFORE_ALL_LINUX: > - yum install -y bzip2-devel flac-devel xz-devel pcre-devel zziplib-devel && - .github/workflows/bootstrap.sh --disable-python && - make + yum install -y cmake bzip2-devel flac-devel xz-devel pcre-devel zziplib-devel CIBW_BEFORE_ALL_MACOS: > - brew install bzip2 flac xz pcre libzzip && - .github/workflows/bootstrap.sh --disable-python && - make + brew install --quiet cmake bzip2 flac xz pcre libzzip + CIBW_BEFORE_ALL_WINDOWS: > + choco install cmake --no-progress CIBW_BEFORE_BUILD: > - python -m pip install "numpy>=2.0" && - .github/workflows/bootstrap.sh && - make -C bindings/python pyconstants.c - CIBW_REPAIR_WHEEL_COMMAND_LINUX: > - LD_LIBRARY_PATH=$PWD/src/.libs auditwheel repair -w {dest_dir} {wheel} - CIBW_REPAIR_WHEEL_COMMAND_MACOS: > - DYLD_LIBRARY_PATH=$PWD/src/.libs delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} + python -m pip install "scikit-build-core>=0.5" "numpy>=2.0" CIBW_BUILD_VERBOSITY: 1 - CIBW_TEST_COMMAND: > - cd {package}/test && - PYTHONPATH=`python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])'`:$PYTHONPATH make check + CIBW_TEST_COMMAND_LINUX: > + python -c "import pygetdata; print(f'pygetdata version: {pygetdata.__version__}')" && + cd {project}/bindings/python/test && + python big_test.py + CIBW_TEST_COMMAND_MACOS: > + python -c "import pygetdata; print(f'pygetdata version: {pygetdata.__version__}')" && + cd {project}/bindings/python/test && + python big_test.py + CIBW_TEST_COMMAND_WINDOWS: > + python -c "import pygetdata; print(f'pygetdata version: {pygetdata.__version__}')" && + cd /d {project}\bindings\python\test && + python big_test.py - name: Upload artifacts uses: actions/upload-artifact@v4 From 817c385687ada1800aa9ae0ce7f711cd742dd2ec Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 11:57:24 -0800 Subject: [PATCH 13/29] test/c89*: place GD_C89_API in an #ifndef guard to squash redefinition warnings Since cmake on Windows unconditionally defines GD_C89_API, Windows otherwise gives us warnings like: \path\to\alter_crecip89.c(22,9): warning C4005: 'GD_C89_API': macro redefinition --- test/add_crecip89.c | 4 +++- test/alter_crecip89.c | 4 +++- test/alter_crecip89_null.c | 4 +++- test/flac_put_complex128.c | 4 +++- test/header_complex.c | 4 +++- test/madd_crecip89.c | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/test/add_crecip89.c b/test/add_crecip89.c index d81e6941..e7d7b3e0 100644 --- a/test/add_crecip89.c +++ b/test/add_crecip89.c @@ -18,7 +18,9 @@ * along with GetData; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define GD_C89_API +#ifndef GD_C89_API +# define GD_C89_API +#endif #include "test.h" #include diff --git a/test/alter_crecip89.c b/test/alter_crecip89.c index b2ecde71..36b11246 100644 --- a/test/alter_crecip89.c +++ b/test/alter_crecip89.c @@ -19,7 +19,9 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Test field modifying */ -#define GD_C89_API +#ifndef GD_C89_API +# define GD_C89_API +#endif #include "test.h" int main(void) diff --git a/test/alter_crecip89_null.c b/test/alter_crecip89_null.c index 19cf91f7..54b30a2a 100644 --- a/test/alter_crecip89_null.c +++ b/test/alter_crecip89_null.c @@ -18,7 +18,9 @@ * along with GetData; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define GD_C89_API +#ifndef GD_C89_API +# define GD_C89_API +#endif #include "test.h" int main(void) diff --git a/test/flac_put_complex128.c b/test/flac_put_complex128.c index 914c9f33..d5f8ab6a 100644 --- a/test/flac_put_complex128.c +++ b/test/flac_put_complex128.c @@ -18,7 +18,9 @@ * along with GetData; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define GD_C89_API +#ifndef GD_C89_API +# define GD_C89_API +#endif #include "test.h" int main(void) diff --git a/test/header_complex.c b/test/header_complex.c index a800f758..0daca309 100644 --- a/test/header_complex.c +++ b/test/header_complex.c @@ -19,7 +19,9 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Check if GD_C89_API produces a useable API */ -#define GD_C89_API +#ifndef GD_C89_API +# define GD_C89_API +#endif #include "test.h" int main(void) diff --git a/test/madd_crecip89.c b/test/madd_crecip89.c index 9d113121..6313d004 100644 --- a/test/madd_crecip89.c +++ b/test/madd_crecip89.c @@ -18,7 +18,9 @@ * along with GetData; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define GD_C89_API +#ifndef GD_C89_API +# define GD_C89_API +#endif #include "test.h" #include From 1c7ab3cf6da646472ce9e6ccffa407d5e2f86d76 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 12:06:49 -0800 Subject: [PATCH 14/29] test/version_5: fix #ifdef within macro expansion This works within GCC but not within MSVC, and the c++ preprocessor documentation (see 16.3.4 in N4594) seems to disavow this behaviour. --- test/version_5.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/version_5.c b/test/version_5.c index b618f35d..6247345c 100644 --- a/test/version_5.c +++ b/test/version_5.c @@ -33,16 +33,21 @@ int main(void) rmdirfile(); mkdir(filedir, 0700); +#ifdef WORDS_BIGENDIAN MAKEFORMATFILE(format, "/VERSION 5\n" -#ifdef WORDS_BIGENDIAN "/ENDIAN little\n" + "a.r RAW UINT8 8\n" + "ENCODING PHASE a.r 0\n" + ); #else + MAKEFORMATFILE(format, + "/VERSION 5\n" "/ENDIAN big\n" -#endif "a.r RAW UINT8 8\n" "ENCODING PHASE a.r 0\n" ); +#endif MAKEDATAFILE(data, unsigned char, i, 256); D = gd_open(filedir, GD_RDONLY | GD_VERBOSE); From 39d279c2b5554ec7eb707e20ca3b468f17e1570d Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 16 Dec 2025 15:38:39 -0800 Subject: [PATCH 15/29] Remove HAVE_CONFIG_H macro entirely Now that CMake generates gd_config.h (consistent with the automake flow), this macro was redundant and can be safely removed. --- bindings/cxx/internal.h | 2 -- bindings/cxx/test/big_test.cpp | 2 -- bindings/idl/getdata.c | 4 +--- bindings/make_parameters.c | 2 -- bindings/matlab/matlab.c | 2 -- bindings/python/setup.py.in | 1 - cmake/bindings/CMakeLists.txt | 1 - cmake/bindings/python/CMakeLists.txt | 1 - cmake/src/CMakeLists.txt | 2 -- src/internal.h | 2 -- util/checkdirfile.c | 2 -- 11 files changed, 1 insertion(+), 20 deletions(-) diff --git a/bindings/cxx/internal.h b/bindings/cxx/internal.h index 877de2e7..6e979631 100644 --- a/bindings/cxx/internal.h +++ b/bindings/cxx/internal.h @@ -18,9 +18,7 @@ // along with GetData; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // -#ifdef HAVE_CONFIG_H #include "gd_config.h" -#endif /* To avoid including stuff out of tree, we include everything here, * even though getdata/dirfile.h will try to include it again. diff --git a/bindings/cxx/test/big_test.cpp b/bindings/cxx/test/big_test.cpp index 2a6c54c7..d90c7a91 100644 --- a/bindings/cxx/test/big_test.cpp +++ b/bindings/cxx/test/big_test.cpp @@ -18,9 +18,7 @@ // along with GetData; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // -#ifdef HAVE_CONFIG_H #include "gd_config.h" -#endif #undef GETDATA_LEGACY_API #include "getdata/dirfile.h" diff --git a/bindings/idl/getdata.c b/bindings/idl/getdata.c index 5cdfea93..6dfb4cf9 100644 --- a/bindings/idl/getdata.c +++ b/bindings/idl/getdata.c @@ -28,9 +28,7 @@ #undef _POSIX_C_SOURCE #undef _SVID_SOURCE -#ifdef HAVE_CONFIG_H -# include "gd_config.h" -#endif +#include "gd_config.h" #ifdef GD_EXTERNAL # include diff --git a/bindings/make_parameters.c b/bindings/make_parameters.c index a5926d4a..af20eeeb 100644 --- a/bindings/make_parameters.c +++ b/bindings/make_parameters.c @@ -18,9 +18,7 @@ * along with GetData; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef HAVE_CONFIG_H #include "gd_config.h" -#endif #include #include diff --git a/bindings/matlab/matlab.c b/bindings/matlab/matlab.c index d0a415a3..0b8cf2e8 100644 --- a/bindings/matlab/matlab.c +++ b/bindings/matlab/matlab.c @@ -19,9 +19,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef HAVE_CONFIG_H #include "gd_config.h" -#endif #ifdef GD_EXTERNAL # define GD_C89_API diff --git a/bindings/python/setup.py.in b/bindings/python/setup.py.in index 1e5bebb7..688a9ed8 100644 --- a/bindings/python/setup.py.in +++ b/bindings/python/setup.py.in @@ -95,7 +95,6 @@ setup( include_dirs = includes, library_dirs = [ join(libbuild_dir, '.libs') ], libraries = [ 'getdata' ], - define_macros = [ ('HAVE_CONFIG_H','1') ] ) ] ) diff --git a/cmake/bindings/CMakeLists.txt b/cmake/bindings/CMakeLists.txt index 11c7bb50..13e2e446 100644 --- a/cmake/bindings/CMakeLists.txt +++ b/cmake/bindings/CMakeLists.txt @@ -6,7 +6,6 @@ if(BUILD_PYTHON) add_executable(make_parameters ${GD_DIR}/bindings/make_parameters.c) target_include_directories(make_parameters PRIVATE ${GD_DIR}/src ${CMAKE_BINARY_DIR}) target_link_libraries(make_parameters PRIVATE getdata) - target_compile_definitions(make_parameters PRIVATE HAVE_CONFIG_H) add_subdirectory(python) endif() diff --git a/cmake/bindings/python/CMakeLists.txt b/cmake/bindings/python/CMakeLists.txt index 963c4f65..14b10b94 100644 --- a/cmake/bindings/python/CMakeLists.txt +++ b/cmake/bindings/python/CMakeLists.txt @@ -26,7 +26,6 @@ target_include_directories(pygetdata PRIVATE # Link against static library for self-contained wheels target_link_libraries(pygetdata PRIVATE getdata_static) -target_compile_definitions(pygetdata PRIVATE HAVE_CONFIG_H) # Remove 'lib' prefix on Unix-like systems set_target_properties(pygetdata PROPERTIES PREFIX "") diff --git a/cmake/src/CMakeLists.txt b/cmake/src/CMakeLists.txt index ace471b0..b5f3f2d8 100644 --- a/cmake/src/CMakeLists.txt +++ b/cmake/src/CMakeLists.txt @@ -53,7 +53,6 @@ set_target_properties(getdata PROPERTIES VERSION 11.0.0 SOVERSION 11 ) -target_compile_definitions(getdata PRIVATE HAVE_CONFIG_H) # Build static library (parallel to autotools .a) add_library(getdata_static STATIC ${gd_sources} ${gd_headers} ${CMAKE_BINARY_DIR}/getdata.h) @@ -61,7 +60,6 @@ set_target_properties(getdata_static PROPERTIES OUTPUT_NAME getdata POSITION_INDEPENDENT_CODE ON ) -target_compile_definitions(getdata_static PRIVATE HAVE_CONFIG_H) # Macro to configure both shared and static libraries with the same dependencies macro(configure_getdata_target target) diff --git a/src/internal.h b/src/internal.h index 2b1c95db..d4bf9c67 100644 --- a/src/internal.h +++ b/src/internal.h @@ -26,9 +26,7 @@ #define _LARGEFILE64_SOURCE #endif -#ifdef HAVE_CONFIG_H #include "gd_config.h" -#endif #define GD_64BIT_API #include "getdata.h" diff --git a/util/checkdirfile.c b/util/checkdirfile.c index 1b4b77a9..0495e619 100644 --- a/util/checkdirfile.c +++ b/util/checkdirfile.c @@ -16,9 +16,7 @@ * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef HAVE_CONFIG_H #include "gd_config.h" -#endif #ifndef HAVE_SNPRINTF #ifdef HAVE__SNPRINTF From 049f87b57eff1a5532b4d01cd6a3cb440553ef4c Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Wed, 17 Dec 2025 11:49:07 -0800 Subject: [PATCH 16/29] .github/workflows/package.yml: upgrade cibuildwheel; add Python 3.13/3.14 --- .github/workflows/package.yml | 44 ++++------------------------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 66309108..bdb6bc7e 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -16,51 +16,15 @@ jobs: matrix: include: # macos-15-intel for x86_64 (min macOS 15.0), macos-14 for ARM (min macOS 14.0) - - os: macos-15-intel - python: '3.9' - build: 'cp39-macosx_x86_64' - target: '15.0' - prefix: /usr/local - - - os: macos-15-intel - python: '3.10' - build: 'cp310-macosx_x86_64' - target: '15.0' - prefix: /usr/local - - - os: macos-15-intel - python: '3.11' - build: 'cp311-macosx_x86_64' - target: '15.0' - prefix: /usr/local - - os: macos-15-intel python: '3.12' - build: 'cp312-macosx_x86_64' + build: 'cp*-macosx_x86_64' target: '15.0' prefix: /usr/local - - os: macos-14 - python: '3.9' - build: 'cp39-macosx_arm64' - target: '14.0' - prefix: /opt/homebrew - - - os: macos-14 - python: '3.10' - build: 'cp310-macosx_arm64' - target: '14.0' - prefix: /opt/homebrew - - - os: macos-14 - python: '3.11' - build: 'cp311-macosx_arm64' - target: '14.0' - prefix: /opt/homebrew - - os: macos-14 python: '3.12' - build: 'cp312-macosx_arm64' + build: 'cp*-macosx_arm64' target: '14.0' prefix: /opt/homebrew @@ -95,7 +59,7 @@ jobs: echo "MACOSX_DEPLOYMENT_TARGET=${{ matrix.target }}" >> $GITHUB_ENV - name: Install cibuildwheel - run: python -m pip install cibuildwheel==2.21.3 + run: python -m pip install cibuildwheel==3.3.0 - name: Build wheels run: python -m cibuildwheel --output-dir wheelhouse bindings/python @@ -127,7 +91,7 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: cibw-wheel-${{ matrix.os }}-${{ matrix.python }} + name: cibw-wheel-${{ matrix.os }} path: ./wheelhouse/pygetdata*.whl upload_pypi: From 030e0d1eccfa33692189b63e0df4c957c7edfa14 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Wed, 17 Dec 2025 12:11:40 -0800 Subject: [PATCH 17/29] bindings/python/pyproject.toml: Teach scikit-build to extract the version number --- bindings/python/pyproject.toml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 69e2aaad..321e87a0 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["scikit-build-core>=0.5", "numpy>=2.0"] +requires = ["scikit-build-core>=0.5", "numpy>=2.0", "setuptools-scm"] build-backend = "scikit_build_core.build" [project] @@ -13,3 +13,11 @@ cmake.build-type = "Release" cmake.args = ["-DBUILD_PYTHON=ON", "-DGD_TEST=OFF", "-DGD_UTIL=OFF"] wheel.install-dir = "." +[tool.scikit-build.metadata.version] +provider = "scikit_build_core.metadata.setuptools_scm" + +[tool.setuptools_scm] +root = "../.." +version_scheme = "no-guess-dev" +local_scheme = "no-local-version" + From ca9b776804539480465e3fe62c0ae70a81933c11 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Wed, 17 Dec 2025 12:15:28 -0800 Subject: [PATCH 18/29] package.yml: wheel builder: no need to SKIP Python 3.6/3.7 any more Squashes the warning: Warning: cibuildwheel: Invalid skip selector: 'cp36*'. cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update `skip`. This selector will have no effect. Warning: cibuildwheel: Invalid skip selector: 'cp37*'. cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update `skip`. This selector will have no effect. --- .github/workflows/package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index bdb6bc7e..8df329fe 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -65,7 +65,7 @@ jobs: run: python -m cibuildwheel --output-dir wheelhouse bindings/python env: CIBW_BUILD: ${{ matrix.build }} - CIBW_SKIP: cp36* cp37* cp38* + CIBW_SKIP: cp38* CIBW_BEFORE_ALL_LINUX: > yum install -y cmake bzip2-devel flac-devel xz-devel pcre-devel zziplib-devel CIBW_BEFORE_ALL_MACOS: > From d8852ed608df636254986c59ca10d2528311fea0 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Thu, 18 Dec 2025 09:03:03 -0800 Subject: [PATCH 19/29] CMake/wheels: properly configure and install utils (checkdirfile, dirfile2ascii) --- bindings/python/pyproject.toml | 2 +- cmake/CMakeLists.txt | 1 + cmake/util/CMakeLists.txt | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 321e87a0..710bc30c 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -10,7 +10,7 @@ dynamic = ["version"] [tool.scikit-build] cmake.source-dir = "../../cmake" cmake.build-type = "Release" -cmake.args = ["-DBUILD_PYTHON=ON", "-DGD_TEST=OFF", "-DGD_UTIL=OFF"] +cmake.args = ["-DBUILD_PYTHON=ON", "-DGD_TEST=OFF", "-DGD_UTIL=ON"] wheel.install-dir = "." [tool.scikit-build.metadata.version] diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f0f778b7..01f64b5d 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -165,6 +165,7 @@ check_function_exists(ftello HAVE_FTELLO) check_function_exists(ftello64 HAVE_FTELLO64) check_function_exists(ftruncate HAVE_FTRUNCATE) check_function_exists(getcwd HAVE_GETCWD) +check_function_exists(getopt_long HAVE_GETOPT_LONG) check_function_exists(gmtime HAVE_GMTIME) check_function_exists(gmtime_r HAVE_GMTIME_R) check_function_exists(lseek64 HAVE_LSEEK64) diff --git a/cmake/util/CMakeLists.txt b/cmake/util/CMakeLists.txt index a6c9af3f..db346eb7 100644 --- a/cmake/util/CMakeLists.txt +++ b/cmake/util/CMakeLists.txt @@ -4,8 +4,8 @@ add_executable(checkdirfile ${GD_DIR}/util/checkdirfile.c) target_link_libraries(checkdirfile getdata) install(TARGETS checkdirfile DESTINATION bin) -## dirfile2ascii uses getopt_long.... -# -#add_executable(dirfile2ascii ${GD_DIR}/util/dirfile2ascii.c) -#target_link_libraries(dirfile2ascii getdata) -#install(TARGETS dirfile2ascii DESTINATION bin) +if(HAVE_GETOPT_LONG) + add_executable(dirfile2ascii ${GD_DIR}/util/dirfile2ascii.c) + target_link_libraries(dirfile2ascii getdata) + install(TARGETS dirfile2ascii DESTINATION bin) +endif() From 6ead6494811985d895412a78e46f6cbccaaa9a1f Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Thu, 18 Dec 2025 11:27:18 -0800 Subject: [PATCH 20/29] MSVC: work around #define snprintf _snprintf in stdio.h --- cmake/CMakeLists.txt | 5 ++--- util/checkdirfile.c | 12 ++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 01f64b5d..3582cc6d 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -175,7 +175,8 @@ check_function_exists(readdir_r HAVE_READDIR_R) check_function_exists(readlink HAVE_READLINK) check_function_exists(regcomp HAVE_REGCOMP) check_function_exists(renameat HAVE_RENAMEAT) -check_function_exists(snprintf HAVE_SNPRINTF) +check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) +check_function_exists(_snprintf HAVE__SNPRINTF) check_function_exists(strtoll HAVE_STRTOLL) check_function_exists(strtoull HAVE_STRTOULL) check_function_exists(symlink HAVE_SYMLINK) @@ -271,7 +272,6 @@ if(MSVC) -DHAVE__ISNAN -DHAVE__MKDIR -DHAVE__RMDIR - -DHAVE__SNPRINTF -DHAVE__STAT64 -DHAVE__STRTOI64 -DHAVE__STRTOUI64 @@ -328,7 +328,6 @@ elseif(MINGW) -DHAVE__OPEN -DHAVE__READ -DHAVE__RMDIR - -DHAVE__SNPRINTF -DHAVE__STAT64 -DHAVE__STRTOI64 -DHAVE__STRTOUI64 diff --git a/util/checkdirfile.c b/util/checkdirfile.c index 0495e619..f6124cee 100644 --- a/util/checkdirfile.c +++ b/util/checkdirfile.c @@ -18,12 +18,6 @@ */ #include "gd_config.h" -#ifndef HAVE_SNPRINTF -#ifdef HAVE__SNPRINTF -#define snprintf _snprintf -#endif -#endif - #ifdef HAVE_INTTYPES_H #include #endif @@ -33,6 +27,12 @@ #include #include "getdata.h" +#ifndef HAVE_SNPRINTF +#ifdef HAVE__SNPRINTF +#define snprintf _snprintf +#endif +#endif + #ifndef PACKAGE_STRING #define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION #endif From 187676fc397f75605abfb88cc2583b12611f8c0a Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Thu, 18 Dec 2025 11:28:06 -0800 Subject: [PATCH 21/29] wheel build: use shared libraries; teach wheel repair steps how to find them --- .github/workflows/package.yml | 4 ++++ cmake/bindings/python/CMakeLists.txt | 18 +++++++++++++++--- cmake/src/CMakeLists.txt | 1 + cmake/test/CMakeLists.txt | 13 ++++++++++--- cmake/util/CMakeLists.txt | 23 +++++++++++++++++++++++ 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 8df329fe..fab29b76 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -74,6 +74,10 @@ jobs: choco install cmake --no-progress CIBW_BEFORE_BUILD: > python -m pip install "scikit-build-core>=0.5" "numpy>=2.0" + CIBW_BEFORE_BUILD_WINDOWS: > + pip install delvewheel "scikit-build-core>=0.5" "numpy>=2.0" + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: > + delvewheel repair --extract-dir {dest_dir}\..\extract --add-path {dest_dir}\..\extract\bin -vv -w {dest_dir} {wheel} CIBW_BUILD_VERBOSITY: 1 CIBW_TEST_COMMAND_LINUX: > python -c "import pygetdata; print(f'pygetdata version: {pygetdata.__version__}')" && diff --git a/cmake/bindings/python/CMakeLists.txt b/cmake/bindings/python/CMakeLists.txt index 14b10b94..f7af35a2 100644 --- a/cmake/bindings/python/CMakeLists.txt +++ b/cmake/bindings/python/CMakeLists.txt @@ -23,11 +23,23 @@ target_include_directories(pygetdata PRIVATE ${Python3_NumPy_INCLUDE_DIRS} ) -# Link against static library for self-contained wheels -target_link_libraries(pygetdata PRIVATE getdata_static) - +# Link against shared library - wheel repair tools will bundle it +target_link_libraries(pygetdata PRIVATE getdata) # Remove 'lib' prefix on Unix-like systems set_target_properties(pygetdata PROPERTIES PREFIX "") +# For wheel builds, set RPATH so repair tools can find the library +if(SKBUILD) + if(APPLE) + set_target_properties(pygetdata PROPERTIES + INSTALL_RPATH "@loader_path/lib" + BUILD_WITH_INSTALL_RPATH FALSE) + else() + set_target_properties(pygetdata PROPERTIES + INSTALL_RPATH "$ORIGIN/lib" + BUILD_WITH_INSTALL_RPATH FALSE) + endif() +endif() + install(TARGETS pygetdata LIBRARY DESTINATION .) diff --git a/cmake/src/CMakeLists.txt b/cmake/src/CMakeLists.txt index b5f3f2d8..d05fcdba 100644 --- a/cmake/src/CMakeLists.txt +++ b/cmake/src/CMakeLists.txt @@ -52,6 +52,7 @@ add_library(getdata SHARED ${gd_sources} ${gd_headers} ${CMAKE_BINARY_DIR}/getda set_target_properties(getdata PROPERTIES VERSION 11.0.0 SOVERSION 11 + WINDOWS_EXPORT_ALL_SYMBOLS ON ) # Build static library (parallel to autotools .a) diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt index 5009dced..27a9c9d5 100644 --- a/cmake/test/CMakeLists.txt +++ b/cmake/test/CMakeLists.txt @@ -152,8 +152,15 @@ if(BUILD_PYTHON) ) # Set PYTHONPATH to find pygetdata module # $ is Release/Debug on multi-config (Windows), empty on single-config (Unix) - set_tests_properties(python_${testname} PROPERTIES - ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib/$" - ) + # On Windows, also add DLL directory to PATH so getdata.dll can be found + if(WIN32) + set_tests_properties(python_${testname} PROPERTIES + ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib/$;PATH=${CMAKE_BINARY_DIR}/bin/$;$ENV{PATH}" + ) + else() + set_tests_properties(python_${testname} PROPERTIES + ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib/$" + ) + endif() endforeach() endif() diff --git a/cmake/util/CMakeLists.txt b/cmake/util/CMakeLists.txt index db346eb7..ca7fbb80 100644 --- a/cmake/util/CMakeLists.txt +++ b/cmake/util/CMakeLists.txt @@ -2,10 +2,33 @@ include_directories(${GD_DIR}/util) add_executable(checkdirfile ${GD_DIR}/util/checkdirfile.c) target_link_libraries(checkdirfile getdata) +# For wheel builds, set RPATH so repair tools can find the library +if(SKBUILD) + if(APPLE) + set_target_properties(checkdirfile PROPERTIES + INSTALL_RPATH "@loader_path/../lib" + BUILD_WITH_INSTALL_RPATH FALSE) + else() + set_target_properties(checkdirfile PROPERTIES + INSTALL_RPATH "$ORIGIN/../lib" + BUILD_WITH_INSTALL_RPATH FALSE) + endif() +endif() install(TARGETS checkdirfile DESTINATION bin) if(HAVE_GETOPT_LONG) add_executable(dirfile2ascii ${GD_DIR}/util/dirfile2ascii.c) target_link_libraries(dirfile2ascii getdata) + if(SKBUILD) + if(APPLE) + set_target_properties(dirfile2ascii PROPERTIES + INSTALL_RPATH "@loader_path/../lib" + BUILD_WITH_INSTALL_RPATH FALSE) + else() + set_target_properties(dirfile2ascii PROPERTIES + INSTALL_RPATH "$ORIGIN/../lib" + BUILD_WITH_INSTALL_RPATH FALSE) + endif() + endif() install(TARGETS dirfile2ascii DESTINATION bin) endif() From 9b6e3cc05849f8b7f180535665cc7f2577898d7d Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Thu, 18 Dec 2025 14:37:05 -0800 Subject: [PATCH 22/29] CMake: Add BUILD_CXX compile option; disable it for pyproject.toml entry point --- bindings/python/pyproject.toml | 2 +- cmake/CMakeLists.txt | 1 + cmake/bindings/CMakeLists.txt | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 710bc30c..33f7707a 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -10,7 +10,7 @@ dynamic = ["version"] [tool.scikit-build] cmake.source-dir = "../../cmake" cmake.build-type = "Release" -cmake.args = ["-DBUILD_PYTHON=ON", "-DGD_TEST=OFF", "-DGD_UTIL=ON"] +cmake.args = ["-DBUILD_PYTHON=ON", "-DGD_TEST=OFF", "-DGD_UTIL=ON", "-DBUILD_CXX=OFF"] wheel.install-dir = "." [tool.scikit-build.metadata.version] diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3582cc6d..d6c90bb2 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.15) project(getdata) option(BUILD_PYTHON "Build Python bindings" ON) +option(BUILD_CXX "Build C++ bindings" ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) diff --git a/cmake/bindings/CMakeLists.txt b/cmake/bindings/CMakeLists.txt index 13e2e446..07a8f5af 100644 --- a/cmake/bindings/CMakeLists.txt +++ b/cmake/bindings/CMakeLists.txt @@ -1,5 +1,7 @@ -add_subdirectory(cxx) +if(BUILD_CXX) + add_subdirectory(cxx) +endif() if(BUILD_PYTHON) # Build make_parameters utility for generating pyconstants.c From fbdfa26e18d18e7841bc70d23c78eac663e793e7 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Thu, 18 Dec 2025 16:08:53 -0800 Subject: [PATCH 23/29] CMake: Correct .dll placement for Windows --- cmake/CMakeLists.txt | 6 +++++- cmake/test/CMakeLists.txt | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index d6c90bb2..2ae82533 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -6,8 +6,12 @@ option(BUILD_PYTHON "Build Python bindings" ON) option(BUILD_CXX "Build C++ bindings" ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +if(WIN32) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +else() + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +endif() if(BUILD_PYTHON) set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries" FORCE) diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt index 27a9c9d5..989fc3cc 100644 --- a/cmake/test/CMakeLists.txt +++ b/cmake/test/CMakeLists.txt @@ -151,11 +151,11 @@ if(BUILD_PYTHON) WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bindings/python ) # Set PYTHONPATH to find pygetdata module + # Windows: in bin/ (with DLLs), Unix: in lib/ (with shared libraries) # $ is Release/Debug on multi-config (Windows), empty on single-config (Unix) - # On Windows, also add DLL directory to PATH so getdata.dll can be found if(WIN32) set_tests_properties(python_${testname} PROPERTIES - ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/lib/$;PATH=${CMAKE_BINARY_DIR}/bin/$;$ENV{PATH}" + ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/bin/$" ) else() set_tests_properties(python_${testname} PROPERTIES From 4dbcfe8fb7fcd54910c195bb2424d80cd59d0489 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Thu, 18 Dec 2025 17:00:46 -0800 Subject: [PATCH 24/29] CMake: extract GETDATA_VERSION macros from m4/version.m4 This is a little clunky but reduces the number of redundant places where the version numbering must be updated. --- cmake/CMakeLists.txt | 48 +++++++++++++++++++++++++++++++++----------- cmake/gd_config.h.in | 12 +++++------ 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 2ae82533..207f44db 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,6 +1,27 @@ cmake_minimum_required(VERSION 3.15) -project(getdata) +if(NOT GD_DIR) + set(GD_DIR ${CMAKE_SOURCE_DIR}/..) +endif() + +# Parse version from m4/version.m4 +file(STRINGS "${GD_DIR}/m4/version.m4" VERSION_M4) +foreach(line ${VERSION_M4}) + if(line MATCHES "^m4_define\\(getdata_major,[ ]*([0-9]+)\\)") + set(GETDATA_MAJOR ${CMAKE_MATCH_1}) + elseif(line MATCHES "^m4_define\\(getdata_minor,[ ]*([0-9]+)\\)") + set(GETDATA_MINOR ${CMAKE_MATCH_1}) + elseif(line MATCHES "^m4_define\\(getdata_revision,[ ]*([0-9]+)\\)") + set(GETDATA_REVISION ${CMAKE_MATCH_1}) + elseif(line MATCHES "^m4_define\\(getdata_extra,[ ]*\\[([^]]*)\\]\\)") + set(GETDATA_VERSION_SUFFIX "${CMAKE_MATCH_1}") + endif() +endforeach() +if(NOT DEFINED GETDATA_MAJOR OR NOT DEFINED GETDATA_MINOR OR NOT DEFINED GETDATA_REVISION) + message(FATAL_ERROR "Failed to parse version from ${GD_DIR}/m4/version.m4") +endif() + +project(getdata VERSION ${GETDATA_MAJOR}.${GETDATA_MINOR}.${GETDATA_REVISION}) option(BUILD_PYTHON "Build Python bindings" ON) option(BUILD_CXX "Build C++ bindings" ON) @@ -91,11 +112,6 @@ if(PCRE_FOUND) endif() endif() -if(NOT GD_DIR) - set(GD_DIR ${CMAKE_SOURCE_DIR}/..) -endif() - - macro(GD_FILES name folder) file(GLOB ${name}_folder_sources ${GD_DIR}/${folder}/*.c) file(GLOB ${name}_folder_sources_cpp ${GD_DIR}/${folder}/*.cpp) @@ -112,9 +128,17 @@ add_definitions( # kst2 doesn't need the legacy API set(DEFINE_GD_LEGACY_API "/* #undef GD_LEGACY_API */") -# Version macros -set(DEFINE_GD_GETDATA_VERSION "#define GD_GETDATA_VERSION \"0.11.0\"") -set(DEFINE_GD_GETDATA_INT_VERSION "#define GD_GETDATA_INT_VERSION 1100") +# Build version string +set(GETDATA_VERSION_STRING "${PROJECT_VERSION}${GETDATA_VERSION_SUFFIX}") +set(DEFINE_GD_GETDATA_VERSION "#define GD_GETDATA_VERSION \"${GETDATA_VERSION_STRING}\"") + +# Compute integer version (matches configure.ac:383) +if(PROJECT_VERSION_MAJOR EQUAL 0) + math(EXPR GETDATA_INT_VERSION "${PROJECT_VERSION_MINOR} * 100 + ${PROJECT_VERSION_PATCH}") +else() + math(EXPR GETDATA_INT_VERSION "${PROJECT_VERSION_MAJOR} * 10000 + ${PROJECT_VERSION_MINOR} * 100 + ${PROJECT_VERSION_PATCH}") +endif() +set(DEFINE_GD_GETDATA_INT_VERSION "#define GD_GETDATA_INT_VERSION ${GETDATA_INT_VERSION}") # Platform-independent configuration checks include(CheckIncludeFile) @@ -377,9 +401,9 @@ add_definitions( -DSIZEOF_UNSIGNED_INT=${SIZEOF_UNSIGNED_INT} -DSIZEOF_SIZE_T=${SIZEOF_SIZE_T} -DSIZEOF_VOID_P=${SIZEOF_VOID_P} - -DGETDATA_MAJOR=0 - -DGETDATA_MINOR=11 - -DGETDATA_REVISION=0 + -DGETDATA_MAJOR=${PROJECT_VERSION_MAJOR} + -DGETDATA_MINOR=${PROJECT_VERSION_MINOR} + -DGETDATA_REVISION=${PROJECT_VERSION_PATCH} -DSTDC_HEADERS -DGD_RESTRICT_ARRAY_OK=1 ) diff --git a/cmake/gd_config.h.in b/cmake/gd_config.h.in index 3deb5892..f4f16ec5 100644 --- a/cmake/gd_config.h.in +++ b/cmake/gd_config.h.in @@ -5,8 +5,8 @@ /* Package information */ #define PACKAGE_NAME "GetData" -#define PACKAGE_VERSION "0.11.0" -#define PACKAGE_STRING "GetData 0.11.0" +#define PACKAGE_VERSION "@GETDATA_VERSION_STRING@" +#define PACKAGE_STRING "GetData @GETDATA_VERSION_STRING@" #define PACKAGE_BUGREPORT "https://github.com/ketiltrout/getdata/issues" /* Headers */ @@ -118,10 +118,10 @@ #cmakedefine HAVE_LSEEK64 1 /* Version macros */ -#define GETDATA_MAJOR 0 -#define GETDATA_MINOR 11 -#define GETDATA_REVISION 0 -#define GETDATA_VERSION_SUFFIX "" +#define GETDATA_MAJOR @PROJECT_VERSION_MAJOR@ +#define GETDATA_MINOR @PROJECT_VERSION_MINOR@ +#define GETDATA_REVISION @PROJECT_VERSION_PATCH@ +#define GETDATA_VERSION_SUFFIX "@GETDATA_VERSION_SUFFIX@" /* Feature flags */ #define STDC_HEADERS 1 From a5eef4996be4bfa603f9c5d121abc78dc38d8d2f Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Mon, 26 Jan 2026 14:40:54 -0800 Subject: [PATCH 25/29] bindings/python: fix encoding_support return codes The DocStrings for the Python bindings report: encoding_support(encoding) The 'encoding' parameter should be one of the pygetdata.*_ENCODED symbols. This method will return pygetdata.RDWR if the library can read and write the encoding, pygetdata.RDONLY if the library can only read the encoding, or None otherwise. See gd_encoding_support(3). However, the code returned None on GD_RDONLY==0 and the integer value of the gd_encoding_support return code otherwise (typically GD_RDWR, GD_E_UNKNOWN_ENCODING, or GD_E_UNSUPPORTED). --- bindings/python/pygetdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/pygetdata.c b/bindings/python/pygetdata.c index 0e3bf3c4..5944e5cb 100644 --- a/bindings/python/pygetdata.c +++ b/bindings/python/pygetdata.c @@ -922,7 +922,7 @@ static PyObject *gdpy_encoding_support(struct gdpy_fragment_t *self, n = gd_encoding_support(enc); - if (n == 0) { + if (n < 0) { Py_INCREF(Py_None); dreturn("%p", Py_None); return Py_None; From f85bb2a15ed6bc682f6c4db3bbdf12bb7597122e Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Thu, 5 Feb 2026 14:00:38 -0800 Subject: [PATCH 26/29] wheel build: teach arm64 macos to find, build, and install plugins --- .github/workflows/package.yml | 3 +++ cmake/CMakeLists.txt | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index fab29b76..c76a5415 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -72,6 +72,9 @@ jobs: brew install --quiet cmake bzip2 flac xz pcre libzzip CIBW_BEFORE_ALL_WINDOWS: > choco install cmake --no-progress + CIBW_ENVIRONMENT_MACOS: > + PKG_CONFIG_PATH=${{ matrix.prefix }}/lib/pkgconfig + PREFIX=${{ matrix.prefix }} CIBW_BEFORE_BUILD: > python -m pip install "scikit-build-core>=0.5" "numpy>=2.0" CIBW_BEFORE_BUILD_WINDOWS: > diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 207f44db..ee687a51 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -41,6 +41,11 @@ if(BUILD_PYTHON) endif() # Optional encoding libraries +# On macOS, help CMake find Homebrew libraries +if(APPLE AND DEFINED ENV{PREFIX}) + list(APPEND CMAKE_PREFIX_PATH "$ENV{PREFIX}") +endif() + find_package(BZip2) find_package(ZLIB) find_package(LibLZMA) From 7e6234479891323b1bc899c1183efeb8ad9b8db7 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Fri, 6 Feb 2026 08:15:11 -0800 Subject: [PATCH 27/29] wheel build: restructure .whl files; statically link The static link, in particular, is intended to sidestep upstream issues that still seem unsettled: https://github.com/pypa/auditwheel/issues/340 https://github.com/aestream/aestream/issues/112 --- bindings/python/pyproject.toml | 1 + cmake/CMakeLists.txt | 1 + cmake/bindings/python/CMakeLists.txt | 24 +++++++------------ cmake/src/CMakeLists.txt | 32 +++++++++++++++---------- cmake/util/CMakeLists.txt | 35 ++++++++++------------------ 5 files changed, 42 insertions(+), 51 deletions(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 33f7707a..e77b6fc9 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -11,6 +11,7 @@ dynamic = ["version"] cmake.source-dir = "../../cmake" cmake.build-type = "Release" cmake.args = ["-DBUILD_PYTHON=ON", "-DGD_TEST=OFF", "-DGD_UTIL=ON", "-DBUILD_CXX=OFF"] +install.components = ["Runtime"] wheel.install-dir = "." [tool.scikit-build.metadata.version] diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ee687a51..df164414 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -419,6 +419,7 @@ endif() configure_file(${GD_DIR}/src/getdata.h.in ${CMAKE_BINARY_DIR}/getdata.h @ONLY) +include(GNUInstallDirs) include_directories(${GD_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}) if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) diff --git a/cmake/bindings/python/CMakeLists.txt b/cmake/bindings/python/CMakeLists.txt index f7af35a2..9a525786 100644 --- a/cmake/bindings/python/CMakeLists.txt +++ b/cmake/bindings/python/CMakeLists.txt @@ -23,23 +23,15 @@ target_include_directories(pygetdata PRIVATE ${Python3_NumPy_INCLUDE_DIRS} ) -# Link against shared library - wheel repair tools will bundle it -target_link_libraries(pygetdata PRIVATE getdata) +# For wheel builds, statically link to eliminate libgetdata.so from the wheel +# Plugin libraries will still be dynamically linked and bundled by auditwheel/delocate +if(SKBUILD) + target_link_libraries(pygetdata PRIVATE getdata_static) +else() + target_link_libraries(pygetdata PRIVATE getdata) +endif() # Remove 'lib' prefix on Unix-like systems set_target_properties(pygetdata PROPERTIES PREFIX "") -# For wheel builds, set RPATH so repair tools can find the library -if(SKBUILD) - if(APPLE) - set_target_properties(pygetdata PROPERTIES - INSTALL_RPATH "@loader_path/lib" - BUILD_WITH_INSTALL_RPATH FALSE) - else() - set_target_properties(pygetdata PROPERTIES - INSTALL_RPATH "$ORIGIN/lib" - BUILD_WITH_INSTALL_RPATH FALSE) - endif() -endif() - -install(TARGETS pygetdata LIBRARY DESTINATION .) +install(TARGETS pygetdata LIBRARY DESTINATION . COMPONENT Runtime) diff --git a/cmake/src/CMakeLists.txt b/cmake/src/CMakeLists.txt index d05fcdba..68791f5a 100644 --- a/cmake/src/CMakeLists.txt +++ b/cmake/src/CMakeLists.txt @@ -81,20 +81,17 @@ macro(configure_getdata_target target) endif() if(FLAC_FOUND) target_include_directories(${target} PRIVATE ${FLAC_INCLUDE_DIRS}) - target_link_directories(${target} PRIVATE ${FLAC_LIBRARY_DIRS}) - target_link_libraries(${target} PRIVATE ${FLAC_LIBRARIES}) + target_link_libraries(${target} PRIVATE ${FLAC_LINK_LIBRARIES}) target_compile_definitions(${target} PRIVATE HAVE_LIBFLAC HAVE_FLAC_ALL_H USE_FLAC) endif() if(ZZIP_FOUND) target_include_directories(${target} PRIVATE ${ZZIP_INCLUDE_DIRS}) - target_link_directories(${target} PRIVATE ${ZZIP_LIBRARY_DIRS}) - target_link_libraries(${target} PRIVATE ${ZZIP_LIBRARIES}) + target_link_libraries(${target} PRIVATE ${ZZIP_LINK_LIBRARIES}) target_compile_definitions(${target} PRIVATE HAVE_LIBZZIP HAVE_ZZIP_LIB_H USE_ZZIP) endif() if(PCRE_FOUND) target_include_directories(${target} PRIVATE ${PCRE_INCLUDE_DIRS}) - target_link_directories(${target} PRIVATE ${PCRE_LIBRARY_DIRS}) - target_link_libraries(${target} PRIVATE ${PCRE_LIBRARIES}) + target_link_libraries(${target} PRIVATE ${PCRE_LINK_LIBRARIES}) target_compile_definitions(${target} PRIVATE HAVE_LIBPCRE HAVE_PCRE_H) endif() endmacro() @@ -102,10 +99,21 @@ endmacro() configure_getdata_target(getdata) configure_getdata_target(getdata_static) -install(FILES ${CMAKE_BINARY_DIR}/getdata.h DESTINATION include) +# Link math library on Unix +if(UNIX) + target_link_libraries(getdata PRIVATE m) + target_link_libraries(getdata_static PRIVATE m) +endif() + +install(FILES ${CMAKE_BINARY_DIR}/getdata.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT Development) -# Install both shared and static libraries -install(TARGETS getdata getdata_static - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin - ARCHIVE DESTINATION lib) +# Install static library (Development component, filtered out by wheel builds via pyproject.toml) +install(TARGETS getdata_static + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development) + +# Install shared library (skip for wheel builds where everything is statically linked) +if(NOT SKBUILD) + install(TARGETS getdata + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) +endif() diff --git a/cmake/util/CMakeLists.txt b/cmake/util/CMakeLists.txt index ca7fbb80..f4c5be37 100644 --- a/cmake/util/CMakeLists.txt +++ b/cmake/util/CMakeLists.txt @@ -1,34 +1,23 @@ include_directories(${GD_DIR}/util) add_executable(checkdirfile ${GD_DIR}/util/checkdirfile.c) -target_link_libraries(checkdirfile getdata) -# For wheel builds, set RPATH so repair tools can find the library if(SKBUILD) - if(APPLE) - set_target_properties(checkdirfile PROPERTIES - INSTALL_RPATH "@loader_path/../lib" - BUILD_WITH_INSTALL_RPATH FALSE) - else() - set_target_properties(checkdirfile PROPERTIES - INSTALL_RPATH "$ORIGIN/../lib" - BUILD_WITH_INSTALL_RPATH FALSE) - endif() + # For wheel builds, statically link to avoid auditwheel complications with scripts + target_link_libraries(checkdirfile getdata_static) + install(TARGETS checkdirfile DESTINATION ${SKBUILD_SCRIPTS_DIR} COMPONENT Runtime) +else() + target_link_libraries(checkdirfile getdata) + install(TARGETS checkdirfile DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) endif() -install(TARGETS checkdirfile DESTINATION bin) if(HAVE_GETOPT_LONG) add_executable(dirfile2ascii ${GD_DIR}/util/dirfile2ascii.c) - target_link_libraries(dirfile2ascii getdata) if(SKBUILD) - if(APPLE) - set_target_properties(dirfile2ascii PROPERTIES - INSTALL_RPATH "@loader_path/../lib" - BUILD_WITH_INSTALL_RPATH FALSE) - else() - set_target_properties(dirfile2ascii PROPERTIES - INSTALL_RPATH "$ORIGIN/../lib" - BUILD_WITH_INSTALL_RPATH FALSE) - endif() + # For wheel builds, statically link to avoid auditwheel complications with scripts + target_link_libraries(dirfile2ascii getdata_static) + install(TARGETS dirfile2ascii DESTINATION ${SKBUILD_SCRIPTS_DIR} COMPONENT Runtime) + else() + target_link_libraries(dirfile2ascii getdata) + install(TARGETS dirfile2ascii DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) endif() - install(TARGETS dirfile2ascii DESTINATION bin) endif() From a1a001e392f5311f3868d3df215d0e786b09185a Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Fri, 6 Feb 2026 10:50:28 -0800 Subject: [PATCH 28/29] pyproject.toml: parse version from m4/version.m4 --- bindings/python/pyproject.toml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index e77b6fc9..66195f49 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["scikit-build-core>=0.5", "numpy>=2.0", "setuptools-scm"] +requires = ["scikit-build-core>=0.5", "numpy>=2.0"] build-backend = "scikit_build_core.build" [project] @@ -15,10 +15,12 @@ install.components = ["Runtime"] wheel.install-dir = "." [tool.scikit-build.metadata.version] -provider = "scikit_build_core.metadata.setuptools_scm" - -[tool.setuptools_scm] -root = "../.." -version_scheme = "no-guess-dev" -local_scheme = "no-local-version" +provider = "scikit_build_core.metadata.regex" +input = "../../m4/version.m4" +regex = ''' +m4_define\(getdata_major,\s*(?P\d+)\)[\s\S]* +m4_define\(getdata_minor,\s*(?P\d+)\)[\s\S]* +m4_define\(getdata_revision,\s*(?P\d+)\) +''' +result = "{major}.{minor}.{micro}" From ee05e9ce2ddbf3db5f9cb8a79108bf4acf814ea5 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Fri, 6 Feb 2026 13:43:46 -0800 Subject: [PATCH 29/29] CMake: correctly parse .so versioning information from m4/version.m4 --- cmake/CMakeLists.txt | 20 ++++++++++++++++++++ cmake/src/CMakeLists.txt | 5 +++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index df164414..e1d157e1 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -15,14 +15,34 @@ foreach(line ${VERSION_M4}) set(GETDATA_REVISION ${CMAKE_MATCH_1}) elseif(line MATCHES "^m4_define\\(getdata_extra,[ ]*\\[([^]]*)\\]\\)") set(GETDATA_VERSION_SUFFIX "${CMAKE_MATCH_1}") + elseif(line MATCHES "^m4_define\\(getdata_iface_version,[ ]*([0-9]+)\\)") + set(GETDATA_IFACE_VERSION ${CMAKE_MATCH_1}) + elseif(line MATCHES "^m4_define\\(getdata_impl_revision,[ ]*([0-9]+)\\)") + set(GETDATA_IMPL_REVISION ${CMAKE_MATCH_1}) + elseif(line MATCHES "^m4_define\\(getdata_iface_age,[ ]*([0-9]+)\\)") + set(GETDATA_IFACE_AGE ${CMAKE_MATCH_1}) endif() endforeach() if(NOT DEFINED GETDATA_MAJOR OR NOT DEFINED GETDATA_MINOR OR NOT DEFINED GETDATA_REVISION) message(FATAL_ERROR "Failed to parse version from ${GD_DIR}/m4/version.m4") endif() +if(NOT DEFINED GETDATA_IFACE_VERSION OR NOT DEFINED GETDATA_IMPL_REVISION OR NOT DEFINED GETDATA_IFACE_AGE) + message(FATAL_ERROR "Failed to parse library interface version from ${GD_DIR}/m4/version.m4") +endif() + +# Convert libtool versioning (CURRENT:REVISION:AGE) to CMake VERSION/SOVERSION +# Libtool: -version-info CURRENT:REVISION:AGE +# CMake SOVERSION = CURRENT - AGE +# CMake VERSION = (CURRENT-AGE).AGE.REVISION +math(EXPR GETDATA_SO_VERSION "${GETDATA_IFACE_VERSION} - ${GETDATA_IFACE_AGE}") +set(GETDATA_LIB_VERSION "${GETDATA_SO_VERSION}.${GETDATA_IFACE_AGE}.${GETDATA_IMPL_REVISION}") project(getdata VERSION ${GETDATA_MAJOR}.${GETDATA_MINOR}.${GETDATA_REVISION}) +message(STATUS "GetData project version: ${PROJECT_VERSION}") +message(STATUS "GetData library versioning: CURRENT=${GETDATA_IFACE_VERSION} REVISION=${GETDATA_IMPL_REVISION} AGE=${GETDATA_IFACE_AGE}") +message(STATUS "GetData shared library: VERSION=${GETDATA_LIB_VERSION} SOVERSION=${GETDATA_SO_VERSION}") + option(BUILD_PYTHON "Build Python bindings" ON) option(BUILD_CXX "Build C++ bindings" ON) diff --git a/cmake/src/CMakeLists.txt b/cmake/src/CMakeLists.txt index 68791f5a..ef333b7f 100644 --- a/cmake/src/CMakeLists.txt +++ b/cmake/src/CMakeLists.txt @@ -48,10 +48,11 @@ endif() list(REMOVE_ITEM gd_sources ${files_ignored}) # Build shared library (parallel to autotools .so) +# VERSION and SOVERSION are computed from libtool versioning in m4/version.m4 add_library(getdata SHARED ${gd_sources} ${gd_headers} ${CMAKE_BINARY_DIR}/getdata.h) set_target_properties(getdata PROPERTIES - VERSION 11.0.0 - SOVERSION 11 + VERSION ${GETDATA_LIB_VERSION} + SOVERSION ${GETDATA_SO_VERSION} WINDOWS_EXPORT_ALL_SYMBOLS ON )