From b3f583f96587256f85fd966b11cb76b5e093c593 Mon Sep 17 00:00:00 2001 From: valord577 Date: Fri, 10 Jul 2026 17:11:46 +0800 Subject: [PATCH 1/3] add libsqlite3 --- .github/workflows/sqlite3.yml | 30 ++++++++ build_v2.py | 41 +++++++++++ modules/sqlite3.py | 132 ++++++++++++++++++++++++++++++++++ x_utils.py | 6 +- 4 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/sqlite3.yml create mode 100755 modules/sqlite3.py diff --git a/.github/workflows/sqlite3.yml b/.github/workflows/sqlite3.yml new file mode 100644 index 0000000..52a8e68 --- /dev/null +++ b/.github/workflows/sqlite3.yml @@ -0,0 +1,30 @@ +name: sqlite3 +on: + workflow_dispatch: + push: + branches: + - main + paths: + - '.github/matrix*.json' + - '.github/workflows/_matrix.yml' + - '.github/workflows/sqlite3.yml' + - 'patches/sqlite3/**' + - 'modules/sqlite3.py' + pull_request: + branches: + - main + paths: + - '.github/matrix*.json' + - '.github/workflows/_matrix.yml' + - '.github/workflows/sqlite3.yml' + - 'patches/sqlite3/**' + - 'modules/sqlite3.py' + +jobs: + build: + # if: ${{ false }} + secrets: inherit + uses: ./.github/workflows/_matrix.yml + with: + disable_static: true + select_platforms: "macosx, linux, android" diff --git a/build_v2.py b/build_v2.py index 9fe4dea..351d04a 100755 --- a/build_v2.py +++ b/build_v2.py @@ -16,10 +16,12 @@ x.loge('Required Python Interpreter ≥ 3.8') # pyright: ignore[reportUnreachable] # ---------------------------- +import http.client import os import runpy import shutil import time +import urllib.request from dataclasses import dataclass from typing import Callable, Literal, TypedDict, cast @@ -134,6 +136,45 @@ def fetch_source_from_git(self, 'PKG_ZIPNAME': f'{self.args.module}_{self.args.target_plat}_{self.args.target_archinfo}_{ver}_{x.feature("PKG_TYPE")}', }) + def fetch_source_from_http(self, + version: "str", url: "str", *, + archive_format: "Literal['zip']", + archive_prefix: "str | None" = None, + extracted_file: "list[str] | None" = None, + ): + self._subproj_src.mkdir(parents=True, exist_ok=True) + if not any(self._subproj_src.iterdir()): + archive = (self._subproj_src.parent / f'{self._subproj_src.name}.{archive_format}') + x.logv(f'fetch source from "{url}" > "{archive.as_posix()}"') + if not archive.exists(): + with cast(http.client.HTTPResponse, + urllib.request.urlopen( + urllib.request.Request(url) + ) + ) as resp: + if resp.status != 200: + x.loge(f"respcode: {resp.status}, respbody: ->\n{resp.read().decode(errors='ignore')}") + with archive.open('wb') as dst: + shutil.copyfileobj(resp, dst) + + if False: + pass # pyright: ignore[reportUnreachable] + elif archive_format == 'zip': + archive_prefix = (archive_prefix or '') + + files: list[str] = [] + for src in (extracted_file or []): + files.append(f'{archive_prefix}{src}') + x.unzip_with_softlink(archive, extract_dir=self._subproj_src.as_posix(), files=files) + + + _ = self._subproj_ver.write_text(version) + + x.gha_append_env({ + 'PKG_VERSION': version, + 'PKG_ZIPNAME': f'{self.args.module}_{self.args.target_plat}_{self.args.target_archinfo}_{version}_{x.feature("PKG_TYPE")}', + }) + def subproj_src_dir(self, *subdir: "str | Path") -> Path: if not subdir: return self._subproj_src diff --git a/modules/sqlite3.py b/modules/sqlite3.py new file mode 100755 index 0000000..3ad69de --- /dev/null +++ b/modules/sqlite3.py @@ -0,0 +1,132 @@ +# fmt: off + +import sys +from pathlib import Path + +sys.dont_write_bytecode = True + +_this_file = (Path(__file__).absolute().resolve()) +sys.path.append( + (_this_file.parents[1]).as_posix() +); import x_utils as x + +if __name__ == "__main__": x.loge_usage() +# ---------------------------- +from typing import Callable, cast +from build_v2 import BuildCtx +ctx = cast(BuildCtx, globals()["ctx"]) +# ---------------------------- +def build_steps() -> "list[Callable[[], None]]": + return [ + _fetch_source, + _build_step_0, + ] +# ---------------------------- +def get_build_env() -> "dict[str, str]": + env = x.ENVIRON + if ctx.args.target_plat == 'win-msvc': + env.update(ctx.args.win32_msvc_env_target) + env['CFLAGS'] = '/utf-8' + env['CXXFLAGS'] = env['CFLAGS'] + return env +# ---------------------------- +archive_prefix = 'sqlite-amalgamation-3530300' +# ---------------------------- +def _fetch_source(): + ctx.fetch_source_from_http(version='v3.53.3', + url='https://sqlite.org/2026/{archive_prefix}.zip', + archive_format='zip', + archive_prefix=f'{archive_prefix}/', + extracted_file=['sqlite3.c', 'sqlite3.h'], + ) +def _build_step_0(): + import shutil + + args = ctx.args.cc + ctx.args.ldflags + [ + '-DHAVE_FDATASYNC=1', + '-DSQLITE_DQS=0', + '-DSQLITE_THREADSAFE=1', + '-DSQLITE_DEFAULT_AUTOMATIC_INDEX=1', + '-DSQLITE_DEFAULT_AUTOVACUUM=0', + '-DSQLITE_DEFAULT_FOREIGN_KEYS=0', + '-DSQLITE_DEFAULT_MMAP_SIZE=0', + '-DSQLITE_DEFAULT_MEMSTATUS=0', + '-DSQLITE_DEFAULT_SYNCHRONOUS=3', + '-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=3', + '-DSQLITE_JSON_MAX_DEPTH=64', + '-DSQLITE_LIKE_DOESNT_MATCH_BLOBS', + '-DSQLITE_TEMP_STORE=3', + '-DSQLITE_MAX_EXPR_DEPTH=0', + '-DSQLITE_OMIT_AUTORESET', + '-DSQLITE_OMIT_AUTOINIT', + '-DSQLITE_OMIT_DECLTYPE', + '-DSQLITE_OMIT_DEPRECATED', + '-DSQLITE_OMIT_LOAD_EXTENSION', + '-DSQLITE_OMIT_PROGRESS_CALLBACK', + '-DSQLITE_OMIT_SHARED_CACHE', + '-DSQLITE_OMIT_UTF16', + '-DSQLITE_STRICT_SUBTYPE=1', + ] + [ + '-std=c11', '-fPIC', '-Wall', '-Wextra', + '-shared', '-v', '-O3', '-DNDEBUG', + '-ffunction-sections', '-fdata-sections', + '-Wl,--icf=safe', '-pthread', + ] + + output = (Path(ctx.args.pkg_inst_dir)) + if ctx.args.target_plat in {'linux', 'android'}: + output = (output / 'lib' / 'libsqlite3.so'); \ + output.parent.mkdir(parents=True, exist_ok=True) + args.extend([ + '-Wl,--gc-sections', '-Wl,-rpath,$ORIGIN', '-Wl,--build-id', + '-o', output.as_posix(), f'-Wl,--soname={output.name}', '-lm', + ]) + elif ctx.args.target_plat == 'win-mingw': + pass + else: # apple platform + output = (output / 'lib' / 'libsqlite3.dylib'); \ + output.parent.mkdir(parents=True, exist_ok=True) + args.extend([ + '-Wl,--gc-sections', '-Wl,--build-id', + '-o', output.as_posix(), '-install_name', output.name, + ]) + args.extend([ + f'-I{ctx.subproj_src_dir(archive_prefix).as_posix()}', + ctx.subproj_src_dir(archive_prefix, 'sqlite3.c').as_posix(), + ]) + x.run_as_subprocess(env=get_build_env(), args=args) + + + src_dst_mapping: list[dict[Path, Path]] = [ + { + (ctx.subproj_src_dir(archive_prefix, 'sqlite3.h')): + (Path(ctx.args.pkg_inst_dir) / 'include' / 'sqlite3.h'), + }, + ] + for map in src_dst_mapping: + for src, dst in map.items(): + if src.is_file(): + dst.unlink(missing_ok=True) + dst.parent.mkdir(parents=True, exist_ok=True) + _ = shutil.copy2(src, dst) + if src.is_dir(): + shutil.rmtree(dst, ignore_errors=True) + _ = src.rename(dst) + + _pkgconf_content = '''\ +prefix=${pcfiledir}/../.. +includedir=${prefix}/include +libdir=${prefix}/lib + +Name: SQLite +Description: SQL database engine +Version: @PKGCONFIG_VERSION@ +Requires: +Cflags: -I${includedir} +Libs: -L${libdir} -lsqlite3 +''' + _pkgconf_content = _pkgconf_content.replace('@PKGCONFIG_VERSION@', ctx.subproj_src_ver()) + + _pkgconf = (Path(ctx.args.pkg_inst_dir) / 'lib' / 'pkgconfig' / 'sqlite3.pc'); \ + _pkgconf.parent.mkdir(parents=True, exist_ok=True) + _ = _pkgconf.write_text(_pkgconf_content) diff --git a/x_utils.py b/x_utils.py index 0c7d7f1..ed2d93f 100644 --- a/x_utils.py +++ b/x_utils.py @@ -175,10 +175,12 @@ def runpy_pip(pkgs: "list[str]"): args.extend(['pip', *pkgs]) runpy(args=args) # ---------------------------- -def unzip_with_softlink(zipfile: Path, extract_dir: "str | None" = None, is_msys64: bool = False): +def unzip_with_softlink(zipfile: Path, *, + extract_dir: "str | None" = None, files: "list[str] | None" = None, is_msys64: bool = False +): if not extract_dir: extract_dir = zipfile.parent.as_posix() - cmd = ['unzip', '-o', zipfile.as_posix(), '-d', extract_dir] + cmd = ['unzip', '-o', zipfile.as_posix(), '-d', extract_dir] + (files or []) if (NATIVE_PLAT == 'windows') and (is_msys64): cmd = ['C:/msys64/usr/bin/bash.exe', '-c', ' '.join(cmd)] run_as_subprocess(args=cmd) From 93fa72bec400f30c943e1a6fe772a6de9b396ac7 Mon Sep 17 00:00:00 2001 From: valord577 Date: Fri, 10 Jul 2026 17:13:29 +0800 Subject: [PATCH 2/3] add libsqlite3 --- modules/sqlite3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sqlite3.py b/modules/sqlite3.py index 3ad69de..2840227 100755 --- a/modules/sqlite3.py +++ b/modules/sqlite3.py @@ -34,7 +34,7 @@ def get_build_env() -> "dict[str, str]": # ---------------------------- def _fetch_source(): ctx.fetch_source_from_http(version='v3.53.3', - url='https://sqlite.org/2026/{archive_prefix}.zip', + url=f'https://sqlite.org/2026/{archive_prefix}.zip', archive_format='zip', archive_prefix=f'{archive_prefix}/', extracted_file=['sqlite3.c', 'sqlite3.h'], From 39961914958a0c29b9b4db790691387f778818a2 Mon Sep 17 00:00:00 2001 From: valord577 Date: Fri, 10 Jul 2026 17:16:35 +0800 Subject: [PATCH 3/3] add libsqlite3 --- modules/sqlite3.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/sqlite3.py b/modules/sqlite3.py index 2840227..4a24589 100755 --- a/modules/sqlite3.py +++ b/modules/sqlite3.py @@ -70,7 +70,7 @@ def _build_step_0(): '-std=c11', '-fPIC', '-Wall', '-Wextra', '-shared', '-v', '-O3', '-DNDEBUG', '-ffunction-sections', '-fdata-sections', - '-Wl,--icf=safe', '-pthread', + '-pthread', ] output = (Path(ctx.args.pkg_inst_dir)) @@ -78,7 +78,8 @@ def _build_step_0(): output = (output / 'lib' / 'libsqlite3.so'); \ output.parent.mkdir(parents=True, exist_ok=True) args.extend([ - '-Wl,--gc-sections', '-Wl,-rpath,$ORIGIN', '-Wl,--build-id', + '-Wl,--gc-sections', '-Wl,--build-id', + '-Wl,--icf=safe', '-Wl,-rpath,$ORIGIN', '-o', output.as_posix(), f'-Wl,--soname={output.name}', '-lm', ]) elif ctx.args.target_plat == 'win-mingw': @@ -87,7 +88,7 @@ def _build_step_0(): output = (output / 'lib' / 'libsqlite3.dylib'); \ output.parent.mkdir(parents=True, exist_ok=True) args.extend([ - '-Wl,--gc-sections', '-Wl,--build-id', + '-Wl,-dead_strip', '-o', output.as_posix(), '-install_name', output.name, ]) args.extend([