diff --git a/Makefile.win b/Makefile.win new file mode 100644 index 00000000..d27ebd32 --- /dev/null +++ b/Makefile.win @@ -0,0 +1,330 @@ +# Makefile to build curl-impersonate +# Some Makefile tricks were taken from https://tech.davis-hansson.com/p/make/ + +SHELL := bash +.ONESHELL: +.SHELLFLAGS := -euc +.DELETE_ON_ERROR: +# MAKEFLAGS += --warn-undefined-variables +# MAKEFLAGS += --no-builtin-rules + +BROTLI_VERSION := 1.0.9 + # In case this is changed, update build-and-test-make.yml as well +BORING_SSL_COMMIT := d24a38200fef19150eef00cad35b138936c08767 +NGHTTP2_VERSION := nghttp2-1.56.0 +NGHTTP2_URL := https://github.com/nghttp2/nghttp2/releases/download/v1.56.0/nghttp2-1.56.0.tar.bz2 +CURL_VERSION := curl-8.1.1 + +brotli_install_dir := $(abspath brotli-$(BROTLI_VERSION)/out/installed) +brotli_static_libs := $(brotli_install_dir)/lib/libbrotlicommon-static.a $(brotli_install_dir)/lib/libbrotlidec-static.a +boringssl_install_dir := $(abspath boringssl/build) +boringssl_static_libs := $(boringssl_install_dir)/lib/libssl.a $(boringssl_install_dir)/lib/libcrypto.a +nghttp2_install_dir := $(abspath $(NGHTTP2_VERSION)/installed) +nghttp2_static_libs := $(nghttp2_install_dir)/lib/libnghttp2.a + +# Dependencies needed to compile the Chrome version +chrome_libs := $(brotli_static_libs) $(boringssl_static_libs) $(nghttp2_static_libs) + +# The following variables will be set by the configure script. +prefix = /usr/local +exec_prefix = ${prefix} +srcdir = /Users/yifei/repos/curl-impersonate/build/.. +host = aarch64-apple-darwin23.0.0 +host_alias = +host_cpu = aarch64 +host_os = darwin23.0.0 +build = aarch64-apple-darwin23.0.0 +# Whether to link curl-impersonate with libcurl-impersonate statically. +static_build = no +# Whether the user provided a specific find for zlib +with_zlib = +# Path to be passed to curl's --with-ca-bundle configure option. +with_ca_bundle = +# Path to be passed to curl's --with-ca-path configure option. +with_ca_path = +# Path to be passed to curl's --with-libnssckbi configure option (an option +# added for curl-impersonate). +with_libnssckbi = + +CC = gcc +CXX = g++ +STRIP = strip + +# Auto-generate Makefile help. +# Borrowed from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html +help: ## Show this help message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' +.PHONY: help +.DEFAULT_GOAL := help + +chrome-build: $(CURL_VERSION)/.chrome ## Build the Chrome version of curl-impersonate + cd $(CURL_VERSION) + # Don't pass this Makefile's MAKEFLAGS + $(MAKE) MAKEFLAGS= +.PHONY: chrome-build + +chrome-checkbuild: ## Run basic checks on the built binary +ifeq ($(host),$(build)) + cd $(CURL_VERSION) + # Make sure all needed features were compiled in + ./src/curl-impersonate-chrome -V | grep -q zlib + ./src/curl-impersonate-chrome -V | grep -q brotli + ./src/curl-impersonate-chrome -V | grep -q nghttp2 + ./src/curl-impersonate-chrome -V | grep -q BoringSSL + $(info Build OK) +else + $(info Cross compiling, skipping checkbuild) +endif +.PHONY: chrome-checkbuild + +chrome-install: ## Install the Chrome version of curl-impersonate after build + cd $(CURL_VERSION) + $(MAKE) install-exec MAKEFLAGS= + # Wrapper scripts for the Chrome version (e.g. 'curl_chrome99') + install $(srcdir)/chrome/curl_chrome* $(srcdir)/chrome/curl_edge* $(srcdir)/chrome/curl_safari* ${exec_prefix}/bin +.PHONY: chrome-install + +chrome-install-strip: ## Like 'chrome-install', but strip binaries for smaller size + cd $(CURL_VERSION) + $(MAKE) install-exec MAKEFLAGS= + # We could have used 'install-strip' but then the docs would be installed as well. + # Instead strip manually. + $(STRIP) ${exec_prefix}/bin/curl-impersonate-chrome + # Wrapper scripts for the Chrome version (e.g. 'curl_chrome99') + install $(srcdir)/chrome/curl_chrome* $(srcdir)/chrome/curl_edge* $(srcdir)/chrome/curl_safari* ${exec_prefix}/bin +.PHONY: chrome-install-strip + +chrome-uninstall: ## Uninstall the Chrome version of curl-impersonate after 'make install' + cd $(CURL_VERSION) + $(MAKE) uninstall MAKEFLAGS= + rm -Rf ${exec_prefix}/bin/curl_chrome* ${exec_prefix}/bin/curl_edge* ${exec_prefix}/bin/curl_safari* +.PHONY: chrome-uninstall + +chrome-clean: ## Clean build artifacts of the Chrome version. Use after re-running './configure' + cd $(CURL_VERSION) + $(MAKE) clean MAKEFLAGS= + rm -f .chrome +.PHONY: chrome-clean + +clean: ## Remove all build artifacts, including dependencies + rm -Rf brotli-$(BROTLI_VERSION).tar.gz brotli-$(BROTLI_VERSION) + rm -Rf $(NSS_VERSION).tar.gz $(NSS_VERSION) + rm -Rf boringssl.zip boringssl + rm -Rf $(NGHTTP2_VERSION).tar.bz2 $(NGHTTP2_VERSION) + rm -Rf $(CURL_VERSION).tar.xz $(CURL_VERSION) + +brotli-$(BROTLI_VERSION).tar.gz: + curl -L "https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz" \ + -o "brotli-${BROTLI_VERSION}.tar.gz" + +$(brotli_static_libs): brotli-$(BROTLI_VERSION).tar.gz + tar xf brotli-$(BROTLI_VERSION).tar.gz + cd brotli-$(BROTLI_VERSION) + mkdir -p out + cd out + + # Convert autoconf style os name to CMake style os name. + case $(host_os) in \ + linux*) \ + system_name=Linux \ + ;; \ + darwin*) \ + system_name=Darwin \ + ;; \ + *) \ + system_name=$(host_os) \ + ;; \ + esac + + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=./installed \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_CXX_COMPILER=$(CXX) \ + -DCMAKE_C_COMPILER=$(CC) \ + -DCMAKE_SYSTEM_NAME=$$system_name \ + -DCMAKE_SYSTEM_PROCESSOR=$(host_cpu) \ + .. + + cmake --build . --config Release --target install + + +$(NSS_VERSION).tar.gz: + curl -L -o $(NSS_VERSION).tar.gz $(NSS_URL) + +$(nss_static_libs): $(NSS_VERSION).tar.gz + tar xf $(NSS_VERSION).tar.gz + +ifeq ($(host),$(build)) + # Native build, use NSS' build script. + cd $(NSS_VERSION)/nss + ./build.sh -o --disable-tests --static --python=python3 +else + # We are cross compiling. + # Cross compiling NSS is not supported by its build script and is poorly + # documented. We need to compile NSPR manually and only then compile nss. + case $(host_cpu) in \ + *64*) \ + use_64="1"; \ + nspr_configure_flags="--enable-64bit"; \ + ;; \ + *) \ + use_64="0"; \ + nspr_configure_flags=""; \ + ;; \ + esac + + # Cross-compile nspr separately + cd $(NSS_VERSION)/nspr + ./configure --prefix=$(nss_install_dir) \ + --disable-debug --enable-optimize \ + --target=$(host_alias) \ + $$nspr_configure_flags + $(MAKE) MAKEFLAGS= + $(MAKE) install MAKEFLAGS= + + # Now we can run ./build.sh with the already built nspr + cd ../nss + CC=$(CC) CXX=$(CXX) CCC=$(CXX) \ + ./build.sh -o --disable-tests --static --python=python3 \ + --with-nspr=$(nss_install_dir)/include/nspr:$(nss_install_dir)/lib \ + --target=$(host_cpu) \ + -Duse_system_zlib=0 \ + -Dsign_libs=0 +endif + # Hack for macOS: Remove dynamic libraries to force the linker to use the + # static ones when linking curl. + rm -Rf $(nss_install_dir)/lib/*.dylib + + +boringssl.zip: + curl -L https://github.com/google/boringssl/archive/$(BORING_SSL_COMMIT).zip \ + -o boringssl.zip + +# Patch boringssl and use a dummy '.patched' file to mark it patched +boringssl/.patched: $(srcdir)/chrome/patches/boringssl-*.patch + unzip -q -o boringssl.zip + mv boringssl-$(BORING_SSL_COMMIT) boringssl + cd boringssl/ + for p in $^; do patch -p1 < $$p; done + touch .patched + +$(boringssl_static_libs): boringssl.zip boringssl/.patched + mkdir -p $(boringssl_install_dir) + cd $(boringssl_install_dir) + + # Convert autoconf style os name to CMake style os name. + case $(host_os) in \ + linux*) \ + system_name=Linux \ + ;; \ + darwin*) \ + system_name=Darwin \ + ;; \ + *) \ + system_name=Linux \ + ;; \ + esac + + # The extra CMAKE_C_FLAGS are needed because otherwise boringssl fails to + # compile in release mode on some systems with gcc 12 (e.g. Fedora). + # In addition, guard these options with -Wno-unknown-warning-option to + # prevent clang from failing on them. + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_POSITION_INDEPENDENT_CODE=on \ + -DCMAKE_C_FLAGS="-Wno-unknown-warning-option -Wno-stringop-overflow -Wno-array-bounds" \ + -DCMAKE_CXX_COMPILER=$(CXX) \ + -DCMAKE_C_COMPILER=$(CC) \ + -DCMAKE_SYSTEM_NAME=$$system_name \ + -DCMAKE_SYSTEM_PROCESSOR=$(host_cpu) \ + -GNinja \ + .. + ninja + # Fix the directory structure so that curl can compile against it. + # See https://everything.curl.dev/source/build/tls/boringssl + mkdir -p lib + ln -sf ../crypto/libcrypto.a lib/libcrypto.a + ln -sf ../ssl/libssl.a lib/libssl.a + cp -Rf ../include . + + +$(NGHTTP2_VERSION).tar.bz2: + curl -L $(NGHTTP2_URL) -o $(NGHTTP2_VERSION).tar.bz2 + +$(nghttp2_static_libs): $(NGHTTP2_VERSION).tar.bz2 + tar -xf $(NGHTTP2_VERSION).tar.bz2 + cd $(NGHTTP2_VERSION) + + # Set up the configure flags to nghttp2. + # If the user provided the --host flag to our configure script + # (for cross compilation), then pass it on to nghttp2. + { \ + config_flags="--prefix=$(nghttp2_install_dir)"; \ + config_flags="$$config_flags --with-pic --enable-lib-only"; \ + config_flags="$$config_flags --disable-shared --disable-python-bindings"; \ + if test -n "$(host_alias)"; then \ + config_flags="$$config_flags --host=$(host_alias)"; \ + fi; \ + } + + ./configure $$config_flags + $(MAKE) MAKEFLAGS= + $(MAKE) install MAKEFLAGS= + +$(CURL_VERSION).tar.xz: + curl -L "https://curl.se/download/$(CURL_VERSION).tar.xz" \ + -o "$(CURL_VERSION).tar.xz" + +# Apply the "Chorme version" patches and mark using a dummy file +$(CURL_VERSION)/.patched-chrome: $(srcdir)/chrome/patches/curl-*.patch + rm -Rf $(CURL_VERSION) + tar -xf $(CURL_VERSION).tar.xz + cd $(CURL_VERSION) + for p in $^; do patch -p1 < $$p; done + # Re-generate the configure script + autoreconf -fi + touch .patched-chrome + rm -f .patched-ff + +# This is a small hack that flags that curl was patched and configured in the "chrome" version +$(CURL_VERSION)/.chrome: $(chrome_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION)/.patched-chrome + cd $(CURL_VERSION) + + # Set up the configure flags to curl. + # If the user provided the --host flag to our configure script + # (for cross compilation), then pass it on to curl. + { \ + config_flags="--prefix=/usr/local"; \ + config_flags="$$config_flags --with-nghttp2=$(nghttp2_install_dir)"; \ + config_flags="$$config_flags --with-brotli=$(brotli_install_dir)"; \ + config_flags="$$config_flags --with-openssl=$(boringssl_install_dir)"; \ + config_flags="$$config_flags --without-zstd"; \ + config_flags="$$config_flags --enable-websockets"; \ + config_flags="$$config_flags --enable-ech"; \ + config_flags="$$config_flags USE_CURL_SSLKEYLOGFILE=true"; \ + if test "$(static_build)" = "yes"; then \ + config_flags="$$config_flags --enable-static --disable-shared"; + fi; \ + if test -n "$(host_alias)"; then \ + config_flags="$$config_flags --host=$(host_alias)"; \ + fi; \ + if test -n "$(with_zlib)"; then \ + config_flags="$$config_flags --with-zlib=$(with_zlib)"; \ + else \ + config_flags+=" --with-zlib"; \ + fi; \ + if test -n "$(with_ca_bundle)"; then \ + config_flags="$$config_flags --with-ca-bundle=$(with_ca_bundle)"; \ + fi; \ + if test -n "$(with_ca_path)"; then \ + config_flags="$$config_flags --with-ca-path=$(with_ca_path)"; \ + fi; \ + add_libs="-pthread"; \ + } + + echo "Configuring curl with: $$config_flags" + + ./configure $$config_flags LIBS="$$add_libs" + + # Remove possible leftovers from a previous compilation + $(MAKE) clean MAKEFLAGS= + touch .chrome