diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..02c2e52 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,197 @@ +name: ci / nimble +permissions: + contents: read + pull-requests: read + checks: write +on: + pull_request: + branches: [master] + push: + branches: [master] + workflow_dispatch: + +jobs: + test: + name: 'test / ${{ matrix.os }}' + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: jiro4989/setup-nim-action@v2 + with: + nim-version: '2.2.4' + + - name: Install dependencies + run: nimble setup -l + + - name: Run test suite + run: nimble test + + build-linux: + name: 'linux / ${{ matrix.task }}' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + task: + - libsdsDynamicLinux + - libsdsStaticLinux + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: jiro4989/setup-nim-action@v2 + with: + nim-version: '2.2.4' + + - name: Install dependencies + run: nimble setup -l + + - name: Build ${{ matrix.task }} + run: nimble ${{ matrix.task }} + + - uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.task }} + path: build/ + + build-mac: + name: 'macos / ${{ matrix.task }}' + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + task: + - libsdsDynamicMac + - libsdsStaticMac + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: jiro4989/setup-nim-action@v2 + with: + nim-version: '2.2.4' + + - name: Install dependencies + run: nimble setup -l + + - name: Build ${{ matrix.task }} + run: nimble ${{ matrix.task }} + + - uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.task }} + path: build/ + + build-windows: + name: 'windows / ${{ matrix.task }}' + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + task: + - libsdsDynamicWindows + - libsdsStaticWindows + steps: + - name: Enable Git long paths + run: git config --global core.longpaths true + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: jiro4989/setup-nim-action@v2 + with: + nim-version: '2.2.4' + + # nim-lsquic (transitive dep via libp2p) contains boringssl submodule with + # deeply-nested test paths. Nimble's temp dir path + those file names exceed + # 260 chars even with core.longpaths=true because Nim's runtime doesn't use + # the \\?\ extended-path prefix. Redirect TEMP/TMP to a short root dir so + # nimble's working directory stays well under the limit. + - name: Shorten TEMP path for nimble + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path C:\T | Out-Null + "TEMP=C:\T" >> $env:GITHUB_ENV + "TMP=C:\T" >> $env:GITHUB_ENV + + - name: Install dependencies + run: nimble setup -l + + - name: Build ${{ matrix.task }} + run: nimble ${{ matrix.task }} + + - uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.task }} + path: build/ + + build-ios: + name: 'macos / libsdsIOS' + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '16.2' + + - uses: jiro4989/setup-nim-action@v2 + with: + nim-version: '2.2.4' + + - name: Install dependencies + run: nimble setup -l + + - name: Build libsdsIOS + run: nimble libsdsIOS + + - uses: actions/upload-artifact@v4 + with: + name: libsdsIOS + path: build/ + + build-android: + name: 'linux / ${{ matrix.task }}' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + task: [libsdsAndroidArm64, libsdsAndroidAmd64, libsdsAndroidX86] + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: jiro4989/setup-nim-action@v2 + with: + nim-version: '2.2.4' + + - uses: nttld/setup-ndk@v1 + id: setup-ndk + with: + ndk-version: r27c + + - name: Install dependencies + run: nimble setup -l + + - name: Build ${{ matrix.task }} + env: + ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} + run: nimble ${{ matrix.task }} + + - uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.task }} + path: build/ diff --git a/Makefile b/Makefile deleted file mode 100644 index ecff78e..0000000 --- a/Makefile +++ /dev/null @@ -1,141 +0,0 @@ -.PHONY: libsds deps - -LINK_PCRE := 0 - -# default target, because it's the first one that doesn't start with '.' -all: | libsds - -clean: - rm -rf build - -## Git version -GIT_VERSION ?= $(shell git describe --abbrev=6 --always --tags) -## Compilation parameters. If defined in the CLI the assignments won't be executed -NIM_PARAMS := $(NIM_PARAMS) -d:git_version=\"$(GIT_VERSION)\" - -ifeq ($(DEBUG), 0) -NIM_PARAMS := $(NIM_PARAMS) -d:release -else -NIM_PARAMS := $(NIM_PARAMS) -d:debug -endif - -STATIC ?= 0 - -detected_OS ?= Linux -ifeq ($(OS),Windows_NT) -detected_OS := Windows -else -detected_OS := $(shell uname -s) -endif - -BUILD_COMMAND ?= libsdsDynamic -ifeq ($(STATIC), 1) - BUILD_COMMAND = libsdsStatic -endif - -ifeq ($(detected_OS),Windows) - BUILD_COMMAND := $(BUILD_COMMAND)Windows -else ifeq ($(detected_OS),Darwin) - BUILD_COMMAND := $(BUILD_COMMAND)Mac - export IOS_SDK_PATH := $(shell xcrun --sdk iphoneos --show-sdk-path) -else ifeq ($(detected_OS),Linux) - BUILD_COMMAND := $(BUILD_COMMAND)Linux -endif - -libsds: - nimble --verbose $(BUILD_COMMAND) $(NIM_PARAMS) sds.nimble - -##################### -## Mobile Bindings ## -##################### -.PHONY: libsds-android \ - libsds-android-precheck \ - libsds-android-arm64 \ - libsds-android-amd64 \ - libsds-android-x86 \ - libsds-android-arm \ - build-libsds-for-android-arch - -ANDROID_TARGET ?= 30 -ifeq ($(detected_OS),Darwin) - ANDROID_TOOLCHAIN_DIR := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/darwin-x86_64 -else - ANDROID_TOOLCHAIN_DIR := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64 -endif -# Fixes "clang: not found" errors -PATH := $(ANDROID_TOOLCHAIN_DIR)/bin:$(PATH) - -libsds-android-precheck: -ifndef ANDROID_NDK_ROOT - $(error ANDROID_NDK_ROOT is not set) -endif - -build-libsds-for-android-arch: NIM_PARAMS := $(NIM_PARAMS) --passC="--sysroot=$(ANDROID_TOOLCHAIN_DIR)/sysroot" -build-libsds-for-android-arch: NIM_PARAMS := $(NIM_PARAMS) --passL="--sysroot=$(ANDROID_TOOLCHAIN_DIR)/sysroot" -build-libsds-for-android-arch: NIM_PARAMS := $(NIM_PARAMS) --passC="--target=$(ANDROID_ARCH)$(ANDROID_TARGET)" -build-libsds-for-android-arch: NIM_PARAMS := $(NIM_PARAMS) --passL="--target=$(ANDROID_ARCH)$(ANDROID_TARGET)" -build-libsds-for-android-arch: NIM_PARAMS := $(NIM_PARAMS) --passC="-I$(ANDROID_TOOLCHAIN_DIR)/sysroot/usr/include" -build-libsds-for-android-arch: NIM_PARAMS := $(NIM_PARAMS) --passC="-I$(ANDROID_TOOLCHAIN_DIR)/sysroot/usr/include/$(ARCH_DIRNAME)" -build-libsds-for-android-arch: NIM_PARAMS := $(NIM_PARAMS) --passL="-L$(ANDROID_TOOLCHAIN_DIR)/sysroot/usr/lib/$(ARCH_DIRNAME)/$(ANDROID_TARGET)" -build-libsds-for-android-arch: - CC=$(ANDROID_TOOLCHAIN_DIR)/bin/$(ANDROID_ARCH)$(ANDROID_TARGET)-clang \ - ARCH=$(ARCH) ABIDIR=$(ABIDIR) \ - ARCH_DIRNAME=$(ARCH_DIRNAME) \ - ANDROID_ARCH=$(ANDROID_ARCH) \ - ANDROID_TOOLCHAIN_DIR=$(ANDROID_TOOLCHAIN_DIR) \ - nimble libsdsAndroid $(NIM_PARAMS) sds.nimble - -libsds-android-arm64: ANDROID_ARCH=aarch64-linux-android -libsds-android-arm64: ARCH=arm64 -libsds-android-arm64: ABIDIR=arm64-v8a -libsds-android-arm64: ARCH_DIRNAME=aarch64-linux-android -libsds-android-arm64: | libsds-android-precheck - $(MAKE) build-libsds-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) \ - ARCH=$(ARCH) ABIDIR=$(ABIDIR) ARCH_DIRNAME=$(ARCH_DIRNAME) - -libsds-android-amd64: ANDROID_ARCH=x86_64-linux-android -libsds-android-amd64: ARCH=amd64 -libsds-android-amd64: ABIDIR=x86_64 -libsds-android-amd64: ARCH_DIRNAME=x86_64-linux-android -libsds-android-amd64: | libsds-android-precheck - $(MAKE) build-libsds-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) \ - ARCH=$(ARCH) ABIDIR=$(ABIDIR) ARCH_DIRNAME=$(ARCH_DIRNAME) - -libsds-android-x86: ANDROID_ARCH=i686-linux-android -libsds-android-x86: ARCH=i386 -libsds-android-x86: ABIDIR=x86 -libsds-android-x86: ARCH_DIRNAME=i686-linux-android -libsds-android-x86: | libsds-android-precheck - $(MAKE) build-libsds-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) \ - ARCH=$(ARCH) ABIDIR=$(ABIDIR) ARCH_DIRNAME=$(ARCH_DIRNAME) - -libsds-android-arm: ANDROID_ARCH=armv7a-linux-androideabi -libsds-android-arm: ARCH=arm -libsds-android-arm: ABIDIR=armeabi-v7a -libsds-android-arm: ARCH_DIRNAME=arm-linux-androideabi -libsds-android-arm: | libsds-android-precheck -# cross-rs target architecture name does not match the one used in android - $(MAKE) build-libsds-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) \ - ARCH=$(ARCH) ABIDIR=$(ABIDIR) ARCH_DIRNAME=$(ARCH_DIRNAME) \ - -libsds-android: -ifeq ($(ARCH),arm64) - $(MAKE) libsds-android-arm64 -else ifeq ($(ARCH),amd64) - $(MAKE) libsds-android-amd64 -else ifeq ($(ARCH),x86) - $(MAKE) libsds-android-x86 -# else ifeq ($(ARCH),arm) -# $(MAKE) libsds-android-arm -# This target is disabled because on recent versions of cross-rs complain with the following error -# relocation R_ARM_THM_ALU_PREL_11_0 cannot be used against symbol 'stack_init_trampoline_return'; recompile with -fPIC -# It's likely this architecture is not used so we might just not support it. -else - $(error Unsupported ARCH '$(ARCH)'. Please set ARCH to one of: arm64, arm, amd64, x86) -endif - -# Target iOS - -libsds-ios: | - nimble libsdsIOS $(NIM_PARAMS) sds.nimble - diff --git a/flake.nix b/flake.nix index 6eaffdd..a1f4b49 100644 --- a/flake.nix +++ b/flake.nix @@ -47,14 +47,14 @@ src = self; }; - # All potential targets + # All potential targets — must match nimble task names in sds.nimble. allTargets = [ "libsds" - "libsds-android-arm64" - "libsds-android-amd64" - "libsds-android-x86" - "libsds-android-arm" - "libsds-ios" + "libsdsAndroidArm64" + "libsdsAndroidAmd64" + "libsdsAndroidX86" + "libsdsAndroidArm" + "libsdsIOS" ]; # Create a package for each target @@ -65,13 +65,25 @@ in allPackages // { default = allPackages.libsds; + # Convenience aliases matching old hyphenated names. + libsds-android-arm64 = allPackages.libsdsAndroidArm64; + libsds-android-amd64 = allPackages.libsdsAndroidAmd64; + libsds-android-x86 = allPackages.libsdsAndroidX86; + libsds-android-arm = allPackages.libsdsAndroidArm; + libsds-ios = allPackages.libsdsIOS; } ); - devShells = forAllSystems (system: { - default = pkgsFor.${system}.callPackage ./nix/shell.nix { - }; - }); + devShells = forAllSystems (system: + let pkgs = pkgsFor.${system}; in { + default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + nim-2_2 + nimble + ]; + }; + } + ); }; } diff --git a/nix/default.nix b/nix/default.nix index 3710861..1ac95f1 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -1,10 +1,8 @@ { pkgs, src ? ../., - # Options: 0,1,2 - verbosity ? 2, - # Make targets - targets ? ["libsds-android-arm64"], + # Nimble targets to build (task names from sds.nimble). + targets ? ["libsdsAndroidArm64"], # These are the only platforms tested in CI and considered stable. stableSystems ? ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" "x86_64-windows"], }: @@ -14,7 +12,7 @@ let inherit (lib) any match substring optionals optionalString; # Check if build is for android platform. - containsAndroid = s: (match ".*android.*" s) != null; + containsAndroid = s: (match ".*[Aa]ndroid.*" s) != null; isAndroidBuild = any containsAndroid targets; tools = callPackage ./tools.nix {}; @@ -22,9 +20,60 @@ let revision = substring 0 8 (src.rev or src.dirtyRev or "00000000"); version = tools.findKeyValue "^version = \"([a-f0-9.-]+)\"$" ../sds.nimble; - nimbleDeps = callPackage ./deps.nix { - inherit src version revision; - }; + # Fetched dep sources, keyed by package name. + deps = import ./deps.nix { inherit pkgs; }; + + # nimble.lock metadata (version + checksums) for pkgs2 directory naming. + lockFile = builtins.fromJSON (builtins.readFile ../nimble.lock); + lockPkgs = lockFile.packages; + + # nimble.paths for the Nim compiler (read by config.nims). + # Paths must be double-quoted so that NimScript can parse the include correctly. + nimblePaths = pkgs.writeText "nimble.paths" ( + builtins.concatStringsSep "\n" ( + [ "--noNimblePath" ] ++ + builtins.concatMap (p: [ "--path:\"${p}\"" "--path:\"${p}/src\"" ]) + (builtins.attrValues deps) + ) + ); + + # Shell commands to populate pkgs2 with writable copies of only the Nim + # source files nimble needs for dependency resolution. Full source for + # compilation is provided via nimble.paths pointing to the Nix store. + # Using rsync (same file filter as the old fixed-output deps derivation). + # Each dir also gets a nimblemeta.json so nimble recognises it as installed + # and does not attempt to re-download the package. + pkgs2SetupCmds = lib.concatStringsSep "\n" ( + lib.mapAttrsToList (name: dep: + let + meta = lockPkgs.${name}; + dirName = "${name}-${meta.version}-${meta.checksums.sha1}"; + nimbleMeta = pkgs.writeText "${name}-nimblemeta.json" (builtins.toJSON { + version = 1; + metaData = { + url = meta.url; + downloadMethod = "git"; + vcsRevision = meta.vcsRevision; + files = []; + binaries = []; + specialVersions = [ meta.version ]; + }; + }); + in '' + mkdir -p "$NIMBLE_DIR/pkgs2/${dirName}" + rsync -a \ + --include='*/' \ + --include='*.nim' \ + --include='*.nims' \ + --include='*.nimble' \ + --include='*.json' \ + --exclude='*' \ + ${dep}/ "$NIMBLE_DIR/pkgs2/${dirName}/" + chmod -R u+w "$NIMBLE_DIR/pkgs2/${dirName}" + cp ${nimbleMeta} "$NIMBLE_DIR/pkgs2/${dirName}/nimblemeta.json" + '' + ) deps + ); in stdenv.mkDerivation { pname = "nim-sds"; @@ -38,30 +87,32 @@ in stdenv.mkDerivation { }; buildInputs = with pkgs; [ - openssl gmp zip nim git nimble + openssl gmp zip nim-2_2 git nimble ]; # Dependencies that should only exist in the build environment. nativeBuildInputs = with pkgs; [ - nim cmake which patchelf nimbleDeps + nim-2_2 nimble rsync cmake which patchelf ] ++ optionals stdenv.isLinux [ pkgs.lsb-release ]; - makeFlags = targets ++ [ - "V=${toString verbosity}" - ]; - - # Provide dependencies via Nimble deps derivation. configurePhase = '' export NIMBLE_DIR=$NIX_BUILD_TOP/nimbledeps - cp -r ${nimbleDeps}/nimbledeps $NIMBLE_DIR - cp ${nimbleDeps}/nimble.paths ./ - chmod 775 -R $NIMBLE_DIR - # Fix relative paths to absolute paths - sed -i "s|./nimbledeps|$NIMBLE_DIR|g" nimble.paths + mkdir -p $NIMBLE_DIR/pkgs2 + + # Populate pkgs2 with writable copies so nimble considers deps installed + # and does not attempt to download them (which fails in the Nix sandbox). + ${pkgs2SetupCmds} + + # Write nimble.paths so config.nims passes --path: flags to the Nim compiler. + cp ${nimblePaths} ./nimble.paths ''; + buildPhase = lib.concatMapStringsSep "\n" (target: '' + nimble --verbose ${target} + '') targets; + installPhase = let androidManifest = '' diff --git a/nix/deps.nix b/nix/deps.nix index b50b607..062e9a9 100644 --- a/nix/deps.nix +++ b/nix/deps.nix @@ -1,55 +1,167 @@ -{ pkgs, stdenv, src, version, revision }: +# AUTOGENERATED from nimble.lock — do not edit manually. +# Regenerate with: ./tools/gen-nix-deps.sh nimble.lock nix/deps.nix +{ pkgs }: -stdenv.mkDerivation { - pname = "nim-sds-nimble-deps"; - version = "${version}-${revision}"; +{ + unittest2 = pkgs.fetchgit { + url = "https://github.com/status-im/nim-unittest2"; + rev = "26f2ef3ae0ec72a2a75bfe557e02e88f6a31c189"; + sha256 = "1n8n36kad50m97b64y7bzzknz9n7szffxhp0bqpk3g2v7zpda8sw"; + fetchSubmodules = true; + }; - inherit src; + bearssl = pkgs.fetchgit { + url = "https://github.com/status-im/nim-bearssl"; + rev = "11e798b62b8e6beabe958e048e9e24c7e0f9ee63"; + sha256 = "0qx36iiawrhmx9qjqcyfvz0134ph9dy8ryq3ch8d31gq6ir7aw84"; + fetchSubmodules = true; + }; - nativeBuildInputs = with pkgs; [ - jq rsync git nimble cacert moreutils - ]; + bearssl_pkey_decoder = pkgs.fetchgit { + url = "https://github.com/vacp2p/bearssl_pkey_decoder"; + rev = "21dd3710df9345ed2ad8bf8f882761e07863b8e0"; + sha256 = "0bl3f147zmkazbhdkr4cj1nipf9rqiw3g4hh1j424k9hpl55zdpg"; + fetchSubmodules = true; + }; - configurePhase = '' - export XDG_CACHE_HOME=$TMPDIR - export NIMBLE_DIR=$NIX_BUILD_TOP/nimbledir - export HOME=$TMPDIR - ''; + results = pkgs.fetchgit { + url = "https://github.com/arnetheduck/nim-results"; + rev = "df8113dda4c2d74d460a8fa98252b0b771bf1f27"; + sha256 = "1h7amas16sbhlr7zb7n3jb5434k98ji375vzw72k1fsc86vnmcr9"; + fetchSubmodules = true; + }; - buildPhase = '' - nimble --version - nimble --silent --localdeps setup - nimble --silent --localdeps install -y --depsOnly - ''; + stew = pkgs.fetchgit { + url = "https://github.com/status-im/nim-stew"; + rev = "b66168735d6f3841c5239c3169d3fe5fe98b1257"; + sha256 = "10n71vfa6klzd9dmal96jy0hiqk04gaj8wc9g91z6fclryf0yq92"; + fetchSubmodules = true; + }; - installPhase = '' - mkdir -p $out/nimbledeps + faststreams = pkgs.fetchgit { + url = "https://github.com/status-im/nim-faststreams"; + rev = "ce27581a3e881f782f482cb66dc5b07a02bd615e"; + sha256 = "0y6bw2scnmr8cxj4fg18w7f34l2bh9qwg5nhlgd84m9fpr5bqarn"; + fetchSubmodules = true; + }; - cp nimble.paths $out/nimble.paths + serialization = pkgs.fetchgit { + url = "https://github.com/status-im/nim-serialization"; + rev = "b0f2fa32960ea532a184394b0f27be37bd80248b"; + sha256 = "0wip1fjx7ka39ck1g1xvmyarzq1p5dlngpqil6zff8k8z5skiz27"; + fetchSubmodules = true; + }; - rsync -ra \ - --prune-empty-dirs \ - --include='*/' \ - --include='*.json' \ - --include='*.nim' \ - --include='*.nimble' \ - --exclude='*' \ - $NIMBLE_DIR/pkgs2 $out/nimbledeps - ''; + json_serialization = pkgs.fetchgit { + url = "https://github.com/status-im/nim-json-serialization"; + rev = "c343b0e243d9e17e2c40f3a8a24340f7c4a71d44"; + sha256 = "0i8sq51nqj8lshf6bfixaz9a7sq0ahsbvq3chkxdvv4khsqvam91"; + fetchSubmodules = true; + }; - fixupPhase = '' - # Replace build path with deterministic $out. - sed "s|$NIMBLE_DIR|./nimbledeps|g" $out/nimble.paths \ - | sort | sponge $out/nimble.paths + testutils = pkgs.fetchgit { + url = "https://github.com/status-im/nim-testutils"; + rev = "e4d37dc1652d5c63afb89907efb5a5e812261797"; + sha256 = "0nv0a9jm5b1rn3y52cxvyj8xz3jg235mp0xbirfp2cda0icgy1si"; + fetchSubmodules = true; + }; - # Nimble does not maintain order of files list. - for META_FILE in $(find $out -name nimblemeta.json); do - jq '.metaData.files |= sort' $META_FILE | sponge $META_FILE - done - ''; + chronicles = pkgs.fetchgit { + url = "https://github.com/status-im/nim-chronicles"; + rev = "27ec507429a4eb81edc20f28292ee8ec420be05b"; + sha256 = "1xx9fcfwgcaizq3s7i3s03mclz253r5j8va38l9ycl19fcbc96z9"; + fetchSubmodules = true; + }; + + httputils = pkgs.fetchgit { + url = "https://github.com/status-im/nim-http-utils"; + rev = "c53852d9e24205b6363bba517fa8ee7bde823691"; + sha256 = "1b332smfyp2yvhvfjrfqy4kvh9pc5w6hqh17f1yclz5z1j5xdpf1"; + fetchSubmodules = true; + }; + + chronos = pkgs.fetchgit { + url = "https://github.com/status-im/nim-chronos"; + rev = "0646c444fce7c7ed08ef6f2c9a7abfd172ffe655"; + sha256 = "1r499jl0lhnjq7hgddwgjl0gh3y1mprnqkhk0h6yh3cwgsmr5ym9"; + fetchSubmodules = true; + }; + + dnsclient = pkgs.fetchgit { + url = "https://github.com/ba0f3/dnsclient.nim"; + rev = "23214235d4784d24aceed99bbfe153379ea557c8"; + sha256 = "03mf3lw5c0m5nq9ppa49nylrl8ibkv2zzlc0wyhqg7w09kz6hks6"; + fetchSubmodules = true; + }; + + jwt = pkgs.fetchgit { + url = "https://github.com/vacp2p/nim-jwt.git"; + rev = "18f8378de52b241f321c1f9ea905456e89b95c6f"; + sha256 = "1986czmszdxj6g9yr7xn1fx8y2y9mwpb3f1bn9nc6973qawsdm0p"; + fetchSubmodules = true; + }; + + nimcrypto = pkgs.fetchgit { + url = "https://github.com/cheatfate/nimcrypto"; + rev = "b3dbc9c4d08e58c5b7bfad6dc7ef2ee52f2f4c08"; + sha256 = "1v4rz42lwcazs6isi3kmjylkisr84mh0kgmlqycx4i885dn3g0l4"; + fetchSubmodules = true; + }; + + metrics = pkgs.fetchgit { + url = "https://github.com/status-im/nim-metrics"; + rev = "11d0cddfb0e711aa2a8c75d1892ae24a64c299fc"; + sha256 = "1jrf2cf7v3iqjsk6grzvivxic1shhaxnvab6d35rxs2kcy6b5dv0"; + fetchSubmodules = true; + }; + + secp256k1 = pkgs.fetchgit { + url = "https://github.com/status-im/nim-secp256k1"; + rev = "d8f1288b7c72f00be5fc2c5ea72bf5cae1eafb15"; + sha256 = "1qjrmwbngb73f6r1fznvig53nyal7wj41d1cmqfksrmivk2sgrn2"; + fetchSubmodules = true; + }; + + zlib = pkgs.fetchgit { + url = "https://github.com/status-im/nim-zlib"; + rev = "e680f269fb01af2c34a2ba879ff281795a5258fe"; + sha256 = "1xw9f1gjsgqihdg7kdkbaq1wankgnx2vn9l3ihc6nqk2jzv5bvk5"; + fetchSubmodules = true; + }; + + websock = pkgs.fetchgit { + url = "https://github.com/status-im/nim-websock"; + rev = "35ae76f1559e835c80f9c1a3943bf995d3dd9eb5"; + sha256 = "1j6dklzb6b6bv2aiglbiyflja2vdpmyxfirv98f49y62mykq0yrw"; + fetchSubmodules = true; + }; + + lsquic = pkgs.fetchgit { + url = "https://github.com/vacp2p/nim-lsquic"; + rev = "4fb03ee7bfb39aecb3316889fdcb60bec3d0936f"; + sha256 = "0qdhcd4hyp185szc9sv3jvwdwc9zp3j0syy7glxv13k9bchfmkfg"; + fetchSubmodules = true; + }; + + libp2p = pkgs.fetchgit { + url = "https://github.com/vacp2p/nim-libp2p"; + rev = "ca48c3718246bb411ff0e354a70cb82d9a28de0d"; + sha256 = "07qfjjrq6w7bj9dbchvcrpla47jidngbrgmigbhl7fh3cfkdabc9"; + fetchSubmodules = true; + }; + + stint = pkgs.fetchgit { + url = "https://github.com/status-im/nim-stint"; + rev = "470b7892561b5179ab20bd389a69217d6213fe58"; + sha256 = "1isfwmbj98qfi5pm9acy0yyvq0vlz38nxp30xl43jx2mmaga2w22"; + fetchSubmodules = true; + }; + + taskpools = pkgs.fetchgit { + url = "https://github.com/status-im/nim-taskpools"; + rev = "9e8ccc754631ac55ac2fd495e167e74e86293edb"; + sha256 = "1y78l33vdjxmb9dkr455pbphxa73rgdsh8m9gpkf4d9b1wm1yivy"; + fetchSubmodules = true; + }; - # Make this a fixed-output derivation to allows internet access for Nimble. - outputHash = "sha256-OnirsXLj4HMVTbk+b4fcC+1K9MSMJyae6I7JO16WDno="; - outputHashAlgo = "sha256"; - outputHashMode = "recursive"; } diff --git a/nix/shell.nix b/nix/shell.nix index 53b0663..575d791 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -1,6 +1,5 @@ { pkgs ? import { }, - nim ? null, }: let @@ -12,7 +11,8 @@ in pkgs.mkShell { ]; buildInputs = with pkgs; [ - nim + nim-2_2 + nimble which git cmake diff --git a/sds.nimble b/sds.nimble index b63566a..fb5f43d 100644 --- a/sds.nimble +++ b/sds.nimble @@ -8,9 +8,9 @@ license = "MIT" srcDir = "sds" # Dependencies -requires "nim >= 2.2.6" +requires "nim >= 2.2.4" requires "chronos >= 4.0.4" -requires "libp2p >= 1.15.1" +requires "libp2p >= 1.15.2" requires "chronicles" requires "stew" requires "stint" @@ -42,11 +42,26 @@ proc buildLibrary( " --threads:on --app:lib --opt:size --noMain --mm:refc --header --nimMainPrefix:libsds " & extra_params & " " & srcDir & name & ".nim" -proc getArch(): string = - let arch = getEnv("ARCH") - if arch != "": return $arch - let (archFromUname, _) = gorgeEx("uname -m") - return $archFromUname +proc getMyCpu(): string = + ## Returns a Nim-compatible CPU name (e.g. amd64, arm64) for the host. + ## Respects the ARCH environment variable when set. + let envArch = getEnv("ARCH") + if envArch != "": + return envArch + when defined(arm64): + return "arm64" + elif defined(amd64): + return "amd64" + else: + let (archFromUname, _) = gorgeEx("uname -m") + let a = archFromUname.strip() + return + if a == "x86_64": + "amd64" + elif a == "aarch64": + "arm64" + else: + a # Tasks task test, "Run the test suite": @@ -73,13 +88,17 @@ task libsdsDynamicMac, "Generate bindings": let outLibNameAndExt = "libsds.dylib" let name = "libsds" - let arch = getArch() + let cpu = getMyCpu() + let clangArch = if cpu == "amd64": "x86_64" else: cpu let sdkPath = staticExec("xcrun --show-sdk-path").strip() - let archFlags = (if arch == "arm64": "--cpu:arm64 --passC:\"-arch arm64\" --passL:\"-arch arm64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" - else: "--cpu:amd64 --passC:\"-arch x86_64\" --passL:\"-arch x86_64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"") + let archFlags = + "--cpu:" & cpu & " --passC:\"-arch " & clangArch & "\" --passL:\"-arch " & clangArch & + "\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" buildLibrary outLibNameAndExt, - name, "library/", - archFlags & " -d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE", + name, + "library/", + archFlags & + " -d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE", "dynamic" task libsdsStaticWindows, "Generate bindings": @@ -102,13 +121,17 @@ task libsdsStaticMac, "Generate bindings": let outLibNameAndExt = "libsds.a" let name = "libsds" - let arch = getArch() + let cpu = getMyCpu() + let clangArch = if cpu == "amd64": "x86_64" else: cpu let sdkPath = staticExec("xcrun --show-sdk-path").strip() - let archFlags = (if arch == "arm64": "--cpu:arm64 --passC:\"-arch arm64\" --passL:\"-arch arm64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" - else: "--cpu:amd64 --passC:\"-arch x86_64\" --passL:\"-arch x86_64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"") + let archFlags = + "--cpu:" & cpu & " --passC:\"-arch " & clangArch & "\" --passL:\"-arch " & clangArch & + "\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" buildLibrary outLibNameAndExt, - name, "library/", - archFlags & " -d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE", + name, + "library/", + archFlags & + " -d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE", "static" # Build Mobile iOS @@ -117,6 +140,8 @@ proc buildMobileIOS(srcDir = ".", sdkPath = "") = let outDir = "build" let nimcacheDir = outDir & "/nimcache" + if dirExists nimcacheDir: + rmDir nimcacheDir if not dirExists outDir: mkDir outDir @@ -125,26 +150,30 @@ proc buildMobileIOS(srcDir = ".", sdkPath = "") = let aFile = outDir & "/libsds.a" let aFileTmp = outDir & "/libsds_tmp.a" - let arch = getArch() + let cpu = getMyCpu() + let clangArch = if cpu == "amd64": "x86_64" else: cpu # 1) Generate C sources from Nim (no linking) # Use unique symbol prefix to avoid conflicts with other Nim libraries - exec "nim c" & - " --nimcache:" & nimcacheDir & " --os:ios --cpu:" & arch & - " --compileOnly:on" & - " --noMain --mm:orc" & - " --threads:on --opt:size --header" & - " --nimMainPrefix:libsds --skipParentCfg:on" & - " --cc:clang" & - " -d:useMalloc" & - " " & srcDir & "/libsds.nim" + exec "nim c" & " --nimcache:" & nimcacheDir & " --os:ios --cpu:" & cpu & + " --compileOnly:on" & " --noMain --mm:refc" & " --threads:on --opt:size --header" & + " --nimMainPrefix:libsds" & " --cc:clang" & " -d:useMalloc" & " " & srcDir & + "/libsds.nim" # 2) Compile all generated C files to object files with hidden visibility # This prevents symbol conflicts with other Nim libraries (e.g., libnim_status_client) - let clangFlags = "-arch " & arch & " -isysroot " & sdkPath & - " -I./vendor/nimbus-build-system/vendor/Nim/lib/" & - " -fembed-bitcode -miphoneos-version-min=16.0 -O2" & - " -fvisibility=hidden" + # Locate nimbase.h: try next to the nim binary first (jiro4989/setup-nim-action + # puts nim at .nim_runtime/bin/nim with lib/ alongside), then fall back to the + # choosenim toolchain directory (~/.choosenim/toolchains/nim-VERSION/lib/). + let (nimBin, _) = gorgeEx("which nim") + let nimLibFromBin = parentDir(parentDir(nimBin.strip())) / "lib" + let nimLibChoosenim = getHomeDir() / ".choosenim/toolchains/nim-" & NimVersion & "/lib" + let nimLibDir = + if fileExists(nimLibFromBin / "nimbase.h"): nimLibFromBin + else: nimLibChoosenim + let clangFlags = + "-arch " & clangArch & " -isysroot " & sdkPath & " -I" & nimLibDir & + " -fembed-bitcode -miphoneos-version-min=16.2 -O2" & " -fvisibility=hidden" var objectFiles: seq[string] = @[] for cFile in listFiles(nimcacheDir): @@ -159,32 +188,126 @@ proc buildMobileIOS(srcDir = ".", sdkPath = "") = # 4) Use libtool to localize all non-public symbols # Keep only Sds* functions as global, hide everything else to prevent conflicts # with nim runtime symbols from libnim_status_client - let keepSymbols = "_Sds*:_libsdsNimMain:_libsdsDatInit*:_libsdsInit*:_NimMainModule__libsds*" + let keepSymbols = + "_Sds*:_libsdsNimMain:_libsdsDatInit*:_libsdsInit*:_NimMainModule__libsds*" exec "xcrun libtool -static -o " & aFile & " " & aFileTmp & - " -exported_symbols_list /dev/stdin <<< '" & keepSymbols & "' 2>/dev/null || cp " & aFileTmp & " " & aFile + " -exported_symbols_list /dev/stdin <<< '" & keepSymbols & "' 2>/dev/null || cp " & + aFileTmp & " " & aFile echo "✔ iOS library created: " & aFile task libsdsIOS, "Build the mobile bindings for iOS": let srcDir = "./library" - let sdkPath = getEnv("IOS_SDK_PATH") + var sdkPath = getEnv("IOS_SDK_PATH") + if sdkPath.len == 0: + let (detected, exitCode) = gorgeEx("xcrun --show-sdk-path --sdk iphoneos") + if exitCode == 0: + sdkPath = detected.strip() buildMobileIOS srcDir, sdkPath ### Mobile Android -proc buildMobileAndroid(srcDir = ".", extra_params = "") = - let cpu = getArch() +proc checkAndroidNdk() = + let ndkRoot = getEnv("ANDROID_NDK_ROOT") + if ndkRoot.len == 0: + quit """Error: ANDROID_NDK_ROOT is not set.""" + if not dirExists(ndkRoot): + quit "Error: ANDROID_NDK_ROOT points to a non-existent directory: " & ndkRoot + # source.properties contains Pkg.Revision — present in every NDK since r10. + let propsFile = ndkRoot / "source.properties" + if not fileExists(propsFile): + quit "Error: " & ndkRoot & " does not look like a valid NDK (source.properties not found)." + let (props, _) = gorgeEx("cat " & propsFile) + var revision = "" + for line in props.splitLines(): + if line.startsWith("Pkg.Revision"): + let parts = line.split('=') + if parts.len == 2: + revision = parts[1].strip() + if revision.len == 0: + quit "Error: Could not read NDK version from " & propsFile + echo "Android NDK version: " & revision - let outDir = "build/" +proc buildMobileAndroid(srcDir = ".", extra_params = "") = + let cpu = getMyCpu() + let ndkRoot = getEnv("ANDROID_NDK_ROOT") + let androidTarget = "30" + + # Map Nim CPU name → NDK target triple and include dirname. + let (androidArch, archDirname) = + if cpu == "arm64": ("aarch64-linux-android", "aarch64-linux-android") + elif cpu == "amd64": ("x86_64-linux-android", "x86_64-linux-android") + elif cpu == "i386": ("i686-linux-android", "i686-linux-android") + else: ("armv7a-linux-androideabi","arm-linux-androideabi") + + # NDK prebuilt toolchain — location differs by host OS. + let (hostOS, _) = gorgeEx("uname -s") + let ndkHostTag = + if hostOS.strip() == "Darwin": "darwin-x86_64" + else: "linux-x86_64" + let toolchainDir = ndkRoot / "toolchains/llvm/prebuilt" / ndkHostTag + let sysroot = toolchainDir / "sysroot" + let ndkClang = toolchainDir / "bin" / (androidArch & androidTarget & "-clang") + + let outDir = "build" if not dirExists outDir: mkDir outDir - exec "nim c" & " --out:" & outDir & - "/libsds.so --threads:on --app:lib --opt:size --noMain --mm:refc --nimMainPrefix:libsds " & - "-d:chronicles_sinks=textlines[dynamic] --header --passL:-L" & outdir & - " --passL:-llog --cpu:" & cpu & " --os:android -d:androidNDK -d:chronosEventEngine=epoll " & extra_params & " " & - srcDir & "/libsds.nim" + exec "nim c" & + " --out:" & outDir & "/libsds.so" & + " --threads:on --app:lib --opt:size --noMain --mm:refc --nimMainPrefix:libsds" & + " --cc:clang" & + " --clang.exe:\"" & ndkClang & "\"" & + " --clang.linkerexe:\"" & ndkClang & "\"" & + " --cpu:" & cpu & + " --os:android" & + " -d:androidNDK" & + " -d:chronosEventEngine=epoll" & + " --passC:\"--sysroot=" & sysroot & "\"" & + " --passL:\"--sysroot=" & sysroot & "\"" & + " --passC:\"--target=" & androidArch & androidTarget & "\"" & + " --passL:\"--target=" & androidArch & androidTarget & "\"" & + " --passC:\"-I" & sysroot & "/usr/include\"" & + " --passC:\"-I" & sysroot & "/usr/include/" & archDirname & "\"" & + " --passL:\"-L" & sysroot & "/usr/lib/" & archDirname & "/" & androidTarget & "\"" & + " --passL:-llog" & + " -d:chronicles_sinks=textlines[dynamic]" & + " --header" & + " " & extra_params & + " " & srcDir & "/libsds.nim" -task libsdsAndroid, "Build the mobile bindings for Android": +task libsdsAndroid, "Build the mobile bindings for Android (uses ARCH env var)": + checkAndroidNdk() let srcDir = "./library" - let extraParams = "-d:chronicles_log_level=ERROR" - buildMobileAndroid srcDir, extraParams + buildMobileAndroid srcDir, "-d:chronicles_log_level=ERROR" + +task libsdsAndroidArm64, "Build Android arm64 bindings": + checkAndroidNdk() + putEnv("ARCH", "arm64") + buildMobileAndroid "./library", "-d:chronicles_log_level=ERROR" + +task libsdsAndroidAmd64, "Build Android amd64 bindings": + checkAndroidNdk() + putEnv("ARCH", "amd64") + buildMobileAndroid "./library", "-d:chronicles_log_level=ERROR" + +task libsdsAndroidX86, "Build Android x86 bindings": + checkAndroidNdk() + putEnv("ARCH", "i386") + buildMobileAndroid "./library", "-d:chronicles_log_level=ERROR" + +task libsdsAndroidArm, "Build Android arm bindings": + checkAndroidNdk() + putEnv("ARCH", "arm") + buildMobileAndroid "./library", "-d:chronicles_log_level=ERROR" + +task libsds, "Build the shared library for the current platform": + when defined(macosx): + exec "nimble libsdsDynamicMac" + elif defined(windows): + exec "nimble libsdsDynamicWindows" + else: + exec "nimble libsdsDynamicLinux" + +task clean, "Remove build artifacts": + if dirExists "build": + rmDir "build" diff --git a/tools/gen-nix-deps.sh b/tools/gen-nix-deps.sh new file mode 100755 index 0000000..c601ecd --- /dev/null +++ b/tools/gen-nix-deps.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# Generates nix/deps.nix from nimble.lock using nix-prefetch-git. +# Usage: ./tools/gen-nix-deps.sh [nimble.lock] [nix/deps.nix] +set -euo pipefail + +usage() { + cat < + +Example: + $0 nimble.lock nix/deps.nix +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage; exit 0 +fi + +if [[ $# -ne 2 ]]; then + usage; exit 1 +fi + +LOCKFILE="$1" +OUTFILE="$2" + +command -v jq >/dev/null || { echo "error: jq required"; exit 1; } +command -v nix-prefetch-git >/dev/null || { echo "error: nix-prefetch-git required"; exit 1; } + +if [[ ! -f "$LOCKFILE" ]]; then + echo "[!] $LOCKFILE not found" + echo "[*] Generating $LOCKFILE via 'nimble lock'" + nimble lock +fi + +echo "[*] Generating $OUTFILE from $LOCKFILE" +mkdir -p "$(dirname "$OUTFILE")" + +cat > "$OUTFILE" <<'EOF' +# AUTOGENERATED from nimble.lock — do not edit manually. +# Regenerate with: ./tools/gen-nix-deps.sh nimble.lock nix/deps.nix +{ pkgs }: + +{ +EOF + +jq -c ' + .packages + | to_entries[] + | select(.value.downloadMethod == "git") + | select(.key != "nim" and .key != "nimble") +' "$LOCKFILE" | while read -r entry; do + name=$(jq -r '.key' <<<"$entry") + url=$(jq -r '.value.url' <<<"$entry") + rev=$(jq -r '.value.vcsRevision' <<<"$entry") + + echo " [*] Prefetching $name @ $rev" + + sha=$(nix-prefetch-git \ + --url "$url" \ + --rev "$rev" \ + --fetch-submodules \ + | jq -r '.sha256') + + cat >> "$OUTFILE" <> "$OUTFILE" <<'EOF' +} +EOF + +echo "[✓] Wrote $OUTFILE"