diff --git a/BearSSL.mk b/BearSSL.mk new file mode 100644 index 000000000..98e933ebd --- /dev/null +++ b/BearSSL.mk @@ -0,0 +1,39 @@ +# Copyright (c) 2022 Status Research & Development GmbH. Licensed under +# either of: +# - Apache License, version 2.0 +# - MIT license +# at your option. This file may not be copied, modified, or distributed except +# according to those terms. + +########################### +## bearssl (nimbledeps) ## +########################### +# Rebuilds libbearssl.a from the package installed by nimble under +# nimbledeps/pkgs2/. Used by `make update` / $(NIMBLEDEPS_STAMP). +# +# BEARSSL_NIMBLEDEPS_DIR is evaluated at parse time, so targets that +# depend on it must be invoked via a recursive $(MAKE) call so the sub-make +# re-evaluates the variable after nimble setup has populated nimbledeps/. +# +# `ls -dt` (sort by modification time, newest first) is used to pick the +# latest installed version and is portable across Linux, macOS, and +# Windows (MSYS/MinGW). + +BEARSSL_NIMBLEDEPS_DIR := $(shell ls -dt $(CURDIR)/nimbledeps/pkgs2/bearssl-* 2>/dev/null | head -1) +BEARSSL_CSOURCES_DIR := $(BEARSSL_NIMBLEDEPS_DIR)/bearssl/csources + +.PHONY: clean-bearssl-nimbledeps rebuild-bearssl-nimbledeps + +clean-bearssl-nimbledeps: +ifeq ($(BEARSSL_NIMBLEDEPS_DIR),) + $(error No bearssl package found under nimbledeps/pkgs2/ — run 'make update' first) +endif + + [ -e "$(BEARSSL_CSOURCES_DIR)/build" ] && \ + "$(MAKE)" -C "$(BEARSSL_CSOURCES_DIR)" clean || true + +rebuild-bearssl-nimbledeps: | clean-bearssl-nimbledeps +ifeq ($(BEARSSL_NIMBLEDEPS_DIR),) + $(error No bearssl package found under nimbledeps/pkgs2/ — run 'make update' first) +endif + @echo "Rebuilding bearssl from $(BEARSSL_CSOURCES_DIR)" + + "$(MAKE)" -C "$(BEARSSL_CSOURCES_DIR)" lib \ No newline at end of file diff --git a/Makefile b/Makefile index afd2389d2..8c043a325 100644 --- a/Makefile +++ b/Makefile @@ -4,28 +4,13 @@ # - MIT license # at your option. This file may not be copied, modified, or distributed except # according to those terms. -export BUILD_SYSTEM_DIR := vendor/nimbus-build-system -export EXCLUDED_NIM_PACKAGES := vendor/nim-dnsdisc/vendor + +include Nat.mk +include BearSSL.mk + LINK_PCRE := 0 FORMAT_MSG := "\\x1B[95mFormatting:\\x1B[39m" -# we don't want an error here, so we can handle things later, in the ".DEFAULT" target --include $(BUILD_SYSTEM_DIR)/makefiles/variables.mk - - -ifeq ($(NIM_PARAMS),) -# "variables.mk" was not included, so we update the submodules. -GIT_SUBMODULE_UPDATE := git submodule update --init --recursive -.DEFAULT: - +@ echo -e "Git submodules not found. Running '$(GIT_SUBMODULE_UPDATE)'.\n"; \ - $(GIT_SUBMODULE_UPDATE); \ - echo -# Now that the included *.mk files appeared, and are newer than this file, Make will restart itself: -# https://www.gnu.org/software/make/manual/make.html#Remaking-Makefiles -# -# After restarting, it will execute its original goal, so we don't have to start a child Make here -# with "$(MAKE) $(MAKECMDGOALS)". Isn't hidden control flow great? - -else # "variables.mk" was included. Business as usual until the end of this file. +BUILD_MSG := "Building:" # Determine the OS detected_OS := $(shell uname -s) @@ -33,28 +18,30 @@ ifneq (,$(findstring MINGW,$(detected_OS))) detected_OS := Windows endif +# NIM binary location +NIM_BINARY := $(shell which nim) +NPH := $(CURDIR)/nimbledeps/bin/nph +NIMBLEDEPS_STAMP := nimbledeps/.nimble-setup + +# Compilation parameters +NIM_PARAMS ?= + ifeq ($(detected_OS),Windows) - # Update MINGW_PATH to standard MinGW location MINGW_PATH = /mingw64 NIM_PARAMS += --passC:"-I$(MINGW_PATH)/include" NIM_PARAMS += --passL:"-L$(MINGW_PATH)/lib" - NIM_PARAMS += --passL:"-Lvendor/nim-nat-traversal/vendor/miniupnp/miniupnpc" - NIM_PARAMS += --passL:"-Lvendor/nim-nat-traversal/vendor/libnatpmp-upstream" - - LIBS = -lws2_32 -lbcrypt -liphlpapi -luserenv -lntdll -lminiupnpc -lnatpmp -lpq + LIBS = -lws2_32 -lbcrypt -liphlpapi -luserenv -lntdll -lpq NIM_PARAMS += $(foreach lib,$(LIBS),--passL:"$(lib)") NIM_PARAMS += --passL:"-Wl,--allow-multiple-definition" - export PATH := /c/msys64/usr/bin:/c/msys64/mingw64/bin:/c/msys64/usr/lib:/c/msys64/mingw64/lib:$(PATH) - endif ########## ## Main ## ########## -.PHONY: all test update clean examples +.PHONY: all test update clean examples deps nimble -# default target, because it's the first one that doesn't start with '.' +# default target all: | wakunode2 libwaku examples: | example2 chat2 chat2bridge @@ -71,102 +58,80 @@ ifeq ($(strip $(test_file)),) else $(MAKE) compile-test TEST_FILE="$(test_file)" TEST_NAME="$(call test_name)" endif -# this prevents make from erroring on unknown targets like "Index" + +# this prevents make from erroring on unknown targets %: @true waku.nims: ln -s waku.nimble $@ -update: | update-common - rm -rf waku.nims && \ - $(MAKE) waku.nims $(HANDLE_OUTPUT) +$(NIMBLEDEPS_STAMP): | waku.nims + git submodule update --init --recursive + nimble setup --localdeps $(MAKE) build-nph + $(MAKE) rebuild-nat-libs-nimbledeps + $(MAKE) rebuild-bearssl-nimbledeps + touch $@ + +update: + rm -f $(NIMBLEDEPS_STAMP) + rm nimble.lock + $(MAKE) $(NIMBLEDEPS_STAMP) + nimble lock clean: rm -rf build + rm -rf nimbledeps + rm nimble.lock 2> /dev/null || true + rm -fr nimcache + nimble clean -# must be included after the default target --include $(BUILD_SYSTEM_DIR)/makefiles/targets.mk +build: + mkdir -p build + +nimble: + echo "Inside nimble target, checking for nimble..." && \ + command -v nimble >/dev/null 2>&1 || { \ + mv nimbledeps nimbledeps_backup 2>/dev/null || true; \ + echo "choosenim not found, installing ..."; \ + curl -sSf https://nim-lang.org/choosenim/init.sh | sh; \ + mv nimbledeps_backup nimbledeps 2>/dev/null || true; \ + } ## Possible values: prod; debug TARGET ?= prod ## 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)\" ## Heaptracker options HEAPTRACKER ?= 0 HEAPTRACKER_INJECT ?= 0 ifeq ($(HEAPTRACKER), 1) -# Assumes Nim's lib/system/alloc.nim is patched! TARGET := debug-with-heaptrack - ifeq ($(HEAPTRACKER_INJECT), 1) -# the Nim compiler will load 'libheaptrack_inject.so' HEAPTRACK_PARAMS := -d:heaptracker -d:heaptracker_inject NIM_PARAMS := $(NIM_PARAMS) -d:heaptracker -d:heaptracker_inject else -# the Nim compiler will load 'libheaptrack_preload.so' HEAPTRACK_PARAMS := -d:heaptracker NIM_PARAMS := $(NIM_PARAMS) -d:heaptracker endif - -endif -## end of Heaptracker options - -################## -## Dependencies ## -################## -.PHONY: deps libbacktrace - -FOUNDRY_VERSION := 1.5.0 -PNPM_VERSION := 10.23.0 - - -rustup: -ifeq (, $(shell which cargo)) -# Install Rustup if it's not installed -# -y: Assume "yes" for all prompts -# --default-toolchain stable: Install the stable toolchain - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable endif -rln-deps: rustup - ./scripts/install_rln_tests_dependencies.sh $(FOUNDRY_VERSION) $(PNPM_VERSION) - -deps: | deps-common nat-libs waku.nims - - -### nim-libbacktrace - -# "-d:release" implies "--stacktrace:off" and it cannot be added to config.nims +# Debug/Release mode ifeq ($(DEBUG), 0) -NIM_PARAMS := $(NIM_PARAMS) -d:release -d:lto_incremental -d:strip +NIM_PARAMS := $(NIM_PARAMS) -d:release else NIM_PARAMS := $(NIM_PARAMS) -d:debug endif -ifeq ($(USE_LIBBACKTRACE), 0) NIM_PARAMS := $(NIM_PARAMS) -d:disable_libbacktrace -endif # enable experimental exit is dest feature in libp2p mix NIM_PARAMS := $(NIM_PARAMS) -d:libp2p_mix_experimental_exit_is_dest -libbacktrace: - + $(MAKE) -C vendor/nim-libbacktrace --no-print-directory BUILD_CXX_LIB=0 - -clean-libbacktrace: - + $(MAKE) -C vendor/nim-libbacktrace clean $(HANDLE_OUTPUT) - -# Extend deps and clean targets -ifneq ($(USE_LIBBACKTRACE), 0) -deps: | libbacktrace -endif - ifeq ($(POSTGRES), 1) NIM_PARAMS := $(NIM_PARAMS) -d:postgres -d:nimDebugDlOpen endif @@ -175,14 +140,26 @@ ifeq ($(DEBUG_DISCV5), 1) NIM_PARAMS := $(NIM_PARAMS) -d:debugDiscv5 endif -clean: | clean-libbacktrace +# Export NIM_PARAMS so nimble can access it +export NIM_PARAMS -### Create nimble links (used when building with Nix) +################## +## Dependencies ## +################## +.PHONY: deps -nimbus-build-system-nimble-dir: - NIMBLE_DIR="$(CURDIR)/$(NIMBLE_DIR)" \ - PWD_CMD="$(PWD)" \ - $(CURDIR)/scripts/generate_nimble_links.sh +FOUNDRY_VERSION := 1.5.0 +PNPM_VERSION := 10.23.0 + +rustup: +ifeq (, $(shell which cargo)) + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable +endif + +rln-deps: rustup + ./scripts/install_rln_tests_dependencies.sh $(FOUNDRY_VERSION) $(PNPM_VERSION) + +deps: | nimble ################## ## RLN ## @@ -200,7 +177,7 @@ endif $(LIBRLN_FILE): echo -e $(BUILD_MSG) "$@" && \ - ./scripts/build_rln.sh $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(LIBRLN_FILE) + bash scripts/build_rln.sh $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(LIBRLN_FILE) librln: | $(LIBRLN_FILE) $(eval NIM_PARAMS += --passL:$(LIBRLN_FILE) --passL:-lm) @@ -209,7 +186,6 @@ clean-librln: cargo clean --manifest-path vendor/zerokit/rln/Cargo.toml rm -f $(LIBRLN_FILE) -# Extend clean target clean: | clean-librln ################# @@ -217,74 +193,71 @@ clean: | clean-librln ################# .PHONY: testcommon -testcommon: | build deps +testcommon: | build echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim testcommon $(NIM_PARAMS) waku.nims - + nimble testcommon ########## ## Waku ## ########## .PHONY: testwaku wakunode2 testwakunode2 example2 chat2 chat2bridge liteprotocoltester -# install rln-deps only for the testwaku target -testwaku: | build deps rln-deps librln +testwaku: | build rln-deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim test -d:os=$(shell uname) $(NIM_PARAMS) waku.nims + nimble test -wakunode2: | build deps librln +wakunode2: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - \ - $(ENV_SCRIPT) nim wakunode2 $(NIM_PARAMS) waku.nims + nimble wakunode2 -benchmarks: | build deps librln +benchmarks: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim benchmarks $(NIM_PARAMS) waku.nims + nimble benchmarks -testwakunode2: | build deps librln +testwakunode2: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim testwakunode2 $(NIM_PARAMS) waku.nims + nimble testwakunode2 -example2: | build deps librln +example2: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim example2 $(NIM_PARAMS) waku.nims + nimble example2 -chat2: | build deps librln +chat2: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim chat2 $(NIM_PARAMS) waku.nims + nimble chat2 -chat2mix: | build deps librln +chat2mix: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim chat2mix $(NIM_PARAMS) waku.nims + nimble chat2mix -rln-db-inspector: | build deps librln +rln-db-inspector: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim rln_db_inspector $(NIM_PARAMS) waku.nims + nimble rln_db_inspector -chat2bridge: | build deps librln +chat2bridge: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim chat2bridge $(NIM_PARAMS) waku.nims + nimble chat2bridge -liteprotocoltester: | build deps librln +liteprotocoltester: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim liteprotocoltester $(NIM_PARAMS) waku.nims + nimble liteprotocoltester -lightpushwithmix: | build deps librln +lightpushwithmix: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim lightpushwithmix $(NIM_PARAMS) waku.nims + nimble lightpushwithmix -api_example: | build deps librln +api_example: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ $(ENV_SCRIPT) nim api_example $(NIM_PARAMS) waku.nims -build/%: | build deps librln +build/%: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$*" && \ - $(ENV_SCRIPT) nim buildone $(NIM_PARAMS) waku.nims $* + nimble buildone $* -compile-test: | build deps librln +compile-test: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "$(TEST_FILE)" "\"$(TEST_NAME)\"" && \ - $(ENV_SCRIPT) nim buildTest $(NIM_PARAMS) waku.nims $(TEST_FILE) && \ - $(ENV_SCRIPT) nim execTest $(NIM_PARAMS) waku.nims $(TEST_FILE) "\"$(TEST_NAME)\""; \ + nimble buildTest $(TEST_FILE) && \ + nimble execTest $(TEST_FILE) "\"$(TEST_NAME)\"" ################ ## Waku tools ## @@ -293,29 +266,26 @@ compile-test: | build deps librln tools: networkmonitor wakucanary -wakucanary: | build deps librln +wakucanary: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim wakucanary $(NIM_PARAMS) waku.nims + nimble wakucanary -networkmonitor: | build deps librln +networkmonitor: | $(NIMBLEDEPS_STAMP) build deps librln echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim networkmonitor $(NIM_PARAMS) waku.nims + nimble networkmonitor ############ ## Format ## ############ .PHONY: build-nph install-nph clean-nph print-nph-path -# Default location for nph binary shall be next to nim binary to make it available on the path. -NPH:=$(shell dirname $(NIM_BINARY))/nph - build-nph: | build deps -ifeq ("$(wildcard $(NPH))","") - $(ENV_SCRIPT) nim c --skipParentCfg:on vendor/nph/src/nph.nim && \ - mv vendor/nph/src/nph $(shell dirname $(NPH)) - echo "nph utility is available at " $(NPH) +ifneq ($(detected_OS),Windows) + nimble install nph@0.7.0 -y + echo "Check if nph utility is available:" + PATH="$(CURDIR)/nimbledeps/bin:$$PATH" command -v nph else - echo "nph utility already exists at " $(NPH) + echo "Skipping nph build on Windows (nph is only used on Unix-like systems)" endif GIT_PRE_COMMIT_HOOK := .git/hooks/pre-commit @@ -335,9 +305,8 @@ nph/%: | build-nph clean-nph: rm -f $(NPH) -# To avoid hardcoding nph binary location in several places print-nph-path: - echo "$(NPH)" + @echo "$(NPH)" clean: | clean-nph @@ -346,25 +315,20 @@ clean: | clean-nph ################### .PHONY: docs coverage -# TODO: Remove unused target docs: | build deps echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) nim doc --run --index:on --project --out:.gh-pages waku/waku.nim waku.nims + nimble doc --run --index:on --project --out:.gh-pages waku/waku.nim waku.nims coverage: echo -e $(BUILD_MSG) "build/$@" && \ - $(ENV_SCRIPT) ./scripts/run_cov.sh -y - + ./scripts/run_cov.sh -y ##################### ## Container image ## ##################### -# -d:insecure - Necessary to enable Prometheus HTTP endpoint for metrics -# -d:chronicles_colors:none - Necessary to disable colors in logs for Docker DOCKER_IMAGE_NIMFLAGS ?= -d:chronicles_colors:none -d:insecure -d:postgres DOCKER_IMAGE_NIMFLAGS := $(DOCKER_IMAGE_NIMFLAGS) $(HEAPTRACK_PARAMS) -# build a docker image for the fleet docker-image: MAKE_TARGET ?= wakunode2 docker-image: DOCKER_IMAGE_TAG ?= $(MAKE_TARGET)-$(GIT_VERSION) docker-image: DOCKER_IMAGE_NAME ?= wakuorg/nwaku:$(DOCKER_IMAGE_TAG) @@ -372,7 +336,6 @@ docker-image: docker build \ --build-arg="MAKE_TARGET=$(MAKE_TARGET)" \ --build-arg="NIMFLAGS=$(DOCKER_IMAGE_NIMFLAGS)" \ - --build-arg="NIM_COMMIT=$(DOCKER_NIM_COMMIT)" \ --build-arg="LOG_LEVEL=$(LOG_LEVEL)" \ --build-arg="HEAPTRACK_BUILD=$(HEAPTRACKER)" \ --label="commit=$(shell git rev-parse HEAD)" \ @@ -384,7 +347,7 @@ docker-quick-image: MAKE_TARGET ?= wakunode2 docker-quick-image: DOCKER_IMAGE_TAG ?= $(MAKE_TARGET)-$(GIT_VERSION) docker-quick-image: DOCKER_IMAGE_NAME ?= wakuorg/nwaku:$(DOCKER_IMAGE_TAG) docker-quick-image: NIM_PARAMS := $(NIM_PARAMS) -d:chronicles_colors:none -d:insecure -d:postgres --passL:$(LIBRLN_FILE) --passL:-lm -docker-quick-image: | build deps librln wakunode2 +docker-quick-image: | build librln wakunode2 docker build \ --build-arg="MAKE_TARGET=$(MAKE_TARGET)" \ --tag $(DOCKER_IMAGE_NAME) \ @@ -398,19 +361,14 @@ docker-push: #################################### ## Container lite-protocol-tester ## #################################### -# -d:insecure - Necessary to enable Prometheus HTTP endpoint for metrics -# -d:chronicles_colors:none - Necessary to disable colors in logs for Docker DOCKER_LPT_NIMFLAGS ?= -d:chronicles_colors:none -d:insecure -# build a docker image for the fleet docker-liteprotocoltester: DOCKER_LPT_TAG ?= latest docker-liteprotocoltester: DOCKER_LPT_NAME ?= wakuorg/liteprotocoltester:$(DOCKER_LPT_TAG) -# --no-cache docker-liteprotocoltester: docker build \ --build-arg="MAKE_TARGET=liteprotocoltester" \ --build-arg="NIMFLAGS=$(DOCKER_LPT_NIMFLAGS)" \ - --build-arg="NIM_COMMIT=$(DOCKER_NIM_COMMIT)" \ --build-arg="LOG_LEVEL=TRACE" \ --label="commit=$(shell git rev-parse HEAD)" \ --label="version=$(GIT_VERSION)" \ @@ -430,39 +388,38 @@ docker-quick-liteprotocoltester: | liteprotocoltester docker-liteprotocoltester-push: docker push $(DOCKER_LPT_NAME) - ################ ## C Bindings ## ################ .PHONY: cbindings cwaku_example libwaku liblogosdelivery liblogosdelivery_example +detected_OS ?= Linux +ifeq ($(OS),Windows_NT) +detected_OS := Windows +else +detected_OS := $(shell uname -s) +endif + +BUILD_COMMAND ?= Dynamic STATIC ?= 0 -LIBWAKU_BUILD_COMMAND ?= libwakuDynamic -LIBLOGOSDELIVERY_BUILD_COMMAND ?= liblogosdeliveryDynamic +ifeq ($(STATIC), 1) + BUILD_COMMAND = Static +endif ifeq ($(detected_OS),Windows) - LIB_EXT_DYNAMIC = dll - LIB_EXT_STATIC = lib + BUILD_COMMAND := $(BUILD_COMMAND)Windows else ifeq ($(detected_OS),Darwin) - LIB_EXT_DYNAMIC = dylib - LIB_EXT_STATIC = a + BUILD_COMMAND := $(BUILD_COMMAND)Mac + export IOS_SDK_PATH := $(shell xcrun --sdk iphoneos --show-sdk-path) else ifeq ($(detected_OS),Linux) - LIB_EXT_DYNAMIC = so - LIB_EXT_STATIC = a + BUILD_COMMAND := $(BUILD_COMMAND)Linux endif -LIB_EXT := $(LIB_EXT_DYNAMIC) -ifeq ($(STATIC), 1) - LIB_EXT = $(LIB_EXT_STATIC) - LIBWAKU_BUILD_COMMAND = libwakuStatic - LIBLOGOSDELIVERY_BUILD_COMMAND = liblogosdeliveryStatic -endif +libwaku: | $(NIMBLEDEPS_STAMP) librln + nimble --verbose libwaku$(BUILD_COMMAND) $(NIM_PARAMS) waku.nimble -libwaku: | build deps librln - echo -e $(BUILD_MSG) "build/$@.$(LIB_EXT)" && $(ENV_SCRIPT) nim $(LIBWAKU_BUILD_COMMAND) $(NIM_PARAMS) waku.nims $@.$(LIB_EXT) - -liblogosdelivery: | build deps librln - echo -e $(BUILD_MSG) "build/$@.$(LIB_EXT)" && $(ENV_SCRIPT) nim $(LIBLOGOSDELIVERY_BUILD_COMMAND) $(NIM_PARAMS) waku.nims $@.$(LIB_EXT) +liblogosdelivery: | $(NIMBLEDEPS_STAMP) librln + nimble --verbose liblogosdelivery$(BUILD_COMMAND) $(NIM_PARAMS) waku.nimble logosdelivery_example: | build liblogosdelivery @echo -e $(BUILD_MSG) "build/$@" @@ -492,17 +449,35 @@ else ifeq ($(detected_OS),Windows) -lws2_32 endif +cwaku_example: | build libwaku + echo -e $(BUILD_MSG) "build/$@" && \ + cc -o "build/$@" \ + ./examples/cbindings/waku_example.c \ + ./examples/cbindings/base64.c \ + -lwaku -Lbuild/ \ + -pthread -ldl -lm + +cppwaku_example: | build libwaku + echo -e $(BUILD_MSG) "build/$@" && \ + g++ -o "build/$@" \ + ./examples/cpp/waku.cpp \ + ./examples/cpp/base64.cpp \ + -lwaku -Lbuild/ \ + -pthread -ldl -lm + +nodejswaku: | build deps + echo -e $(BUILD_MSG) "build/$@" && \ + node-gyp build --directory=examples/nodejs/ + ##################### ## Mobile Bindings ## ##################### .PHONY: libwaku-android \ - libwaku-android-precheck \ - libwaku-android-arm64 \ - libwaku-android-amd64 \ - libwaku-android-x86 \ - libwaku-android-arm \ - rebuild-nat-libs \ - build-libwaku-for-android-arch + libwaku-android-precheck \ + libwaku-android-arm64 \ + libwaku-android-amd64 \ + libwaku-android-x86 \ + libwaku-android-arm ANDROID_TARGET ?= 30 ifeq ($(detected_OS),Darwin) @@ -511,22 +486,19 @@ else ANDROID_TOOLCHAIN_DIR := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/linux-x86_64 endif -rebuild-nat-libs: | clean-cross nat-libs - libwaku-android-precheck: ifndef ANDROID_NDK_HOME - $(error ANDROID_NDK_HOME is not set) + $(error ANDROID_NDK_HOME is not set) endif build-libwaku-for-android-arch: ifneq ($(findstring /nix/store,$(LIBRLN_FILE)),) mkdir -p $(CURDIR)/build/android/$(ABIDIR)/ - cp $(LIBRLN_FILE) $(CURDIR)/build/android/$(ABIDIR)/ + CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_ARCH=$(ANDROID_ARCH) ANDROID_COMPILER=$(ANDROID_COMPILER) ANDROID_TOOLCHAIN_DIR=$(ANDROID_TOOLCHAIN_DIR) nimble libWakuAndroid else ./scripts/build_rln_android.sh $(CURDIR)/build $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(CROSS_TARGET) $(ABIDIR) endif - $(MAKE) rebuild-nat-libs CC=$(ANDROID_TOOLCHAIN_DIR)/bin/$(ANDROID_COMPILER) - CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_ARCH=$(ANDROID_ARCH) ANDROID_COMPILER=$(ANDROID_COMPILER) ANDROID_TOOLCHAIN_DIR=$(ANDROID_TOOLCHAIN_DIR) $(ENV_SCRIPT) nim libWakuAndroid $(NIM_PARAMS) waku.nims + $(MAKE) rebuild-nat-libs-nimbledeps CC=$(ANDROID_TOOLCHAIN_DIR)/bin/$(ANDROID_COMPILER) libwaku-android-arm64: ANDROID_ARCH=aarch64-linux-android libwaku-android-arm64: CPU=arm64 @@ -550,29 +522,23 @@ libwaku-android-arm: ANDROID_ARCH=armv7a-linux-androideabi libwaku-android-arm: CPU=arm libwaku-android-arm: ABIDIR=armeabi-v7a libwaku-android-arm: | libwaku-android-precheck build deps -# cross-rs target architecture name does not match the one used in android $(MAKE) build-libwaku-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) CROSS_TARGET=armv7-linux-androideabi CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_COMPILER=$(ANDROID_ARCH)$(ANDROID_TARGET)-clang libwaku-android: $(MAKE) libwaku-android-amd64 $(MAKE) libwaku-android-arm64 $(MAKE) libwaku-android-x86 -# 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. -# $(MAKE) libwaku-android-arm ################# ## iOS Bindings # ################# .PHONY: libwaku-ios-precheck \ - libwaku-ios-device \ - libwaku-ios-simulator \ - libwaku-ios + libwaku-ios-device \ + libwaku-ios-simulator \ + libwaku-ios IOS_DEPLOYMENT_TARGET ?= 18.0 -# Get SDK paths dynamically using xcrun define get_ios_sdk_path $(shell xcrun --sdk $(1) --show-sdk-path 2>/dev/null) endef @@ -584,59 +550,25 @@ else $(error iOS builds are only supported on macOS) endif -# Build for iOS architecture build-libwaku-for-ios-arch: - IOS_SDK=$(IOS_SDK) IOS_ARCH=$(IOS_ARCH) IOS_SDK_PATH=$(IOS_SDK_PATH) $(ENV_SCRIPT) nim libWakuIOS $(NIM_PARAMS) waku.nims + IOS_SDK=$(IOS_SDK) IOS_ARCH=$(IOS_ARCH) IOS_SDK_PATH=$(IOS_SDK_PATH) nimble libWakuIOS -# iOS device (arm64) libwaku-ios-device: IOS_ARCH=arm64 libwaku-ios-device: IOS_SDK=iphoneos libwaku-ios-device: IOS_SDK_PATH=$(call get_ios_sdk_path,iphoneos) libwaku-ios-device: | libwaku-ios-precheck build deps $(MAKE) build-libwaku-for-ios-arch IOS_ARCH=$(IOS_ARCH) IOS_SDK=$(IOS_SDK) IOS_SDK_PATH=$(IOS_SDK_PATH) -# iOS simulator (arm64 - Apple Silicon Macs) libwaku-ios-simulator: IOS_ARCH=arm64 libwaku-ios-simulator: IOS_SDK=iphonesimulator libwaku-ios-simulator: IOS_SDK_PATH=$(call get_ios_sdk_path,iphonesimulator) libwaku-ios-simulator: | libwaku-ios-precheck build deps $(MAKE) build-libwaku-for-ios-arch IOS_ARCH=$(IOS_ARCH) IOS_SDK=$(IOS_SDK) IOS_SDK_PATH=$(IOS_SDK_PATH) -# Build all iOS targets libwaku-ios: $(MAKE) libwaku-ios-device $(MAKE) libwaku-ios-simulator -cwaku_example: | build libwaku - echo -e $(BUILD_MSG) "build/$@" && \ - cc -o "build/$@" \ - ./examples/cbindings/waku_example.c \ - ./examples/cbindings/base64.c \ - -lwaku -Lbuild/ \ - -pthread -ldl -lm \ - -lminiupnpc -Lvendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/build/ \ - -lnatpmp -Lvendor/nim-nat-traversal/vendor/libnatpmp-upstream/ \ - vendor/nim-libbacktrace/libbacktrace_wrapper.o \ - vendor/nim-libbacktrace/install/usr/lib/libbacktrace.a - -cppwaku_example: | build libwaku - echo -e $(BUILD_MSG) "build/$@" && \ - g++ -o "build/$@" \ - ./examples/cpp/waku.cpp \ - ./examples/cpp/base64.cpp \ - -lwaku -Lbuild/ \ - -pthread -ldl -lm \ - -lminiupnpc -Lvendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/build/ \ - -lnatpmp -Lvendor/nim-nat-traversal/vendor/libnatpmp-upstream/ \ - vendor/nim-libbacktrace/libbacktrace_wrapper.o \ - vendor/nim-libbacktrace/install/usr/lib/libbacktrace.a - -nodejswaku: | build deps - echo -e $(BUILD_MSG) "build/$@" && \ - node-gyp build --directory=examples/nodejs/ - -endif # "variables.mk" was not included - ################### # Release Targets # ################### @@ -649,6 +581,4 @@ release-notes: -u $(shell id -u) \ docker.io/wakuorg/sv4git:latest \ release-notes |\ - sed -E 's@#([0-9]+)@[#\1](https://github.com/waku-org/nwaku/issues/\1)@g' -# I could not get the tool to replace issue ids with links, so using sed for now, -# asked here: https://github.com/bvieira/sv4git/discussions/101 + sed -E 's@#([0-9]+)@[#\1](https://github.com/waku-org/nwaku/issues/\1)@g' \ No newline at end of file diff --git a/Nat.mk b/Nat.mk new file mode 100644 index 000000000..31ad4e018 --- /dev/null +++ b/Nat.mk @@ -0,0 +1,54 @@ +# Copyright (c) 2022 Status Research & Development GmbH. Licensed under +# either of: +# - Apache License, version 2.0 +# - MIT license +# at your option. This file may not be copied, modified, or distributed except +# according to those terms. + +########################### +## nat-libs (nimbledeps) ## +########################### +# Builds miniupnpc and libnatpmp from the package installed by nimble under +# nimbledeps/pkgs2/. Used by `make update` / $(NIMBLEDEPS_STAMP). +# +# NAT_TRAVERSAL_NIMBLEDEPS_DIR is evaluated at parse time, so targets that +# depend on it must be invoked via a recursive $(MAKE) call so the sub-make +# re-evaluates the variable after nimble setup has populated nimbledeps/. +# +# `ls -dt` (sort by modification time, newest first) is used to pick the +# latest installed version and is portable across Linux, macOS, and +# Windows (MSYS/MinGW). + +NAT_TRAVERSAL_NIMBLEDEPS_DIR := $(shell ls -dt $(CURDIR)/nimbledeps/pkgs2/nat_traversal-* 2>/dev/null | head -1) + +.PHONY: clean-cross-nimbledeps rebuild-nat-libs-nimbledeps + +clean-cross-nimbledeps: +ifeq ($(NAT_TRAVERSAL_NIMBLEDEPS_DIR),) + $(error No nat_traversal package found under nimbledeps/pkgs2/ — run 'make update' first) +endif + + [ -e "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/miniupnp/miniupnpc" ] && \ + "$(MAKE)" -C "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/miniupnp/miniupnpc" CC=$(CC) clean $(HANDLE_OUTPUT) || true + + [ -e "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/libnatpmp-upstream" ] && \ + "$(MAKE)" -C "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/libnatpmp-upstream" CC=$(CC) clean $(HANDLE_OUTPUT) || true + +rebuild-nat-libs-nimbledeps: | clean-cross-nimbledeps +ifeq ($(NAT_TRAVERSAL_NIMBLEDEPS_DIR),) + $(error No nat_traversal package found under nimbledeps/pkgs2/ — run 'make update' first) +endif + @echo "Rebuilding nat-libs from $(NAT_TRAVERSAL_NIMBLEDEPS_DIR)" +ifeq ($(OS), Windows_NT) + + [ -e "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/miniupnp/miniupnpc/libminiupnpc.a" ] || \ + PATH=".;$${PATH}" "$(MAKE)" -C "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/miniupnp/miniupnpc" \ + -f Makefile.mingw CC=$(CC) CFLAGS="-Os -fPIC" libminiupnpc.a $(HANDLE_OUTPUT) + + "$(MAKE)" -C "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/libnatpmp-upstream" \ + OS=mingw CC=$(CC) \ + CFLAGS="-Wall -Wno-cpp -Os -fPIC -DWIN32 -DNATPMP_STATICLIB -DENABLE_STRNATPMPERR -DNATPMP_MAX_RETRIES=4 $(CFLAGS)" \ + libnatpmp.a $(HANDLE_OUTPUT) +else + + "$(MAKE)" -C "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/miniupnp/miniupnpc" \ + CC=$(CC) CFLAGS="-Os -fPIC" build/libminiupnpc.a $(HANDLE_OUTPUT) + + "$(MAKE)" CFLAGS="-Wall -Wno-cpp -Os -fPIC -DENABLE_STRNATPMPERR -DNATPMP_MAX_RETRIES=4 $(CFLAGS)" \ + -C "$(NAT_TRAVERSAL_NIMBLEDEPS_DIR)/vendor/libnatpmp-upstream" \ + CC=$(CC) libnatpmp.a $(HANDLE_OUTPUT) +endif diff --git a/waku.nimble b/waku.nimble index 51c7f993d..622489d94 100644 --- a/waku.nimble +++ b/waku.nimble @@ -10,30 +10,57 @@ description = "Waku, Private P2P Messaging for Resource-Restricted Devices" license = "MIT or Apache License 2.0" #bin = @["build/waku"] +requires "nim == 2.2.6" +requires "nimble == 0.20.1" + ### Dependencies -requires "nim >= 2.2.4", +requires "chronos >= 4.2.0", + "taskpools", + # Logging & Configuration "chronicles", "confutils", - "chronos", - "dnsdisc", - "eth", - "json_rpc", - "libbacktrace", - "nimcrypto", + # Serialization "serialization", + "json_serialization", + "toml_serialization", + "faststreams", + # Networking & P2P + "https://github.com/vacp2p/nim-libp2p.git#ff8d51857b4b79a68468e7bcc27b2026cca02996", + "eth", + "nat_traversal", + "dnsdisc", + "dnsclient", + "httputils >= 0.4.1", + "websock >= 0.2.1", + # Cryptography + "nimcrypto", + "secp256k1", + "bearssl", + # RPC & APIs + "json_rpc", + "presto", + "web3", + # Database + "db_connector", + "sqlite3_abi", + # Utilities "stew", "stint", "metrics", - "libp2p >= 1.15.0", - "web3", - "presto", "regex", + "unicodedb", "results", - "db_connector", "minilru", - "lsquic", - "jwt", - "ffi" + "zlib", + # Debug & Testing + "testutils", + "unittest2" + +# Packages not on nimble (use git URLs) +requires "https://github.com/logos-messaging/nim-ffi" + +requires "https://github.com/vacp2p/nim-lsquic" +requires "https://github.com/vacp2p/nim-jwt.git#18f8378de52b241f321c1f9ea905456e89b95c6f" proc getMyCPU(): string = ## Need to se cpu more explicit manner to avoid arch issues between dependencies @@ -46,6 +73,9 @@ proc getMyCPU(): string = elif defined(amd64): return " --cpu:amd64 " +proc getNimParams(): string = + return " " & getEnv("NIM_PARAMS") & " " + ### Helper functions proc buildModule(filePath, params = "", lang = "c"): bool = if not dirExists "build": @@ -68,28 +98,67 @@ proc buildModule(filePath, params = "", lang = "c"): bool = proc buildBinary(name: string, srcDir = "./", params = "", lang = "c") = if not dirExists "build": mkDir "build" - # allow something like "nim nimbus --verbosity:0 --hints:off nimbus.nims" - var extra_params = params - for i in 2 ..< paramCount(): - extra_params &= " " & paramStr(i) - exec "nim " & lang & " --out:build/" & name & " --mm:refc " & getMyCPU() & extra_params & " " & + exec "nim " & lang & " --out:build/" & name & " --mm:refc " & getMyCPU() & getNimParams() & " " & srcDir & name & ".nim" proc buildLibrary(lib_name: string, srcDir = "./", params = "", `type` = "static", srcFile = "libwaku.nim", mainPrefix = "libwaku") = if not dirExists "build": mkDir "build" - # allow something like "nim nimbus --verbosity:0 --hints:off nimbus.nims" - var extra_params = params - for i in 2 ..< (paramCount() - 1): - extra_params &= " " & paramStr(i) + if `type` == "static": exec "nim c" & " --out:build/" & lib_name & " --threads:on --app:staticlib --opt:speed --noMain --mm:refc --header -d:metrics --nimMainPrefix:" & mainPrefix & " --skipParentCfg:on -d:discv5_protocol_id=d5waku " & - getMyCPU() & extra_params & " " & srcDir & srcFile + getMyCPU() & getNimParams() & srcDir & "/" & srcFile else: exec "nim c" & " --out:build/" & lib_name & " --threads:on --app:lib --opt:speed --noMain --mm:refc --header -d:metrics --nimMainPrefix:" & mainPrefix & " --skipParentCfg:off -d:discv5_protocol_id=d5waku " & - getMyCPU() & extra_params & " " & srcDir & srcFile + getMyCPU() & getNimParams() & " " & srcDir & "/" & srcFile + +proc buildLibDynamicWindows(libName: string, folderName: string) = + buildLibrary libName & ".dll", folderName, + """-d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE """, + "dynamic" + +proc buildLibDynamicLinux(libName: string, folderName: string) = + buildLibrary libName & ".so", folderName, + """-d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE """, + "dynamic" + +proc buildLibDynamicMac(libName: string, folderName: string) = + let sdkPath = staticExec("xcrun --show-sdk-path").strip() + when defined(arm64): + let archFlags = "--cpu:arm64 --passC:\"-arch arm64\" --passL:\"-arch arm64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" + elif defined(amd64): + let archFlags = "--cpu:amd64 --passC:\"-arch x86_64\" --passL:\"-arch x86_64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" + else: + {.error: "Unsupported macOS architecture".} + buildLibrary libName & ".dylib", folderName, + archFlags & " -d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE", + "dynamic" + +proc buildLibStaticWindows(libName: string, folderName: string) = + buildLibrary libName & ".lib", folderName, + """-d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE """, + "static" + +proc buildLibStaticLinux(libName: string, folderName: string) = + buildLibrary libName & ".a", folderName, + """-d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE """, + "static" + +proc buildLibStaticMac(libName: string, folderName: string) = + let sdkPath = staticExec("xcrun --show-sdk-path").strip() + when defined(arm64): + let archFlags = "--cpu:arm64 --passC:\"-arch arm64\" --passL:\"-arch arm64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" + elif defined(amd64): + let archFlags = "--cpu:amd64 --passC:\"-arch x86_64\" --passL:\"-arch x86_64\" --passC:\"-isysroot " & sdkPath & "\" --passL:\"-isysroot " & sdkPath & "\"" + else: + {.error: "Unsupported macOS architecture".} + buildLibrary libName & ".a", folderName, + archFlags & " -d:chronicles_line_numbers --warning:Deprecated:off --warning:UnusedImport:on -d:chronicles_log_level=TRACE", + "static" + +### Mobile Android proc buildMobileAndroid(srcDir = ".", params = "") = let cpu = getEnv("CPU") @@ -99,14 +168,204 @@ proc buildMobileAndroid(srcDir = ".", params = "") = if not dirExists outDir: mkDir outDir - var extra_params = params - for i in 2 ..< paramCount(): - extra_params &= " " & paramStr(i) - exec "nim c" & " --out:" & outDir & - "/libwaku.so --threads:on --app:lib --opt:speed --noMain --mm:refc -d:chronicles_sinks=textlines[dynamic] --header -d:chronosEventEngine=epoll --passL:-L" & - outdir & " --passL:-lrln --passL:-llog --cpu:" & cpu & " --os:android -d:androidNDK " & - extra_params & " " & srcDir & "/libwaku.nim" + "/liblogosdelivery.so --threads:on --app:lib --opt:speed --noMain --mm:refc -d:chronicles_sinks=textlines[dynamic] --header -d:chronosEventEngine=epoll --passL:-L" & + outdir & " --passL:-lrln --passL:-llog --cpu:" & cpu & " --os:android -d:androidNDK " & params & + getNimParams() & " " & srcDir & "/liblogosdelivery.nim" + +task libLogosDeliveryAndroid, "Build the mobile bindings for Android": + let srcDir = "./library" + buildMobileAndroid srcDir, "-d:chronicles_log_level=ERROR" + +### Mobile iOS + +import std/sequtils + +proc buildMobileIOS(srcDir = ".", params = "") = + echo "Building iOS libwaku library" + + let iosArch = getEnv("IOS_ARCH") + let iosSdk = getEnv("IOS_SDK") + let sdkPath = getEnv("IOS_SDK_PATH") + + if sdkPath.len == 0: + quit "Error: IOS_SDK_PATH not set. Set it to the path of the iOS SDK" + + # Get nimble package paths + let bearsslPath = gorge("nimble path bearssl").strip() + let secp256k1Path = gorge("nimble path secp256k1").strip() + let natTraversalPath = gorge("nimble path nat_traversal").strip() + + # Get Nim standard library path + let nimPath = gorge("nim --fullhelp 2>&1 | head -1 | sed 's/.*\\[//' | sed 's/\\].*//'").strip() + let nimLibPath = nimPath.parentDir.parentDir / "lib" + + # Use SDK name in path to differentiate device vs simulator + let outDir = "build/ios/" & iosSdk & "-" & iosArch + if not dirExists outDir: + mkDir outDir + + var extra_params = params + let args = commandLineParams() + for arg in args: + extra_params &= " " & arg + + let cpu = if iosArch == "arm64": "arm64" else: "amd64" + + # The output static library + let nimcacheDir = outDir & "/nimcache" + let objDir = outDir & "/obj" + let vendorObjDir = outDir & "/vendor_obj" + let aFile = outDir & "/libwaku.a" + + if not dirExists objDir: + mkDir objDir + if not dirExists vendorObjDir: + mkDir vendorObjDir + + let clangBase = "clang -arch " & iosArch & " -isysroot " & sdkPath & + " -mios-version-min=18.0 -fembed-bitcode -fPIC -O2" + + # Generate C sources from Nim (no linking) + exec "nim c" & + " --nimcache:" & nimcacheDir & + " --os:ios --cpu:" & cpu & + " --compileOnly:on" & + " --noMain --mm:refc" & + " --threads:on --opt:size --header" & + " -d:metrics -d:discv5_protocol_id=d5waku" & + " --nimMainPrefix:libwaku --skipParentCfg:on" & + " --cc:clang" & + " " & extra_params & + " " & srcDir & "/libwaku.nim" + + # Compile vendor C libraries for iOS + + # --- BearSSL --- + echo "Compiling BearSSL for iOS..." + let bearSslSrcDir = bearsslPath / "bearssl/csources/src" + let bearSslIncDir = bearsslPath / "bearssl/csources/inc" + for path in walkDirRec(bearSslSrcDir): + if path.endsWith(".c"): + let relPath = path.replace(bearSslSrcDir & "/", "").replace("/", "_") + let baseName = relPath.changeFileExt("o") + let oFile = vendorObjDir / ("bearssl_" & baseName) + if not fileExists(oFile): + exec clangBase & " -I" & bearSslIncDir & " -I" & bearSslSrcDir & " -c " & path & " -o " & oFile + + # --- secp256k1 --- + echo "Compiling secp256k1 for iOS..." + let secp256k1Dir = secp256k1Path / "vendor/secp256k1" + let secp256k1Flags = " -I" & secp256k1Dir & "/include" & + " -I" & secp256k1Dir & "/src" & + " -I" & secp256k1Dir & + " -DENABLE_MODULE_RECOVERY=1" & + " -DENABLE_MODULE_ECDH=1" & + " -DECMULT_WINDOW_SIZE=15" & + " -DECMULT_GEN_PREC_BITS=4" + + # Main secp256k1 source + let secp256k1Obj = vendorObjDir / "secp256k1.o" + if not fileExists(secp256k1Obj): + exec clangBase & secp256k1Flags & " -c " & secp256k1Dir & "/src/secp256k1.c -o " & secp256k1Obj + + # Precomputed tables (required for ecmult operations) + let secp256k1PreEcmultObj = vendorObjDir / "secp256k1_precomputed_ecmult.o" + if not fileExists(secp256k1PreEcmultObj): + exec clangBase & secp256k1Flags & " -c " & secp256k1Dir & "/src/precomputed_ecmult.c -o " & secp256k1PreEcmultObj + + let secp256k1PreEcmultGenObj = vendorObjDir / "secp256k1_precomputed_ecmult_gen.o" + if not fileExists(secp256k1PreEcmultGenObj): + exec clangBase & secp256k1Flags & " -c " & secp256k1Dir & "/src/precomputed_ecmult_gen.c -o " & secp256k1PreEcmultGenObj + + # --- miniupnpc --- + echo "Compiling miniupnpc for iOS..." + let miniupnpcSrcDir = natTraversalPath / "vendor/miniupnp/miniupnpc/src" + let miniupnpcIncDir = natTraversalPath / "vendor/miniupnp/miniupnpc/include" + let miniupnpcBuildDir = natTraversalPath / "vendor/miniupnp/miniupnpc/build" + let miniupnpcFiles = @[ + "addr_is_reserved.c", "connecthostport.c", "igd_desc_parse.c", + "minisoap.c", "minissdpc.c", "miniupnpc.c", "miniwget.c", + "minixml.c", "portlistingparse.c", "receivedata.c", "upnpcommands.c", + "upnpdev.c", "upnperrors.c", "upnpreplyparse.c" + ] + for fileName in miniupnpcFiles: + let srcPath = miniupnpcSrcDir / fileName + let oFile = vendorObjDir / ("miniupnpc_" & fileName.changeFileExt("o")) + if fileExists(srcPath) and not fileExists(oFile): + exec clangBase & + " -I" & miniupnpcIncDir & + " -I" & miniupnpcSrcDir & + " -I" & miniupnpcBuildDir & + " -DMINIUPNPC_SET_SOCKET_TIMEOUT" & + " -D_BSD_SOURCE -D_DEFAULT_SOURCE" & + " -c " & srcPath & " -o " & oFile + + # --- libnatpmp --- + echo "Compiling libnatpmp for iOS..." + let natpmpSrcDir = natTraversalPath / "vendor/libnatpmp-upstream" + # Only compile natpmp.c - getgateway.c uses net/route.h which is not available on iOS + let natpmpObj = vendorObjDir / "natpmp_natpmp.o" + if not fileExists(natpmpObj): + exec clangBase & + " -I" & natpmpSrcDir & + " -DENABLE_STRNATPMPERR" & + " -c " & natpmpSrcDir & "/natpmp.c -o " & natpmpObj + + # Use iOS-specific stub for getgateway + let getgatewayStubSrc = "./library/ios_natpmp_stubs.c" + let getgatewayStubObj = vendorObjDir / "natpmp_getgateway_stub.o" + if fileExists(getgatewayStubSrc) and not fileExists(getgatewayStubObj): + exec clangBase & " -c " & getgatewayStubSrc & " -o " & getgatewayStubObj + + # --- BearSSL stubs (for tools functions not in main library) --- + echo "Compiling BearSSL stubs for iOS..." + let bearSslStubsSrc = "./library/ios_bearssl_stubs.c" + let bearSslStubsObj = vendorObjDir / "bearssl_stubs.o" + if fileExists(bearSslStubsSrc) and not fileExists(bearSslStubsObj): + exec clangBase & " -c " & bearSslStubsSrc & " -o " & bearSslStubsObj + + # Compile all Nim-generated C files to object files + echo "Compiling Nim-generated C files for iOS..." + var cFiles: seq[string] = @[] + for kind, path in walkDir(nimcacheDir): + if kind == pcFile and path.endsWith(".c"): + cFiles.add(path) + + for cFile in cFiles: + let baseName = extractFilename(cFile).changeFileExt("o") + let oFile = objDir / baseName + exec clangBase & + " -DENABLE_STRNATPMPERR" & + " -I" & nimLibPath & + " -I" & bearsslPath & "/bearssl/csources/inc/" & + " -I" & bearsslPath & "/bearssl/csources/tools/" & + " -I" & bearsslPath & "/bearssl/abi/" & + " -I" & secp256k1Path & "/vendor/secp256k1/include/" & + " -I" & natTraversalPath & "/vendor/miniupnp/miniupnpc/include/" & + " -I" & natTraversalPath & "/vendor/libnatpmp-upstream/" & + " -I" & nimcacheDir & + " -c " & cFile & + " -o " & oFile + + # Create static library from all object files + echo "Creating static library..." + var objFiles: seq[string] = @[] + for kind, path in walkDir(objDir): + if kind == pcFile and path.endsWith(".o"): + objFiles.add(path) + for kind, path in walkDir(vendorObjDir): + if kind == pcFile and path.endsWith(".o"): + objFiles.add(path) + + exec "libtool -static -o " & aFile & " " & objFiles.join(" ") + + echo "iOS library created: " & aFile + +task libWakuIOS, "Build the mobile bindings for iOS": + let srcDir = "./library" + let extraParams = "-d:chronicles_log_level=ERROR" + buildMobileIOS srcDir, extraParams proc test(name: string, params = "-d:chronicles_log_level=DEBUG", lang = "c") = # XXX: When running `> NIM_PARAMS="-d:chronicles_log_level=INFO" make test2` @@ -187,14 +446,6 @@ task lightpushwithmix, "Build lightpushwithmix": let name = "lightpush_publisher_mix" buildBinary name, "examples/lightpush_mix/" -task api_example, "Build api_example": - let name = "api_example" - buildBinary name, "examples/api_example/" - -task buildone, "Build custom target": - let filepath = paramStr(paramCount()) - discard buildModule filepath - task buildTest, "Test custom target": let filepath = paramStr(paramCount()) discard buildModule(filepath) @@ -219,203 +470,42 @@ let chroniclesParams = """-d:chronicles_disabled_topics="eth,dnsdisc.client" """ & "--warning:Deprecated:off " & "--warning:UnusedImport:on " & "-d:chronicles_log_level=TRACE" -task libwakuStatic, "Build the cbindings waku node library": - let lib_name = paramStr(paramCount()) - buildLibrary lib_name, "library/", chroniclesParams, "static" +## Libwaku build tasks -task libwakuDynamic, "Build the cbindings waku node library": - let lib_name = paramStr(paramCount()) - buildLibrary lib_name, "library/", chroniclesParams, "dynamic" +task libwakuDynamicWindows, "Generate bindings": + buildLibDynamicWindows("libwaku", "library") -### Mobile Android -task libWakuAndroid, "Build the mobile bindings for Android": - let srcDir = "./library" - let extraParams = "-d:chronicles_log_level=ERROR" - buildMobileAndroid srcDir, extraParams +task libwakuDynamicLinux, "Generate bindings": + buildLibDynamicLinux("libwaku", "library") -### Mobile iOS -import std/sequtils +task libwakuDynamicMac, "Generate bindings": + buildLibDynamicMac("libwaku", "library") -proc buildMobileIOS(srcDir = ".", params = "") = - echo "Building iOS libwaku library" +task libwakuStaticWindows, "Generate bindings": + buildLibStaticWindows("libwaku", "library") - let iosArch = getEnv("IOS_ARCH") - let iosSdk = getEnv("IOS_SDK") - let sdkPath = getEnv("IOS_SDK_PATH") +task libwakuStaticLinux, "Generate bindings": + buildLibStaticLinux("libwaku", "library") - if sdkPath.len == 0: - quit "Error: IOS_SDK_PATH not set. Set it to the path of the iOS SDK" +task libwakuStaticMac, "Generate bindings": + buildLibStaticMac("libwaku", "library") - # Use SDK name in path to differentiate device vs simulator - let outDir = "build/ios/" & iosSdk & "-" & iosArch - if not dirExists outDir: - mkDir outDir +## Liblogosdelivery build tasks - var extra_params = params - for i in 2 ..< paramCount(): - extra_params &= " " & paramStr(i) +task liblogosdeliveryDynamicWindows, "Generate bindings": + buildLibDynamicWindows("liblogosdelivery", "liblogosdelivery") - let cpu = if iosArch == "arm64": "arm64" else: "amd64" +task liblogosdeliveryDynamicLinux, "Generate bindings": + buildLibDynamicLinux("liblogosdelivery", "liblogosdelivery") - # The output static library - let nimcacheDir = outDir & "/nimcache" - let objDir = outDir & "/obj" - let vendorObjDir = outDir & "/vendor_obj" - let aFile = outDir & "/libwaku.a" +task liblogosdeliveryDynamicMac, "Generate bindings": + buildLibDynamicMac("liblogosdelivery", "liblogosdelivery") - if not dirExists objDir: - mkDir objDir - if not dirExists vendorObjDir: - mkDir vendorObjDir +task liblogosdeliveryStaticWindows, "Generate bindings": + buildLibStaticWindows("liblogosdelivery", "liblogosdelivery") - let clangBase = "clang -arch " & iosArch & " -isysroot " & sdkPath & - " -mios-version-min=18.0 -fembed-bitcode -fPIC -O2" +task liblogosdeliveryStaticLinux, "Generate bindings": + buildLibStaticLinux("liblogosdelivery", "liblogosdelivery") - # Generate C sources from Nim (no linking) - exec "nim c" & - " --nimcache:" & nimcacheDir & - " --os:ios --cpu:" & cpu & - " --compileOnly:on" & - " --noMain --mm:refc" & - " --threads:on --opt:speed --header" & - " -d:metrics -d:discv5_protocol_id=d5waku" & - " --nimMainPrefix:libwaku --skipParentCfg:on" & - " --cc:clang" & - " " & extra_params & - " " & srcDir & "/libwaku.nim" - - # Compile vendor C libraries for iOS - - # --- BearSSL --- - echo "Compiling BearSSL for iOS..." - let bearSslSrcDir = "./vendor/nim-bearssl/bearssl/csources/src" - let bearSslIncDir = "./vendor/nim-bearssl/bearssl/csources/inc" - for path in walkDirRec(bearSslSrcDir): - if path.endsWith(".c"): - let relPath = path.replace(bearSslSrcDir & "/", "").replace("/", "_") - let baseName = relPath.changeFileExt("o") - let oFile = vendorObjDir / ("bearssl_" & baseName) - if not fileExists(oFile): - exec clangBase & " -I" & bearSslIncDir & " -I" & bearSslSrcDir & " -c " & path & " -o " & oFile - - # --- secp256k1 --- - echo "Compiling secp256k1 for iOS..." - let secp256k1Dir = "./vendor/nim-secp256k1/vendor/secp256k1" - let secp256k1Flags = " -I" & secp256k1Dir & "/include" & - " -I" & secp256k1Dir & "/src" & - " -I" & secp256k1Dir & - " -DENABLE_MODULE_RECOVERY=1" & - " -DENABLE_MODULE_ECDH=1" & - " -DECMULT_WINDOW_SIZE=15" & - " -DECMULT_GEN_PREC_BITS=4" - - # Main secp256k1 source - let secp256k1Obj = vendorObjDir / "secp256k1.o" - if not fileExists(secp256k1Obj): - exec clangBase & secp256k1Flags & " -c " & secp256k1Dir & "/src/secp256k1.c -o " & secp256k1Obj - - # Precomputed tables (required for ecmult operations) - let secp256k1PreEcmultObj = vendorObjDir / "secp256k1_precomputed_ecmult.o" - if not fileExists(secp256k1PreEcmultObj): - exec clangBase & secp256k1Flags & " -c " & secp256k1Dir & "/src/precomputed_ecmult.c -o " & secp256k1PreEcmultObj - - let secp256k1PreEcmultGenObj = vendorObjDir / "secp256k1_precomputed_ecmult_gen.o" - if not fileExists(secp256k1PreEcmultGenObj): - exec clangBase & secp256k1Flags & " -c " & secp256k1Dir & "/src/precomputed_ecmult_gen.c -o " & secp256k1PreEcmultGenObj - - # --- miniupnpc --- - echo "Compiling miniupnpc for iOS..." - let miniupnpcSrcDir = "./vendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/src" - let miniupnpcIncDir = "./vendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/include" - let miniupnpcBuildDir = "./vendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/build" - let miniupnpcFiles = @[ - "addr_is_reserved.c", "connecthostport.c", "igd_desc_parse.c", - "minisoap.c", "minissdpc.c", "miniupnpc.c", "miniwget.c", - "minixml.c", "portlistingparse.c", "receivedata.c", "upnpcommands.c", - "upnpdev.c", "upnperrors.c", "upnpreplyparse.c" - ] - for fileName in miniupnpcFiles: - let srcPath = miniupnpcSrcDir / fileName - let oFile = vendorObjDir / ("miniupnpc_" & fileName.changeFileExt("o")) - if fileExists(srcPath) and not fileExists(oFile): - exec clangBase & - " -I" & miniupnpcIncDir & - " -I" & miniupnpcSrcDir & - " -I" & miniupnpcBuildDir & - " -DMINIUPNPC_SET_SOCKET_TIMEOUT" & - " -D_BSD_SOURCE -D_DEFAULT_SOURCE" & - " -c " & srcPath & " -o " & oFile - - # --- libnatpmp --- - echo "Compiling libnatpmp for iOS..." - let natpmpSrcDir = "./vendor/nim-nat-traversal/vendor/libnatpmp-upstream" - # Only compile natpmp.c - getgateway.c uses net/route.h which is not available on iOS - let natpmpObj = vendorObjDir / "natpmp_natpmp.o" - if not fileExists(natpmpObj): - exec clangBase & - " -I" & natpmpSrcDir & - " -DENABLE_STRNATPMPERR" & - " -c " & natpmpSrcDir & "/natpmp.c -o " & natpmpObj - - # Use iOS-specific stub for getgateway - let getgatewayStubSrc = "./library/ios_natpmp_stubs.c" - let getgatewayStubObj = vendorObjDir / "natpmp_getgateway_stub.o" - if fileExists(getgatewayStubSrc) and not fileExists(getgatewayStubObj): - exec clangBase & " -c " & getgatewayStubSrc & " -o " & getgatewayStubObj - - # --- BearSSL stubs (for tools functions not in main library) --- - echo "Compiling BearSSL stubs for iOS..." - let bearSslStubsSrc = "./library/ios_bearssl_stubs.c" - let bearSslStubsObj = vendorObjDir / "bearssl_stubs.o" - if fileExists(bearSslStubsSrc) and not fileExists(bearSslStubsObj): - exec clangBase & " -c " & bearSslStubsSrc & " -o " & bearSslStubsObj - - # Compile all Nim-generated C files to object files - echo "Compiling Nim-generated C files for iOS..." - var cFiles: seq[string] = @[] - for kind, path in walkDir(nimcacheDir): - if kind == pcFile and path.endsWith(".c"): - cFiles.add(path) - - for cFile in cFiles: - let baseName = extractFilename(cFile).changeFileExt("o") - let oFile = objDir / baseName - exec clangBase & - " -DENABLE_STRNATPMPERR" & - " -I./vendor/nimbus-build-system/vendor/Nim/lib/" & - " -I./vendor/nim-bearssl/bearssl/csources/inc/" & - " -I./vendor/nim-bearssl/bearssl/csources/tools/" & - " -I./vendor/nim-bearssl/bearssl/abi/" & - " -I./vendor/nim-secp256k1/vendor/secp256k1/include/" & - " -I./vendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/include/" & - " -I./vendor/nim-nat-traversal/vendor/libnatpmp-upstream/" & - " -I" & nimcacheDir & - " -c " & cFile & - " -o " & oFile - - # Create static library from all object files - echo "Creating static library..." - var objFiles: seq[string] = @[] - for kind, path in walkDir(objDir): - if kind == pcFile and path.endsWith(".o"): - objFiles.add(path) - for kind, path in walkDir(vendorObjDir): - if kind == pcFile and path.endsWith(".o"): - objFiles.add(path) - - exec "libtool -static -o " & aFile & " " & objFiles.join(" ") - - echo "✔ iOS library created: " & aFile - -task libWakuIOS, "Build the mobile bindings for iOS": - let srcDir = "./library" - let extraParams = "-d:chronicles_log_level=ERROR" - buildMobileIOS srcDir, extraParams - -task liblogosdeliveryStatic, "Build the liblogosdelivery (Logos Messaging Delivery API) static library": - let lib_name = paramStr(paramCount()) - buildLibrary lib_name, "liblogosdelivery/", chroniclesParams, "static", "liblogosdelivery.nim", "liblogosdelivery" - -task liblogosdeliveryDynamic, "Build the liblogosdelivery (Logos Messaging Delivery API) dynamic library": - let lib_name = paramStr(paramCount()) - buildLibrary lib_name, "liblogosdelivery/", chroniclesParams, "dynamic", "liblogosdelivery.nim", "liblogosdelivery" +task liblogosdeliveryStaticMac, "Generate bindings": + buildLibStaticMac("liblogosdelivery", "liblogosdelivery")