nostr_core_lib/build.sh

677 lines
23 KiB
Bash
Executable File

#!/bin/bash
# NOSTR Core Library - Customer Build Script with Auto-Detection
# Automatically detects which NIPs are needed based on #include statements
set -e # Exit on error
# Color constants
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033[34m'
BOLD='\033[1m'
RESET='\033[0m'
# Detect if we should use colors (terminal output and not piped)
USE_COLORS=true
if [ ! -t 1 ] || [ "$NO_COLOR" = "1" ]; then
USE_COLORS=false
fi
# Function to print output with colors
print_info() {
if [ "$USE_COLORS" = true ]; then
echo -e "${BLUE}[INFO]${RESET} $1"
else
echo "[INFO] $1"
fi
}
print_success() {
if [ "$USE_COLORS" = true ]; then
echo -e "${GREEN}${BOLD}[SUCCESS]${RESET} $1"
else
echo "[SUCCESS] $1"
fi
}
print_warning() {
if [ "$USE_COLORS" = true ]; then
echo -e "${YELLOW}[WARNING]${RESET} $1"
else
echo "[WARNING] $1"
fi
}
print_error() {
if [ "$USE_COLORS" = true ]; then
echo -e "${RED}${BOLD}[ERROR]${RESET} $1"
else
echo "[ERROR] $1"
fi
}
# Default values
ARCHITECTURE=""
FORCE_NIPS=""
VERBOSE=false
HELP=false
BUILD_TESTS=false
NO_COLOR_FLAG=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
x64|x86_64|amd64)
ARCHITECTURE="x64"
shift
;;
arm64|aarch64)
ARCHITECTURE="arm64"
shift
;;
--nips=*)
FORCE_NIPS="${1#*=}"
shift
;;
--verbose|-v)
VERBOSE=true
shift
;;
--tests|-t)
BUILD_TESTS=true
shift
;;
--no-color)
NO_COLOR_FLAG=true
shift
;;
--help|-h)
HELP=true
shift
;;
*)
print_error "Unknown argument: $1"
HELP=true
shift
;;
esac
done
# Apply no-color flag
if [ "$NO_COLOR_FLAG" = true ]; then
USE_COLORS=false
fi
# Show help
if [ "$HELP" = true ]; then
echo "NOSTR Core Library - Customer Build Script"
echo ""
echo "Usage: $0 [architecture] [options]"
echo ""
echo "Architectures:"
echo " x64, x86_64, amd64 Build for x86-64 architecture"
echo " arm64, aarch64 Build for ARM64 architecture"
echo " (default) Build for current architecture"
echo ""
echo "Options:"
echo " --nips=1,5,6,19 Force specific NIPs (comma-separated)"
echo " --nips=all Include all available NIPs"
echo " --tests, -t Build all test programs in tests/ directory"
echo " --verbose, -v Verbose output"
echo " --no-color Disable colored output"
echo " --help, -h Show this help"
echo ""
echo "Auto-Detection:"
echo " Script automatically scans your .c files for #include statements"
echo " like #include \"nip001.h\" and compiles only needed NIPs."
echo ""
echo "Available NIPs:"
echo " 001 - Basic Protocol (event creation, signing)"
echo " 004 - Encryption (legacy)"
echo " 005 - DNS-based identifiers"
echo " 006 - Key derivation from mnemonic"
echo " 011 - Relay information document"
echo " 013 - Proof of Work"
echo " 019 - Bech32 encoding (nsec/npub)"
echo " 042 - Authentication of clients to relays"
echo " 044 - Encryption (modern)"
echo ""
echo "Examples:"
echo " $0 # Auto-detect NIPs, build for current arch"
echo " $0 x64 # Auto-detect NIPs, build for x64"
echo " $0 --nips=1,6,19 # Force NIPs 1,6,19 only"
echo " $0 arm64 --nips=all # Build all NIPs for ARM64"
echo " $0 -t # Build library and all tests"
exit 0
fi
print_info "NOSTR Core Library - Customer Build Script"
# Check if we're running from the correct directory
CURRENT_DIR=$(basename "$(pwd)")
if [ "$CURRENT_DIR" != "nostr_core_lib" ]; then
print_error "Build script must be run from the nostr_core_lib directory"
echo ""
echo "Current directory: $CURRENT_DIR"
echo "Expected directory: nostr_core_lib"
echo ""
echo "Please change to the nostr_core_lib directory first, then run the build script."
echo ""
echo "Correct usage:"
echo " cd nostr_core_lib"
echo " ./build.sh"
echo ""
echo "Or if nostr_core_lib is in your project directory:"
echo " cd nostr_core_lib"
echo " ./build.sh"
echo " cd .."
echo " gcc your_app.c nostr_core_lib/libnostr_core_x64.a -lz -ldl -lpthread -lm -lssl -lcrypto -lcurl -o your_app"
echo ""
exit 1
fi
print_info "Auto-detecting needed NIPs from your source code..."
###########################################################################################
###########################################################################################
############ AUTODETECT NIPS FROM SOURCE FILES
###########################################################################################
###########################################################################################
NEEDED_NIPS=""
if [ -n "$FORCE_NIPS" ]; then
if [ "$FORCE_NIPS" = "all" ]; then
NEEDED_NIPS="001 004 005 006 011 013 019 042 044"
print_info "Forced: Building all available NIPs"
else
# Convert comma-separated list to space-separated with 3-digit format
NEEDED_NIPS=$(echo "$FORCE_NIPS" | tr ',' ' ' | sed 's/\b\([0-9]\)\b/00\1/g' | sed 's/\b\([0-9][0-9]\)\b/0\1/g')
print_info "Forced NIPs: $NEEDED_NIPS"
fi
else
# Auto-detect from .c files in current directory
if ls *.c >/dev/null 2>&1; then
# Scan for nip*.h includes (with or without nostr_core/ prefix)
DETECTED=$(grep -h '#include[[:space:]]*["\<]\(nostr_core/\)\?nip[0-9][0-9][0-9]\.h["\>]' *.c 2>/dev/null | \
sed 's/.*nip0*\([0-9]*\)\.h.*/\1/' | \
sort -u | \
sed 's/\b\([0-9]\)\b/00\1/g' | sed 's/\b\([0-9][0-9]\)\b/0\1/g')
# Check for nostr_core.h (includes everything)
if grep -q '#include[[:space:]]*["\<]nostr_core\.h["\>]' *.c 2>/dev/null; then
print_info "Found #include \"nostr_core.h\" - building all NIPs"
NEEDED_NIPS="001 004 005 006 011 013 019 042 044"
elif [ -n "$DETECTED" ]; then
NEEDED_NIPS="$DETECTED"
print_success "Auto-detected NIPs: $(echo $NEEDED_NIPS | tr ' ' ',')"
else
print_warning "No NIP includes detected in *.c files"
print_info "Defaulting to basic NIPs: 001, 006, 019"
NEEDED_NIPS="001 006 019"
fi
else
print_warning "No .c files found in current directory"
print_info "Defaulting to basic NIPs: 001, 006, 019"
NEEDED_NIPS="001 006 019"
fi
fi
# If building tests, include all NIPs to ensure test compatibility
if [ "$BUILD_TESTS" = true ] && [ -z "$FORCE_NIPS" ]; then
NEEDED_NIPS="001 004 005 006 011 013 019 042 044"
print_info "Building tests - including all available NIPs for test compatibility"
fi
# Ensure NIP-001 is always included (required for core functionality)
if ! echo "$NEEDED_NIPS" | grep -q "001"; then
NEEDED_NIPS="001 $NEEDED_NIPS"
print_info "Added NIP-001 (required for core functionality)"
fi
###########################################################################################
###########################################################################################
############ AUTODETECT SYSTEM ARCHITECTURE
###########################################################################################
###########################################################################################
# Determine architecture
if [ -z "$ARCHITECTURE" ]; then
ARCH=$(uname -m)
case $ARCH in
x86_64|amd64)
ARCHITECTURE="x64"
;;
aarch64|arm64)
ARCHITECTURE="arm64"
;;
*)
ARCHITECTURE="x64" # Default fallback
print_warning "Unknown architecture '$ARCH', defaulting to x64"
;;
esac
fi
print_info "Target architecture: $ARCHITECTURE"
# Set compiler based on architecture
case $ARCHITECTURE in
x64)
CC="gcc"
ARCH_SUFFIX="x64"
;;
arm64)
CC="aarch64-linux-gnu-gcc"
ARCH_SUFFIX="arm64"
;;
*)
print_error "Unsupported architecture: $ARCHITECTURE"
exit 1
;;
esac
# Check if compiler exists
if ! command -v $CC &> /dev/null; then
print_error "Compiler $CC not found"
if [ "$ARCHITECTURE" = "arm64" ]; then
print_info "Install ARM64 cross-compiler: sudo apt install gcc-aarch64-linux-gnu"
fi
exit 1
fi
###########################################################################################
###########################################################################################
############ CHECK AND BUILD DEPENDENCIES BASED ON NEEDED NIPS
###########################################################################################
###########################################################################################
print_info "Checking dependencies based on needed NIPs..."
# Determine which dependencies are needed based on NIPs
NEED_SECP256K1=false
NEED_OPENSSL=false
NEED_CURL=false
# secp256k1 is always needed (core cryptography for NIP-001)
NEED_SECP256K1=true
# Check if network-dependent NIPs are included
NETWORK_NIPS="005 011" # NIP-005 (DNS), NIP-011 (Relay info)
for nip in $NEEDED_NIPS; do
case $nip in
005|011)
NEED_CURL=true
print_info "NIP-$nip requires HTTP functionality - curl needed"
;;
esac
done
# WebSocket functionality is always enabled (using system OpenSSL)
NEED_OPENSSL=true
NEED_CURL=true
print_info "WebSocket functionality enabled - system OpenSSL and curl required"
if [ "$VERBOSE" = true ]; then
print_info "Dependency requirements:"
[ "$NEED_SECP256K1" = true ] && echo " ✓ secp256k1 (core crypto)"
[ "$NEED_OPENSSL" = true ] && echo " ✓ OpenSSL (TLS/WebSocket)"
[ "$NEED_CURL" = true ] && echo " ✓ curl (HTTP requests)"
fi
# Function to detect system secp256k1
detect_system_secp256k1() {
if [ "$NEED_SECP256K1" != true ]; then
return 0
fi
print_info "Detecting system secp256k1..."
# Try pkg-config first
if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists libsecp256k1; then
SECP256K1_CFLAGS=$(pkg-config --cflags libsecp256k1)
SECP256K1_LIBS=$(pkg-config --libs libsecp256k1)
if [ "$VERBOSE" = true ]; then
print_success "Found secp256k1 via pkg-config"
print_info " CFLAGS: $SECP256K1_CFLAGS"
print_info " LIBS: $SECP256K1_LIBS"
fi
return 0
fi
# Fallback to standard locations
SECP256K1_CFLAGS=""
SECP256K1_LIBS="-lsecp256k1"
# Check common header locations
for header_path in /usr/include/secp256k1.h /usr/local/include/secp256k1.h; do
if [ -f "$header_path" ]; then
if [ "$header_path" != "/usr/include/secp256k1.h" ]; then
SECP256K1_CFLAGS="-I$(dirname $header_path)"
fi
if [ "$VERBOSE" = true ]; then
print_success "Found secp256k1 headers at: $header_path"
fi
break
fi
done
# Check if we can find the libraries
if ! echo '#include <secp256k1.h>' | gcc $SECP256K1_CFLAGS -E - >/dev/null 2>&1; then
print_error "secp256k1 development headers not found"
print_info "Install with: sudo apt install libsecp256k1-dev (Ubuntu/Debian)"
print_info " sudo yum install libsecp256k1-devel (CentOS/RHEL)"
print_info " brew install secp256k1 (macOS)"
exit 1
fi
print_success "System secp256k1 detected"
}
# Function to detect system OpenSSL
detect_system_openssl() {
if [ "$NEED_OPENSSL" != true ]; then
return 0
fi
print_info "Detecting system OpenSSL..."
# Try pkg-config first
if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists openssl; then
OPENSSL_CFLAGS=$(pkg-config --cflags openssl)
OPENSSL_LIBS=$(pkg-config --libs openssl)
if [ "$VERBOSE" = true ]; then
print_success "Found OpenSSL via pkg-config"
print_info " CFLAGS: $OPENSSL_CFLAGS"
print_info " LIBS: $OPENSSL_LIBS"
fi
return 0
fi
# Fallback to standard locations
OPENSSL_CFLAGS=""
OPENSSL_LIBS="-lssl -lcrypto"
# Check common header locations
for header_path in /usr/include/openssl /usr/local/include/openssl; do
if [ -f "$header_path/ssl.h" ]; then
if [ "$header_path" != "/usr/include/openssl" ]; then
OPENSSL_CFLAGS="-I$(dirname $header_path)"
fi
if [ "$VERBOSE" = true ]; then
print_success "Found OpenSSL headers at: $header_path"
fi
break
fi
done
# Check if we can find the libraries
if ! echo '#include <openssl/ssl.h>' | gcc $OPENSSL_CFLAGS -E - >/dev/null 2>&1; then
print_error "OpenSSL development headers not found"
print_info "Install with: sudo apt install libssl-dev (Ubuntu/Debian)"
print_info " sudo yum install openssl-devel (CentOS/RHEL)"
print_info " brew install openssl (macOS)"
exit 1
fi
print_success "System OpenSSL detected"
}
# Function to detect system curl
detect_system_curl() {
if [ "$NEED_CURL" != true ]; then
return 0
fi
print_info "Detecting system curl..."
# Try pkg-config first
if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists libcurl; then
CURL_CFLAGS=$(pkg-config --cflags libcurl)
CURL_LIBS=$(pkg-config --libs libcurl)
if [ "$VERBOSE" = true ]; then
print_success "Found curl via pkg-config"
print_info " CFLAGS: $CURL_CFLAGS"
print_info " LIBS: $CURL_LIBS"
fi
return 0
fi
# Fallback to standard locations
CURL_CFLAGS=""
CURL_LIBS="-lcurl"
# Check common header locations
for header_path in /usr/include/curl /usr/local/include/curl; do
if [ -f "$header_path/curl.h" ]; then
if [ "$header_path" != "/usr/include/curl" ]; then
CURL_CFLAGS="-I$(dirname $header_path)"
fi
if [ "$VERBOSE" = true ]; then
print_success "Found curl headers at: $header_path"
fi
break
fi
done
# Check if we can find the libraries
if ! echo '#include <curl/curl.h>' | gcc $CURL_CFLAGS -E - >/dev/null 2>&1; then
print_error "curl development headers not found"
print_info "Install with: sudo apt install libcurl4-openssl-dev (Ubuntu/Debian)"
print_info " sudo yum install libcurl-devel (CentOS/RHEL)"
print_info " brew install curl (macOS)"
exit 1
fi
print_success "System curl detected"
}
# Build only the needed dependencies
detect_system_secp256k1
detect_system_openssl
detect_system_curl
###########################################################################################
###########################################################################################
############ ADD CORE DEPENDENCIES THAT NEED TO BE BUILT TO THE $SOURCES VARIABLE
###########################################################################################
###########################################################################################
SOURCES="nostr_core/crypto/nostr_secp256k1.c"
SOURCES="$SOURCES nostr_core/crypto/nostr_aes.c"
SOURCES="$SOURCES nostr_core/crypto/nostr_chacha20.c"
SOURCES="$SOURCES cjson/cJSON.c"
SOURCES="$SOURCES nostr_core/utils.c"
SOURCES="$SOURCES nostr_core/nostr_common.c"
SOURCES="$SOURCES nostr_core/core_relays.c"
SOURCES="$SOURCES nostr_websocket/nostr_websocket_openssl.c"
SOURCES="$SOURCES nostr_core/request_validator.c"
NIP_DESCRIPTIONS=""
for nip in $NEEDED_NIPS; do
NIP_FILE="nostr_core/nip${nip}.c"
if [ -f "$NIP_FILE" ]; then
SOURCES="$SOURCES $NIP_FILE"
case $nip in
001) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-001(Basic)" ;;
004) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-004(Encrypt)" ;;
005) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-005(DNS)" ;;
006) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-006(Keys)" ;;
011) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-011(Relay-Info)" ;;
013) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-013(PoW)" ;;
019) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-019(Bech32)" ;;
042) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-042(Auth)" ;;
044) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-044(Encrypt)" ;;
esac
else
print_warning "NIP file not found: $NIP_FILE - skipping"
fi
done
# Build flags
CFLAGS="-Wall -Wextra -std=c99 -fPIC -O2"
CFLAGS="$CFLAGS -DENABLE_FILE_LOGGING -DENABLE_WEBSOCKET_LOGGING -DENABLE_DEBUG_LOGGING"
INCLUDES="-I. -Inostr_core -Inostr_core/crypto -Icjson -Inostr_websocket"
# Add system library includes
if [ -n "$SECP256K1_CFLAGS" ]; then
INCLUDES="$INCLUDES $SECP256K1_CFLAGS"
fi
if [ -n "$OPENSSL_CFLAGS" ]; then
INCLUDES="$INCLUDES $OPENSSL_CFLAGS"
fi
if [ -n "$CURL_CFLAGS" ]; then
INCLUDES="$INCLUDES $CURL_CFLAGS"
fi
# System libraries
SYSTEM_LIBS=""
if [ -n "$SECP256K1_LIBS" ]; then
SYSTEM_LIBS="$SYSTEM_LIBS $SECP256K1_LIBS"
fi
if [ -n "$OPENSSL_LIBS" ]; then
SYSTEM_LIBS="$SYSTEM_LIBS $OPENSSL_LIBS"
fi
if [ -n "$CURL_LIBS" ]; then
SYSTEM_LIBS="$SYSTEM_LIBS $CURL_LIBS"
fi
# Output library name
OUTPUT="libnostr_core_${ARCH_SUFFIX}.a"
print_info "Compiling with: $CC"
print_info "Including:$NIP_DESCRIPTIONS"
if [ "$VERBOSE" = true ]; then
print_info "Sources: $SOURCES"
print_info "Flags: $CFLAGS $INCLUDES"
fi
###########################################################################################
###########################################################################################
############ COMPILE EACH SOURCE FROM $SOURCES INTO A .o FILE
###########################################################################################
###########################################################################################
OBJECTS=""
for source in $SOURCES; do
if [ -f "$source" ]; then
obj_name=$(basename "$source" .c).${ARCH_SUFFIX}.o
OBJECTS="$OBJECTS $obj_name"
if [ "$VERBOSE" = true ]; then
print_info "Compiling: $source -> $obj_name"
fi
#################################################
# THE ACTUAL COMMAND TO COMPILE .c FILES
#################################################
$CC $CFLAGS $INCLUDES -c "$source" -o "$obj_name"
if [ $? -ne 0 ]; then
print_error "Failed to compile $source"
exit 1
fi
else
print_error "Source file not found: $source"
exit 1
fi
done
###########################################################################################
###########################################################################################
############ CREATE THE FINAL STATIC LIBRARY FOR THE PROJECT: libnostr_core_XX.a
############ BY LINKING IN ALL OUR .o FILES THAT ARE REQUESTED TO BE ADDED.
###########################################################################################
###########################################################################################
print_info "Creating static library with system dependencies: $OUTPUT"
# Note: All crypto libraries (secp256k1, OpenSSL, curl) are now system dependencies
# Only our own object files are included in the static library
#########################################################
### THE ACTUAL COMMAND TO LINK .o FILES INTO A .a FILE
#########################################################
ar rcs "$OUTPUT" $OBJECTS
AR_RESULT=$?
###########################################################################################
###########################################################################################
############ IF THE LINKING OCCURED SUCCESSFULLY, BUILD THE TEST FILE EXECUTABLES
############ BY LINKING IN ALL OUR .o FILES THAT ARE REQUESTED TO BE ADDED.
###########################################################################################
###########################################################################################
if [ $AR_RESULT -eq 0 ]; then
# Cleanup object files
rm -f $OBJECTS
# Show library info
size_kb=$(du -k "$OUTPUT" | cut -f1)
print_success "Built $OUTPUT (${size_kb}KB) with:$NIP_DESCRIPTIONS"
# Build tests if requested
if [ "$BUILD_TESTS" = true ]; then
print_info "Scanning tests/ directory for test programs..."
if [ ! -d "tests" ]; then
print_warning "tests/ directory not found - skipping test builds"
else
TEST_COUNT=0
SUCCESS_COUNT=0
# Find all .c files in tests/ directory (not subdirectories)
while IFS= read -r -d '' test_file; do
TEST_COUNT=$((TEST_COUNT + 1))
test_name=$(basename "$test_file" .c)
test_exe="tests/$test_name"
print_info "Building test: $test_name"
# Test compilation with system libraries
LINK_FLAGS="-lz -ldl -lpthread -lm $SYSTEM_LIBS"
if [ "$VERBOSE" = true ]; then
print_info " Command: $CC $CFLAGS $INCLUDES \"$test_file\" -o \"$test_exe\" ./$OUTPUT $LINK_FLAGS"
fi
if $CC $CFLAGS $INCLUDES "$test_file" -o "$test_exe" "./$OUTPUT" $LINK_FLAGS; then
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
print_success "Built $test_name"
if [ "$VERBOSE" = true ]; then
print_info " Executable: $test_exe"
fi
else
print_error " Failed to build: $test_name"
fi
done < <(find tests/ -maxdepth 1 -name "*.c" -type f -print0)
if [ $TEST_COUNT -eq 0 ]; then
print_warning "No .c files found in tests/ directory"
else
print_success "Built $SUCCESS_COUNT/$TEST_COUNT test programs"
fi
fi
echo ""
fi
echo "Usage in your project:"
echo " gcc your_app.c $OUTPUT -lz -ldl -lpthread -lm $SYSTEM_LIBS -o your_app"
echo ""
else
print_error "Failed to create static library"
exit 1
fi